Skip to main content

Sepolia Contracts

All contracts were deployed in a single atomic deployment starting at block 10,391,511.
ContractAddressDescription
Protocol0xC20E775e274314570DAa1d50a191750753F686dARoot registry for all contract addresses and role assignments
Config0x8653f27FB34bF845c7C16Dca07DFf7A0cd2A6557Configurable parameters (margin factors, fee rates, tenors, risk caps)
OracleModule0x1f78995b606CCF768E0a532Be8A1AB6eDf3Cd4D5Pyth spot prices + publisher-pushed forward prices with safeguards
ModeController0x2b7775De7a4696f05D875BDE8f983303A3d49582Operating mode state machine (NORMAL / DEGRADED / REDUCE_ONLY / PAUSED)
RiskManager0xd82515b62501F011DA2BaFA877B57f8713dc20EePer-position, per-account, and pool-level exposure caps and validation
MarginAccounts0x12c310A5A5B5771459ff96979931CddE75A6D935Collateral deposits, margin locking, and PnL settlement
PoolVault0x61208f0337eE40278b0cbc55daEE7A37Fa180618ERC-4626 liquidity pool for LP deposits and share token management
PositionManager0x8d81E9f1D0F0d1BdAAc0a91AFc2976522429A0cdPosition lifecycle: open, increase, reduce, close, margin management
SettlementEngine0x86f9339EC3Ca09aa51E1862911678C696eC09470Settlement at maturity, liquidation, and early termination processing
MockUSDC0x319FeC6Cc374922A183A354a41E89b7A313EE547Test USDC token (6 decimals) with public mint faucet function
Start Block: 10391511 — Use this as the startBlock in subgraph configurations and event scanning to avoid processing blocks before the deployment. All contract events begin at or after this block.

External Dependencies

The protocol integrates with external infrastructure that is not operated by the Nile Markets team.
DependencyIdentifierPurpose
Pyth EUR/USD Price Feed0xa995d00bb36a63cef7fd2c287dc105fc8f3d93779f062f09551b0af3e81ec30bReal-time EUR/USD spot price used for fixing prices and oracle health checks
Pyth Network (Sepolia)pyth.networkDecentralized oracle network providing the underlying price feed
The Pyth price feed ID is a bytes32 identifier, not an Ethereum address. It is used by the publisher service to fetch prices from the Pyth Hermes API and by the OracleModule to verify onchain price updates.

Block Explorer

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

Contract Architecture

The contracts are organized into shared infrastructure (singletons) and per-pool instances:
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). Parameters are configurable via the Config contract, but contract logic is immutable. 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, which resolves the correct address based on the connected chain ID:
import { getAddress } from "@/config/addresses";
import { useChainId } from "wagmi";
import { positionManagerAbi } from "@nile-markets/sdk";

const chainId = useChainId();
const positionManager = getAddress(chainId, "positionManager");
Address resolution by chain:
  • Chain ID 11155111 (Sepolia) loads from deployments/sepolia/addresses.json
  • Chain ID 31337 (Anvil) loads from deployments/anvil/addresses.json

TypeScript (Standalone / Node.js)

For scripts or services that do not use wagmi, reference addresses directly:
import { createPublicClient, http } from "viem";
import { sepolia } from "viem/chains";
import { poolVaultAbi } from "@nile-markets/sdk";

const client = createPublicClient({
  chain: sepolia,
  transport: http("YOUR_RPC_URL"),
});

const POOL_VAULT = "0x61208f0337eE40278b0cbc55daEE7A37Fa180618";

const totalAssets = await client.readContract({
  address: POOL_VAULT,
  abi: poolVaultAbi,
  functionName: "totalAssets",
});

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;

let address: Address = std::env::var("SETTLEMENT_ENGINE_ADDRESS")
    .expect("SETTLEMENT_ENGINE_ADDRESS required")
    .parse()
    .expect("Invalid address");

let contract = SettlementEngine::new(address, &provider);
For the EUR/USD pair ID constant (pre-computed keccak256("EUR/USD")):
use fx_contracts::EUR_USD_PAIR_ID;
let pair_id = EUR_USD_PAIR_ID;

Subgraph

The subgraph references contract addresses in subgraph.yaml data sources:
dataSources:
  - kind: ethereum
    name: PositionManager
    source:
      address: "0x8d81E9f1D0F0d1BdAAc0a91AFc2976522429A0cd"
      abi: PositionManager
      startBlock: 10391511
    mapping:
      # ...handler configuration

Deployment JSON

The canonical source of truth for addresses is the deployment JSON file generated by the deploy script:
{
  "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. This ensures a single source of truth that stays in sync across all consumers (frontend, subgraph, tests).