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 (UMA and Pyth), batch operations, 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:

  • 100+ external functions across 18 business domains — far beyond the 24KB contract size limit
  • Individual facets can be upgraded without touching unrelated logic
  • New features — like Pyth-powered price markets, batch order operations, or per-market access control — can be added by deploying a single new facet

Facets

The protocol deploys 21 facets: 3 core Diamond infrastructure + 18 business logic.

Core Infrastructure

FacetPurpose
DiamondCutFacetUpgrade entry point — diamondCut()
DiamondLoupeFacetIntrospection — facets(), facetAddress()
OwnershipFacetDiamond ownership — transferOwnership(), owner()

Business Logic

FacetDomainKey Functions
VenueFacetVenue configcreateVenue(), updateFees(), updateVenue(), setPaused()
ProtocolFacetProtocol configsetProtocolFeeBps(), setProtocolTreasury(), suspendVenue()
AccessControlFacetAccess gatessetMarketAccessControl(), isTradingAllowed()
MarketsFacetMarket creationcreateMarket(), pauseMarket(), unpauseMarket()
MarketGroupFacetMarket groupscreateMarketGroup(), addMarketToGroup(), activateMarketGroup()
PriceMarketFacetPrice marketscreatePriceMarket() (Pyth-fed)
MetadataFacetEvent metadataupdateMarketMetadata(), updateMarketGroupMetadata()
TagsFacetEvent tagsupdateMarketTags(), updateMarketGroupTags()
LimitOrdersFacetLimit ordersplaceOrder(), cancelOrder(), cancelOrdersOnResolvedMarket()
MarketOrdersFacetMarket ordersplaceMarketOrder() (FOK/FAK)
BatchOrdersFacetBatch operationsbatchPlaceOrders(), batchCancelOrders(), cancelAndReplace()
MatchingFacetOrder matchingmatchOrders()
OrderBookFacetRead-only queriesgetTopOfBook(), getMarkPrice()
VaultFacetToken custodysplitPosition(), mergePositions()
ResolutionFacetUMA resolutionassertMarketOutcome(), settleAssertion(), reportResolution()
PythResolutionFacetPyth resolutionresolvePriceMarket()
NegRiskFacetPosition conversionconvertPositions()
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. Every new facet (batch orders, price markets, per-market access control) was added this way without disturbing existing storage or state.

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
LibProtocolStorageProtocol fee bps, treasury, oracle addresses
LibVenueStorageVenue configs, ID counter
LibMarketRegistryStorageMarket lifecycle, ID counter
LibMarketTradingStoragePosition IDs, volume, paused flag
LibMarketOracleStorageCTF condition, UMA params
LibOrderStorageOrder structs, ID counter
LibOrderBookStorageTick levels, top of book
LibFillStorageFill records
LibMarketGroupStorageGroup data
LibResolutionStorageUMA assertion data
LibPriceMarketStoragePyth feed, strike, close time
LibNegRiskStorageWrapped collateral mappings
LibAccessControlStoragePer-market access overrides

External Dependencies

DependencyPurpose
Gnosis CTFERC-1155 outcome tokens — split, merge, redeem positions
UMA Optimistic Oracle V3Decentralized dispute resolution for binary and grouped markets
Pyth NetworkPrice feeds for auto-resolving price markets
OpenZeppelinReentrancyGuard, IERC20, IERC1155

Security Model

TierWhoCan Do
Diamond OwnerProtocol adminUpgrade facets, set treasury/oracle/CTF, set protocol fee (0–200 bps), suspend venues
Venue Operatormsg.sender of createVenueUpdate venue config, pause/unpause venue, pause individual markets (immutable role)
Market Creatormsg.sender of createMarketUpdate tags/metadata, set per-market access control
External Access ControlOptional per-venue or per-market contractsGate trading and market creation
ParticipantsAnyonePlace orders, match, assert outcomes, resolve price markets

There is no global protocol pause. Pausing is scoped to individual venues (by their operator) or individual markets (by operator/creator). The protocol owner holds a separate suspend lever for emergencies.

What's Next