Skip to content

Contracts ​

The contracts are in contracts/src/. They use Solidity 0.8.28 with the optimizer at 200 runs, IR compilation, and the cancun EVM version.

Test contracts

TestUSDC has a public mint function. TestOracle accepts prices from one test operator. Market.testOracle() always returns true. These contracts are not suitable for real funds. No external security audit is complete.

ContractFilePurpose
MarketMarket.solBook, ladders, collateral, funding, margin, and liquidation for one asset
QueuedMarketQueuedMarket.solMarket plus an on-chain order queue and combined quote calls
SessionRegistrySessionRegistry.solSession permissions for each account, session key, and market
TestOracleTestOracle.solTest price records. Its owner is the oracle signer.
TestUSDCTestUSDC.solTest collateral token with 6 decimals and the symbol tUSDC
VarianceMathVarianceMath.solFixed-point logarithm and squared return

Build and test ​

sh
forge build --root contracts
forge test --root contracts -vv
forge fmt --root contracts --check

The test files are Market.t.sol, MarketBook.t.sol, MarketLadder.t.sol, MarketGas.t.sol, and QueuedMarket.t.sol in contracts/test/.

Units ​

Prices, quantities, cash, fees, and margin have 18 decimals. deposit and withdraw take raw token amounts with 6 decimals. One token unit becomes 1e12 accounting units. All token operations use the account of the caller. A session cannot name a different withdrawal account.

Constants of Market ​

ConstantValueMeaning
MULTIPLIER100USDC for each contract and each unit of annualized variance
HORIZON_SECONDS7 daysFunding horizon
YEAR_SECONDS365 daysYear basis
RETURN_CAP0.0025Largest paid squared log return for each accepted observation
POSITION_LIMIT1,000 contractsFor each account and reserved direction
MAX_QUOTE100Largest order price and quote center
MAX_ORDERS128Largest number of real resting orders
MAX_MATCHES32Largest number of match attempts for one order
MAX_ORDER_AGE3,600 secondsLargest order life and quote life
MAX_ORACLE_DELAY5 secondsLargest delay between the observation timestamp and the block time
MAX_LADDERS4Ladder slots in one market
MAX_LEVELS32Levels of one ladder
SIZE_UNIT0.01 contractsUnit of a ladder size
MAX_DEPTH384Largest depth argument of getBook

Values that a market gets at deployment:

ValueRule
observationSecondsConstructor input, from 1 to 600 seconds
maxGap3 * observationSeconds
maxMarkAge2 * observationSeconds
quoterConstructor input. Only this address can call quote.
oracleSignerThe owner of the TestOracle at deployment

Other rules:

RuleValue
Trade fee0.05% of size * 100 * execution price for each side
Initial mark reserve100 * (0.25 + 0.5 * mark) for each contract
Maintenance mark reserve60% of the initial reserve
Funding buffers, initial and maintenance3 and 1 observations
Liquidation price range25% from the current valid mark
Mark depth2 contracts for each side, from two or more owners, with a spread of at most 20% of the midpoint

See Margin and liquidation and Order book and mark for the rules in context.

Functions of Market ​

Collateral ​

FunctionCallerNotes
deposit(amount)AccountRaw token amount with 6 decimals. The account must approve the market first.
withdraw(amount)AccountNeeds a valid mark, no due observation, no oracle halt, and initial margin after the withdrawal

Orders ​

FunctionCallerNotes
placeOrder(isBuy, price, size, ioc, expiry, maxMatches)AccountReturns the order ID and the filled, resting, and canceled sizes
placeOrderWithSig(action, signature)Any address, usually the relayerThe session key signs the OrderAction
cancel(orderId)Order ownerStays available during an oracle halt
cancelWithSig(action, signature)Any address, usually the relayerThe session key signs the CancelAction

Maker ladders and quotes ​

FunctionCallerNotes
setLadder(index, first, step, levels, base, sizeStep)MakerRegisters or replaces the ladder in one slot. levels = 0 clears it.
quote(center, tick, validUntil, updateData)QuoterMoves all ladders and updates the mark. With update data, it also submits the observation.

Oracle, mark, and risk ​

FunctionCallerNotes
submitObservation(updateData)Any addressThe data must carry a valid signature of the oracle signer, or the timestamp of a stored record
updateMark()Any addressCalculates the mark from the current book
syncAccount(account)Any addressStores the pending funding of an account
liquidate(account, maxMatches)Any addressIOC close attempt for an account below maintenance margin

Reads ​

FunctionResult
accountState(account)Cash, positions, entry, funding, fees, equity, margins, free collateral, and the liquidation flag
getBook(depth)Bids and asks of the merged book, real orders and ladder levels
markPrice(), charge()The current mark and the charge of the current interval
oraclePrice(), oracleTime()The last accepted price and its timestamp
nextBoundary(), observationDue()The next observation boundary and whether it passed
halted(), markFrozen()The oracle halt state and the mark freeze state
fundingIndex(), fundingIndices(epoch), epoch()The funding index and its history
varianceAccumulator(), rawAccumulator()Sums of the capped and the raw squared returns
ladders(index), ladderFills(index), quoteState()Ladder shapes, used ladder size, and the last quote
nonces(account, session)The next nonce of a session
feePool()Recorded trade fees. There is no fee withdrawal function.

Functions of QueuedMarket ​

FunctionCallerNotes
enqueue(requests)AccountUp to 16 IOC requests for each call. At most 128 pending requests. Needs a valid mark and no oracle halt.
cancelQueued(id)Request ownerReleases the reservation
clearQueue(maxOrders)Any addressProcesses up to 16 requests in queue sequence
quoteAndClear(center, tick, validUntil, updateData, maxOrders)Quoterquote, then clearQueue
quoteAndTake(center, tick, validUntil, updateData, isBuy, price, size, expiry, maxMatches)Quoterquote, then one IOC order for the caller
queueHead(), queueTail(), pendingOrders(id)ReadQueue state

An expired queue entry keeps its reservation until a call cancels or processes it.

Events of Market ​

EventWhen
Deposited, WithdrawnCollateral moves
OrderPlacedThe contract accepts an order for execution
OrderResultEnd of an order call: filled, resting, canceled
OrderCanceledA resting order or a ladder side leaves the book. Reasons: 0 owner, 1 expired, 2 maker margin, 3 liquidation.
TradeOne fill between a maker and a taker. liquidation is true for a forced fill.
MarkUpdatedEach mark calculation, with the freeze state
ObservationEach accepted observation, with the raw and capped squared return, the payment, the charges, and the skipped and chargeFrozen flags
AccountSyncedThe contract stores funding for an account
LiquidationAttemptEach liquidate call, with the filled size, the remaining position, the equity, the deficit, and the waiting flag
LadderSet, QuotedLadder registration and each quote

QueuedMarket adds OrderQueued, QueueExecuted, and QueueCanceled. The reasons of QueueCanceled are 0 owner cancellation, 1 expired, and 2 rejected at execution.

SessionRegistry ​

FunctionNotes
authorize(session, market, expiry, maxExposure)The caller gives a session key permission for one market. maxExposure is at most 1,000,000 contracts in 18-decimal units. The market position limit still applies.
revoke(session, market)The caller removes the permission
check(account, session, market)Returns the exposure limit. Reverts when the permission is expired or revoked.

Signed actions ​

EIP-712 uses the domain name VarianceMarket, the version 1, the current chain ID, and the market address.

text
OrderAction(address account,address session,bool isBuy,uint256 price,uint256 size,
            bool ioc,uint64 expiry,uint32 maxMatches,uint256 nonce,uint64 deadline)

CancelAction(address account,address session,uint256 orderId,uint256 nonce,uint64 deadline)

Nonces are sequential. They are scoped to the account and the session in each market. The contract checks the signature, the action deadline, the session expiry, the revocation, the market scope, and the reserved exposure limit.

A session expiry or a revocation blocks new signed actions. It does not cancel orders that the contract already accepted. The main wallet can still cancel them.

The test oracle signature uses this type:

text
Observation(uint256 chainId,address oracle,bytes32 feedId,uint256 price,uint64 timestamp)

TestOracle ​

FunctionNotes
owner()The deployer. The market uses this address as the oracle signer.
publish(feedId, price, timestamp)Owner only. Stores one price record. A record cannot change.
read(feedId, updateData)Returns the stored price for a timestamp

The feed IDs of the scripts are the ASCII symbols MON and ETH, padded with zeros to 32 bytes.

VarianceMath ​

logRatio normalizes the larger price ratio by powers of two. It evaluates the odd atanh series through denominator 59 on the interval from 1 to 2. Negative returns use the negative logarithm of the inverse ratio. The source price bounds are 1e6 through 1e30 in 18-decimal units. These bounds prevent division underflow and keep all intermediate products below 256 bits.

Rounding ​

Margin calculations round up. Fees, funding, and profit calculations round toward zero. Weighted entry prices round down. These small differences can accumulate. They are not an insurance fund.

Foundry deployment script ​

The applications use the deployment scripts in scripts/. A separate Foundry script is available:

sh
forge script --root contracts contracts/script/Deploy.s.sol:Deploy \
  --rpc-url http://127.0.0.1:8545 --broadcast --private-key "$LOCAL_DEPLOYER_KEY"

This script requires the local chain ID 31337. It emits the addresses. It does not write the application deployment file. Use a local test key only.

Growth and limits ​

  • The funding index history and the order records grow over time. They are not pruned.
  • The recorded gas measurements are Foundry measurements. They are not a Monad benchmark. See Implementation status.
  • No production oracle test and no default recovery test are complete.

Deployed on Monad testnet.