Deployment Checklist
Use this as the operator runbook for contracts/script/Deploy.s.sol.
1. Network model
- Deployment profile is selected by
ETHEREUM_CHAIN_ID. - Supported values:
31337(local),11155111(sepolia),1(mainnet). Deploy.s.solenforcesblock.chainid == ETHEREUM_CHAIN_ID.
2. Env setup
For live deploys, use contracts/.env:
- Copy
contracts/.env.exampletocontracts/.env. - Optionally copy values from one of these templates:
contracts/.example-sepolia.envcontracts/.example-sepolia-mocked-aztec.envcontracts/.example-mainnet.env
- Edit
contracts/.envfor your target live network.
For local deploys, yarn deploy:local uses:
contracts/.example-local.env
Notes:
- Forge reads
contracts/.envautomatically when run fromcontracts/. - Set both
SEPOLIA_RPC_URLandMAINNET_RPC_URLin.envand choose alias with--rpc-url sepoliaor--rpc-url mainnet. yarn deploy:localintentionally keeps usingcontracts/.example-local.env.
Per-network requirements:
- Local (
31337):MOCK_AZTEC=trueandTIMELOCK_DURATION=0are typical defaults. - Sepolia (
11155111):PRIVATE_KEY, explicitMOCK_AZTEC, andLZ_ENDPOINTare required. - Sepolia with real Aztec (
MOCK_AZTEC=false):ASSETandROLLUP_REGISTRYare required. - Mainnet (
1):PRIVATE_KEY,LZ_ENDPOINT,ASSET,ROLLUP_REGISTRY,GOVERNANCE,TREASURY,PROVIDER_ADMIN, andGUARDIANare required. - Mainnet:
MOCK_AZTEC=trueis forbidden. - Strict address separation (Sepolia/Mainnet when
MOCK_AZTEC=false):deployermust differ fromgovernance,treasury,providerAdmin, andguardian.governancemust differ fromproviderAdmin.
3. Preflight
- Install dependencies once:
cd contracts && forge soldeer install - Build:
yarn forge:build - Run tests:
yarn test
4. Deploy
DEPLOY_WITH_VERIFY=true is an intent/guardrail flag checked by Deploy.s.sol; actual explorer verification only runs when --verify is included.
Local (Anvil)
# terminal 1
yarn dev:chain
# terminal 2
yarn deploy:local
Sepolia (enforced two-step flow)
cd contracts
# 1) dry-run
DEPLOY_STEP=dry-run forge script script/Deploy.s.sol --rpc-url sepolia
# NOTE: do not pass --broadcast for dry-run (enforced by Deploy.s.sol)
# 2) broadcast (no verify)
DEPLOY_STEP=broadcast DEPLOY_DRY_RUN_DONE=true DEPLOY_WITH_VERIFY=true \
forge script script/Deploy.s.sol --broadcast --rpc-url sepolia
# 3) optional separate verify pass
DEPLOY_STEP=broadcast DEPLOY_DRY_RUN_DONE=true DEPLOY_WITH_VERIFY=true \
forge script script/Deploy.s.sol --broadcast --verify --rpc-url sepolia
Mainnet (enforced two-step flow)
cd contracts
# 1) dry-run
DEPLOY_STEP=dry-run forge script script/Deploy.s.sol --rpc-url mainnet
# NOTE: do not pass --broadcast for dry-run (enforced by Deploy.s.sol)
# 2) broadcast (no verify)
DEPLOY_STEP=broadcast DEPLOY_DRY_RUN_DONE=true DEPLOY_WITH_VERIFY=true \
forge script script/Deploy.s.sol --broadcast --rpc-url mainnet
# 3) optional separate verify pass
DEPLOY_STEP=broadcast DEPLOY_DRY_RUN_DONE=true DEPLOY_WITH_VERIFY=true \
forge script script/Deploy.s.sol --broadcast --verify --rpc-url mainnet
Deploy.s.sol enforces on strict chains:
DEPLOY_STEPmust bedry-runorbroadcast.DEPLOY_STEP=dry-runcannot be executed with--broadcast.- Broadcast requires
DEPLOY_DRY_RUN_DONE=trueandDEPLOY_WITH_VERIFY=true.
5. Resume after failure
If deploy/broadcast fails mid-run, rerun the same command with the same env values.
- Resume source:
deployments/<network>.json. - Default behavior: dry-run resume off, broadcast resume on.
- Optional override: set
DEPLOY_RESUME=trueto force resume in dry-run mode.
Rules:
- Do not hand-edit deployment addresses in
deployments/<network>.json. - If you hit
ADDRESS_STATE_MISMATCHorCONFIG_MISMATCH_WITH_EXISTING_DEPLOYMENT, fix env/config mismatch before retrying.
6. Post-deploy activation (strict chains)
On strict chains (Sepolia/Mainnet), deployment is complete but protocol is not fully operational
until governance actions execute (including when TIMELOCK_DURATION=0).
ETHEREUM_CHAIN_ID=<11155111-or-1> forge script script/ops/GovSetVault.s.sol --broadcast --rpc-url <sepolia-or-mainnet>
ETHEREUM_CHAIN_ID=<11155111-or-1> forge script script/ops/GovUnpauseCore.s.sol --broadcast --rpc-url <sepolia-or-mainnet>
ETHEREUM_CHAIN_ID=<11155111-or-1> forge script script/ops/GovUnpauseVault.s.sol --broadcast --rpc-url <sepolia-or-mainnet>
Each ops script is idempotent: first run may schedule, later run executes, re-runs become no-op.
Optional override env vars for ops scripts:
GOVERNANCE_PROXY,CORE,VAULT
7. Post-deploy bridge hardening (LayerZero)
- Configure
StAztecOFTAdapter.setEnforcedOptions(...)for each destination EID. - Set msgType
1(SEND) with a baseline receive gas budget (for example200_000). - If
SEND_AND_CALLis enabled, also set msgType2with a higher budget (~350k-500k).
8. Final verification
ETHEREUM_CHAIN_ID=<11155111-or-1> forge script script/ops/PrintDeployment.s.sol --rpc-url <sepolia-or-mainnet>
ETHEREUM_CHAIN_ID=<11155111-or-1> forge script script/ops/PrintState.s.sol --rpc-url <sepolia-or-mainnet>
-
deployments/<network>.jsonexists (local.json,sepolia.json, ormainnet.json). -
deployments/<network>.jsonhas compatiblemode.mockAztecandinputs.*values for current env. -
OllaGovernance.core()points toOllaCoreproxy. - On strict chains,
OllaCore.vault()is either unset (pre-activation) or points toOllaVaultafterGovSetVault. - On non-strict chains with
TIMELOCK_DURATION==0:OllaCore.vault()points toOllaVaultproxy. - On non-strict chains with
TIMELOCK_DURATION>0:OllaCore.vault()stays unset untilGovSetVaultexecutes. -
OllaCore.safetyModule()andOllaVault.withdrawalQueue()point to deployed addresses. - If
TIMELOCK_DURATION>0: core and vault are unpaused only after governance ops scripts complete. - On strict chains, deployer no longer retains governance admin roles (and, for non-mock deploys, SafetyModule guardian).