Skip to main content
These contracts are deployed on Ethereum Sepolia testnet only. This is not a production deployment. All parameters, addresses, and behaviors are subject to change. Do not use with real funds.

Sepolia Contracts

All contracts were deployed in a single atomic deployment starting at block 10,391,511.
ContractAddressDescription
Protocol0xC20E775e274314570DAa1d50a191750753F686dARoot registry for all contract addresses
Config0x8653f27FB34bF845c7C16Dca07DFf7A0cd2A6557Configurable parameters (margin, fees, tenors)
OracleModule0x1f78995b606CCF768E0a532Be8A1AB6eDf3Cd4D5Pyth spot prices + publisher-pushed forward prices
ModeController0x2b7775De7a4696f05D875BDE8f983303A3d49582Operating mode state machine (NORMAL/DEGRADED/REDUCE_ONLY/PAUSED)
RiskManager0xd82515b62501F011DA2BaFA877B57f8713dc20EeRisk caps, exposure limits, and validation
MarginAccounts0x12c310A5A5B5771459ff96979931CddE75A6D935Collateral deposits, margin locking, PnL settlement
PoolVault0x61208f0337eE40278b0cbc55daEE7A37Fa180618ERC-4626 liquidity pool for LP deposits
PositionManager0x8d81E9f1D0F0d1BdAAc0a91AFc2976522429A0cdPosition lifecycle (open, increase, close)
SettlementEngine0x86f9339EC3Ca09aa51E1862911678C696eC09470Settlement, liquidation, and early termination
MockUSDC0x319FeC6Cc374922A183A354a41E89b7A313EE547Test USDC token (6 decimals, faucet-mintable)
Start Block: 10391511 — Use this as the startBlock in subgraph configurations to avoid scanning from genesis. All contract events begin at or after this block.

Block Explorer

All contracts are verified on Sepolia Etherscan. You can view source code, read/write functions, and transaction history:
https://sepolia.etherscan.io/address/<CONTRACT_ADDRESS>
For example, to view the PositionManager:
https://sepolia.etherscan.io/address/0x8d81E9f1D0F0d1BdAAc0a91AFc2976522429A0cd

Contract Architecture

Protocol (Root Registry)
+-- Shared Infrastructure
|   +-- Config             -- All configurable parameters
|   +-- OracleModule       -- Pyth spot + publisher-pushed forwards
|   +-- ModeController     -- Operating mode state machine
|   +-- RiskManager        -- Risk caps and validation
+-- Pool 0 (USDC)
    +-- MarginAccounts     -- Collateral and margin management
    +-- PoolVault          -- ERC-4626 liquidity pool
    +-- PositionManager    -- Position lifecycle
    +-- SettlementEngine   -- Settlement, liquidation, termination
All contracts are non-upgradeable (no proxy pattern). Logic changes require a full redeployment.

Loading Addresses in Code

TypeScript (Frontend / SDK)

The frontend loads addresses from the deployment JSON file via the getAddress helper:
import { getAddress } from "@/config/addresses";
import { useChainId } from "wagmi";
import { positionManagerAbi } from "@nile-markets/sdk";

// In a React component
const chainId = useChainId();
const positionManagerAddress = getAddress(chainId, "positionManager");

// Use with wagmi hooks
const { data } = useReadContract({
  address: positionManagerAddress,
  abi: positionManagerAbi,
  functionName: "getPosition",
  args: [positionId],
});
The address configuration automatically resolves based on the connected chain ID (e.g., 31337 for Anvil, 11155111 for Sepolia).

Rust (Keeper / Publisher)

Rust services receive contract addresses via environment variables or CLI arguments:
use alloy::primitives::Address;
use fx_contracts::generated::settlement_engine::SettlementEngine;

// Address from environment variable
let settlement_address: Address = std::env::var("SETTLEMENT_ENGINE_ADDRESS")
    .expect("SETTLEMENT_ENGINE_ADDRESS required")
    .parse()
    .expect("Invalid address");

// Create contract instance
let contract = SettlementEngine::new(settlement_address, &provider);

// Call contract functions
let stats = contract.getPositionStats(pair_id).call().await?;
For the EUR/USD pair ID constant:
use fx_contracts::EUR_USD_PAIR_ID;

// Pre-computed keccak256("EUR/USD") -- matches the TypeScript SDK
let pair_id = EUR_USD_PAIR_ID;

Subgraph

The subgraph references contract addresses in subgraph.yaml:
dataSources:
  - kind: ethereum
    name: PositionManager
    source:
      address: "0x8d81E9f1D0F0d1BdAAc0a91AFc2976522429A0cd"
      abi: PositionManager
      startBlock: 10391511
    mapping:
      # ...
After each redeployment, update the startBlock values in subgraph.yaml to match the new deployment block. Starting from block 0 forces Graph Node to scan every block from genesis, which is extremely slow on Sepolia.

Deployment JSON

{
  "config": "0x8653f27FB34bF845c7C16Dca07DFf7A0cd2A6557",
  "marginAccounts": "0x12c310A5A5B5771459ff96979931CddE75A6D935",
  "modeController": "0x2b7775De7a4696f05D875BDE8f983303A3d49582",
  "oracleModule": "0x1f78995b606CCF768E0a532Be8A1AB6eDf3Cd4D5",
  "poolVault": "0x61208f0337eE40278b0cbc55daEE7A37Fa180618",
  "positionManager": "0x8d81E9f1D0F0d1BdAAc0a91AFc2976522429A0cd",
  "protocol": "0xC20E775e274314570DAa1d50a191750753F686dA",
  "riskManager": "0xd82515b62501F011DA2BaFA877B57f8713dc20Ee",
  "settlementEngine": "0x86f9339EC3Ca09aa51E1862911678C696eC09470",
  "startBlock": 10391511,
  "usdc": "0x319FeC6Cc374922A183A354a41E89b7A313EE547"
}
Contract addresses should never be stored in environment variables. They are always loaded from the deployment JSON file, which is generated by the deploy script and committed to the repository.