DomFiDomination Finance

Quick Start

From zero to your first DomFi contract interaction in under 10 minutes. Read prices, open trades, and deposit into the vault.

Prerequisites

  • JavaScript path: Node.js 18+
  • Solidity / CLI path: Foundry (includes forge, cast, and anvil)
  • A wallet with ETH on Base for gas and oracle fees
  • USDC on Base for collateral
  • An RPC endpoint for Base: https://mainnet.base.org for public access, or Alchemy/Infura for production

Install

npm install viem
npm install ethers
curl -L https://foundry.paradigm.xyz | bash
foundryup

Includes forge (build/test/script), cast (CLI calls), and anvil (local node). No Node.js required.

Connect to the Protocol

Start from the deployed Base mainnet addresses below. DomfiRegistry is the discovery entry point, but most integrations pin the current proxy addresses directly.

ContractAddressUse For
DomfiRegistry0xe438360464EaDa40b7921C993322bD4dA8881103Discover all other contracts
DomfiTrading0x7447cb5350a096364A13bEAf77916dfB35db9445Open and close trades
DomfiOracle0x1aB9c3A2E1A09f2D06bf4A75d1721c7e113B8D4DRead dominance prices
DomfiVault0xA194082Aabb75Dd1Ca9Dc1BA573A5528BeB8c2FbLP deposits and withdrawals
DomfiTradingStorage0x608ff95777F419040a3b1E42ed73dD3EFf42Cc24Query open positions
import { createPublicClient, http } from 'viem';
import { base } from 'viem/chains';

const client = createPublicClient({
  chain: base,
  transport: http('https://mainnet.base.org'),
});

Or verify your connection with cast (included with Foundry):

cast chain-id --rpc-url https://mainnet.base.org
# Expected: 8453

Use minimal ABI fragments for the specific calls you make. For full verified ABIs, use BaseScan:

Read a Dominance Price

const price = await client.readContract({
  address: '0x1aB9c3A2E1A09f2D06bf4A75d1721c7e113B8D4D',
  abi: [{
    name: 'getPrice',
    type: 'function',
    stateMutability: 'view',
    inputs: [{ name: 'pairIndex', type: 'uint16' }],
    outputs: [{ name: '', type: 'uint256' }],
  }],
  functionName: 'getPrice',
  args: [0], // 0 = BTCDOM
});

console.log('BTCDOM price:', Number(price) / 1e18);
// Expected: ~52.5 (Bitcoin dominance percentage)
import { Contract, JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://mainnet.base.org');
const oracle = new Contract(
  '0x1aB9c3A2E1A09f2D06bf4A75d1721c7e113B8D4D',
  [{
    name: 'getPrice',
    type: 'function',
    stateMutability: 'view',
    inputs: [{ name: 'pairIndex', type: 'uint16' }],
    outputs: [{ name: '', type: 'uint256' }],
  }],
  provider,
);

const price = await oracle.getPrice(0);

console.log('BTCDOM price:', Number(price) / 1e18);
// Expected: ~52.5 (Bitcoin dominance percentage)
// ReadPrice.s.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Script, console} from "forge-std/Script.sol";

interface IDomfiOracle {
    function getPrice(uint16 pairIndex) external view returns (uint256);
}

contract ReadPrice is Script {
    function run() external view {
        IDomfiOracle oracle = IDomfiOracle(
            0x1aB9c3A2E1A09f2D06bf4A75d1721c7e113B8D4D
        );

        uint256 price = oracle.getPrice(0); // 0 = BTCDOM
        console.log("BTCDOM price (18 decimals):", price);
        // Expected: ~52500000000000000000 (52.5%)
    }
}
forge script ReadPrice.s.sol --rpc-url https://mainnet.base.org

No setup required — read a price in one command:

cast call 0x1aB9c3A2E1A09f2D06bf4A75d1721c7e113B8D4D \
  "getPrice(uint16)(uint256)" \
  0 \
  --rpc-url https://mainnet.base.org
# Returns: 52500000000000000000 (18 decimals → 52.5% BTCDOM)
IndexPair
0BTCDOM
1ETHDOM
2USDTDOM
3BNBDOM
4SOLDOM

Open a Trade (Write)

openTrade() submits a real on-chain order. Approve USDC to DomfiTradingStorage, not DomfiTrading, then wait for the approval receipt before you submit the trade. Both steps spend real gas, and openTrade() also requires an ETH oracle fee.

Before you send the transaction:

  • USDC must be approved to DomfiTradingStorage, not DomfiTrading. This is the most common integration mistake.
  • openTrade() requires ETH as msg.value for the oracle fee, typically around 0.00003 ETH.
  • Collateral uses 6 decimals because USDC on Base is 6-decimal native USDC.
  • Leverage uses 2-decimal precision: 100 = 1x, 1000 = 10x, 5000 = 50x, 25000 = 250x.
  • Execution is asynchronous. openTrade() queues the order, then an off-chain bot fulfills the price.
import { createPublicClient, createWalletClient, http, parseUnits } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { base } from 'viem/chains';

const USDC_ADDRESS = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
const TRADING_ADDRESS = '0x7447cb5350a096364A13bEAf77916dfB35db9445';
const TRADING_STORAGE_ADDRESS = '0x608ff95777F419040a3b1E42ed73dD3EFf42Cc24';
const ORACLE_FEE_WEI = 30000000000000n;

const erc20Abi = [{
  name: 'approve',
  type: 'function',
  stateMutability: 'nonpayable',
  inputs: [
    { name: 'spender', type: 'address' },
    { name: 'amount', type: 'uint256' },
  ],
  outputs: [{ name: '', type: 'bool' }],
}] as const;

const tradingAbi = [{
  name: 'openTrade',
  type: 'function',
  stateMutability: 'payable',
  inputs: [
    {
      name: 't',
      type: 'tuple',
      components: [
        { name: 'collateral', type: 'uint256' },
        { name: 'openPrice', type: 'uint192' },
        { name: 'tp', type: 'uint192' },
        { name: 'sl', type: 'uint192' },
        { name: 'trader', type: 'address' },
        { name: 'leverage', type: 'uint32' },
        { name: 'pairIndex', type: 'uint16' },
        { name: 'index', type: 'uint8' },
        { name: 'buy', type: 'bool' },
      ],
    },
    { name: 'orderType', type: 'uint8' },
    { name: 'slippageP', type: 'uint256' },
  ],
  outputs: [],
}] as const;

const account = privateKeyToAccount('0xYOUR_PRIVATE_KEY');
const publicClient = createPublicClient({
  chain: base,
  transport: http('https://mainnet.base.org'),
});
const walletClient = createWalletClient({
  account,
  chain: base,
  transport: http('https://mainnet.base.org'),
});

// Step 1: Approve USDC to TradingStorage (not Trading)
const approvalHash = await walletClient.writeContract({
  address: USDC_ADDRESS,
  abi: erc20Abi,
  functionName: 'approve',
  args: [TRADING_STORAGE_ADDRESS, parseUnits('100', 6)],
});

await publicClient.waitForTransactionReceipt({ hash: approvalHash });

// Step 2: Submit a 10x long on BTCDOM
await walletClient.writeContract({
  address: TRADING_ADDRESS,
  abi: tradingAbi,
  functionName: 'openTrade',
  args: [
    {
      trader: account.address,
      pairIndex: 0,
      index: 0,
      collateral: parseUnits('100', 6),
      openPrice: 0n,
      buy: true,
      leverage: 1000,
      tp: 0n,
      sl: 0n,
    },
    0,
    50,
  ],
  value: ORACLE_FEE_WEI,
});
// OpenTrade.s.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Script} from "forge-std/Script.sol";

interface IERC20 {
    function approve(address spender, uint256 amount) external returns (bool);
}

interface IDomfiTrading {
    struct Trade {
        uint256 collateral;
        uint192 openPrice;
        uint192 tp;
        uint192 sl;
        address trader;
        uint32 leverage;
        uint16 pairIndex;
        uint8 index;
        bool buy;
    }
    function openTrade(Trade calldata t, uint8 orderType, uint256 slippageP) external payable;
}

contract OpenTrade is Script {
    address constant USDC = 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913;
    address constant TRADING = 0x7447cb5350a096364A13bEAf77916dfB35db9445;
    address constant TRADING_STORAGE = 0x608ff95777F419040a3b1E42ed73dD3EFf42Cc24;

    function run() external {
        vm.startBroadcast();

        // Step 1: Approve USDC to TradingStorage (not Trading)
        IERC20(USDC).approve(TRADING_STORAGE, 100e6); // 100 USDC

        // Step 2: Submit a 10x long on BTCDOM
        IDomfiTrading(TRADING).openTrade{value: 0.00003 ether}(
            IDomfiTrading.Trade({
                collateral: 100e6,   // 100 USDC (6 decimals)
                openPrice: 0,        // market order — filled by oracle
                tp: 0,               // no take profit
                sl: 0,               // no stop loss
                trader: msg.sender,
                leverage: 1000,      // 10x (2 decimal precision)
                pairIndex: 0,        // BTCDOM
                index: 0,            // first trade slot
                buy: true            // long
            }),
            0,  // 0 = market order
            50  // 0.5% slippage (2 decimals)
        );

        vm.stopBroadcast();
    }
}
forge script OpenTrade.s.sol \
  --rpc-url https://mainnet.base.org \
  --private-key 0xYOUR_PRIVATE_KEY \
  --broadcast

The order is not opened immediately. Wait for the price bot to fulfill it, then read the resulting position from DomfiTradingStorage or watch the MarketOpenExecuted event.

Decimal Reference

ValuePrecisionExample
USDC amounts (collateral)6 decimals$100 = 100000000
Prices (dominance)18 decimals52.5% = 52500000000000000000
Leverage2 decimals10x = 1000, 250x = 25000
Slippage2 decimals0.5% = 50
Fee rates2 decimals0.1% = 10