OddMaki
Protocol

Architecture

OddMaki's smart contract architecture — EIP-2535 Diamond proxy, facets, and modular upgrade mechanism.

OddMaki is deployed as a single EIP-2535 Diamond proxy on Base. All protocol functionality — venue management, market creation, orderbook, matching, resolution, and vault custody — lives in separate facets that share state through isolated storage libraries.

Diamond Proxy (EIP-2535)

The Diamond pattern splits a monolithic contract into multiple implementation contracts (facets) behind a single proxy address. When a call arrives, the fallback() function looks up which facet implements the called selector, then delegatecalls into it. All facets share the same storage space.

Why EIP-2535:

  • 65+ external functions across 12 business domains — far beyond the 24KB contract size limit
  • Individual facets can be upgraded without touching unrelated logic
  • New features can be added by deploying a single new facet

Facets

The protocol deploys 15 facets: 3 core Diamond infrastructure + 12 business logic.

FacetDomainKey Functions
DiamondCutFacetUpgradesdiamondCut()
DiamondLoupeFacetIntrospectionfacets(), facetAddress()
OwnershipFacetOwnershiptransferOwnership(), owner()
VenueFacetVenue configcreateVenue(), updateVenueFees(), pauseVenue()
MarketsFacetMarket creationcreateMarket(), addMarket(), addPlaceholderMarkets()
MarketGroupFacetMarket groupscreateMarketGroup(), activateMarketGroup()
LimitOrdersFacetLimit ordersplaceOrder(), cancelOrder()
MatchingFacetOrder matchingmatchOrders()
MarketOrdersFacetMarket ordersplaceMarketOrder() (FOK/FAK)
OrderBookFacetRead-only queriesgetTopOfBook(), getMarkPrice()
VaultFacetToken custodysplitPosition(), mergePositions()
ResolutionFacetUMA resolutionassertMarketOutcome(), settleAssertion(), reportResolution()
NegRiskFacetPosition conversionconvertPositions()
ProtocolFacetProtocol configsetProtocolTreasury(), setUmaOracle()
ERC1155ReceiverFacetToken receivingonERC1155Received()

Upgrade Mechanism

The Diamond owner calls diamondCut() with an array of FacetCut structs:

ActionWhat It Does
AddMap new function selectors to a new facet
ReplacePoint existing selectors to an updated facet
RemoveDelete selector mappings (facetAddress must be address(0))

An optional initialization hook (_init + _calldata) runs after applying cuts — useful for one-time migration logic.

Storage Model

All state uses namespaced storage — each domain gets its own struct at a unique keccak256 slot. This prevents collision between facets.

Storage LibraryDomain
LibVenueStorageVenue configs, ID counter
LibMarketRegistryStorageMarket lifecycle, ID counter
LibMarketTradingStoragePosition IDs, volume, active flag
LibMarketOracleStorageCTF condition, UMA params
LibOrderStorageOrder structs, ID counter
LibOrderBookStorageTick levels, top of book
LibFillStorageFill records
LibMarketGroupStorageGroup data
LibResolutionStorageUMA assertion data
LibNegRiskStorageWrapped collateral mappings

External Dependencies

DependencyPurpose
Gnosis CTFERC-1155 outcome tokens — split, merge, redeem positions
UMA Optimistic Oracle V3Decentralized dispute resolution for market outcomes
OpenZeppelinReentrancyGuard, IERC20, IERC1155

Security Model

TierWhoCan Do
Diamond OwnerProtocol adminUpgrade facets, set treasury/oracle/CTF
Venue Operatormsg.sender of createVenueUpdate venue config, pause/unpause (immutable role)
External Access ControlOptional per-venue contractsGate trading and market creation
ParticipantsAnyonePlace orders, match, assert outcomes

There is no global protocol pause. Pausing is scoped to individual venues.

What's Next