Cannonfiles contain a series of steps defined in a TOML file.
Each step has a type and a name. Each type accepts a specific set of inputs and modifies a return object. The return object is accessible in steps executed at later steps. The resulting return object is provided to any cannonfile that imports it with the import
step.
⚠️ Use the depends input to specify an array of steps that a particular step relies upon. For example, you must include depends = ["contract.myStorage"]
on an invoke step which calls a function on a contract deployed by the contract.myStorage step. Note that two steps which effect the same state need to have one depend on the other (like two transfer functions that may effect the same user balances).
Every step updates the return object by adding an entry to the txns
key with the step's name. The value of the entry is an object with the properties hash
(which is the hash of this transstep) and events
(which is an array of objects with the name
of each event emitted by this call and the corresponding event data as args
).
For example, the step below has the type contract
and is named myStorage
. It requires the input artifact
, which is the name of the contract to deploy. (In this example, it's the contract named Storage
.)
[contract.myStorage]
artifact = "Storage"
This updates the return object such that, for example, a later invoke
step could call this contract with the input target = ["<%= contracts.myStorage.address %>"]
.
There are five types of steps you can use in a Cannonfile:
contract
step deploys a contract.import
step will import a cannonfile from a package hosted with the package manager.invoke
step calls a specified function on your node.provision
step attempts to deploy the specified package (unlike the import command, which only injects existing deployment data). Third-party packages can execute arbitrary code on your computer when provisioning. Only provision packages that you have verified or trust.run
step executes a custom script. This script is passed a ChainBuilder object as parameter. The run command breaks composability. Only use this as a last resort. Use a custom Cannon plug-in if this is necessary for your deployment.A setting
may also be defined, which is a user-configurable option that can be referenced in other steps' inputs. For example, a cannonfile may define [setting.sampleSetting]
and then reference sampleValue
as "<%= settings.sampleSetting %>"
after running npx hardhat cannon sampleSetting="sampleValue"
Available properties for top level config
Name | Type | Description |
---|---|---|
name | string | Name of the package |
version | string | version of the package |
description? | string | Description for the package |
keywords? | [string] | keywords for search indexing |
setting? | { description?: string; type?: "string" | "number" | "boolean" | undefined; defaultValue?: string; }\ | Object that allows the definition of values for use in next steps toml [settings.owner] defaultValue: "some-eth-address" |
Available properties for run step
Name | Type | Description |
---|---|---|
exec | string | The javascript (or typescript) file to load |
func | string | The function to call in this file |
modified | [string] | An array of files and directories that this script depends on. The cache of the cannonfile's build is recreated when these files change. |
args? | [string] | Arguments passed to the function (after the ChainBuilder object) |
env? | [string] | Environment variables to be set on the script |
depends? | [string] | List of steps that this action depends on |
Available properties for contract step
Name | Type | Description |
---|---|---|
artifact | string | Artifact name or path of the target contract |
create2? | boolean | Determines whether to deploy the contract using create2 |
from? | string | Contract deployer address. Must match the ethereum address format |
nonce? | string | - |
abi? | string | Abi of the contract being deployed |
abiOf? | [string] | An array of contract artifacts that have already been deployed with Cannon. This is useful when deploying proxy contracts. |
args? | (string | number | boolean | (string | number | boolean )[] | string | number | boolean \ | string | number | boolean [])[] | Constructor or initializer args |
libraries? | string \ | An array of contract action names that deploy libraries this contract depends on. |
salt? | string | Used to force new copy of a contract (not actually used) |
value? | string | Native currency value to send in the transaction |
overrides? | { gasLimit?: string; } | Override transaction settings |
depends? | [string] | List of steps that this action depends on |
Available properties for import step
Name | Type | Description |
---|---|---|
source | string | Source of the cannonfile package to import from Can be a cannonfile step name or package name |
chainId? | number | ID of the chain to import the package from |
preset? | string | Preset label of the package being imported |
depends? | [string] | Previous steps this step is dependent on toml depends = ['contract.Storage', 'import.Contract'] |
Available properties for invoke step
Name | Type | Description |
---|---|---|
target | Object | Names of the contract to call or contract action that deployed the contract to call |
func | string | Name of the function to call on the contract |
abi? | string | JSON file of the contract ABI Required if the target contains an address rather than a contract action name. |
args? | (string | number | boolean | (string | number | boolean )[] | string | number | boolean \ | string | number | boolean [])[] | Arguments to use when invoking this call. |
from? | string | The calling address to use when invoking this call. |
fromCall? | { func : string ; args? : (string | number | boolean | (string | number | boolean )[] | string | number | boolean \ | string | number | boolean [])[] } | Specify a function to use as the 'from' value in a function call. Example owner() . |
fromCall.func | string | The name of a view function to call on this contract. The result will be used as the from input. |
fromCall.args? | (string | number | boolean | (string | number | boolean )[] | string | number | boolean \ | string | number | boolean [])[] | The arguments to pass into the function being called. |
value? | string | The amount of ether/wei to send in the transaction. |
overrides? | { gasLimit : string } | Override transaction settings |
overrides.gasLimit | string | Gas limit to send along with the transaction |
extra? | { event : string ; arg : number ; allowEmptyEvents? : boolean }\ | Object defined to hold extra transaction result data. For now its limited to getting event data so it can be reused in other steps |
factory? | { event : string ; arg : number ; artifact? : string ; abiOf? : [string] ; constructorArgs? : (string | number | boolean | (string | number | boolean )[] | string | number | boolean \ | string | number | boolean [])[] ; allowEmptyEvents? : boolean }\ | Object defined to hold deployment transaction result data. For now its limited to getting deployment event data so it can be reused in other steps |
depends? | [string] | Previous steps this step is dependent on |
Available properties for provision step
Name | Type | Description |
---|---|---|
source | string | Name of the package to provision |
chainId? | number | ID of the chain to import the package from Default - 13370 |
sourcePreset? | string | Override the preset to use when provisioning this package. Default - "main" |
targetPreset? | string | Set the new preset to use for this package. Default - "main" |
options? | string \ | The settings to be used when initializing this Cannonfile. Overrides any defaults preset in the source package. |
tags? | [string] | Additional tags to set on the registry for when this provisioned package is published. |
depends? | [string] | Previous steps this step is dependent on |
Available properties for router step
Name | Type | Description |
---|---|---|
contracts | [string] | Set of contracts that will be passed to the router |
from? | string | Address to pass to the from call |
salt? | string | Used to force new copy of a contract (not actually used) |
depends? | [string] | List of steps that this action depends on |
Smart contracts may have functions which deploy other smart contracts. Contracts which deploy others are typically referred to as factory contracts. You can reference contracts deployed by factories in your cannonfile.
For example, if the deployPool
function below deploys a contract, the following invoke command registers that contract based on event data emitted from that call.
[invoke.deployment]
target = ["PoolFactory"]
func = "deployPool"
factory.MyPoolDeployment.artifact = "Pool"
# alternatively, if the code for the deployed contract is not available in your artifacts, you can also reference the ABI like:
# factory.MyPoolDeployment.abiOf = "PreviousPool"
factory.MyPoolDeployment.event = "NewDeployment"
factory.MyPoolDeployment.arg = 0
Specifically, this would anticipate this invoke call will emit an event named NewDeployment with a contract address as the first data argument (per arg
, a zero-based index). This contract should implement the Pool
contract. Now, a subsequent invoke
step could set target = ["MyPoolDeployment"]
.
To reference contract information for a contract deployed on a previous invoke step such as the example shown above call the contracts
object inside your cannonfile.
For example <%= contracts.MyPoolDeployment.address %>
would return the address of the Pool
contract deployed by the PoolFactory
contract.
If the invoked function deploys multiple contracts of the same name, you can specify them by index through the contracts
object.
<%= contracts.MyPoolDeployment.address %>
would return the first deployed Pool
contract address<%= contracts.MyPoolDeployment_0.address %>
would return the second deployed Pool
contract addressThese contracts are added to the return object as they would be if deployed by a contract
step.
If an invoked function emits an event, cannon can parse the event data in your cannonfile by using the extras
property,
This lets you reference previously emitted event's data in subsequent invoke
steps.
For example, to track the NewDeployment event data from the PoolFactory
deployment from the example above, add the extra
property and set an attribute
for the event like so:
[invoke.deployment]
target = ["PoolFactory"]
....
extra.NewDeploymentEvent.event = "NewDeployment"
extra.NewDeploymentEvent.arg = 0
Now, calling "<% = extras.NewDeploymentEvent %>"
in a subsequent invoke
step would return the first data argument for NewDeployment.
If an invoked function emits multiple events you can specify them by index.
For example if the PoolFactory
emitted multiple NewDeployment events:
<%= extras.NewDeploymentEvent_0 %>
would return the first emitted event of this kind<% = extras.NewDeploymentEvent_4 %>
would reference the fifth emitted event of this kindIf an event is specified in the cannonfile but the invoke
function does not emit any events or emits an event that doesn't match the one specified in the cannonfile, the invoke
step will fail with an error.
You can bypass the event error logging by setting it like extras.NewDeploymentEvent.allowEmptyEvents = true
or factory.MyPoolDeployment.allowEmptyEvents = true
under the factory or extra property that throws an error.
An useful example would for this would be when an event is only emitted under certain conditions but you still need to reference it when it is emitted or don't want to halt execution when it's not emitted.
Keep in mind you wont be able to reference event or contract data through the contracts
or extras
properties if a matching event wasnt emitted