Skip to main content

Local Development Environment

The full local stack runs via docker-compose. All services connect to a local Anvil chain with deployed contracts and mock oracles. Start the stack with cd infra && docker compose --profile m2 up -d. For system-level sequence diagrams, see System Flows.

Forking Sepolia

To test against the live Sepolia deployment without deploying your own contracts, fork the testnet locally:
anvil --fork-url $SEPOLIA_RPC_URL --fork-block-number <LATEST_BLOCK>
This creates a local chain with all deployed contracts at their current state. You can interact with them using the same addresses as on Sepolia, while having full control over block production and account balances.
Use cast rpc anvil_setBalance <address> <amount> to give test accounts ETH for gas, and interact with the MockUSDC contract to mint test collateral.

Test Vectors

The following test vectors can be used to verify your integration calculations match the protocol’s onchain behavior.

PnL Calculation

InputValue
Notional1,000 USDC (1,000,000,000 raw, 6 decimals)
Entry Price1.08 EUR/USD (1,080,000,000,000,000,000 raw, 18 decimals)
Current Price1.10 EUR/USD (1,100,000,000,000,000,000 raw, 18 decimals)
Expected PnL (LONG)+20 USDC
Expected PnL (SHORT)-20 USDC
PnL formula: notional × (currentPrice − entryPrice) / entryPrice. For SHORT positions, the sign is inverted. See PnL Calculation for details.

Margin Requirements

InputValue
Notional1,000 USDC
IM Factor200 bps (2%)
Required Initial Margin20 USDC
MM Factor100 bps (1%)
Required Maintenance Margin10 USDC

Common Errors

When integrating with the protocol, you may encounter these revert errors:
ErrorCauseResolution
OracleInvalid()The publisher has not published forward prices yet, or oracle data has gone staleStart the publisher service and wait for the first price update
ProtocolPaused()The protocol is in PAUSED modeCheck the ModeController state. If auto-paused due to oracle, restore oracle data and have admin de-escalate
InsufficientAvailableBalance()The account does not have enough free collateral for the requested operationDeposit more USDC collateral or reduce existing position sizes to free up margin
ReduceOnlyMode()The protocol is in DEGRADED or REDUCE_ONLY modeOnly closing operations (close, settle, liquidate) are permitted. Wait for admin to restore NORMAL mode

Debugging Tips

Reading Contract State

Use Foundry’s cast tool to query onchain state directly:
# Read the current protocol mode
cast call <ModeController> "currentMode()(uint8)" --rpc-url $RPC_URL

# Read an account's collateral balance
cast call <MarginAccounts> "collateralBalance(address)(uint256)" <account> --rpc-url $RPC_URL

# Read a position's details
cast call <PositionManager> "getPosition(uint256)((address,uint8,uint8,uint8,uint256,uint256,int256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint8))" <positionId> --rpc-url $RPC_URL

Sending Transactions

Use cast send to interact with contracts from the command line:
# Deposit collateral (after approving USDC)
cast send <MarginAccounts> "deposit(uint256)" <amount> --private-key $PRIVATE_KEY --rpc-url $RPC_URL

# Open a position
cast send <PositionManager> "openPosition(bytes32,uint8,uint8,uint256,uint256)" \
  <pairId> <side> <tenor> <notional> <margin> \
  --private-key $PRIVATE_KEY --rpc-url $RPC_URL
Always start the publisher before attempting to open positions. Without published forward prices, the oracle will return invalid data and all position operations will revert with OracleInvalid().