OddMaki
Configuration

Access Control

Control who can trade and create markets on your venue — open access, token gating, whitelists, or custom logic.

OddMaki venues have two independent access gates at the venue level. Trading access can also be overridden per-market for more granular control. Each gate points to a contract implementing IAccessControl, or the zero address for public access.

Two Independent Gates

GateControlsScope
tradingAccessControlWho can place orders and tradeVenue-level, can be overridden per-market
creationAccessControlWho can create marketsVenue-level only

Both are set at venue creation and can be updated later via client.venue.updateVenue(). The venue operator always bypasses both checks.

Every access control contract implements a single function:

interface IAccessControl {
    function isAllowed(address user) external view returns (bool);
}

If the external call reverts, access is denied (the protocol uses try/catch internally).

How Access Is Checked

Trading access (checked when placing orders):

  1. Venue operator? → always allowed
  2. Market-level AC override set? → call isAllowed(user) on the market-level contract
  3. Venue-level tradingAccessControl set? → call isAllowed(user) on the venue-level contract
  4. Neither set (address(0))? → public, anyone can trade

Creation access (checked when creating markets):

  1. Venue operator? → always allowed
  2. Venue-level creationAccessControl set? → call isAllowed(user) on the venue-level contract
  3. Not set (address(0))? → public, anyone can create

Open Access

Set the access control address to 0x0000000000000000000000000000000000000000 (the zero address) for permissionless access. This is the default.

const tx = await client.venue.createVenue({
  // ...
  tradingAccessControl: '0x0000000000000000000000000000000000000000',   // anyone can trade
  creationAccessControl: '0x0000000000000000000000000000000000000000',  // anyone can create markets
});

Pre-built Contracts

The protocol ships three access control contracts you can deploy directly through the SDK — no need to write or deploy Solidity yourself.

ContractUse CaseConfiguration
WhitelistAccessControlOwner-managed address allowlistMutable: add/remove addresses after deploy
TokenGatedAccessControlERC-20 minimum balance checkImmutable: token and minBalance set at deploy
NFTGatedAccessControlERC-721 or ERC-1155 ownership checkImmutable: NFT contract set at deploy

Deploy any of these via the SDK:

// Deploy a whitelist — caller becomes owner
const hash = await client.accessControl.deployWhitelist();

// Deploy a token gate — holders of ≥100 USDC can access
const hash = await client.accessControl.deployTokenGated({
  token: '0xUSDCAddress...',
  minBalance: parseUnits('100', 6),
});

// Deploy an NFT gate — any holder of the ERC-721 can access
const hash = await client.accessControl.deployNFTGated({
  nftContract: '0xNFTAddress...',
  isERC1155: false,
  tokenId: 0n,
});

// Deploy an ERC-1155 gate — holders of a specific token ID
const hash = await client.accessControl.deployNFTGated({
  nftContract: '0xERC1155Address...',
  isERC1155: true,
  tokenId: 42n,
});

The deployed contract address is emitted in the AccessControlDeployed event log. Extract it from the transaction receipt.

Market-Level Overrides

Trading access can be overridden for individual markets. This lets you apply a different access policy to specific markets while keeping a venue-wide default. Creation access is venue-level only — there is no per-market override for market creation.

// Set a different AC contract for a specific market
const hash = await client.accessControl.setMarketTradingAC({
  marketId: 42n,
  acContract: '0xMarketSpecificWhitelist...',
});

// Remove the override (falls back to venue-level AC)
const hash = await client.accessControl.removeMarketTradingAC({
  marketId: 42n,
});

// Query: can this user trade on this specific market?
const allowed = await client.accessControl.canTradeOnMarket({
  user: '0xUserAddress...',
  marketId: 42n,
});

Only the venue operator can set or remove market-level overrides.

Managing Whitelists

For WhitelistAccessControl contracts, the SDK provides methods to manage the allowlist. These call the whitelist contract directly (not through the Diamond).

// Add users to the whitelist (owner only)
await client.accessControl.addToWhitelist({
  acContract: '0xWhitelistAddress...',
  users: ['0xAlice...', '0xBob...'],
});

// Remove users
await client.accessControl.removeFromWhitelist({
  acContract: '0xWhitelistAddress...',
  users: ['0xAlice...'],
});

// Check if a user is whitelisted
const ok = await client.accessControl.isWhitelisted({
  acContract: '0xWhitelistAddress...',
  user: '0xAlice...',
});

Updating Venue-Level Access Control

Update either gate after venue creation:

const hash = await client.venue.updateVenue({
  venueId: 1n,
  name: 'My Venue',
  metadata: '',
  tradingAccessControl: newTradingAccessControl,
  creationAccessControl: newCreationAccessControl,
  feeRecipient: '0xFeeRecipient...',
});

Changes take effect immediately. The feeRecipient cannot be the zero address.

Custom Contracts

Any contract that implements the IAccessControl interface works. This lets you build logic beyond what the pre-built contracts offer — time windows, reputation scores, multi-sig approvals, or any on-chain condition.

What's Next