Contracts & Addresses

The protocol core is deployed via CREATE3, so the addresses are identical on testnet and mainnet:

ContractAddress (testnet 50312 = mainnet 5031)
BinaryMarketsModule0x3ecC694Cef705358864a646142ac17A90E29e388
MarketsCore0x2802504314685D89bF6C992CA5a8e7cC78bc0294
BinarySettlement0xbF4a49e0Dfd092e5FBE8E5761064C49533e6Ed23
OutcomeToken69090xB52c5934113Af5c0Bb20eb3C72290C8215f755b9
OracleHub0xe40db387cC98601Dd11bd634fF2f3AD5686dE32b
CollateralRouter0xbC0C9834B15ACE38bB50dDaa7d7f7C7CC4DC183C

Per-market contracts (the market and its pool) are read from the module registry — markets(marketId) — or from the SDK; never hardcode them, since pools are recycled across windows.

Collateral is per-venue:

NetworkTokenAddressDecimals
MainnetUSDso0x00000022dA000002656c64D9eA6011ea952D008A18
TestnettUSDC0x70a86D8842FB63C4Ad2b7cdddF530eBf1BB25d8E6

The two differ by a factor of 10^12. A constant that converts correctly on testnet misprices every order, book read and balance on mainnet, and nothing reverts to tell you — derive the scale from the collateral's decimals() rather than from a literal.

These are proxies, so each one's implementation can roll forward while the address stays put. Check any of them on the Somnia explorer: mainnet and testnet.

Working from a non-JS stack? @somnia-chain/markets-sdk exports the ABIs you need directly (binaryModuleReadAbi, binaryModuleWriteAbi, binarySettlementAbi, erc6909Abi, oracleHubAbi), so you can pull them out of the package and drive the contracts with any RPC client. The package ships its own sources, so npm pack and open src/ to read them as human-readable signature strings that mirror the Solidity.

Confirm the addresses on-chain before trading real funds, and never hardcode a market or pool address: those are per-window, and pools are recycled across windows. Read them from the module registry or the SDK instead.

Getting testnet collateral

The testnet token mints on demand, so there is no faucet page and no address to paste anywhere: faucet(uint256 amount) credits msg.sender, and each call is capped at 10,000 tUSDC. Asking for more reverts with FaucetCapExceeded.

ts
await exchange.trader.faucet();                       // 10,000 tUSDC, the cap
await exchange.trader.faucet({ amount: 500n * 10n ** 6n });  // raw units, 6 decimals