Deploy Celo core contract releases using Foundry tooling. Use when releasing contracts, testing releases on forks, generating governance proposals, or when user mentions release, deploy, upgrade contracts, CR14, CR15, make-release, or verify-deployed.
Deploy and test Celo core contract releases using Foundry-based tooling.
| Step | Command | Output |
|---|---|---|
| 1. Generate libraries.json | verify-deployed:foundry -b <PREVIOUS_TAG> | libraries.json |
| 2. Generate report | check-versions:foundry -a <PREVIOUS_TAG> -b <NEW_BRANCH> | releaseData/versionReports/releaseN-report.json |
| 3. Deploy & create proposal | make-release:foundry -b <NEW_BRANCH> | proposal.json + deployed contracts |
| Network | Chain ID | RPC URL | Use Case |
|---|
| Celo Mainnet | 42220 | https://forno.celo.org | Production releases |
| Celo Sepolia | 11142220 | https://forno.celo-sepolia.celo-testnet.org | Testnet releases |
| Local Fork | varies | http://127.0.0.1:8545 | Testing releases |
Deployer keys are stored in encrypted mnemonic files in the repo root:
| Network | Mnemonic File | Encrypted File |
|---|---|---|
| Celo Sepolia | .env.mnemonic.celosepolia | N/A (manual) |
| Mainnet | .env.mnemonic.mainnet | .env.mnemonic.mainnet.enc |
# Decrypt all mnemonic files using GCP KMS
yarn keys:decrypt
Each mnemonic file exports DEPLOYER_PRIVATE_KEY. Source it before running release commands:
# For Celo Sepolia
source .env.mnemonic.celosepolia
# For Mainnet
source .env.mnemonic.mainnet
Then use $DEPLOYER_PRIVATE_KEY in release commands.
IMPORTANT: Before executing any release commands, you MUST:
Query available tags and branches:
git tag -l 'core-contracts.*' | sort -V | tail -15
git branch -a | grep 'release/core-contracts'
Determine the release source using this priority order:
Tag priority (check in order, use first match):
core-contracts.vN.post-audit or core-contracts.vN.post_auditcore-contracts.vNrelease/core-contracts/N (only if no tags exist)Note: Not all releases have post-audit tags. If one exists, use it; otherwise use the base tag.
For the NEW release: Check for post-audit tag first, then base tag, then branch. For the PREVIOUS release: Same logic - use post-audit tag if available, otherwise base tag.
Present a confirmation to the user with:
core-contracts.v14 or core-contracts.v14.post-auditcelo-sepolia or celoUse the AskQuestion tool to get explicit confirmation:
Only proceed with the release after user confirmation.
Example confirmation prompt (when post-audit tag exists):
I plan to release with the following parameters:
- Previous release tag: core-contracts.v14.post-audit
- New release tag: core-contracts.v15.post-audit
- Target network: celo-sepolia
Please confirm or specify different values.
Example confirmation prompt (when only base tag exists):
I plan to release with the following parameters:
- Previous release tag: core-contracts.v14
- New release tag: core-contracts.v15
- Target network: celo-sepolia
Please confirm or specify different values.
Example confirmation prompt (when only branch exists):
I plan to release with the following parameters:
- Previous release tag: core-contracts.v14
- New release branch: release/core-contracts/15 (no tag found)
- Target network: celo-sepolia
Please confirm or specify different values.
Verify the currently deployed release to get library addresses:
cd packages/protocol
# For Celo Sepolia
yarn release:verify-deployed:foundry -b core-contracts.v${PREVIOUS} -n celo-sepolia
# For Mainnet
yarn release:verify-deployed:foundry -b core-contracts.v${PREVIOUS} -n celo
Output: libraries.json in packages/protocol/
Compare previous release to new release branch:
yarn release:check-versions:foundry \
-a core-contracts.v${PREVIOUS} \
-b release/core-contracts/${NEW} \
-r ./releaseData/versionReports/release${NEW}-report.json
Output: releaseData/versionReports/release${NEW}-report.json
Create or verify initialization data exists:
# Check if file exists
cat ./releaseData/initializationData/release${NEW}.json
# If missing, create empty (valid if no new contracts)
echo "{}" > ./releaseData/initializationData/release${NEW}.json
yarn release:make:foundry \
-b release/core-contracts/${NEW} \
-k $DEPLOYER_PRIVATE_KEY \
-i ./releaseData/initializationData/release${NEW}.json \
-l ./libraries.json \
-n celo-sepolia \
-p ./proposal-fork.json \
-r ./releaseData/versionReports/release${NEW}-report.json \
-u http://127.0.0.1:8545
yarn release:make:foundry \
-b release/core-contracts/${NEW} \
-k $CELO_SEPOLIA_DEPLOYER_KEY \
-i ./releaseData/initializationData/release${NEW}.json \
-l ./libraries.json \
-n celo-sepolia \
-p ./proposal-celo-sepolia.json \
-r ./releaseData/versionReports/release${NEW}-report.json
# First regenerate libraries.json for mainnet!
yarn release:verify-deployed:foundry -b core-contracts.v${PREVIOUS} -n celo
yarn release:make:foundry \
-b release/core-contracts/${NEW} \
-k $MAINNET_DEPLOYER_KEY \
-i ./releaseData/initializationData/release${NEW}.json \
-l ./libraries.json \
-n celo \
-p ./proposal-mainnet.json \
-r ./releaseData/versionReports/release${NEW}-report.json
| Artifact | Location | Purpose |
|---|---|---|
libraries.json | packages/protocol/ | Library addresses (network-specific!) |
| Version report | releaseData/versionReports/releaseN-report.json | Contract changes & version deltas |
| Init data | releaseData/initializationData/releaseN.json | Constructor args for new contracts |
| Proposal | proposal-*.json | Governance transactions |
Important: libraries.json is network-specific. Regenerate when switching between Celo Sepolia and Mainnet.
Priority: Always prefer git tags over branches. Post-audit tags are preferred over base tags.
# List existing tags (check these FIRST)
git tag -l 'core-contracts.*' | sort -V | tail -15
# List release branches (fallback if no tag exists)
git branch -a | grep 'release/core-contracts'
Tag priority (check in order, use first match):
core-contracts.vN.post-audit or core-contracts.vN.post_audit - Post-audit (if exists)core-contracts.vN - Base tagrelease/core-contracts/N - Branch (fallback only)Note: Not all releases have post-audit tags. Use it if available, otherwise use the base tag.
Selection logic:
Before testing on a local fork, start Anvil with the required parameters:
# Fork Celo Sepolia
anvil --fork-url https://forno.celo-sepolia.celo-testnet.org \
--code-size-limit 500000 \
--gas-limit 100000000
# Fork Mainnet
anvil --fork-url https://forno.celo.org \
--code-size-limit 500000 \
--gas-limit 100000000
Important: The --code-size-limit and --gas-limit flags are required for Celo contract deployments due to large contract sizes.
The release script automatically verifies deployed contracts on:
The script handles verification automatically with:
--libraries flagFOUNDRY_PROFILE environment variable (truffle-compat for 0.5.x, truffle-compat8 for 0.8.x) to ensure bytecode matches0.5.14+commit.01f1aaa4)The API key is required by default for production networks. Get your key from https://etherscan.io/myapikey
Setup options (in order of precedence):
-a YOUR_API_KEYexport CELOSCAN_API_KEY=YOUR_API_KEYpackages/protocol/.env.json
{
"celoScanApiKey": "YOUR_API_KEY"
}
Note: The Etherscan V2 API uses a unified endpoint (api.etherscan.io) that works with a single API key for all supported chains including Celo.
To skip verification (e.g., for testing or if you don't have an API key):
yarn release:make:foundry ... -s
Verification is automatically skipped when using a custom RPC URL (local forks).
FOUNDRY_PROFILE based on contract source path.--libraries flag for contracts that use linked libraries.Run verify-deployed:foundry first with the previous release tag.
Update getVersionNumber() in the contract to match expected version from the report.
Ensure Anvil is started with --code-size-limit 500000 --gas-limit 100000000.
Use anvil's default test key for local forks:
0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
For complete documentation, see RELEASE_PROCESS_FOUNDRY.md