npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@domfi/sdk

v0.1.4

Published

TypeScript SDK for the Domination Finance onchain perpetual futures exchange

Readme

@domfi/sdk

TypeScript SDK for the Domination Finance onchain perpetual futures exchange.

The SDK gives applications one typed client for Domination Finance REST reads, viem-backed RPC reads, wallet-signed trading transactions, token approvals, position valuation, and private vault flows. Wallets remain application-owned; the SDK never takes custody of private keys or relays transactions.

Capabilities

| What you need | Where it lives | |---|---| | Typed REST reads — markets, account, prices, trades | domfi.api | | Raw, schema-shaped REST + generic request() | domfi.raw | | High-level trade & vault actions with lifecycle handles | domfi.actions | | Explicit trading — prepare → simulate → send → track | domfi.trading | | ERC-20 collateral allowance checks & approvals | domfi.token | | Position snapshots — PnL, mark value, liquidation, watch() | domfi.valuation | | Vault LP flows — deposit, withdraw, redeem, locked deposits | domfi.vault | | Delegated trading — EIP-712 grants, delegatedAction | domfi.delegation | | Referral code lookups & eligibility | domfi.referrals | | Points campaigns, wallet breakdowns, proofs & claims | domfi.points | | API/protocol status & SDK compatibility | domfi.system | | Resolved chain config — addresses, collateral, chain id | domfi.chain | | Pure bigint protocol math (no network) | @domfi/sdk/math |

The SDK is one typed client over DomFi REST reads, viem RPC reads, and wallet-signed writes. Wallets stay application-owned — it never holds keys or relays transactions. Both REST and RPC are optional; see Client Modes.

Install

Use the DomFi workspace, a packed artifact, or a configured private package source. viem is a peer dependency supplied by the application.

# pnpm
pnpm add @domfi/sdk viem

# yarn
yarn add @domfi/sdk viem

# bun
bun add @domfi/sdk viem

# npm
npm install @domfi/sdk viem

Requirements

  • Node.js >= 20 (or any modern runtime with a global fetch).
  • viem >= 2.21 — a peer dependency your application supplies.
  • TypeScript 5.6+ recommended.

@domfi/sdk ships dual ESM + CJS builds with type declarations for both, is side-effect-free (tree-shakeable), and pulls in no Node-only APIs — so it runs in Node and in modern browsers. Its only bundled dependency is valibot; viem is the peer dependency you supply.

Quick Start

Create an API-enabled client for read-only REST calls:

import { createDomfiClient } from "@domfi/sdk";

const domfi = createDomfiClient({
  chain: "testnet",
  // Built-in `testnet`/`mainnet` chains ship a default REST API route root
  // (https://testnet-api.domination.finance/api/v2 / https://api.domination.finance/api/v2),
  // so `api.baseUrl` is optional. Pass `api: { baseUrl }` only to override it.
  transport: {
    maxConcurrentRest: 8,
    retryBudget: 2,
  },
});

const status = await domfi.system.apiStatus();
const markets = await domfi.api.markets.list();
const headPrices = await domfi.api.prices.head();

console.log(status.data.ok, markets.data.length, headPrices.data.length);

Add viem clients when you need RPC reads or wallet-signed writes:

import { createPublicClient, createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { baseSepolia } from "viem/chains";
import { createDomfiClient } from "@domfi/sdk";

const account = privateKeyToAccount(process.env.DOMFI_TEST_PRIVATE_KEY as `0x${string}`);

const publicClient = createPublicClient({
  chain: baseSepolia,
  transport: http(process.env.BASE_SEPOLIA_RPC_URL),
});

const walletClient = createWalletClient({
  account,
  chain: baseSepolia,
  transport: http(process.env.BASE_SEPOLIA_RPC_URL),
});

const domfi = createDomfiClient({
  chain: "testnet",
  publicClient,
  walletClient,
  account: account.address,
  // `testnet` supplies its API base URL by default; override only if needed:
  // api: { baseUrl: process.env.DOMFI_API_BASE_URL },
  transport: {
    maxConcurrentRest: 8,
    maxConcurrentRpc: 4,
    retryBudget: 2,
  },
});

API base URL. In this SDK, baseUrl means the full REST route root, not just the domain origin. Built-in testnet/mainnet target the hosted DomFi API and need no api.baseUrl. The SDK appends each route's path (e.g. /markets) to your base URL — trailing slashes are trimmed, but it does not add /api or a version segment — so to point at a custom or self-hosted deployment, pass the full API base it serves under, e.g. api: { baseUrl: "https://your-host/api/v2" }. (The referral read routes are served from the unversioned /api root on hosted DomFi APIs, so a base ending in /api/v2 uses /api for those routes.)

Wallets. privateKeyToAccount above is for server-side scripts and tests. In browser/frontend apps, build the wallet client from the user's wallet connector or provider (injected, WalletConnect, …) — never load private keys into frontend code.

Client Modes

API-enabled clients expose typed REST reads under api (and schema-shaped reads under raw), plus actions, trading, token, valuation, vault, delegation, referrals, points, system, and chain:

domfi.api.markets.list;
domfi.api.account.positions;
domfi.api.prices.ticksIterator;
domfi.api.status.get;
domfi.raw.request;
domfi.trading.prepareOpenTrade;
domfi.token.approvalNeed;
domfi.valuation.positionSnapshot;
domfi.vault.stats;
domfi.actions.openMarket;
domfi.actions.closePosition;
domfi.actions.updateTakeProfit;
domfi.delegation.setDelegateWithSignature;
domfi.referrals.checkEligibility;
domfi.points.summary;
domfi.points.claim;
domfi.system.apiStatus;
domfi.chain.chainId;

With api: false, the api, raw, actions, vault, referrals, and points namespaces are intentionally absent at the type level. chain, token, delegation, trading (receipt-only — no REST-backed order tracking), valuation (unverifiedSlotSnapshot only), and system remain.

import { PairIndex, TradeIndex } from "@domfi/sdk";

const offlineDomfi = createDomfiClient({
  chain: "testnet",
  publicClient,
  walletClient,
  account: account.address,
  api: false,
});

await offlineDomfi.valuation.unverifiedSlotSnapshot({
  wallet: account.address,
  pairIndex: PairIndex.from(7),
  index: TradeIndex.from(0),
});

Core Concepts

A handful of ideas show up throughout the SDK. Learn them once here.

Branded units

Money, prices, leverage, and percentages are branded fixed-point values, not raw numbers — so you can't accidentally pass a price where collateral is expected, and there is never a floating-point rounding surprise. Build them from decimal strings; convert to the raw bigint the contracts use when you need it:

import { Collateral, Leverage, Price } from "@domfi/sdk";

const collateral = Collateral.fromDecimal("25"); // 25 USDC (6dp)
const leverage = Leverage.fromDecimal("4"); // 4x (2dp)
const price = Price.fromDecimal("58.5"); // $58.50 (18dp)

Collateral.toRaw(collateral); // 25000000n — on-chain scale
Collateral.toRawString(collateral); // "25000000"

Most units share fromDecimal / fromRaw / toRaw / toRawString / format. A few add purpose-built constructors: SlippagePercent.fromBps("50") (0.50%), ClosePercent.full() (100%), UsdP6.fromDollar(...). Number-like brands (PairIndex, TradeIndex) use .from(n); id brands (TradeId, OrderId) use .parse(s). Import codecs from the root or @domfi/sdk/units.

Result envelopes, freshness & readiness

REST reads return an envelope: result.data is the mapped value and result.freshness describes block lag/staleness. Each read accepts a readinessPolicy of "strict" | "warn" | "ignore" that decides what happens when the API read model is behind the chain — throw, emit a warning via onEvent, or pass through. Use "strict" before writes; "warn" is a sensible default for UI reads. (Paginated iterators yield page items whose mapped value is on .item, not .data.)

Oracle freshness policy (trade preparation)

The on-chain oracle is a cadence-published feed (a price is expected to be up to one publish interval old between beats), so the market open/close preflights (prepareOpenTrade / prepareClosePosition) guard the fresh oracle price with a threshold of oracleStaleThresholdMs (default: 1.5 × oraclePublishIntervalMs, both set on the chain profile). It clears the normal steady-state age plus jitter but still trips if a publish is more than ~half a cadence late. tp/sl, collateral, and limit-order updates don't read a fresh price and are unaffected. A structurally-invalid read (missing, non-positive, or implausibly-future timestamp) always fails. For an old-but-valid value, the chain profile's oracleFreshnessPolicy decides the behavior:

  • "strict" (default) — throw ValidationError("oracle value is stale");
  • "warn" — proceed and attach an ORACLE_VALUE_STALE warning to the prepared tx ((await prepared.summary()).warnings);
  • "ignore" — proceed silently.

Set it on a custom profile (createDomfiClient({ chain: { ...baseSepoliaDomfiChain, oracleFreshnessPolicy: "warn" } })). Note the chain imposes no on-chain age limit itself; this is a client-side safety rail, so "warn"/"ignore" do not risk on-chain reverts on age.

Verified position refs

Position mutations (close, take-profit, collateral, …) require a VerifiedPositionRef — a provenance-tagged handle to one open position slot (wallet + pair + slot index + tradeId + chainId). Obtain one from:

  • an account position — verifiedPositionRefFromAccountPosition(position, domfi.chain.chainId);
  • a tracked/recovered order — domfi.trading.track() / recoverTransaction(), and the closePosition / removeCollateral action outcomes expose .positionRef;
  • explicit input — verifiedPositionRef({ wallet, pairIndex, index, tradeId, chainId }).

This stops the SDK from acting on an unverified slot index.

Approval & simulation policies

High-level domfi.actions.* writes take two policies (imported from @domfi/sdk/actions):

  • ApprovalActionApprovalPolicy.RequireExisting (default; never sends an approval), AutoExact (approve exactly what's needed), or UnsafeMaxUint256 (approve max — convenient, higher risk).
  • SimulationActionSimulationPolicy.Required (default; simulate before send) or Skip.

Delegated actions must use RequireExisting — a delegate cannot approve the trader's collateral.

Handles

  • Action handles (domfi.actions.*) are synchronous and non-thenable: calling the method starts the write, and txHash(), approval(), waitReceipt(), outcome(), and watch() observe that same started action.
  • Prepared transactions (domfi.trading.prepare*, domfi.vault.prepare*) are explicit: summary()simulate()send(), where send() returns a tx handle for receipt and lifecycle tracking.

Read The API

Domain clients map raw API responses into branded SDK values. Use them for application code:

import { PairIndex, TradeId } from "@domfi/sdk";

const pairIndex = PairIndex.from(7);
const wallet = account.address;

const market = await domfi.api.markets.get(pairIndex);
const state = await domfi.api.markets.state(pairIndex);
const positions = await domfi.api.account.positions(wallet, { limit: 25 });
const orders = await domfi.api.account.orders(wallet, { limit: 25 });

for await (const entry of domfi.api.account.tradesIterator(wallet, { limit: 100 })) {
  // Iterators yield page items: the mapped value is on `.item` (not `.data`).
  console.log(entry.item.tradeId, entry.item.notional);
}

const events = await domfi.api.trades.events(TradeId.parse("12345"), { wallet }, { limit: 50 });

console.log(market.data.symbol, state.data.longOpenInterest, positions.data.length, orders.data.length);
console.log(events.data.events.length);

Use domfi.raw.* or domfi.raw.request(...) only when you need schema-shaped API payloads or route-level debugging.

const rawStatus = await domfi.raw.status.get();
const rawMarket = await domfi.raw.request("markets.get", { pairIndex: 7 });

console.log(rawStatus.data, rawMarket.data);

Token Approval

Trading and vault writes use ERC-20 collateral allowances. Check the required allowance first, then approve only when needed.

import { Collateral } from "@domfi/sdk";

const amount = Collateral.fromDecimal("25");
const spender = domfi.chain.collateral.tradingStorageSpender;

const need = await domfi.token.approvalNeed(account.address, spender, amount);

if (need.action === "approve") {
  const approval = await domfi.token.approve(spender, need.requiredAllowance, {
    account: account.address,
  });
  await approval.waitReceipt({ confirmations: 1, pollingIntervalMs: 1_000 });
}

Delegated Trading

Delegated trading uses DomFi Trading's delegatedAction(trader, callData) flow. The trader signs EIP-712 delegation typed data, the delegate signs delegated trading transactions, and delegation.trader is the affected wallet for positions, orders, collateral allowance, and receipts. setDelegateWithSignature can be submitted by the delegate or any relayer; this example uses the delegate as submitter.

import {
  Collateral,
  Leverage,
  PairIndex,
  SlippagePercent,
  type Address,
  type DomfiClient,
} from "@domfi/sdk";
import { ActionApprovalPolicy } from "@domfi/sdk/actions";
import type { WalletClient } from "@domfi/sdk/trading";

declare const domfi: DomfiClient; // created with the delegate wallet client
declare const traderAccount: { address: Address };
declare const traderWalletClient: WalletClient; // wallet client for traderAccount
declare const delegate: Address; // delegate transaction signer and example submitter

const trader = traderAccount.address;
const expiry = BigInt(Math.floor(Date.now() / 1000) + 60 * 60);

const signed = await domfi.delegation.sign(
  { delegator: trader, delegate, expiry },
  traderWalletClient,
);

await (await domfi.delegation.setDelegateWithSignature(signed, { account: delegate })).waitReceipt();

const opened = domfi.actions.openMarket(
  {
    pairIndex: PairIndex.from(7),
    direction: "long",
    collateral: Collateral.fromDecimal("25"),
    leverage: Leverage.fromDecimal("4"),
    slippage: SlippagePercent.fromBps("50"),
  },
  {
    account: delegate,
    delegation: { trader },
    approval: ActionApprovalPolicy.RequireExisting,
  },
);

const hash = await opened.txHash();
console.log(hash);

Delegated high-level actions require the trader to have pre-approved collateral allowance to the trading storage spender. Auto-approval policies are rejected because a delegate cannot approve ERC-20 collateral for the trader.

Trading

The low-level trading flow is explicit: prepare, optionally simulate, send, wait for the transaction receipt, then track the protocol lifecycle through the API.

import { PairIndex, SlippagePercent } from "@domfi/sdk";
import { TradeDirection } from "@domfi/sdk/trading";

const prepared = await domfi.trading.prepareOpenTrade(
  {
    orderKind: "market",
    pairIndex: PairIndex.from(7),
    direction: TradeDirection.Long,
    collateral: "10",
    leverage: "4",
    slippage: SlippagePercent.fromBps("50"),
  },
  { account: account.address },
);

const summary = await prepared.summary();
console.log(summary.approvals, prepared.estimatedOracleFee);

await prepared.simulate({ account: account.address });

const handle = await prepared.send(walletClient);

const receipt = await handle.waitReceipt({ confirmations: 1 });
const current = await handle.track({ maxDurationMs: 60_000 });
const terminal = await handle.waitTerminal({ maxDurationMs: 180_000, intervalMs: 3_000 });

console.log(receipt.status, current.status, terminal.status);

Oracle fees are charged in USDC by the contracts through transferFrom; prepared approvals include the exact required fee amount.

Use verified refs for position and trigger mutations. A verified position ref can come from account state, receipt recovery, or explicit caller input (see Core Concepts).

import { ClosePercent, SlippagePercent } from "@domfi/sdk";
import { verifiedPositionRefFromAccountPosition } from "@domfi/sdk/trading";

const page = await domfi.api.account.positions(account.address, { limit: 25 });
const openPosition = page.data.find((position) => position.kind === "open_position");

if (openPosition !== undefined) {
  const positionRef = verifiedPositionRefFromAccountPosition(openPosition, domfi.chain.chainId);

  const updateTakeProfit = await domfi.trading.prepareUpdateTakeProfit(positionRef, {
    takeProfit: "1.25",
  });
  await (await updateTakeProfit.send({ account: account.address })).waitReceipt();

  const close = await domfi.trading.prepareClosePosition(positionRef, {
    closePercent: ClosePercent.full(),
    slippage: SlippagePercent.fromBps("50"),
  });
  await (await close.send({ account: account.address })).waitTerminal({
    maxDurationMs: 180_000,
  });
}

High-Level Actions

API-enabled clients expose domfi.actions for the ten trading write flows:

  • openMarket, openLimit, openStop
  • closePosition
  • updateTakeProfit, updateStopLoss
  • topUpCollateral, removeCollateral
  • updateTriggerOrder, cancelTriggerOrder

Each method returns a synchronous, non-thenable ActionHandle. Calling an action method starts/stages the write pipeline immediately; txHash(), approval(), waitReceipt(), outcome(), and watch() observe that started action. Do not create an action handle for preview-only flows; use math helpers or low-level prepare/preflight APIs instead.

Open trigger placement actions resolve to status: "placed" with a receipt-verified trigger order ref. Receipt-only mutations resolve to status: "confirmed" with matched event evidence. Market-style actions resolve protocol terminal outcomes such as executed, canceled, timed_out, identity_mismatch, timeout_available, or unknown.

For most app writes, start with a high-level action and choose explicit approval and simulation policies:

import {
  Collateral,
  Leverage,
  PairIndex,
  SlippagePercent,
} from "@domfi/sdk";
import { ActionApprovalPolicy, ActionSimulationPolicy } from "@domfi/sdk/actions";

const opened = domfi.actions.openMarket(
  {
    pairIndex: PairIndex.from(7),
    direction: "long",
    collateral: Collateral.fromDecimal("25"),
    leverage: Leverage.fromDecimal("4"),
    slippage: SlippagePercent.fromBps("50"),
  },
  {
    account: account.address,
    approval: ActionApprovalPolicy.AutoExact,
    simulation: ActionSimulationPolicy.Required,
  },
);

// The action pipeline has already started/staged; these observe the same action.
const hash = await opened.txHash();
const receipt = await opened.waitReceipt({ confirmations: 1 });
const outcome = await opened.outcome({ maxDurationMs: 180_000, intervalMs: 3_000 });

console.log(hash, receipt.status, outcome.status);

Example outcome handling:

import {
  Collateral,
  Leverage,
  PairIndex,
  Price,
  SlippagePercent,
  type DomfiClient,
} from "@domfi/sdk";
import type { VerifiedPositionRef } from "@domfi/sdk/trading";

declare const domfi: DomfiClient;
declare const positionRef: VerifiedPositionRef;

const placed = await domfi.actions.openLimit({
  pairIndex: PairIndex.from(7),
  direction: "long",
  collateral: Collateral.fromDecimal("10"),
  leverage: Leverage.fromDecimal("5"),
  entryPrice: Price.fromDecimal("58"),
}).outcome();
if (placed.status === "placed") {
  console.log("trigger order", placed.ref);
  const canceled = await domfi.actions.cancelTriggerOrder(placed.ref).outcome();
  console.log("matched cancel event", canceled.eventEvidence);
}

const closed = await domfi.actions.closePosition(positionRef, {
  slippage: SlippagePercent.fromBps("50"),
}).outcome();
switch (closed.status) {
  case "executed":
    console.log("closed", closed.positionRef, closed.result);
    break;
  case "timeout_available":
    console.log("timeout can be handled", closed.result.order);
    break;
  default:
    console.log("terminal or unknown close outcome", closed.status);
}

Use ActionHandle.watch() when you need a streaming lifecycle instead of only the final outcome(). Market-style actions can emit submitted, mined, indexed, tracking, terminal, or unknown phases; receipt-only actions emit the phases that apply to receipt confirmation.

const closeAction = domfi.actions.closePosition(positionRef, {
  slippage: SlippagePercent.fromBps("50"),
});

for await (const state of closeAction.watch({ maxDurationMs: 180_000, intervalMs: 3_000 })) {
  if (state.phase === "indexed") console.log("indexed order", state.orderId);
  if (state.phase === "tracking") console.log("tracking", state.result.status);
  if (state.phase === "terminal") console.log("terminal", state.outcome.status);
}

Valuation

Verified valuation combines API discovery with block-pinned onchain reads. Use it for UI position snapshots, actionability, PnL, mark value, and liquidation data.

const snapshot = await domfi.valuation.positionSnapshot(positionRef, {
  readinessPolicy: "warn",
});

if (snapshot.status === "live") {
  console.log(snapshot.actionability, snapshot.markValue, snapshot.unrealizedPnl);
}

const bulk = await domfi.valuation.positionSnapshots([positionRef], {
  chunkSize: 25,
});

const watcher = domfi.valuation.watchPositionSnapshot(
  positionRef,
  { intervalMs: 3_000, emitImmediately: true },
  (event) => {
    if (event.type === "snapshot") console.log(event.data.status);
    if (event.type === "error") console.warn(event.error.message);
  },
);

watcher.stop();
domfi.valuation.clearConfigCache();
console.log(bulk.length);

api:false clients expose unverifiedSlotSnapshot (display-only slot inspection — it does not prove API identity) plus clearConfigCache. Verified snapshots, bulk reads, and watching require an API-enabled client.

Math Helpers

Use @domfi/sdk/math for pure, bigint-based protocol math in local previews and preflight UI. Math helpers do not perform REST or RPC calls.

import { Collateral, FeePercent, Leverage, Price } from "@domfi/sdk";
import { currentPercentProfit, tradeFee } from "@domfi/sdk/math";

const percentProfitRaw = currentPercentProfit({
  openPriceRaw: Price.toRaw(Price.fromDecimal("58")),
  markPriceRaw: Price.toRaw(Price.fromDecimal("60")),
  buy: true,
  leverageRaw: Leverage.toRaw(Leverage.fromDecimal("4")),
  initialLeverageRaw: Leverage.toRaw(Leverage.fromDecimal("4")),
});

const flatFee = tradeFee({
  collateral: Collateral.fromDecimal("25"),
  leverage: Leverage.fromDecimal("4"),
  feeP: FeePercent.fromDecimal("0.08"),
});

console.log(percentProfitRaw, Collateral.toRawString(flatFee));

Use tradeFee only when you already know the single flat fee rate to apply. For the protocol's real opening cost use openingFee (the maker/taker model) below.

Target-leverage helpers compute the collateral adjustment to reach a leverage. Submit requestedAmount on-chain (via domfi.actions.topUpCollateral / removeCollateral); effectiveAmount is the collateral that actually lands after the contract's rounding, and newLeverage previews the result (always at or below targetLeverage).

import { Collateral, Leverage } from "@domfi/sdk";
import { topUpToReachLeverage, unrealizedPnlPercentFromMarkValue } from "@domfi/sdk/math";

const adjustment = topUpToReachLeverage({
  collateral: Collateral.fromDecimal("100"),
  leverage: Leverage.fromDecimal("4"),
  targetLeverage: Leverage.fromDecimal("2"),
});
// Collateral.toRawString(adjustment.requestedAmount) -> amount to submit to topUpCollateral.

// Net PnL as a signed percent in P6 scale: 100% === 100_000_000n, floored at -100%.
const pnlPercentP6 = unrealizedPnlPercentFromMarkValue({
  collateralRaw: Collateral.toRaw(Collateral.fromDecimal("100")),
  markValueRaw: Collateral.toRaw(Collateral.fromDecimal("150")),
});

console.log(Leverage.toRawString(adjustment.newLeverage), pnlPercentP6);

openingFee is the full maker/taker model (the imbalance-reducing portion of a trade is charged the maker rate, the rest taker); it returns the total base fee the trader pays. priceImpact mirrors the contract's execution-price function: priceAfterImpact is the spread-adjusted price (for opens it becomes your stored openPrice; for closes it's the close execution price), and priceImpactP is the raw guard-scale magnitude (1% == 1e18). Note that at the current contract commit the OI-skew scaling is inert, so the spread is a flat 0.001% against the trader regardless of open interest. Feed real OI from marketState.data.rawState?.oiLong / oiShort (both UnsignedP18, and note rawState is optional), not the display longOpenInterest / shortOpenInterest.

import { FeePercent, Leverage, Price, SignedP6, UnsignedP18, Collateral } from "@domfi/sdk";
import { openingFee, priceImpact } from "@domfi/sdk/math";

const fee = openingFee({
  tradeSize: SignedP6.fromDecimal("500"), // +$500 notional (long); negative for short
  oiDelta: SignedP6.fromDecimal("1000"), // oiLong - oiShort, in USD
  leverage: Leverage.fromDecimal("10"),
  makerFeeP: FeePercent.fromDecimal("0.1"),
  takerFeeP: FeePercent.fromDecimal("0.2"),
  makerMaxLeverage: Leverage.fromDecimal("50"),
});

const { priceAfterImpact } = priceImpact({
  price: Price.fromDecimal("58"),
  oiLong: UnsignedP18.fromDecimal("100"),
  oiShort: UnsignedP18.fromDecimal("50"),
  collateral: Collateral.fromDecimal("1000"),
  leverage: Leverage.fromDecimal("10"),
  isOpen: true,
  isLong: true,
});

console.log(Collateral.toRawString(fee), Price.toRawString(priceAfterImpact));

Vault

The SDK includes a first-class private vault client. Read flows can run with an API-only client; prepare and write flows need public and wallet clients for approval checks, simulation, receipt parsing, and indexing.

import { VaultAsset, VaultShare } from "@domfi/sdk";

const stats = await domfi.vault.stats();
const vaultAccount = await domfi.vault.account(account.address);

const preparedDeposit = await domfi.vault.prepareDeposit(
  {
    assets: VaultAsset.fromDecimal("10"),
    receiver: account.address,
    minShares: VaultShare.fromDecimal("9.95"),
  },
  { account: account.address },
);

const vaultSummary = await preparedDeposit.summary();
await preparedDeposit.simulate({ account: account.address });

const vaultHandle = await preparedDeposit.send({ account: account.address });
const outcome = await vaultHandle.outcome();
const indexed = await vaultHandle.waitIndexed({ maxDurationMs: 60_000 });
const tracked = await vaultHandle.track({ maxDurationMs: 60_000 });

console.log(stats.data.currentEpoch, vaultAccount.data.totalShares, vaultSummary.approvals);
console.log(outcome.eventName, indexed.event.opType, tracked.receipt.status);

High-Level Vault Actions

Direct send helpers mirror prepared methods for user-facing vault writes. They return Promise<VaultTxHandle> and are useful when you prefer an explicit async send call:

const directDeposit = await domfi.vault.deposit(
  { assets: VaultAsset.fromDecimal("10"), receiver: account.address },
  { account: account.address },
);

await directDeposit.track({ maxDurationMs: 60_000 });

The user-facing vault direct-send methods are deposit, mint, makeWithdrawRequest, cancelWithdrawRequest, withdraw, redeem, depositWithDiscountAndLock, mintWithDiscountAndLock, and unlockDeposit. Admin, governance, callback, openPnl, and distributeReward contract methods are not SDK user-facing methods.

For synchronous action handles with approval(), txHash(), waitReceipt(), outcome(), and watch(), use domfi.actions.vaultDeposit, vaultMint, vaultMakeWithdrawRequest, vaultCancelWithdrawRequest, vaultWithdraw, vaultRedeem, vaultDepositWithDiscountAndLock, vaultMintWithDiscountAndLock, and vaultUnlockDeposit.

Referrals

API-enabled clients expose referral lookup helpers. Import referral-specific types from the stable @domfi/sdk/referrals subpath when annotating wrappers or application state.

import { ReferralEligibilityStatus, type ReferralEligibility } from "@domfi/sdk/referrals";

const eligibility: ReferralEligibility = await domfi.referrals.checkEligibility({
  account: account.address,
  code: "ALPHA123",
});

if (eligibility.status === ReferralEligibilityStatus.Usable) {
  console.log("referral code id", eligibility.referral.codeId);
}

Points

API-enabled clients expose points campaign reads and claim helpers under domfi.points. Use the read methods for campaign metadata, pool splits, boost configuration, wallet summaries, per-pool breakdowns, and the current claimable Merkle proof.

import { PointsCampaignStatus, PointsTotalDisplayKind, type PointsProof } from "@domfi/sdk/points";

const campaigns = await domfi.points.campaigns();
const currentCampaign = campaigns.items.find((campaign) => campaign.isCurrent);

if (currentCampaign?.status === PointsCampaignStatus.Active) {
  const summary = await domfi.points.summary({
    wallet: account.address,
    campaignId: currentCampaign.campaignId,
  });
  const pools = await domfi.points.pools({
    wallet: account.address,
    campaignId: currentCampaign.campaignId,
  });

  if (summary.totalDisplayKind === PointsTotalDisplayKind.Projected) {
    console.log("projected points", summary.campaignEstimatedPoints);
  }
  console.log("trader pool", pools.trader.campaignEstimatedPoints);
}

const proof: PointsProof | null = await domfi.points.proof(account.address);
if (proof?.claimableNow === true) {
  const claim = await domfi.points.claimWithProof(proof, { account: account.address });
  await claim.waitReceipt({ confirmations: 1 });
}

domfi.points.claim() fetches the current proof for the sender and submits Distributor.claim in one step. Use claimWithProof() when you already fetched and displayed the proof, or when you want to validate the exact proof that will be submitted. Claim writes need publicClient, walletClient, and a sender account; read-only points helpers need only an API-enabled client.

Errors And Diagnostics

SDK errors have stable public fields: code, kind, transient, required diagnostics, optional hint, optional hash, and original cause when available. Use isDomfiError() instead of instanceof so error handling remains stable across package subpaths and test/bundler module boundaries.

import { isDomfiError } from "@domfi/sdk/errors";

try {
  await domfi.system.apiStatus({ timeoutMs: 5_000 });
} catch (error) {
  if (isDomfiError(error)) {
    console.error(error.code, error.kind, error.transient, error.hint);
  }
  throw error;
}

Pass onEvent when creating a client to observe REST diagnostics and readiness warnings:

const observed = createDomfiClient({
  chain: "testnet",
  api: { baseUrl: "https://api.example.com/api/v2" },
  onEvent(event) {
    if (event.type === "warning") console.warn(event.code, event.message);
  },
});

await observed.system.apiStatus({ readinessPolicy: "warn" });

Common Errors

Every SDK error exposes a stable code and a kind; transient: true marks a retryable condition. Branch on code (stable) rather than the class. Narrow with isDomfiError(err) first.

| code | kind | Typical cause & fix | |---|---|---| | MISSING_API_CLIENT | config | Used an api/actions/vault/referrals/points namespace on an api: false client. Recreate with api. | | MISSING_PUBLIC_CLIENT | config | A read/prepare needs RPC. Pass a viem publicClient. | | MISSING_WALLET_CLIENT | wallet | A write needs signing. Pass a viem walletClient. | | MISSING_ACCOUNT | wallet | No account for the write. Pass account (client option or per-call). | | WALLET_CHAIN_MISMATCH | wallet | Wallet client is on a different chain than the configured chain. | | WALLET_ACCOUNT_MISMATCH | wallet | The wallet's account differs from the account you passed. | | WALLET_DISCONNECTED | wallet | (transient) Wallet/transport dropped. Reconnect and retry. | | READ_MODEL_NOT_READY | api | (transient) API read model is behind the chain. Retry, or relax readinessPolicy. | | PROTOCOL_COMPATIBILITY_MISMATCH | compatibility | On-chain contracts don't match the SDK's expected protocol. Align SDK/chain versions. | | IDENTITY_MISMATCH | identity | A tracked tx resolved to a different trader/trade than expected (often a delegation mixup). | | VALIDATION_ERROR | validation | Bad input, or an API response that failed schema validation. | | API_ERROR / API_* | api | REST call returned an error; inspect httpStatus / details. | | CONTRACT_REVERT / REVERT_* | contract | The contract reverted; REVERT_* is the decoded reason. | | TRANSPORT_ERROR | transport | (transient by default) Network/HTTP failure. | | TIMEOUT | timeout | (transient) Operation exceeded timeoutMs / maxDurationMs. | | ABORTED | abort | (transient) An AbortSignal you passed fired. |

Package Subpaths

The root export is the normal application entry point. Stable subpaths are available for focused imports:

import { createDomfiClient } from "@domfi/sdk";
import { currentPercentProfit, tradeFee } from "@domfi/sdk/math";
import type { DomfiRawClient } from "@domfi/sdk/api";
import { domfiChains } from "@domfi/sdk/config";
import { abis } from "@domfi/sdk/contracts";
import { ApiError } from "@domfi/sdk/errors";
import { PointsCampaignStatus, type PointsClient } from "@domfi/sdk/points";
import { ReferralEligibilityStatus, type ReferralClient } from "@domfi/sdk/referrals";
import { coerceBigInt } from "@domfi/sdk/serde";
import type { TokenClient } from "@domfi/sdk/token";
import { verifiedPositionRef } from "@domfi/sdk/trading";
import { Collateral, PairIndex } from "@domfi/sdk/units";
import type { ValuationClient } from "@domfi/sdk/valuation";
import { VaultAsset } from "@domfi/sdk/vault";

declare const raw: DomfiRawClient;
declare const points: PointsClient;
declare const referrals: ReferralClient;
declare const token: TokenClient;
declare const valuation: ValuationClient;

console.log(createDomfiClient, raw, points, referrals, token, valuation, domfiChains.testnet.chainId);
console.log(
  abis,
  ApiError,
  PointsCampaignStatus,
  ReferralEligibilityStatus,
  coerceBigInt,
  currentPercentProfit,
  tradeFee,
  verifiedPositionRef,
  Collateral,
  PairIndex,
  VaultAsset,
);

Examples & Further Reading

Runnable, type-checked examples live in examples/ (run via pnpm test:examples):

Jump to a domain: Core Concepts · Read The API · Token Approval · Delegated Trading · Trading · High-Level Actions · Valuation · Math Helpers · Vault · Referrals · Points · Errors.

License

Copyright (c) 2026 Domination Finance Ltd. All rights reserved.

This package is proprietary and confidential — it is not open source. No license is granted to use, copy, modify, or distribute it except under a separate written agreement. See LICENSE for the full terms.