Prerequisites
- Copy
.env.exampleto.envand configure the required variables - Ensure you have sufficient funds in the deployer wallet
Environment Configuration
Configure the following variables in your .env file:
# Required: Your deployer's private key
PRIVATE_KEY="0x..."
# Optional: Admin address for all contracts (defaults to deployer wallet)
ADMIN_PUBLIC_KEY=""
# Optional: Fee receiver address (defaults to admin)
SYMMIO_FEE_RECEIVER=""
# Optional: Existing collateral token address
# If not set, a FakeStablecoin will be deployed (useful for local testing)
COLLATERAL_ADDRESS=""
# Deploy SymmioPartyB contract (default: true, set to "false" to skip)
DEPLOY_PARTYB="true"
# Optional: Signer address for SymmioPartyB (ERC-1271 signature verification)
PARTYB_SIGNER=""
# Register a dummy affiliate for testing (default: true, set to "false" to skip)
REGISTER_DUMMY_AFFILIATE="true"
# Setup InstantLayer templates for OpenPosition and ClosePosition flows
# (default: true, set to "false" to skip)
SETUP_INSTANT_LAYER_TEMPLATES="true"
# Optional: existing MuonSignatureVerifier address
# If empty, deploy:system deploys a new MuonSignatureVerifier
MUON_SIGNATURE_VERIFIER_ADDRESS=""
# Optional: Muon app/runtime config on Diamond
# If set, deploy:system calls setMuonIds(muonAppId)
MUON_APP_ID=""
# If BOTH are set, deploy:system calls setMuonConfig(upnlValidTime, priceValidTime)
MUON_UPNL_VALID_TIME=""
MUON_PRICE_VALID_TIME=""
# Optional: seed MuonSignatureVerifier keys/signers
# addPublicKey is called only when BOTH are set
MUON_PUBLIC_KEY_X=""
MUON_PUBLIC_KEY_PARITY="" # 0 or 1
# Comma-separated addresses, e.g. "0xabc...,0xdef..."
MUON_GATEWAY_SIGNERS=""
# Deployment log level: "silent" (default), "minimal", or "verbose"
DEPLOY_LOG_LEVEL="minimal"
Deployment
Local Anvil Deployment (Recommended for PartyB Testing)
- Start a local Anvil node:
anvil #or "anvil --disable-code-size-limit" if you see the limit problem
- Configure
.envfor local testing (minimal config):
# Just the private key - everything else uses sensible defaults
PRIVATE_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
- Run the deployment:
npx hardhat deploy:system --network localhost
Testnet/Mainnet Deployment
npx hardhat deploy:system --network <NETWORK_NAME>
Checkpoint System (Resumable Deployments)
The deployment system supports checkpointing for resumable deployments. If a deployment is interrupted (network error, out of gas, etc.), you can resume from where it left off.
How It Works
- Checkpoint files are saved to
tasks/data/checkpoints/checkpoint-<chainId>.json - Each contract deployment and setup step is checkpointed immediately after completion
- On resume, already-completed steps are skipped automatically
- Diamond cuts are verified on-chain to handle edge cases where tx succeeded but checkpoint wasn't saved
Commands
# Resume from existing checkpoint (default behavior)
npx hardhat deploy:system --network <NETWORK_NAME>
# Force fresh deployment, ignoring any existing checkpoint
npx hardhat deploy:system --network <NETWORK_NAME> --fresh
Checkpoint Status Display
When resuming, you'll see a status display showing:
- Network and chain ID
- When the deployment started and was last updated
- Which contracts are already deployed
- Setup progress (roles granted, parameters set, etc.)
What Gets Deployed
The deploy:system task deploys and configures the following contracts:
- Collateral - FakeStablecoin (or uses existing if
COLLATERAL_ADDRESSis set) - Diamond - Main protocol contract with 29 facets and 3 libraries
-
MuonSignatureVerifier - External Muon verification contract (or uses
MUON_SIGNATURE_VERIFIER_ADDRESSif provided) - AccountLayerDiamond - Unified account/affiliate management with 6 facets
- InstantLayer - Instant settlement layer for batched operations
- SymmioPartyB - PartyB contract (optional, if
DEPLOY_PARTYB=true) - AccountManager - For dummy affiliate (optional, if
REGISTER_DUMMY_AFFILIATE=true)
Roles and Permissions Setup
The task automatically configures:
Diamond Roles (granted to admin)
- SYMBOL_MANAGER_ROLE, PAUSER_ROLE, UNPAUSER_ROLE
- PARTY_B_MANAGER_ROLE, SUSPENDER_ROLE, DISPUTE_ROLE
- AFFILIATE_MANAGER_ROLE, MUON_SETTER_ROLE
- LIQUIDATOR_ROLE, PARTYB_LIQUIDATOR_ROLE
- DEALLOCATE_COOLDOWN_SETTER_ROLE, INSTANT_LAYER_ROLE
- PROTOCOL_CONFIG_ROLE, FEE_ADMIN_ROLE, COOLDOWN_ADMIN_ROLE
- PROVIDER_ADMIN_ROLE, INTEGRATION_ADMIN_ROLE, BRIDGE_MANAGER_ROLE
- SIGNER_ADMIN_ROLE, EMERGENCY_ADMIN_ROLE, UNSUSPENDER_ROLE
- MIGRATION_ROLE, SUSPENDED_FUNDS_WITHDRAWER_ROLE
- FORCE_CLOSE_GAP_RATIO_ADMIN_ROLE
Contract Integrations
- AccountLayerDiamond receives SIGNER_ADMIN_ROLE, AFFILIATE_MANAGER_ROLE, and BALANCE_SETTLER_ROLE on Diamond
- InstantLayer receives INSTANT_LAYER_ROLE on Diamond
- InstantLayer receives INSTANT_LAYER_ROLE on AccountLayerDiamond
- Symmio Core (Diamond) is whitelisted on AccountLayerDiamond
- AccountLayer is registered as the system hook on Diamond (
registerHook(address(0), accountLayerDiamond))
Muon Signature Verifier Setup
When deploy:system runs:
-
If
MUON_SIGNATURE_VERIFIER_ADDRESSis set, deployment first requires contract code andsupportsMuonFunction(uint8(MuonFunction.RemoveMargin)) == true. A legacy verifier without the capability API is rejected before any setup transaction. - Otherwise, a new
MuonSignatureVerifieris deployed. -
Diamond is wired to the verifier using
setSignatureVerifierAddress. The on-chain setter repeats theRemoveMargincapability check; the zero address remains available to disable verification configuration. -
If deployer has admin on verifier, admin receives
DEFAULT_ADMIN_ROLEandSETTER_ROLEon verifier. -
If
MUON_PUBLIC_KEY_XandMUON_PUBLIC_KEY_PARITYare both set,addPublicKeyis called (idempotent check). -
If
MUON_GATEWAY_SIGNERSis set, each signer is added withaddGatewaySigner(idempotent check).
Muon Runtime Config on Diamond
- If
MUON_APP_IDis set,setMuonIdsis called. -
If both
MUON_UPNL_VALID_TIMEandMUON_PRICE_VALID_TIMEare set,setMuonConfigis called. - If only one of those validity vars is set,
setMuonConfigis skipped with a warning.
Muon View-Call Verification
As part of setup, deploy:system verifies Muon config by reading:
getSignatureVerifier()against expected verifier address.getMuonIds()againstMUON_APP_ID(if provided).-
getMuonConfig()againstMUON_UPNL_VALID_TIME/MUON_PRICE_VALID_TIME(if both provided). -
getAllPublicKeys()/getAllGatewaySigners()on verifier (if those seed env vars are provided).
AccountLayerDiamond Setup
- Admin receives DEFAULT_ADMIN_ROLE, SETTER_ROLE, APPROVER_ROLE, PAUSER_ROLE, UNPAUSER_ROLE
InstantLayer Setup
- Admin receives DEFAULT_ADMIN_ROLE and SETTER_ROLE on InstantLayer
- Diamond (Symmio) is whitelisted on InstantLayer (setTargetWhitelist)
- AccountLayerDiamond is whitelisted on InstantLayer (setTargetWhitelist)
- AccountLayer is set on InstantLayer (setAccountLayer)
InstantLayer Templates (if SETUP_INSTANT_LAYER_TEMPLATES=true)
Two templates are registered on InstantLayer to facilitate common trading flows:
OpenPosition Template (6 operations)
| Op | Function | Target | Dependencies |
|---|---|---|---|
| 0 | predictNextVirtualAccountAddress |
AccountLayerDiamond | None (returns virtualAccount) |
| 1 | addMargin |
AccountLayerDiamond | virtualAccount from op 0 (param 1) |
| 2 | sendQuoteWithAffiliateAndData |
Diamond | None (returns quoteId) |
| 3 | allocateForPartyB |
Diamond | partyA from op 0 (param 2) |
| 4 | lockQuote |
Diamond | quoteId from op 2 (param 1) |
| 5 | openPosition |
Diamond | quoteId from op 2 (param 1) |
ClosePosition Template (4 operations)
| Op | Function | Target | Dependencies |
|---|---|---|---|
| 0 | predictNextVirtualAccountAddress |
AccountLayerDiamond | None (returns virtualAccount) |
| 1 | requestToClosePosition |
Diamond | None (quoteId provided by user) |
| 2 | fillCloseRequest |
Diamond | None (quoteId provided by user) |
| 3 | deallocateForPartyB |
Diamond | partyA from op 0 (param 2) |
PartyB Setup (if deployed)
- SymmioPartyB is registered in Diamond
- Admin receives DEFAULT_ADMIN_ROLE, MANAGER_ROLE, and SETTER_ROLE on SymmioPartyB
- InstantLayer receives TRUSTED_ROLE on SymmioPartyB
- InstantLayer is added to multicastWhitelist on SymmioPartyB
- Signer is set on SymmioPartyB (if PARTYB_SIGNER is configured)
- SymmioPartyB is registered on InstantLayer (registerPartyBs - also grants OPERATOR_ROLE)
System Parameters
The following default parameters are configured (matching test environment):
| Parameter | Value |
|---|---|
| Balance Limit Per User | 10,000 |
| Deallocate Cooldown | 120 seconds |
| Settlement Cooldown | 300 seconds |
| Deallocate Debounce Time | 120 seconds |
| Liquidator Share | 10% |
| Liquidation Timeout | 100 seconds |
| Force Close Cooldowns | 300s, 120s |
| Force Cancel Cooldown | 300 seconds |
| Force Cancel Close Cooldown | 300 seconds |
| Pending Quotes Valid Length | 10 |
| Max PartyA Connection Limit | 5 |
Output
After deployment, you will receive:
- Console output - Summary of all deployed contracts and their addresses
- Deployment report - JSON file saved to
data/deployment-report.json -
Verification files - Separate JSON files for contract verification:
data/stablecoin.json- Collateral contractdata/deployed.json- Core Diamond contracts/facets and MuonSignatureVerifierdata/accountlayer.json- AccountLayerDiamond contracts and facetsdata/instantlayer.json- InstantLayer contractdata/partyb.json- SymmioPartyB contracts (proxy, implementation, admin)
Example output:
================================================================================
DEPLOYMENT REPORT
================================================================================
DEPLOYMENT SUMMARY
--------------------------------------------------------------------------------
Total Contracts: 7
Successful: 7
Skipped (from checkpoint): 0
Failed: 0
DEPLOYED ADDRESSES
--------------------------------------------------------------------------------
Collateral: 0x5FbDB2315678afecb367f032d93F642f64180aa3
Diamond: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
MuonSignatureVerifier: 0x8A791620dd6260079BF849Dc5567aDC3F2FdC318
AccountLayerDiamond: 0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0
InstantLayer: 0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9
SymmioPartyB: 0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9
AccountManager: 0x5FC8d32690cc91D4c39d9d3abcBD16989F875707
Note: total/success counts depend on optional flags (DEPLOY_PARTYB, REGISTER_DUMMY_AFFILIATE) and
whether contracts are reused from checkpoint.
Task Options
npx hardhat deploy:system [options]
Options:
--verify Verify contracts on block explorer (default: false)
--log-data Write deployment addresses to data files (default: true)
--fresh Ignore checkpoint and start fresh deployment (default: false)
Contract Verification
After deployment, verify all contracts on the block explorer:
# Verify all contracts from deployment logs
npx hardhat verify:all --network <NETWORK_NAME>
# Skip first N contracts (for resuming)
npx hardhat verify:all --network <NETWORK_NAME> --skip 10
The verify:all task reads from all deployment log files and verifies each contract.
Troubleshooting
Deployment fails mid-way
The checkpoint system will save progress. Simply run the same command again to resume:
npx hardhat deploy:system --network <NETWORK_NAME>
Checkpoint appears corrupted
Force a fresh deployment:
npx hardhat deploy:system --network <NETWORK_NAME> --fresh
Or manually delete the checkpoint file:
rm tasks/data/checkpoints/checkpoint-<chainId>.json
Role granting fails
Ensure the deployer address matches the private key in .env and has admin privileges.
Muon verifier seeding fails
If MUON_PUBLIC_KEY_* or MUON_GATEWAY_SIGNERS are set, deployer must have SETTER_ROLE on
the configured MuonSignatureVerifier. If using an existing verifier where deployer is not admin/setter, seed keys/signers with
a proper verifier admin account.
If an existing verifier fails with does not support MuonFunction.RemoveMargin, deploy the current
forward-compatible MuonSignatureVerifier. Its verifier ABI uses uint8 category IDs and exposes
supportsMuonFunction(uint8); older verifiers without that explicit capability cannot be reused.
Muon config was not applied
setMuonConfig is called only when both MUON_UPNL_VALID_TIME and
MUON_PRICE_VALID_TIME are set. If only one is set, deployment logs a warning and skips that call.
Diamond cut verification mismatch
If a diamond cut transaction succeeded but the checkpoint wasn't saved, the system will detect this on-chain and update the checkpoint automatically.