DomFiDomination Finance

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.

ContractPurposeBaseScan
DomfiVaultERC-4626 vault. LPs deposit USDC, act as collective counterparty to all trades.View
DomfiTradingStoragePersistent storage for open trades, pending orders, and trader state.View
DomfiPairInfosPer-pair fee parameters: opening, closing, funding, and rollover fees.View
DomfiPairsStoragePair definitions, group config, leverage limits, collateral ranges.View
DomfiTradingUser-facing entry point: openTrade(), closeTradeMarket(), updateTp(), updateSl().View
DomfiTradingCallbacksExecutes trades after price fulfillment. Calculates PnL, applies fees, settles with vault.View
DomfiOpenPnlTracks unrealized PnL across all open positions. Used by vault for share pricing.View
DomfiTradesUpKeepAutomated position management: liquidations, stop-loss, take-profit.View
DomfiPriceRouterQueues price requests, routes fulfilled prices to callbacks.View
DomfiPrivatePriceUpKeepReceives signed prices from off-chain bot, forwards to PriceRouter.View

Non-Upgradeable Contracts

ContractPurposeBaseScan
DomfiOracleStores latest verified prices per dominance pair.View
DomfiTimelockOwnerTimelock for governance operations with role-based access control.View
ProxyAdminOpenZeppelin ProxyAdmin for managing proxy upgrades.View
DomfiRegistryCentral contract discovery. All contracts register here and resolve each other by name.View
DomfiLockedDepositNftERC-721 NFT representing locked vault deposits with time-based unlock.View
DomfiVerifierVerifies 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;
ParameterTypeUnitsNotes
t.collateraluint2566 decimals (USDC)$100 = 100000000
t.leverageuint322 decimals50x = 5000, 250x = 25000, 500x = 50000
t.pairIndexuint160=BTCDOM, 1=ETHDOM, 2=USDTDOM, 3=BNBDOM, 4=SOLDOM
t.buybooltrue = long, false = short
t.tp / t.sluint19218 decimalsSet to 0 for no TP/SL
oracle fee6 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

EventParametersMeaning
MarketOpenOrderInitiatedorderId (indexed), trader (indexed), pairIndex (indexed)User submitted a market open order
MarketCloseOrderInitiatedorderId (indexed), tradeId (indexed), trader (indexed), pairIndex, closePercentageUser submitted a market close order
OpenLimitPlacedtrader (indexed), pairIndex (indexed), index, wantedPriceLimit order placed
OpenLimitUpdatedtrader (indexed), pairIndex (indexed), index, newPrice, newTp, newSlLimit order updated
OpenLimitCanceledtrader (indexed), pairIndex (indexed), indexLimit order canceled
TpUpdatedtradeId (indexed), trader (indexed), pairIndex (indexed), index, newTpTake-profit updated on open position
SlUpdatedtradeId (indexed), trader (indexed), pairIndex (indexed), index, newSlStop-loss updated on open position
TopUpCollateralExecutedtradeId (indexed), trader (indexed), pairIndex (indexed), topUpAmount, newLeverageCollateral added to position
RemoveCollateralInitiatedtradeId (indexed), orderId (indexed), trader (indexed), pairIndex, removeAmountCollateral removal queued for oracle
MarketOpenTimeoutExecutedorderId (indexed), order structStale open order timed out and refunded
MarketCloseTimeoutExecutedorderId (indexed), tradeId (indexed), order structStale close order timed out

DomfiTradingCallbacks

EventParametersMeaning
MarketOpenExecutedorderId (indexed), trade struct, priceImpactP, tradeNotionalTrade opened successfully
MarketCloseExecutedorderId (indexed), tradeId (indexed), price, priceImpactP, percentProfit, usdcSentToTrader, percentageClosedTrade closed, PnL settled
MarketOpenCanceledorderId (indexed), trader (indexed), pairIndex (indexed), cancelReasonOpen order rejected (price, slippage, etc.)
MarketCloseCanceledorderId (indexed), tradeId (indexed), trader (indexed), pairIndex, index, cancelReasonClose order rejected
LimitOpenExecutedorderId (indexed), limitIndex, trade struct, priceImpactP, tradeNotionalLimit order triggered and filled
LimitCloseExecutedorderId (indexed), tradeId (indexed), orderType, price, priceImpactP, percentProfit, usdcSentToTraderTP/SL/liquidation executed
RemoveCollateralExecutedorderId (indexed), tradeId (indexed), trader (indexed), pairIndex, removeAmount, leverage, tp, slCollateral removed from position
VaultOpeningFeeChargedtradeId (indexed), trader (indexed), amountOpening fee sent to vault
VaultClosingFeeChargedtradeId (indexed), trader (indexed), amountClosing fee sent to vault
VaultLiqFeeChargedorderId (indexed), tradeId (indexed), trader (indexed), amountLiquidation margin sent to vault
FeesChargedorderId (indexed), tradeId (indexed), trader (indexed), fundingFeesFunding fees settled

DomfiVault

EventParametersMeaning
WithdrawRequestedsender (indexed), owner (indexed), shares, currEpoch, unlockEpoch (indexed)LP requested withdrawal
WithdrawCanceledsender (indexed), owner (indexed), shares, currEpoch, unlockEpoch (indexed)LP canceled pending withdrawal
DepositLockedsender (indexed), owner (indexed), depositId, deposit structLocked deposit created (NFT minted)
DepositUnlockedsender (indexed), receiver (indexed), owner (indexed), depositId, deposit structLocked deposit unlocked (NFT burned)
AssetsSentsender (indexed), receiver (indexed), assetsUSDC paid out to winning trader
AssetsReceivedsender (indexed), user (indexed), assetsUSDC received from losing trader
AccPnlPerTokenUsedUpdatedsender (indexed), newEpoch (indexed), prevOpenPnl, newOpenPnl, newEpochOpenPnl, newAccPnlPerTokenUsedEpoch boundary — PnL committed to share price
DailyAccPnlDeltaResetprevDailyAccPnlDeltaPerTokenDaily circuit breaker counter reset

DomfiPriceRouter

EventParametersMeaning
PriceRequestedorderId (indexed), feed, timestamp, publishIdPrice request queued for oracle
PriceReceivedorderId (indexed), pairIndex (indexed), price, nativeFeeSigned price delivered by oracle bot

DomfiTradesUpKeep

EventParametersMeaning
AutomationOpenOrderInitiatedorderId (indexed), trader (indexed), pairIndex (indexed), indexAutomation bot triggering a limit open
AutomationCloseOrderInitiatedorderId (indexed), tradeId (indexed), trader (indexed), pairIndex, orderTypeAutomation bot triggering TP/SL/liquidation
AutomationExecutePerformedorderId, limitOrder (indexed), pairIndex (indexed), status (indexed), traderAutomation order execution result

Errors

Common Trading Errors

ErrorContractCauseResolution
Insufficient USDC allowanceDomfiTradingStorageApproved USDC below collateral + oracle feeApprove at least collateral + 0.10 USDC to DomfiTradingStorage
WrongLeverageDomfiTradingLeverage exceeds the pair ceiling or below minimumUse leverage 1–500x on BTCDOM (100-50000) and 1–250x on other pairs (100-25000)
WrongTPDomfiTradingTake-profit exceeds 900% capSet TP ≤ 900% of collateral
WrongSLDomfiTradingStop-loss outside valid rangeSet SL between entry and liquidation price
BelowMinLevPosDomfiTradingcollateral × leverage below minimum position sizeIncrease collateral or leverage
ExposureLimitsDomfiTradingTrade would exceed OI cap per direction per pairReduce position size
AboveMaxAllowedCollateralDomfiTradingCollateral exceeds protocol maximumUse less collateral
MaxPendingMarketOrdersReachedDomfiTradingToo many pending orders for this traderWait for existing orders to fill
MaxTradesPerPairReachedDomfiTradingMax open positions on this pair for this traderClose a position first
NoTradeFoundDomfiTradingPosition doesn't exist at given indexCheck trader address, pair, and index
TriggerPendingDomfiTradingCan't modify position while TP/SL/liquidation is pendingWait for pending trigger to resolve
IsPausedDomfiTradingTrading is paused by governanceWait for unpause

Callback / Execution Errors

ErrorContractCause
MarketOpenCanceled (event)DomfiTradingCallbacksOpen rejected — check CancelReason: slippage exceeded, insufficient collateral after fees, pair not listed, max OI exceeded
MarketCloseCanceled (event)DomfiTradingCallbacksClose rejected — trade no longer exists or conditions changed
RemoveCollateralRejected (event)DomfiTradingCallbacksRemoval rejected — position would be under liquidation, exceed max leverage, or at max profit cap

Vault Errors

ErrorContractCauseResolution
MaxDailyPnlReachedDomfiVaultDaily loss cap hit — vault can't pay more winning traders todayRetry after 24-hour reset
NotEnoughAssetsDomfiVaultCumulative PnL cap hit — vault has insufficient reservesRetry after vault receives more fees/losses
PendingWithdrawalDomfiVaultCannot transfer shares while a withdrawal is pendingRaised 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.
WaitNextEpochStartDomfiVaultWithdrawal request submitted while the vault is collecting open-PnL samples to close an epochRaised 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.
WrongLockDurationDomfiVaultLock duration outside 7–365 day rangeUse a duration between 7 and 365 days
DepositNotUnlockedDomfiVaultAttempting to unlock before lock expiresWait for the lock period to end
NotAllowedDomfiVaultCaller is not the NFT owner or approvedMust 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-mainnet

This 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