Skip to content

Commit

Permalink
Add reference to multichain deployment (#1414)
Browse files Browse the repository at this point in the history
* Add reference to multichain deployment

* nits

---------

Co-authored-by: zerosnacks <[email protected]>
  • Loading branch information
grandizzy and zerosnacks authored Jan 31, 2025
1 parent 1e1e56b commit 5f7f3eb
Showing 1 changed file with 65 additions and 11 deletions.
76 changes: 65 additions & 11 deletions src/forge/deploying.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Forge can deploy smart contracts to a given network with the [`forge create`](..

Forge CLI can deploy only one contract at a time.

For deploying and verifying multiple smart contracts in one go, Forge's [Solidity scripting](../tutorials/solidity-scripting.md#deploying-our-contract) would be the more efficient approach.
For deploying and verifying multiple smart contracts on multiple chains in one go, Forge's [Solidity scripting](../tutorials/solidity-scripting.md#deploying-our-contract) would be the more efficient approach.

To deploy a contract, you must provide a RPC URL (env: `ETH_RPC_URL`) and the private key of the account that will deploy the contract.

Expand Down Expand Up @@ -52,6 +52,50 @@ $ forge create --rpc-url <your_rpc_url> \
src/MyToken.sol:MyToken
```

## Multi-chain deployments

Deploying and verifying multiple smart contracts on multiple chains in one go is possible by using forking cheatcodes.

For example, if you want to deploy a `Counter` contract on Sepolia Mainnet and Base Sepolia using a single command, you can configure RPC endpoints and verifiers as:

```toml
[rpc_endpoints]
sepolia = "${SEPOLIA_URL}"
base-sepolia = "${BASE_SEPOLIA_URL}"

[etherscan]
sepolia = { key = "${SEPOLIA_KEY}" }
base-sepolia = { key = "${BASE_SEPOLIA_KEY}" }
```

and create a `CounterScript` script as:

```solidity
contract CounterScript is Script {
function run() public {
vm.createSelectFork("sepolia");
vm.startBroadcast();
new Counter();
vm.stopBroadcast();
vm.createSelectFork("base-sepolia");
vm.startBroadcast();
new Counter();
vm.stopBroadcast();
}
}
```

When running:

```sh
$ forge script script/CounterScript.s.sol --slow --multi --broadcast --private-key <your_private_key> --verify
```

The script will create the Sepolia Mainnet fork (`vm.createSelectFork("sepolia")`), deploy and verify the `Counter` contract, and then move to Base Sepolia chain deployment (`vm.createSelectFork("base-sepolia")`).

For a list of all available forking cheatcodes see [`forking`](../cheatcodes/forking.md) docs.

## Verifying a pre-existing contract

It is recommended to use the `--verify` flag with `forge create` to automatically verify the contract on explorer after a deployment.
Expand All @@ -62,18 +106,20 @@ If you are verifying an already deployed contract, read on.
You can verify a contract on Etherscan, Sourcify, oklink or Blockscout with the [`forge verify-contract`](../reference/forge/forge-verify-contract.md) command.

You must provide:

- the contract address
- the contract name or the path to the contract `<path>:<contractname>`
- your Etherscan API key (env: `ETHERSCAN_API_KEY`) (if verifying on Etherscan).

Moreover, you may need to provide:

- the constructor arguments in the ABI-encoded format, if there are any
- external linked libraries in `src_file_path:library_name:library_address` format, if there are any
- [compiler version](https://etherscan.io/solcversions) used for build, with 8 hex digits from the commit version prefix (the commit will usually not be a nightly build). It is auto-detected if not specified.
- the number of optimizations, if the Solidity optimizer was activated. It is auto-detected if not specified.
- the number of optimizations, if the Solidity optimizer was activated. It is auto-detected if not specified.
- the [chain ID](https://evm-chainlist.netlify.app/), if the contract is not on Ethereum Mainnet

Let's say you want to verify `MyToken` (see above). You set the [number of optimizations](../reference/config/solidity-compiler.md#optimizer_runs) to 1 million, compiled it with v0.8.10, and deployed it, as shown above, to the Sepolia testnet (chain ID: 11155111). Note that `--num-of-optimizations` will default to 0 if not set on verification, while it defaults to 200 if not set on deployment, so make sure you pass `--num-of-optimizations 200` if you left the default compilation settings.
Let's say you want to verify `MyToken` (see above). You set the [number of optimizations](../reference/config/solidity-compiler.md#optimizer_runs) to 1 million, compiled it with v0.8.10, and deployed it, as shown above, to the Sepolia testnet (chain ID: 11155111). Note that `--num-of-optimizations` will default to 0 if not set on verification, while it defaults to 200 if not set on deployment, so make sure you pass `--num-of-optimizations 200` if you left the default compilation settings.

Here's how to verify it:

Expand All @@ -86,21 +132,23 @@ forge verify-contract \
--etherscan-api-key <your_etherscan_api_key> \
--compiler-version v0.8.10+commit.fc410830 \
<the_contract_address> \
src/MyToken.sol:MyToken
src/MyToken.sol:MyToken

Submitted contract for verification:
Response: `OK`
GUID: `a6yrbjp5prvakia6bqp5qdacczyfhkyi5j1r6qbds1js41ak1a`
url: https://sepolia.etherscan.io//address/0x6a54…3a4c#code
```

> ℹ️ **Note:**
>
> External libraries can be specified with `--libraries` argument, one for each linked library. For example, to verify a contract with two linked libraries (`Maths` and `Utils`) the `forge verify-command` should be run with
> ℹ️ **Note:**
>
> External libraries can be specified with `--libraries` argument, one for each linked library. For example, to verify a contract with two linked libraries (`Maths` and `Utils`) the `forge verify-command` should be run with
>
> ```bash
> --libraries src/lib/Maths.sol:Maths:<maths_lib_address> \
> --libraries src/lib/Utils.sol:Utils:<utils_lib_address>
> ```
>
> arguments.
It is recommended to use the [`--watch`](../reference/forge/forge-verify-contract.md#verify-contract-options) flag along
Expand All @@ -117,7 +165,7 @@ Contract successfully verified.
<br>

> 💡 **Tip**
>
>
> Use Cast's [`abi-encode`](../reference/cast/cast-abi-encode.md) to ABI-encode arguments.
>
> In this example, we ran `cast abi-encode "constructor(string,string,uint8,uint256)" "ForgeUSD" "FUSD" 18 1000000000000000000000` to ABI-encode the arguments.
Expand All @@ -131,37 +179,43 @@ Contract successfully verified.
Make sure the private key string begins with `0x`.

##### `EIP-1559 not activated`

EIP-1559 is not supported or not activated on the RPC server. Pass the `--legacy` flag to use legacy transactions instead of the EIP-1559 ones. If you do development in a local environment, you can use Hardhat instead of Ganache.

##### `Failed to parse tokens`

Make sure the passed arguments are of correct type.

##### `Signature error`

Make sure the private key is correct.

##### `Compiler version commit for verify`

If you want to check the exact commit you are running locally, try: ` ~/.svm/0.x.y/solc-0.x.y --version` where `x` and
`y` are major and minor version numbers respectively. The output of this will be something like:
`y` are major and minor version numbers respectively. The output of this will be something like:

```ignore
solc, the solidity compiler commandline interface
Version: 0.8.12+commit.f00d7308.Darwin.appleclang
```

Note: You cannot just paste the entire string "0.8.12+commit.f00d7308.Darwin.appleclang" as the argument for the compiler-version. But you can use the 8 hex digits of the commit to look up exactly what you should copy and paste from [compiler version](https://etherscan.io/solcversions).
Note: You cannot just paste the entire string "0.8.12+commit.f00d7308.Darwin.appleclang" as the argument for the compiler-version. But you can use the 8 hex digits of the commit to look up exactly what you should copy and paste from [compiler version](https://etherscan.io/solcversions).

### Known Issues

#### Verifying Contracts With Ambiguous Import Paths

Forge passes source directories (`src`, `lib`, `test` etc) as `--include-path` arguments to the compiler.
This means that given the following project tree

```text
|- src
|-- folder
|--- Contract.sol
|--- IContract.sol
```

it is possible to import `IContract` inside the `Contract.sol` using `folder/IContract.sol` import path.

Etherscan is not able to recompile such sources. Consider changing the imports to use relative import path.
Expand All @@ -171,4 +225,4 @@ Etherscan is not able to recompile such sources. Consider changing the imports t
Currently, it's not possible to verify contracts on Etherscan with [`bytecode_hash`](../reference/config/solidity-compiler.md#bytecode_hash)
set to `none`.
Click [here](https://docs.soliditylang.org/en/v0.8.13/metadata.html#usage-for-source-code-verification) to learn more about
how metadata hash is used for source code verification.
how metadata hash is used for source code verification.

0 comments on commit 5f7f3eb

Please sign in to comment.