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.
| Contract | Address | Description |
|---|
| Protocol | 0xC20E775e274314570DAa1d50a191750753F686dA | Root registry for all contract addresses |
| Config | 0x8653f27FB34bF845c7C16Dca07DFf7A0cd2A6557 | Configurable parameters (margin, fees, tenors) |
| OracleModule | 0x1f78995b606CCF768E0a532Be8A1AB6eDf3Cd4D5 | Pyth spot prices + publisher-pushed forward prices |
| ModeController | 0x2b7775De7a4696f05D875BDE8f983303A3d49582 | Operating mode state machine (NORMAL/DEGRADED/REDUCE_ONLY/PAUSED) |
| RiskManager | 0xd82515b62501F011DA2BaFA877B57f8713dc20Ee | Risk caps, exposure limits, and validation |
| MarginAccounts | 0x12c310A5A5B5771459ff96979931CddE75A6D935 | Collateral deposits, margin locking, PnL settlement |
| PoolVault | 0x61208f0337eE40278b0cbc55daEE7A37Fa180618 | ERC-4626 liquidity pool for LP deposits |
| PositionManager | 0x8d81E9f1D0F0d1BdAAc0a91AFc2976522429A0cd | Position lifecycle (open, increase, close) |
| SettlementEngine | 0x86f9339EC3Ca09aa51E1862911678C696eC09470 | Settlement, liquidation, and early termination |
| MockUSDC | 0x319FeC6Cc374922A183A354a41E89b7A313EE547 | Test 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.