Deployment Guide

Prerequisites

  • Foundryarrow-up-right installed (forge, anvil, cast)

  • BNB for gas fees

  • Deployer EOA private key

  • BscScan API key (for contract verification)

Environment Variables

export PRIVATE_KEY=0x...                # Deployer private key
export RPC_URL=https://...              # BSC RPC endpoint
export PYTH_ADDRESS=0x...              # Pyth Core contract address (see table below)
export ETHERSCAN_API_KEY=...           # BscScan API key for verification

Pyth Oracle Addresses

Network
Chain ID
Pyth Core Address

BSC Testnet

97

0x5744Cbf430D99456a0A8771208b674F27f8EF0Fb

BSC Mainnet

56

0x4D7E825f80bDf85e913E0DD2A2D54927e9dE1594

Deployment Order

The canonical BSC deploy entrypoint is script/DeployTestnet.s.sol:DeployTestnetScript. Despite the name, it is chain-aware and is the script currently used for both BSC testnet (chainid=97) and BSC mainnet (chainid=56). It also deploys and wires AIResolver.

Contracts must be deployed in this exact order because of immutable constructor references:

Constructor Arguments

Contract
Constructor Args

Vault(admin, collateralToken)

deployer address, USDT address

OutcomeToken(admin)

deployer address

FeeModel(admin, feeBps, protocolFeeCollector)

deployer, 20, deployer

OrderBook(admin, vault, feeModel, outcomeToken)

deployer, Vault address, FeeModel address, OutcomeToken address

BatchAuction(admin, orderBook, vault, outcomeToken)

deployer, OrderBook, Vault, OutcomeToken

MarketFactory(admin, orderBook, outcomeToken)

deployer, OrderBook, OutcomeToken

PythResolver(pyth, factory)

PYTH_ADDRESS, MarketFactory

AIResolver(factory, treasury)

MarketFactory, deployer or configured treasury

Redemption(factory, outcomeToken, vault)

MarketFactory, OutcomeToken, Vault

Role Wiring

After all contracts are deployed, grant the following roles. The deployer holds DEFAULT_ADMIN_ROLE on every AccessControl contract and can call grantRole.

OrderBook.OPERATOR_ROLE

BatchAuction needs OPERATOR_ROLE to call reduceOrderLots, updateTreeVolume, and advanceBatch. MarketFactory needs it to call registerMarket and deactivateMarket. In production, the keeper is also granted OPERATOR_ROLE so it can drive batch clearing.

Vault.PROTOCOL_ROLE

OrderBook calls lock and unlock. BatchAuction calls settleFill and unlock. Redemption calls redeemFromPool.

OutcomeToken.MINTER_ROLE

BatchAuction calls mintSingle during inline settlement. Redemption calls redeem (burns winning tokens).

MarketFactory.ADMIN_ROLE

PythResolver and AIResolver call resolution functions on MarketFactory. Production deployments also grant keeper and resolution-keeper admin access on the factory, plus market-creation rights for the deployer and keeper.

AIResolver Keeper Wiring

PythResolver Admin

PythResolver uses simple ownership (not AccessControl). The admin is set to msg.sender in the constructor (the deployer). Transfer via two-step process:

Deploy Commands

Local Devnet (Anvil)

For local development and testing:

The local-only Deploy.s.sol script deploys a MockPyth instance, wires all roles, and creates a test market automatically.

BSC Testnet / Mainnet

DeployTestnetScript auto-detects block.chainid, chooses the correct real Pyth address for BSC testnet or mainnet, deploys AIResolver, and wires the production role set.

Note: script/DeployMainnet.s.sol still exists in the repo, but the canonical production path is the chain-aware DeployTestnet.s.sol:DeployTestnetScript flow above.

Parimutuel Contract Deployment

The parimutuel stack is intentionally isolated from the binary CLOB contracts and is deployed with script/DeployParimutuel.s.sol:DeployParimutuelScript.

It deploys and wires:

  1. ParimutuelFactory

  2. ParimutuelVault

  3. ParimutuelPoolManager

  4. ParimutuelRedemption

  5. ParimutuelAIResolver

  6. ParimutuelPythResolver

Required env:

Recommended mainnet role env:

PARIMUTUEL_MARKET_CREATOR should be the keeper/admin-server signer so production admin tooling can create markets. PARIMUTUEL_KEEPER should be the resolution keeper because the infra lifecycle task drives AI/Pyth parimutuel resolution with the resolution sender.

Deploy:

After deployment, update the address registry, strike-infra Ansible group vars, and strike-frontend/src/lib/contracts.ts before enabling mainnet UI/keeper flows.

Contract Verification

Deploy scripts pass --verify to auto-verify on BscScan. To verify a contract manually:

For contracts with complex constructor args, use cast abi-encode to produce the correct encoding.

Post-Deploy Validation Checklist

  1. Contract verification -- all contracts verified on BscScan.

  2. Role wiring -- confirm every role grant:

  3. Role checks:

    • OrderBook.hasRole(OPERATOR_ROLE, BatchAuction) -- true

    • OrderBook.hasRole(OPERATOR_ROLE, MarketFactory) -- true

    • Vault.hasRole(PROTOCOL_ROLE, OrderBook) -- true

    • Vault.hasRole(PROTOCOL_ROLE, BatchAuction) -- true

    • Vault.hasRole(PROTOCOL_ROLE, Redemption) -- true

    • OutcomeToken.hasRole(MINTER_ROLE, BatchAuction) -- true

    • OutcomeToken.hasRole(MINTER_ROLE, Redemption) -- true

    • MarketFactory.hasRole(ADMIN_ROLE, PythResolver) -- true

  4. Test market creation -- call MarketFactory.createMarket(...) with a known Pyth price ID (requires MARKET_CREATOR_ROLE) and verify the market appears in activeMarkets.

  5. Test place/cancel cycle -- approve Vault for USDT, call OrderBook.placeOrder(...) and verify USDT collateral is escrowed in Vault. Cancel the order and verify USDT is returned to wallet.

  6. Keepers configured -- batch-keeper, market-keeper, and resolution-keeper (in strike-infra) pointing at correct contract addresses.

  7. Indexer configured -- indexer (in strike-infra) pointing at correct RPC and contract addresses, listening for all relevant events.

  8. SDK / docs updated -- update SDK defaults and published deployment docs/README so integrators pick up the new mainnet and testnet addresses.

Last updated