battlechain
BattleChain Development Standards
Instructions for working with BattleChain, from the Cyfrin security team.
What is BattleChain
BattleChain is a ZKSync-based L2 blockchain that inserts a battle-testing phase between testnet and mainnet: Dev -> Testnet -> BattleChain -> Mainnet. Protocols deploy audited contracts with real funds, whitehats legally attack them for bounties under Safe Harbor agreements, and surviving contracts promote to production.
Full Documentation
For up-to-date contract addresses, function signatures, struct definitions, enums, state transitions, bounty calculation rules, Safe Harbor agreement details, and all other technical reference material, fetch the full docs:
https://docs.battlechain.com/llms-full.txt
Always fetch this URL when you need BattleChain technical details. The docs are the single source of truth and stay current as the protocol evolves.
Deployment
Projects deploying to BattleChain (or any EVM chain) should use cyfrin/battlechain-lib:
forge install cyfrin/battlechain-lib
Add the remapping to foundry.toml:
remappings = ["battlechain-lib/=lib/battlechain-lib/src/"]
Inheritance hierarchy
| Contract | Use when you need |
|---|---|
BCScript |
Full lifecycle: deploy + agreement + attack mode |
BCDeploy |
Deploy only (via CreateX on any chain, BattleChainDeployer on BC) |
BCSafeHarbor |
Agreement creation only |
Key helpers
| Helper | What it does |
|---|---|
bcDeployCreate(bytecode) |
Deploy via BattleChainDeployer on BattleChain, CreateX on 190+ other chains |
bcDeployCreate2(salt, bytecode) |
Deterministic deploy — same address across chains |
bcDeployCreate3(salt, bytecode) |
Address depends only on salt, not bytecode |
defaultAgreementDetails(name, contacts, contracts, recovery) |
Builds agreement with correct scope and URI per chain |
createAndAdoptAgreement(details, owner, salt) |
Create + 14-day commitment + adopt in one call |
requestAttackMode(agreement) |
Enter attack mode (BattleChain only — reverts on other chains) |
_isBattleChain() |
Runtime check: true on chain IDs 626, 627, 624 |
getDeployedContracts() |
All addresses deployed this session via bcDeploy* |
Cross-chain behavior
| BattleChain (626/627/624) | Other EVM chains (190+) | |
|---|---|---|
bcDeployCreate* |
BattleChainDeployer (CreateX + AttackRegistry) | CreateX (0xba5Ed...) directly |
defaultAgreementDetails |
BattleChain scope + BATTLECHAIN_SAFE_HARBOR_URI |
Current chain CAIP-2 scope + SAFE_HARBOR_V3_URI |
requestAttackMode |
Works | Reverts with BCSafeHarbor__NotBattleChain |
createAndAdoptAgreement |
Works | Works (requires registry/factory on that chain) |
Only requestAttackMode is BattleChain-specific. Everything else works on any supported chain.
Foundry
When working with foundry scripts, as of today, you need to pass a flag to skip simulations, for example:
forge script scripts/Deploy.s.sol --skip-simulation
Otherwise, you'll run into errors about gas estimation. You can also combine this with -g:
forge script scripts/Deploy.s.sol --skip-simulation -g 300
If the issues persist. If using a justfile or makefile please add these flags to the targets in those files.
Verification
BattleChain uses a custom block explorer API for contract verification. The battlechain-lib ships a reusable justfile module with verification targets.
Install verification targets
Add to your justfile:
import "lib/battlechain-lib/battlechain.just"
This gives you:
| Target | Usage |
|---|---|
bc-verify <addr> <path:name> |
Verify a single contract |
bc-verify-broadcast <script> |
Verify all contracts from a broadcast file (handles CreateX/BCDeploy factory creates) |
bc-deploy <script> <account> <sender> |
Deploy with standard BC flags |
bc-deploy-verify <script> <account> <sender> |
Deploy + verify in one step |
Verify manually
forge verify-contract <ADDRESS> src/MyVault.sol:MyVault \
--chain-id 627 \
--verifier-url https://block-explorer-api.testnet.battlechain.com/api \
--verifier custom \
--etherscan-api-key "1234" \
--rpc-url https://testnet.battlechain.com:3051
The API key is not validated — any non-empty string works.
Verify during deployment
Add --verify to your forge script call:
forge script script/Deploy.s.sol \
--rpc-url https://testnet.battlechain.com:3051 \
--broadcast --skip-simulation -g 300 \
--verify \
--verifier-url https://block-explorer-api.testnet.battlechain.com/api \
--verifier custom \
--etherscan-api-key 1234
This verifies contracts as they're deployed. For factory-deployed contracts (via CreateX/BCDeploy), use bc-verify-broadcast after deployment instead.
Troubleshooting
AnyTxType(2) transaction can't be built due to missing keys: ["gas_limit"]
This error means a contract exceeds the EVM contract size limit (24,576 bytes). Forge can't estimate gas for an oversized contract, so the deploy transaction fails to build.
Diagnose: Check contract sizes after compiling:
forge build --sizes
Any contract over 24,576 bytes will fail to deploy.
Fix options:
- Split the contract into smaller pieces (libraries, separate contracts)
- Enable the optimizer with more runs:
optimizer = trueandoptimizer_runs = 200infoundry.toml - Use
--via-irfor deeper optimization (slower compile, smaller output) - Extract constants and large string literals into separate libraries
BattleChain does not support EIP-1559
Every forge script and cast send call must include --legacy. Without it, transactions are rejected.
Hardhat
Coming soon...