> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nilemarkets.com/llms.txt
> Use this file to discover all available pages before exploring further.

# TypeScript SDK

> Use the @nile-markets/sdk package with viem or wagmi to read protocol state, open positions, and manage margin — exports typed ABIs, Side/Mode enums, PAIR_IDS, PAIRS, and TENORS constants.

## Installation

<Tabs>
  <Tab title="pnpm">
    ```bash theme={null}
    pnpm add @nile-markets/sdk viem
    ```
  </Tab>

  <Tab title="npm">
    ```bash theme={null}
    npm install @nile-markets/sdk viem
    ```
  </Tab>

  <Tab title="yarn">
    ```bash theme={null}
    yarn add @nile-markets/sdk viem
    ```
  </Tab>
</Tabs>

<Note>
  The SDK has zero runtime dependencies. `viem` is a peer dependency for type compatibility but is not
  imported by the SDK itself. You need `viem` (or `ethers`) separately to interact with the chain.
</Note>

## What the SDK Exports

### ABIs

Typed ABI arrays for every protocol contract, ready to use with `viem` or `wagmi`:

```typescript theme={null}
import {
  positionManagerAbi,
  marginAccountsAbi,
  poolVaultAbi,
  oracleModuleAbi,
  configAbi,
  modeControllerAbi,
  riskManagerAbi,
  settlementEngineAbi,
  mockUsdcAbi,
} from "@nile-markets/sdk";
```

### Constants

Enums and identifiers that match onchain values:

```typescript theme={null}
import {
  Side,
  Mode,
  PositionStatus,
  CloseReason,
  FeeType,
  MarginMode,
  PAIR_IDS,
  PAIRS,
  TENORS,
  getPairById,
  getPairByName,
  getTenorBySeconds,
  getTenorByLabel,
} from "@nile-markets/sdk";

// Side enum
Side.LONG   // 0 — trader profits when the base/quote rate rises
Side.SHORT  // 1 — trader profits when the base/quote rate falls

// Tenors are NOT an enum — use the bundled `TENORS` array
TENORS  // [{ seconds: 86400, label: "1D" }, { seconds: 604800, label: "1W" }, ...]
getTenorBySeconds(86400)?.label   // "1D"
getTenorByLabel("1M")?.seconds    // 2592000

// Protocol mode
Mode.NORMAL       // 0 — all operations enabled
Mode.DEGRADED     // 1 — degraded — opens blocked, closes/settlements/liquidations allowed
Mode.REDUCE_ONLY  // 2 — closes only
Mode.PAUSED       // 3 — all operations halted

// Fee type ordinals (match SettlementEngine.FeesCollected)
FeeType.LIQUIDATION_PENALTY  // 0
FeeType.EARLY_TERMINATION    // 1
FeeType.MATURITY             // 2
FeeType.TRADING              // 3

// Pair identifiers (keccak256 hashes)
PAIR_IDS.EUR_USD  // bytes32 hash of "EUR/USD"
PAIR_IDS.USD_JPY  // bytes32 hash of "USD/JPY"

// Bundled pair metadata cache (mirror of contracts/config/sepolia/defaults.json)
PAIRS  // [{ pairId, name: "EUR/USD", base: "EUR", quote: "USD", pythFeedId, ... }, ...]
getPairByName("EUR/USD")?.pairId
getPairById(PAIR_IDS.USD_JPY)?.displayDecimals  // 3
```

<Note>
  The bundled `PAIRS` and `TENORS` caches are sourced from the canonical defaults file and travel with each SDK release. For authoritative state at runtime, prefer the on-chain getters (`OracleModule.getAllPairs()` and `Config.getEnabledTenors()`) — they always reflect the live registry.
</Note>

### Labels

Pair-agnostic labels ship from the SDK; pair-aware side labels (e.g. `"Long EUR"` vs `"Short USD"`) come from `@nile-markets/shared`. Side labels derive from the pair's base currency — Pyth-native ordering, so `USD/JPY` → `"Long USD"`, not `"Long JPY"`.

```typescript theme={null}
import {
  MODE_LABELS,
  CLOSE_REASON_LABELS,
  POSITION_STATUS_LABELS,
  FEE_TYPE_LABELS,
  MARGIN_MODE_LABELS,
  tenorLabel,
  getPairByName,
} from "@nile-markets/sdk";
import { getSideLabel } from "@nile-markets/shared";

tenorLabel(604800)                                     // "1W"
MODE_LABELS[Mode.NORMAL]                               // "Normal"
CLOSE_REASON_LABELS[CloseReason.LIQUIDATED]            // "Liquidated"
FEE_TYPE_LABELS[FeeType.TRADING]                       // "Trading Fee"
getSideLabel(getPairByName("EUR/USD"), Side.LONG)      // "Long EUR"
getSideLabel(getPairByName("USD/JPY"), Side.SHORT)     // "Short USD"
```

## Setting Up a Client

Create a viem public client to read contract state. For write operations, you also need a wallet
client.

```typescript theme={null}
import { createPublicClient, createWalletClient, http } from "viem";
import { sepolia } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";

// Read-only client
const publicClient = createPublicClient({
  chain: sepolia,
  transport: http("YOUR_RPC_URL"),
});

// Write client (for transactions)
const account = privateKeyToAccount("0xYOUR_PRIVATE_KEY");
const walletClient = createWalletClient({
  account,
  chain: sepolia,
  transport: http("YOUR_RPC_URL"),
});
```

See [Contract Addresses](/build/contract-addresses) for all deployed addresses on Sepolia.

## Reading Contract State

### Pool State

Query the PoolVault for total deposits and share supply:

```typescript theme={null}
import { poolVaultAbi } from "@nile-markets/sdk";
import { formatUnits } from "viem";

const POOL_VAULT = "0x..."; // See Contract Addresses page

const [totalAssets, totalSupply, utilization] = await Promise.all([
  publicClient.readContract({
    address: POOL_VAULT,
    abi: poolVaultAbi,
    functionName: "totalAssets",
  }),
  publicClient.readContract({
    address: POOL_VAULT,
    abi: poolVaultAbi,
    functionName: "totalSupply",
  }),
  publicClient.readContract({
    address: POOL_VAULT,
    abi: poolVaultAbi,
    functionName: "riskCapacityUtilization",
  }),
]);

console.log(`Pool USDC: ${formatUnits(totalAssets, 6)}`);
console.log(`Shares outstanding: ${formatUnits(totalSupply, 6)}`);
console.log(`Share price: ${Number(totalAssets) / Number(totalSupply)}`);
console.log(`Utilization: ${Number(utilization) / 100}%`); // bps → percent
```

### Forward Prices

Read the current EUR/USD forward price for a specific tenor. `getForwardByTenor` resolves the next fixing timestamp for that tenor automatically:

```typescript theme={null}
import { oracleModuleAbi, PAIR_IDS, getTenorByLabel } from "@nile-markets/sdk";
import { formatUnits } from "viem";

const ORACLE_MODULE = "0x..."; // See Contract Addresses page
const tenorSeconds = getTenorByLabel("1W")!.seconds; // 604800

const [fixingTimestamp, forward] = await publicClient.readContract({
  address: ORACLE_MODULE,
  abi: oracleModuleAbi,
  functionName: "getForwardByTenor",
  args: [PAIR_IDS.EUR_USD, tenorSeconds],
});

console.log(`EUR/USD 1W forward: ${formatUnits(forward.forwardPrice, 18)}`);
console.log(`Maturity: ${new Date(Number(fixingTimestamp) * 1000).toISOString()}`);
console.log(`Published at: ${new Date(Number(forward.publishTimestamp) * 1000).toISOString()}`);
```

### Protocol Mode

Check the current operating mode before submitting transactions:

```typescript theme={null}
import { modeControllerAbi, Mode } from "@nile-markets/sdk";

const MODE_CONTROLLER = "0x..."; // See Contract Addresses page

const mode = await publicClient.readContract({
  address: MODE_CONTROLLER,
  abi: modeControllerAbi,
  functionName: "currentMode",
});

if (mode !== Mode.NORMAL) {
  console.warn("Protocol is not in NORMAL mode — new positions are disabled");
}
```

### Margin Account Balance

Read a trader's deposited collateral and available balance:

```typescript theme={null}
import { marginAccountsAbi } from "@nile-markets/sdk";
import { formatUnits } from "viem";

const MARGIN_ACCOUNTS = "0x..."; // See Contract Addresses page
const trader = "0xYOUR_ADDRESS";

const [collateral, locked, available] = await Promise.all([
  publicClient.readContract({
    address: MARGIN_ACCOUNTS,
    abi: marginAccountsAbi,
    functionName: "collateralBalance",
    args: [trader],
  }),
  publicClient.readContract({
    address: MARGIN_ACCOUNTS,
    abi: marginAccountsAbi,
    functionName: "imLockedTotal",
    args: [trader],
  }),
  publicClient.readContract({
    address: MARGIN_ACCOUNTS,
    abi: marginAccountsAbi,
    functionName: "availableBalance",
    args: [trader],
  }),
]);

console.log(`Total collateral: ${formatUnits(collateral, 6)} USDC`);
console.log(`Locked in positions: ${formatUnits(locked, 6)} USDC`);
console.log(`Available to trade: ${formatUnits(available, 6)} USDC`);
```

## Writing Transactions

### Approve USDC and Open a Position

Opening a position requires two transactions: approve USDC spending, then call `openPosition`.

```typescript theme={null}
import {
  positionManagerAbi,
  mockUsdcAbi,
  Side,
  PAIR_IDS,
  getTenorByLabel,
} from "@nile-markets/sdk";
import { parseUnits } from "viem";

const USDC = "0x...";              // See Contract Addresses page
const POSITION_MANAGER = "0x...";  // See Contract Addresses page

const notional = parseUnits("10000", 6);  // 10,000 USDC notional
const margin = parseUnits("500", 6);      // 500 USDC margin
const tenorSeconds = getTenorByLabel("1W")!.seconds; // 604800

// Step 1: Approve PositionManager to spend your USDC
const approveHash = await walletClient.writeContract({
  address: USDC,
  abi: mockUsdcAbi,
  functionName: "approve",
  args: [POSITION_MANAGER, margin],
});

// Wait for approval to confirm
await publicClient.waitForTransactionReceipt({ hash: approveHash });

// Step 2: Open the position
const openHash = await walletClient.writeContract({
  address: POSITION_MANAGER,
  abi: positionManagerAbi,
  functionName: "openPosition",
  args: [
    {
      pairId: PAIR_IDS.EUR_USD,
      side: Side.LONG,
      notional,
      tenorSeconds,
      margin,
    },
  ],
});

const receipt = await publicClient.waitForTransactionReceipt({ hash: openHash });
console.log(`Position opened in tx: ${receipt.transactionHash}`);
```

### Deposit Margin

Deposit USDC collateral into your MarginAccounts balance:

```typescript theme={null}
import { marginAccountsAbi, mockUsdcAbi } from "@nile-markets/sdk";
import { parseUnits } from "viem";

const USDC = "0x...";
const MARGIN_ACCOUNTS = "0x...";

const amount = parseUnits("1000", 6); // 1,000 USDC

// Approve MarginAccounts to pull USDC
const approveHash = await walletClient.writeContract({
  address: USDC,
  abi: mockUsdcAbi,
  functionName: "approve",
  args: [MARGIN_ACCOUNTS, amount],
});
await publicClient.waitForTransactionReceipt({ hash: approveHash });

// Deposit
const depositHash = await walletClient.writeContract({
  address: MARGIN_ACCOUNTS,
  abi: marginAccountsAbi,
  functionName: "deposit",
  args: [amount],
});
await publicClient.waitForTransactionReceipt({ hash: depositHash });
```

## Numeric Precision

All onchain values use fixed-point integers. You need to convert between human-readable numbers and
raw contract values.

| Value Type                            | Decimals | Raw Example           | Human-Readable  |
| ------------------------------------- | -------- | --------------------- | --------------- |
| USDC amounts (notional, margin, fees) | 6        | `10000000000`         | 10,000.00 USDC  |
| Prices (spot, forward, strike)        | 18       | `1080000000000000000` | 1.08000 EUR/USD |
| Basis points (fees, utilization)      | 0        | `200`                 | 2.00%           |

Use viem's `parseUnits` and `formatUnits` for conversion:

```typescript theme={null}
import { parseUnits, formatUnits } from "viem";

// Human → contract
const usdcAmount = parseUnits("500.00", 6);    // 500000000n
const price = parseUnits("1.08500", 18);        // 1085000000000000000n

// Contract → human
const humanUsdc = formatUnits(500000000n, 6);   // "500.0"
const humanPrice = formatUnits(1085000000000000000n, 18); // "1.085"
```

<Warning>
  Never use floating-point arithmetic with contract values. Always operate on `bigint` values and
  convert to human-readable strings only for display.
</Warning>

## Using with wagmi

If you are building a React frontend with wagmi, the SDK ABIs work directly with wagmi hooks:

```typescript theme={null}
import { useReadContract, useWriteContract } from "wagmi";
import { poolVaultAbi } from "@nile-markets/sdk";

function PoolStats({ vaultAddress }: { vaultAddress: `0x${string}` }) {
  const { data: totalAssets } = useReadContract({
    address: vaultAddress,
    abi: poolVaultAbi,
    functionName: "totalAssets",
  });

  return <div>Pool: {totalAssets ? formatUnits(totalAssets, 6) : "..."} USDC</div>;
}
```

## Related Pages

<Columns cols={2}>
  <Card title="Contract Addresses" icon="map-pin" href="/build/contract-addresses">
    Sepolia deployment addresses for all contracts.
  </Card>

  <Card title="Types Reference" icon="code" href="/build/types-reference">
    Full enum and struct definitions used across the protocol.
  </Card>

  <Card title="Quick Start" icon="rocket" href="/build/quick-start">
    End-to-end setup from zero to querying protocol state.
  </Card>

  <Card title="Open a Position" icon="plus" href="/build/open-position-tutorial">
    Step-by-step tutorial for your first trade.
  </Card>
</Columns>
