Deploying Contracts to BattleChain

Learn how to deploy smart contracts using BattleChainDeployer and understand deployment options

This tutorial teaches you how to deploy contracts to BattleChain and why the deployment method matters for the attack mode workflow.

ℹ️

Audience: Developers deploying contracts to BattleChain.

Prerequisites: Familiarity with Solidity and smart contract deployment.

Why BattleChainDeployer?

BattleChain tracks which contracts are eligible for attack mode through the AttackRegistry. When you deploy via BattleChainDeployer, your contracts are automatically registered, which means:

  • You're recorded as the deployer on-chain
  • You can request attack mode without extra authorization steps
  • The DAO has on-chain proof of deployment origin

Without BattleChainDeployer, you can still enter attack mode, but the process requires more DAO scrutiny.

Deployment Methods

BattleChainDeployer wraps CreateX, giving you access to all standard deployment patterns:

CREATE (Simple Deployment)

BattleChainDeployer deployer = BattleChainDeployer(BATTLECHAIN_DEPLOYER_ADDRESS);

// Simple deployment
bytes memory bytecode = type(MyContract).creationCode;
address deployed = deployer.deployCreate(bytecode);

CREATE2 (Deterministic Address)

// Deterministic address based on salt + bytecode
bytes32 salt = keccak256("my-contract-v1");
bytes memory bytecode = type(MyContract).creationCode;

address deployed = deployer.deployCreate2(salt, bytecode);
💡

Use CREATE2 when you need the same contract address across BattleChain and mainnet.

CREATE2 with Initialization

// Deploy and initialize in one transaction
bytes memory bytecode = type(MyProxy).creationCode;
bytes memory initData = abi.encodeCall(MyProxy.initialize, (owner, config));

address deployed = deployer.deployCreate2AndInit(
    salt,
    bytecode,
    initData
);

CREATE3 (Address Independent of Bytecode)

// Address depends only on salt, not bytecode
bytes32 salt = keccak256("my-contract-v1");
bytes memory bytecode = type(MyContract).creationCode;

address deployed = deployer.deployCreate3(salt, bytecode);

Clone Deployment

// Deploy a minimal proxy (EIP-1167 clone)
address implementation = 0x1234...;
address clone = deployer.deployCreate2Clone(salt, implementation);

All Available Methods

MethodAddress DeterminismNotes
deployCreate()Nonce-basedSimplest option
deployCreateAndInit()Nonce-basedDeploys + calls init
deployCreateClone()Nonce-basedEIP-1167 proxy
deployCreate2()Salt + bytecodeSame address cross-chain
deployCreate2AndInit()Salt + bytecodeDeploy + init
deployCreate2Clone()Salt + implDeterministic proxy
deployCreate3()Salt onlyAddress independent of code
deployCreate3AndInit()Salt onlyDeploy + init

What Happens After Deployment

Every deployment through BattleChainDeployer automatically calls AttackRegistry.registerDeployment(), which:

  1. Records the contract address
  2. Sets its state to NEW_DEPLOYMENT
  3. Records you as the deployer
  4. Authorizes you as the agreement owner for that contract
// You can verify registration
address deployer = attackRegistry.getContractDeployer(myContract);
// deployer == your address

IAttackRegistry.ContractState state = attackRegistry.getAgreementState(myContract);
// state == NEW_DEPLOYMENT (1)

Deploying Without BattleChainDeployer

If your contracts are already deployed (e.g., through a custom factory or script), you can still enter the attack flow:

  1. Create your Safe Harbor agreement as normal
  2. Use requestUnderAttackByNonAuthorized() instead of requestUnderAttack()
attackRegistry.requestUnderAttackByNonAuthorized(agreementAddress);
⚠️

Non-BattleChainDeployer contracts face extra DAO scrutiny because there's no on-chain proof of deployment origin. The DAO may take longer to approve or may request additional information.

Next Steps