StockCustody) with external dependencies on StockToken, USDC, a LiquidationRouter, and optionally a lending market. This page covers the contract’s architecture, state layout, and complete function reference.
Architecture
StockCustody 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.
For compliance-checked tokens (security tokens), the contract calls ISecurityToken.canTransfer on deposit and withdrawal. Internal transfers during trade settlement skip this check entirely - compliance validation is the matching engine’s responsibility.
canTransfer validation during deposit and withdrawal of compliance-checked tokens.
StockCustody
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
complianceChecked flag determines whether the token requires ISecurityToken.canTransfer validation on deposit and withdrawal. Set to true for security tokens, false for USDC and other standard ERC-20s.
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
canTransfer(caller, custody, amount) before transfer. The caller must have approved the custody contract for the deposit amount.
canTransfer(custody, caller, amount). 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. 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 - off-chain systems must reconcile via events.
Internal Buyer Settlement
Emergency Controls
Stock Split Reconciliation
numerator / denominator using floor division. The liquidation pool balance for the token is also adjusted. Dust from rounding stays unallocated in the contract’s ERC-20 balance.
Only forward splits are accepted (numerator must exceed denominator).
View Functions
Events
Errors
ILendingMarket
Callback interface that lending market contracts must implement to receive liquidation settlement notifications.StockCustody 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.