Deployer
Description
The deployer pattern in Titanoboa provides a flexible way to deploy contracts with custom settings, initialization parameters, and deployment strategies. Deployers are created by contract loading functions and allow you to configure deployment before actually deploying the contract.
Basic Usage
import boa
# Load contract source without deploying
deployer = boa.load_partial("MyToken.vy")
# Deploy with constructor arguments
token = deployer.deploy("My Token", "MTK", 18, 1000000)
# Deploy at specific address
token2 = deployer.at("0x1234567890123456789012345678901234567890")
Deployer Methods
deploy(*args, **kwargs)
Deploy a new instance of the contract.
Parameters:
- *args - Constructor arguments
- value (optional) - ETH to send with deployment
- gas (optional) - Gas limit for deployment
# Deploy with constructor args
contract = deployer.deploy(arg1, arg2)
# Deploy with ETH value
contract = deployer.deploy(arg1, arg2, value=10**18)
# Deploy with custom gas limit
contract = deployer.deploy(arg1, arg2, gas=3000000)
at(address)
Create a contract instance at an existing address.
Parameters:
- address - Address where the contract is deployed
# Connect to existing contract
existing = deployer.at("0x1234567890123456789012345678901234567890")
# Works with Address objects too
from boa.util.abi import Address
addr = Address("0x1234567890123456789012345678901234567890")
existing = deployer.at(addr)
VyperDeployer
The standard deployer for Vyper contracts loaded from source.
# Create VyperDeployer
deployer = boa.load_partial("Contract.vy")
# Access compiler output
print(deployer.compiler_output) # Full compiler output
print(deployer.bytecode) # Deployment bytecode
print(deployer.abi) # Contract ABI
# Deploy multiple instances
instance1 = deployer.deploy(100)
instance2 = deployer.deploy(200)
instance3 = deployer.deploy(300)
ABIDeployer
Deployer for contracts loaded from ABI and bytecode.
# Load from ABI
abi = [{"type": "constructor", "inputs": [{"name": "x", "type": "uint256"}]}]
bytecode = "0x608060405234801561001057600080fd5b5..."
deployer = boa.loads_abi(abi, bytecode=bytecode)
contract = deployer.deploy(42)
Blueprint Deployment
Deploy contracts as EIP-5202 blueprints:
# Deploy as blueprint
blueprint = boa.load_partial("MyContract.vy").deploy_as_blueprint()
# Create instances from blueprint
from boa.contracts.vyper.vyper_contract import VyperBlueprint
instance1 = VyperBlueprint(blueprint).deploy(arg1, arg2)
instance2 = VyperBlueprint(blueprint).deploy(arg1, arg2)
Factory Pattern
Using deployers to create factory contracts:
# Token factory example
factory_code = """
@external
def create_token(name: String[32], symbol: String[8]) -> address:
# Deploy logic here
return deployed_address
"""
factory = boa.loads(factory_code)
# Load token deployer
token_deployer = boa.load_partial("Token.vy")
# In practice, you'd integrate the deployer with the factory
Deployment Tracking
Track deployed contracts:
deployed_contracts = []
# Deploy multiple contracts
for i in range(5):
contract = deployer.deploy(f"Token{i}", f"TK{i}")
deployed_contracts.append({
"name": f"Token{i}",
"address": contract.address,
"deployer": boa.env.eoa
})
# Access deployment info
for info in deployed_contracts:
print(f"{info['name']} at {info['address']}")
Network Mode Deployment
Deploy contracts on real networks:
# Connect to network
boa.set_network_env("https://eth-mainnet.g.alchemy.com/v2/YOUR-KEY")
# Load deployer
deployer = boa.load_partial("MyContract.vy")
# Deploy with network-specific settings
from boa.network import NetworkEnv
boa.env.tx_settings.gas_price = 30 * 10**9 # 30 gwei
contract = deployer.deploy(constructor_arg)
print(f"Deployed at: {contract.address}")
print(f"Transaction: {contract.receipt.transactionHash.hex()}")
Advanced Patterns
Deterministic Deployment
Deploy contracts to predictable addresses using CREATE2:
# Using a factory with CREATE2
factory = boa.loads("""
@external
def deploy_deterministic(salt: bytes32, bytecode: Bytes[24576]) -> address:
return create2(bytecode, salt=salt)
""")
# Calculate expected address
salt = b"my_unique_salt".ljust(32, b'\0')
# Deploy deterministically
Upgradeable Proxy Pattern
# Deploy implementation
implementation_deployer = boa.load_partial("ImplementationV1.vy")
impl = implementation_deployer.deploy()
# Deploy proxy pointing to implementation
proxy_deployer = boa.load_partial("Proxy.vy")
proxy = proxy_deployer.deploy(impl.address)
# Interact through proxy
contract = implementation_deployer.at(proxy.address)
Batch Deployment
def batch_deploy(deployer, configs):
"""Deploy multiple contracts efficiently"""
contracts = {}
for config in configs:
contract = deployer.deploy(
config["name"],
config["symbol"],
value=config.get("value", 0)
)
contracts[config["name"]] = contract
return contracts
# Deploy batch
configs = [
{"name": "Token A", "symbol": "TKA"},
{"name": "Token B", "symbol": "TKB"},
{"name": "Token C", "symbol": "TKC", "value": 10**18},
]
tokens = batch_deploy(token_deployer, configs)
Error Handling
Handle deployment errors gracefully:
try:
contract = deployer.deploy(invalid_arg)
except Exception as e:
if "constructor" in str(e):
print("Constructor failed")
elif "out of gas" in str(e):
print("Increase gas limit")
else:
raise
# Retry with higher gas
contract = deployer.deploy(valid_arg, gas=5000000)
See Also
- Load Contracts - Loading contracts to create deployers
- VyperDeployer - VyperDeployer class details
- VyperBlueprint - Blueprint deployment
- Testing - Testing deployed contracts