Skip to main content

Common flows

End-to-end examples showing how the contracts work together.

Funding Holdings

Deposit into your own Holdings balance
1. usdc.approve(holdings, amount)
2. holdings.deposit(user, usdc, amount)
Deposit into another user’s Holdings balance
1. usdc.approve(holdings, amount)
2. holdings.deposit(recipient, usdc, amount)
Deposit via Permit2
1. usdc.approve(permit2, amount)  // one-time Permit2 approval
2. Sign PermitTransferFrom with spender = holdings
3. holdings.depositWithPermit(from, to, usdc, amount, nonce, deadline, signature)

Approving Settlement as operator

// Direct call:
holdings.setOperator(settlement, true)

// Or via signature:
1. Sign OperatorApproval(user, operator, approved, nonce, deadline)
2. holdings.setOperatorBySig(user, settlement, true, nonce, deadline, signature)

Acquiring outcome tokens

Mint complete sets directly to a wallet
1. usdc.approve(marketFactory, amount)
2. marketFactory.mintCompleteSets(marketId, amount, recipient)
Mint complete sets from Holdings collateral
// Prerequisite: collateral already in Holdings and Settlement approved as operator
settlement.mintCompleteSetsFromHoldings(marketId, amount)
Mint and deposit from external wallet with Permit2
1. usdc.approve(permit2, amount)
2. Sign PermitTransferFrom with spender = settlement
3. settlement.mintAndDepositWithPermit(marketId, amount, nonce, deadline, signature)

Trading

Sign a limit order
domain: { name: "Settlement", version: "1", chainId, verifyingContract: settlement }
types: Order(bytes32 marketId, address trader, uint256 price, uint256 size, uint8 outcomeIndex, uint8 side, bytes32 nonce, uint256 expiry, uint256 maxFee, uint8 makerRoleConstraint, uint8 inventoryModeConstraint)
Sign a market order intent
domain: { name: "Settlement", version: "1", chainId, verifyingContract: settlement }
types: MarketOrderIntent(bytes32 marketId, address trader, uint256 maxSize, uint256 maxPrice, uint8 outcomeIndex, uint8 side, bytes32 nonce, uint256 expiry, uint256 maxFee)
Execute matched fills
settlement.settleFill(fillData, fillSignature)
// or
settlement.settleFillBatch(fillsArray, fillSignaturesArray)

Moving and exiting Holdings balances

Transfer balance internally
holdings.transfer(recipient, token, amount)
Withdraw to an external address
holdings.withdraw(recipient, token, amount)
Withdraw via signature
1. Sign Withdraw(from, to, token, amount, nonce, deadline)
2. Relayer calls holdings.withdrawBySig(...)

Exiting positions

Burn complete sets from Holdings
settlement.burnCompleteSetsFromHoldings(marketId, amount, recipient, creditInternal)
// creditInternal = true  -> collateral goes back into Holdings
// creditInternal = false -> collateral is sent externally to recipient
Redeem resolved outcomes to Holdings
settlement.redeemOutcomesToHoldings(marketId, amounts)
Withdraw redeemed collateral from Holdings
holdings.withdraw(recipient, token, amount)

Negative-risk conversion

For a multi-binary market with M child questions, converting N NO positions yields:
N NO -> (M - N) YES + (N - 1) collateral
Wallet-based conversion
marketFactory.convertPositions(parentMarketId, indexSet, amount, expectedQuestionCount)
Holdings-based conversion
settlement.convertMultiBinaryPositionsFromHoldings(parentMarketId, indexSet, amount, expectedQuestionCount)
indexSet is a bitmask where bit i means the NO token for child question i is being converted.

Permit2 reference

Used for gasless token pulls in Holdings.depositWithPermit, Holdings.batchDepositWithPermit, and Settlement.mintAndDepositWithPermit. Domain separator calculation:
permit2Address = 0x000000000022D473030F116dDEE9F6B43aC78BA3
domainTypeHash = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)")
nameHash = keccak256("Permit2")
DOMAIN_SEPARATOR = keccak256(abi.encode(domainTypeHash, nameHash, chainId, permit2Address))
PermitTransferFrom structs:
struct TokenPermissions {
    address token;
    uint256 amount;
}

struct PermitTransferFrom {
    TokenPermissions permitted;
    uint256 nonce;
    uint256 deadline;
}
For Holdings deposit flows, the Permit2 spender in the signed hash is address(holdings). For Settlement mint-and-deposit, the Permit2 spender in the signed hash is address(settlement).