CommodityCustody) with external dependencies on commodity tokens, USDC, a LiquidationRouter, and optionally a lending market. This page covers the contract’s architecture, state layout, and complete function reference.
Architecture
CommodityCustody maintains an internal ledger of user balances using a keccak256(user, token) key scheme. Deposits move tokens from the user into the contract and credit the internal balance. Withdrawals debit the internal balance and transfer tokens out. Trade settlements move balances between users internally without any on-chain token transfer.
All tokens - commodity tokens and USDC alike - are registered and treated uniformly via addSupportedToken. There is no compliance classification flag. Commodity tokens enforce their own compliance (KYC, whitelist/blacklist, frozen accounts, pause state) inside their transfer() and transferFrom() implementations. If the custody contract or user fails a compliance check, the commodity token reverts the transfer directly.
Compliance Model Difference from StockCustody
StockCustody performs pre-transfer compliance checks viaISecurityToken.canTransfer() and classifies tokens as compliance-checked or standard. CommodityCustody does not - commodity tokens enforce compliance inside their own transfer() and transferFrom() implementations. The custody contract has no complianceChecked flag and no checkTransferability function. If a compliance check fails, the commodity token reverts the transfer with its own error codes, not CommodityCustody errors.
CommodityCustody
UUPS-upgradeable custody contract with internal ledger, trade settlement, liquidation handling, and emergency controls.Initialization
_operator is address(0), it defaults to the admin address.
State Variables
Access Control
Admin Management
Admin transfer is a two-step process to prevent accidental transfer to an incorrect address.Token Configuration
transfer() and transferFrom().
Removing a token from the supported list does not lock user funds. Users can still withdraw unsupported tokens. New deposits and trade settlements for the removed token are blocked.
Deposit and Withdrawal
transferFrom. For commodity tokens, the token itself enforces KYC, whitelist/blacklist, frozen, and pause checks during the transfer. If any check fails, the commodity token reverts with its own error codes. The caller must have approved the custody contract for the deposit amount.
transfer. The commodity token enforces compliance during the transfer. Blocked if the user is frozen in custody or withdrawals are globally paused. Allows withdrawal of unsupported tokens to prevent fund lockout after token removal.
Balance Locking
The operator locks user balances when orders are matched, before settlement.amount from the user’s available balance (total minus already locked). Reverts with InsufficientBalance if available balance is insufficient.
InsufficientLockedBalance if the locked balance is less than amount.
Trade Settlement
settlementId must be unique - reuse reverts with SettlementAlreadyProcessed.
BatchSettled(batchId, settledCount, totalSubmitted) so callers can detect partial completion.
freezeUser() before locking to prevent withdrawal front-running between the lock and settlement steps. Emits both PrioritySettlement and TradeSettled.
Liquidation
Receiving Collateral
address(this).
External Sale Settlement
tokenRecipient - the commodity token enforces its own compliance during this transfer. USDC is pulled from the operator and sent to the liquidation router. The lending market receives a receiveLiquidationProceeds callback. If the callback reverts, settlement still completes.
Internal Buyer Settlement
Emergency Controls
View Functions
Events
Errors
Commodity token compliance failures (KYC, whitelist, blacklist, frozen, paused) cause the token’s own
transfer or transferFrom call to revert with the commodity token’s error codes, not CommodityCustody errors. Your integration layer must handle both error sources when processing deposits and withdrawals.ILendingMarket
Callback interface that lending market contracts must implement to receive liquidation settlement notifications.CommodityCustody when a liquidation is settled (both settleLiquidation and settleLiquidationWithBuyer). If the callback reverts, settlement still completes. Off-chain systems must reconcile via LiquidationSettled or LiquidationSoldToBuyer events.