Contract Reference
All 16 DomFi contracts on Base Mainnet — type, purpose, and BaseScan links.
16 contracts on Base Mainnet. Ten upgradeable via TransparentUpgradeableProxy, six deployed directly.
Upgradeable Contracts
Interact with the proxy address, not the implementation.
| Contract | Purpose | BaseScan |
|---|---|---|
| DomfiVault | ERC-4626 vault. LPs deposit USDC, act as collective counterparty to all trades. | View |
| DomfiTradingStorage | Persistent storage for open trades, pending orders, and trader state. | View |
| DomfiPairInfos | Per-pair fee parameters: opening, closing, funding, and rollover fees. | View |
| DomfiPairsStorage | Pair definitions, group config, leverage limits, collateral ranges. | View |
| DomfiTrading | User-facing entry point: openTrade(), closeTradeMarket(), updateTp(), updateSl(). | View |
| DomfiTradingCallbacks | Executes trades after price fulfillment. Calculates PnL, applies fees, settles with vault. | View |
| DomfiOpenPnl | Tracks unrealized PnL across all open positions. Used by vault for share pricing. | View |
| DomfiTradesUpKeep | Automated position management: liquidations, stop-loss, take-profit. | View |
| DomfiPriceRouter | Queues price requests, routes fulfilled prices to callbacks. | View |
| DomfiPrivatePriceUpKeep | Receives signed prices from off-chain bot, forwards to PriceRouter. | View |
Non-Upgradeable Contracts
| Contract | Purpose | BaseScan |
|---|---|---|
| DomfiOracle | Stores latest verified prices per dominance pair. | View |
| DomfiTimelockOwner | Timelock for governance operations with role-based access control. | View |
| ProxyAdmin | OpenZeppelin ProxyAdmin for managing proxy upgrades. | View |
| DomfiRegistry | Central contract discovery. All contracts register here and resolve each other by name. | View |
| DomfiLockedDepositNft | ERC-721 NFT representing locked vault deposits with time-based unlock. | View |
| DomfiVerifier | Verifies ECDSA signatures on price data from the publisher bot. | View |
Key Interfaces
Three interfaces cover most integration scenarios.
IDomfiTrading exposes trading entry points: opening and closing positions, updating take-profit and stop-loss. Primary interface for any trading integration.
IDomfiOracle provides read access to the latest verified dominance prices across the listed pairs.
IDomfiVault follows ERC-4626 for LP deposits and withdrawals. Use it for vault integrations, yield aggregators, or monitoring vault health.
Key Functions
Core functions most integrators call. For full signatures, see verified ABIs on BaseScan.
DomfiTrading
openTrade
Opens a leveraged position on a dominance pair.
function openTrade(
Trade calldata t, // Trade struct: pairIndex, collateral, leverage, buy, tp, sl
uint8 orderType, // 0 = market, 1 = limit, 2 = stop
uint256 slippageP // Slippage tolerance, 2-decimal precision (50 = 0.5%)
) external;| Parameter | Type | Units | Notes |
|---|---|---|---|
t.collateral | uint256 | 6 decimals (USDC) | $100 = 100000000 |
t.leverage | uint32 | 2 decimals | 50x = 5000, 250x = 25000, 500x = 50000 |
t.pairIndex | uint16 | — | 0=BTCDOM, 1=ETHDOM, 2=USDTDOM, 3=BNBDOM, 4=SOLDOM |
t.buy | bool | — | true = long, false = short |
t.tp / t.sl | uint192 | 18 decimals | Set to 0 for no TP/SL |
| oracle fee | — | 6 decimals (USDC) | Flat 0.10 USDC, pulled from your USDC approval — approve collateral + fee |
Reverts: MaxLeverageExceeded, TpTooHigh, MaxOpenInterestExceeded, plus a USDC transfer revert if your allowance to DomfiTradingStorage is below collateral + oracle fee
Note: Approve USDC to DomfiTradingStorage for collateral + oracle fee, not DomfiTrading. The oracle fee is charged in USDC — no ETH msg.value is required. Execution is asynchronous — listen for MarketOpenExecuted.
closeTradeMarket
Closes an open position at the current oracle price. Supports partial closes.
function closeTradeMarket(
uint8 pairIndex,
uint8 index, // Position index for this pair
uint256 percentage // 2-decimal precision: 10000 = 100%, 5000 = 50%
) external;Reverts: NoTrade (position doesn't exist). The oracle fee is charged in USDC — ensure your USDC allowance to DomfiTradingStorage covers it.
updateTp / updateSl
Updates take-profit or stop-loss on an open position.
function updateTp(uint8 pairIndex, uint8 index, uint192 newTp) external;
function updateSl(uint8 pairIndex, uint8 index, uint192 newSl) external;Prices use 18-decimal precision. Set to 0 to remove the trigger. Charges the oracle fee in USDC — ensure your USDC allowance to DomfiTradingStorage covers it.
DomfiOracle
getPrice
Returns the latest verified dominance price for a pair.
function getPrice(uint16 pairIndex) external view returns (uint256);Returns an 18-decimal value. BTCDOM at 52.5% returns 52500000000000000000. This is a view function — no gas cost, no oracle fee.
DomfiVault (ERC-4626)
deposit
Deposits USDC into the vault in exchange for $dfUSDC shares.
function deposit(uint256 assets, address receiver) external returns (uint256 shares);assets uses 6 decimals (USDC). Approve USDC to the vault address first. Returns the number of $dfUSDC shares minted.
makeWithdrawRequest
Initiates a withdrawal. Locks $dfUSDC during the cool-off period.
function makeWithdrawRequest(uint256 shares, address owner) external;Cool-off is 1–3 epochs depending on vault collateralization, readable from withdrawEpochsTimelock(). The request is booked to withdrawRequests[owner][unlockEpoch], where unlockEpoch = currentEpoch + withdrawEpochsTimelock(), and is emitted as the indexed unlockEpoch on WithdrawRequested.
Claiming uses the standard ERC-4626 entry points. Call withdraw() or redeem() — or the slippage-guarded withdrawWithSlippage() / redeemWithSlippage() — during the unlock epoch. There is no separate claim function. Both paths settle against withdrawRequests[owner][currentEpoch], so a request is claimable in its unlock epoch and in no other: before it, maxRedeem() returns 0 and the call reverts on the ERC-4626 max check; after it, the entry is stranded under a past epoch key, maxRedeem() returns 0 again, and the shares are unencumbered. Expiry emits no event and costs no transaction — there is nothing to subscribe to. Detect it by comparing the request's unlockEpoch against currentEpoch().
Requests stack. makeWithdrawRequest() enforces only totalSharesBeingWithdrawn(owner) + shares <= balanceOf(owner), so an owner can hold several pending requests at once; it does not revert merely because another request is pending. Requests with different unlock epochs stay separate. Requests that compute to the same unlock epoch land on the same withdrawRequests[owner][unlockEpoch] key and merge, and the stored withdrawPrices[owner][unlockEpoch] keeps the lower of the request-time prices. Shares under any pending request are non-transferable: transfer and transferFrom revert with PendingWithdrawal.
Requesting and claiming are both blocked for the last third of every epoch. Whenever openPnl.nextEpochValuesRequestCount() != 0, makeWithdrawRequest() reverts with WaitNextEpochStart() and maxRedeem() returns 0. That state is scheduled, not incidental: DomfiOpenPnl takes its first sample at currentEpochStart + requestsStart and its last requestsEvery * requestsCount later, and the epoch ends there. At the values live today — requestsStart 172800 (2 days), requestsEvery 10800 (3 hours), requestsCount 8 (24 hours) — an epoch is open to withdrawals for its first 2 days and closed for its last 1.
The consequence for scheduling: the claimable span is [epochStart, epochStart + requestsStart) of the unlock epoch, not the whole epoch. Compute the deadline as vault.currentEpochStart() + openPnl.requestsStart() and act before it; all three request parameters are governance-settable via updateRequestsInfoBatch(), so read them rather than hardcoding 2 days. A claim job that wakes on "unlock epoch reached" and retries until the epoch ends will retry into WaitNextEpochStart() for a full day and then find the request expired.
cancelWithdrawRequest(shares, owner, unlockEpoch) releases a pending request in full or in part and emits WithdrawCanceled. It carries no rollover guard, so it stays callable while the vault is closing an epoch.
Read unlockEpoch and act inside it — epoch length is a configurable protocol parameter, so do not hardcode a duration.
cancelWithdrawRequest
Releases a pending withdrawal request in full or in part.
function cancelWithdrawRequest(uint256 shares, address owner, uint16 unlockEpoch) external;Releases a pending withdrawal request, in full or in part, and emits WithdrawCanceled(sender, owner, shares, currEpoch, unlockEpoch) with unlockEpoch indexed. Reverts with AboveWithdrawAmount() if shares exceeds what is booked at that unlockEpoch, and with NotAllowed(sender) when called by a third party without sufficient allowance. It has no rollover guard and stays callable while the vault is closing an epoch. Cancelling does not restore the request's original price stamp: withdrawPrices[owner][unlockEpoch] is re-evaluated against the current shareToAssetsPrice and keeps the lower of the two.
DomfiTradingStorage
openTrades
Reads an open position's data.
function openTrades(address trader, uint8 index) external view returns (Trade memory);Returns the full Trade struct including entry price, collateral, leverage, and TP/SL levels. View function — no gas cost.
Events
Events are declared in the interface contracts. All events below include their indexed annotations.
DomfiTrading
| Event | Parameters | Meaning |
|---|---|---|
MarketOpenOrderInitiated | orderId (indexed), trader (indexed), pairIndex (indexed) | User submitted a market open order |
MarketCloseOrderInitiated | orderId (indexed), tradeId (indexed), trader (indexed), pairIndex, closePercentage | User submitted a market close order |
OpenLimitPlaced | trader (indexed), pairIndex (indexed), index, wantedPrice | Limit order placed |
OpenLimitUpdated | trader (indexed), pairIndex (indexed), index, newPrice, newTp, newSl | Limit order updated |
OpenLimitCanceled | trader (indexed), pairIndex (indexed), index | Limit order canceled |
TpUpdated | tradeId (indexed), trader (indexed), pairIndex (indexed), index, newTp | Take-profit updated on open position |
SlUpdated | tradeId (indexed), trader (indexed), pairIndex (indexed), index, newSl | Stop-loss updated on open position |
TopUpCollateralExecuted | tradeId (indexed), trader (indexed), pairIndex (indexed), topUpAmount, newLeverage | Collateral added to position |
RemoveCollateralInitiated | tradeId (indexed), orderId (indexed), trader (indexed), pairIndex, removeAmount | Collateral removal queued for oracle |
MarketOpenTimeoutExecuted | orderId (indexed), order struct | Stale open order timed out and refunded |
MarketCloseTimeoutExecuted | orderId (indexed), tradeId (indexed), order struct | Stale close order timed out |
DomfiTradingCallbacks
| Event | Parameters | Meaning |
|---|---|---|
MarketOpenExecuted | orderId (indexed), trade struct, priceImpactP, tradeNotional | Trade opened successfully |
MarketCloseExecuted | orderId (indexed), tradeId (indexed), price, priceImpactP, percentProfit, usdcSentToTrader, percentageClosed | Trade closed, PnL settled |
MarketOpenCanceled | orderId (indexed), trader (indexed), pairIndex (indexed), cancelReason | Open order rejected (price, slippage, etc.) |
MarketCloseCanceled | orderId (indexed), tradeId (indexed), trader (indexed), pairIndex, index, cancelReason | Close order rejected |
LimitOpenExecuted | orderId (indexed), limitIndex, trade struct, priceImpactP, tradeNotional | Limit order triggered and filled |
LimitCloseExecuted | orderId (indexed), tradeId (indexed), orderType, price, priceImpactP, percentProfit, usdcSentToTrader | TP/SL/liquidation executed |
RemoveCollateralExecuted | orderId (indexed), tradeId (indexed), trader (indexed), pairIndex, removeAmount, leverage, tp, sl | Collateral removed from position |
VaultOpeningFeeCharged | tradeId (indexed), trader (indexed), amount | Opening fee sent to vault |
VaultClosingFeeCharged | tradeId (indexed), trader (indexed), amount | Closing fee sent to vault |
VaultLiqFeeCharged | orderId (indexed), tradeId (indexed), trader (indexed), amount | Liquidation margin sent to vault |
FeesCharged | orderId (indexed), tradeId (indexed), trader (indexed), fundingFees | Funding fees settled |
DomfiVault
| Event | Parameters | Meaning |
|---|---|---|
WithdrawRequested | sender (indexed), owner (indexed), shares, currEpoch, unlockEpoch (indexed) | LP requested withdrawal |
WithdrawCanceled | sender (indexed), owner (indexed), shares, currEpoch, unlockEpoch (indexed) | LP canceled pending withdrawal |
DepositLocked | sender (indexed), owner (indexed), depositId, deposit struct | Locked deposit created (NFT minted) |
DepositUnlocked | sender (indexed), receiver (indexed), owner (indexed), depositId, deposit struct | Locked deposit unlocked (NFT burned) |
AssetsSent | sender (indexed), receiver (indexed), assets | USDC paid out to winning trader |
AssetsReceived | sender (indexed), user (indexed), assets | USDC received from losing trader |
AccPnlPerTokenUsedUpdated | sender (indexed), newEpoch (indexed), prevOpenPnl, newOpenPnl, newEpochOpenPnl, newAccPnlPerTokenUsed | Epoch boundary — PnL committed to share price |
DailyAccPnlDeltaReset | prevDailyAccPnlDeltaPerToken | Daily circuit breaker counter reset |
DomfiPriceRouter
| Event | Parameters | Meaning |
|---|---|---|
PriceRequested | orderId (indexed), feed, timestamp, publishId | Price request queued for oracle |
PriceReceived | orderId (indexed), pairIndex (indexed), price, nativeFee | Signed price delivered by oracle bot |
DomfiTradesUpKeep
| Event | Parameters | Meaning |
|---|---|---|
AutomationOpenOrderInitiated | orderId (indexed), trader (indexed), pairIndex (indexed), index | Automation bot triggering a limit open |
AutomationCloseOrderInitiated | orderId (indexed), tradeId (indexed), trader (indexed), pairIndex, orderType | Automation bot triggering TP/SL/liquidation |
AutomationExecutePerformed | orderId, limitOrder (indexed), pairIndex (indexed), status (indexed), trader | Automation order execution result |
Errors
Common Trading Errors
| Error | Contract | Cause | Resolution |
|---|---|---|---|
| Insufficient USDC allowance | DomfiTradingStorage | Approved USDC below collateral + oracle fee | Approve at least collateral + 0.10 USDC to DomfiTradingStorage |
WrongLeverage | DomfiTrading | Leverage exceeds the pair ceiling or below minimum | Use leverage 1–500x on BTCDOM (100-50000) and 1–250x on other pairs (100-25000) |
WrongTP | DomfiTrading | Take-profit exceeds 900% cap | Set TP ≤ 900% of collateral |
WrongSL | DomfiTrading | Stop-loss outside valid range | Set SL between entry and liquidation price |
BelowMinLevPos | DomfiTrading | collateral × leverage below minimum position size | Increase collateral or leverage |
ExposureLimits | DomfiTrading | Trade would exceed OI cap per direction per pair | Reduce position size |
AboveMaxAllowedCollateral | DomfiTrading | Collateral exceeds protocol maximum | Use less collateral |
MaxPendingMarketOrdersReached | DomfiTrading | Too many pending orders for this trader | Wait for existing orders to fill |
MaxTradesPerPairReached | DomfiTrading | Max open positions on this pair for this trader | Close a position first |
NoTradeFound | DomfiTrading | Position doesn't exist at given index | Check trader address, pair, and index |
TriggerPending | DomfiTrading | Can't modify position while TP/SL/liquidation is pending | Wait for pending trigger to resolve |
IsPaused | DomfiTrading | Trading is paused by governance | Wait for unpause |
Callback / Execution Errors
| Error | Contract | Cause |
|---|---|---|
MarketOpenCanceled (event) | DomfiTradingCallbacks | Open rejected — check CancelReason: slippage exceeded, insufficient collateral after fees, pair not listed, max OI exceeded |
MarketCloseCanceled (event) | DomfiTradingCallbacks | Close rejected — trade no longer exists or conditions changed |
RemoveCollateralRejected (event) | DomfiTradingCallbacks | Removal rejected — position would be under liquidation, exceed max leverage, or at max profit cap |
Vault Errors
| Error | Contract | Cause | Resolution |
|---|---|---|---|
MaxDailyPnlReached | DomfiVault | Daily loss cap hit — vault can't pay more winning traders today | Retry after 24-hour reset |
NotEnoughAssets | DomfiVault | Cumulative PnL cap hit — vault has insufficient reserves | Retry after vault receives more fees/losses |
PendingWithdrawal | DomfiVault | Cannot transfer shares while a withdrawal is pending | Raised by transfer and transferFrom, not by makeWithdrawRequest(): shares committed to a pending withdrawal request cannot be moved. Free them by claiming the request during its unlock epoch, by releasing it with cancelWithdrawRequest(), or by letting its unlock epoch pass unclaimed, after which the shares unencumber on their own. Stacking a further request is not what this error guards — requesting more than balanceOf(owner) - totalSharesBeingWithdrawn(owner) reverts with AboveBalance() instead. Cancellation is available on-chain and in the SDK; it is not exposed in the UI. |
WaitNextEpochStart | DomfiVault | Withdrawal request submitted while the vault is collecting open-PnL samples to close an epoch | Raised by makeWithdrawRequest() while openPnl.nextEpochValuesRequestCount() != 0 — currently the last day of each 3-day epoch. Retry once the new epoch has opened. Claims are blocked by the same state but surface it as maxRedeem() == 0 and the ERC-4626 max-check revert, not as this error. Do not treat this as transient: it persists until the epoch rolls, and for a request whose unlock epoch is the one closing, the roll is also the expiry. |
WrongLockDuration | DomfiVault | Lock duration outside 7–365 day range | Use a duration between 7 and 365 days |
DepositNotUnlocked | DomfiVault | Attempting to unlock before lock expires | Wait for the lock period to end |
NotAllowed | DomfiVault | Caller is not the NFT owner or approved | Must be the NFT holder or have approval |
ABIs
Verified source and ABIs are on BaseScan. Click any "View" link above, then navigate to the Contract tab.
For local development, generate TypeScript bindings from contract source:
cd onchain/exchange
make gen-types chain=base-mainnetThis produces ethers-v6 TypeScript types and ABI JSON files in script/deployments/base-mainnet/types/ and script/deployments/base-mainnet/abis/.
SDKs
TypeScript SDK. @domfi/sdk wraps the contracts and the REST reads, including the vault flows on this page — makeWithdrawRequest, cancelWithdrawRequest, withdraw and redeem are exposed on its vault client, with prepare* variants for staging a call. Install it with npm i @domfi/sdk (Node 20+, ESM and CJS builds).
There is no Python SDK; use web3.py with the ABIs linked above.
One gap to know about. The package ships ABIs for the vault and the trading contracts but not for DomfiOpenPnl, so the epoch schedule parameters — requestsStart, requestsEvery, requestsCount — are not reachable through it. Those are what set the claim deadline described under makeWithdrawRequest above. Until they are exposed, bind DomfiOpenPnl directly, resolving its address through DomfiRegistry.
See Also
- Contract Addresses for the full address table (proxy + implementation)
- Integration Guide for architecture and trade lifecycle