Skip to content

Commit

Permalink
Add mainnet deployment (#119)
Browse files Browse the repository at this point in the history
* add mainnet deployment

* fix typos

* add note on RISC Zero managed RiscZeroVerifierRouter

* fmt

* use config files

* ignore mainnet broadcast

* fix typo

* fmt

* fix typo

* use profile config

* fmt

* fix typo

* use riscZeroVerifierAddress

* rename config

* simplify gitignore

* Suggestions for PR #119 (#122)

* refactor to make defaults based on the chainId and support deployment with ledger

* add note about the lack of support for hardware wallets

* run forge fmt

* remove warning tag

---------

Co-authored-by: Victor Graf <[email protected]>
  • Loading branch information
capossele and nategraf authored Jun 26, 2024
1 parent 61e36a4 commit 0eefc99
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 19 deletions.
5 changes: 1 addition & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ cache/
out/

# Ignores development broadcast logs
!/broadcast
/broadcast/*/31337/
/broadcast/*/11155111/
/broadcast/**/dry-run/
broadcast/

# Autogenerated contracts
contracts/ImageID.sol
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ RISC0_USE_DOCKER=1 cargo build

## Deploy Your Application

When you're ready, follow the [deployment guide] to get your application running on [Sepolia].
When you're ready, follow the [deployment guide] to get your application running on [Sepolia] or Ethereum Mainnet.
## Project Structure
Expand Down
102 changes: 95 additions & 7 deletions deployment-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ You can either:

- [Deploy your project to a local network]
- [Deploy to a testnet]
- [Deploy to Ethereum Mainnet]

## Deploy your project on a local network

Expand Down Expand Up @@ -49,6 +50,7 @@ You can deploy your contracts and run an end-to-end test or demo as follows:
```bash
...
== Logs ==
You are deploying on ChainID 31337
Deployed RiscZeroGroth16Verifier to 0x5FbDB2315678afecb367f032d93F642f64180aa3
Deployed EvenNumber to 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
...
Expand Down Expand Up @@ -90,11 +92,11 @@ You can deploy your contracts and run an end-to-end test or demo as follows:
cast call --rpc-url http://localhost:8545 ${EVEN_NUMBER_ADDRESS:?} 'get()(uint256)'
```

## Deploy your project on a testnet
## Deploy your project on Sepolia testnet

You can deploy your contracts on a testnet such as `Sepolia` and run an end-to-end test or demo as follows:
You can deploy your contracts on the `Sepolia` testnet and run an end-to-end test or demo as follows:

1. Get access to Bonsai and an Ethereum node running on a given testnet, e.g., Sepolia (in this example, we will be using [Alchemy](https://www.alchemy.com/) as our Ethereum node provider) and export the following environment variables:
1. Get access to Bonsai and an Ethereum node running on Sepolia testnet (in this example, we will be using [Alchemy](https://www.alchemy.com/) as our Ethereum node provider) and export the following environment variables:
> ***Note:*** *This requires having access to a Bonsai API Key. To request an API key [complete the form here](https://bonsai.xyz/apply).*
> Alternatively you can generate your proofs locally, assuming you have a machine with an x86 architecture and [Docker] installed. In this case do not export Bonsai related env variables.

Expand All @@ -117,12 +119,14 @@ You can deploy your contracts on a testnet such as `Sepolia` and run an end-to-e
forge script script/Deploy.s.sol --rpc-url https://eth-sepolia.g.alchemy.com/v2/${ALCHEMY_API_KEY:?} --broadcast
```

This command should output something similar to:
This command uses the `sepolia` profile defined in the [config][config] file, and should output something similar to:

```bash
...
== Logs ==
Deployed RiscZeroGroth16Verifier to 0x5FbDB2315678afecb367f032d93F642f64180aa3
You are deploying on ChainID 11155111
Deploying using config profile: sepolia
Using IRiscZeroVerifier contract deployed at 0x925d8331ddc0a1F0d96E68CF073DFE1d92b69187
Deployed EvenNumber to 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
...
```
Expand All @@ -139,7 +143,7 @@ You can deploy your contracts on a testnet such as `Sepolia` and run an end-to-e
> export EVEN_NUMBER_ADDRESS=$(jq -re '.transactions[] | select(.contractName == "EvenNumber") | .contractAddress' ./broadcast/Deploy.s.sol/11155111/run-latest.json)
> ```

### Interact with your testnet deployment
### Interact with your Sepolia testnet deployment

1. Query the state:

Expand All @@ -163,10 +167,94 @@ You can deploy your contracts on a testnet such as `Sepolia` and run an end-to-e
cast call --rpc-url https://eth-sepolia.g.alchemy.com/v2/${ALCHEMY_API_KEY:?} ${EVEN_NUMBER_ADDRESS:?} 'get()(uint256)'
```

[Deploy to a testnet]: #deploy-your-project-on-a-testnet
## Deploy your project on Ethereum mainnet

You can deploy your contract on Ethereum Mainnet as follows:

1. Get access to Bonsai and an Ethereum node running on Mainnet (in this example, we will be using [Alchemy](https://www.alchemy.com/) as our Ethereum node provider) and export the following environment variables:
> ***Note:*** *This requires having access to a Bonsai API Key. To request an API key [complete the form here](https://bonsai.xyz/apply).*
> Alternatively you can generate your proofs locally, assuming you have a machine with an x86 architecture and [Docker] installed. In this case do not export Bonsai related env variables.

```bash
export BONSAI_API_KEY="YOUR_API_KEY" # see form linked in the previous section
export BONSAI_API_URL="BONSAI_API_URL" # provided with your api key
export ALCHEMY_API_KEY="YOUR_ALCHEMY_API_KEY" # the API_KEY provided with an alchemy account
export ETH_WALLET_ADDRESS="YOUR_WALLET_ADDRESS" # the account address you want to use for deployment
```

2. Build your project:

```bash
cargo build
```

3. Deploy your contract by running:

You'll need to pass options to forge script to connect to your deployer wallet. See the [Foundry documentation][forge-script-wallet-docs].
The example command below configures Forge to use a Ledger hardware wallet.
```bash
forge script script/Deploy.s.sol --rpc-url https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY:?} --broadcast --ledger
```
This command uses the `mainnet` profile defined in the [config][config] file, and should output something similar to:
```bash
...
== Logs ==
You are deploying on ChainID 1
Deploying using config profile: mainnet
Using IRiscZeroVerifier contract deployed at 0x8EaB2D97Dfce405A1692a21b3ff3A172d593D319
Deployed EvenNumber to 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
...
```
Save the `EvenNumber` contract address to an env variable:
```bash
export EVEN_NUMBER_ADDRESS=#COPY EVEN NUMBER ADDRESS FROM DEPLOY LOGS
```
> You can also use the following command to set the contract address if you have [`jq`][jq] installed:
>
> ```bash
> export EVEN_NUMBER_ADDRESS=$(jq -re '.transactions[] | select(.contractName == "EvenNumber") | .contractAddress' ./broadcast/Deploy.s.sol/1/run-latest.json)
> ```
### Interact with your Ethereum Mainnet deployment
1. Query the state:
```bash
cast call --rpc-url https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY:?} ${EVEN_NUMBER_ADDRESS:?} 'get()(uint256)'
```
2. Publish a new state
> NOTE: Currently only a local wallet, provided by the `ETH_WALLET_PRIVATE_KEY` env var is implemented in the example publisher app.
> Please see https://github.com/risc0/risc0-foundry-template/issues/121 for more details.
```bash
cargo run --bin publisher -- \
--chain-id=1 \
--rpc-url=https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY:?} \
--contract=${EVEN_NUMBER_ADDRESS:?} \
--input=12345678
```
3. Query the state again to see the change:
```bash
cast call --rpc-url https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY:?} ${EVEN_NUMBER_ADDRESS:?} 'get()(uint256)'
```
[Deploy to Ethereum Mainnet]: #deploy-your-project-on-ethereum-mainnet
[Deploy your project to a local network]: #deploy-your-project-on-a-local-network
[RISC Zero]: https://www.risczero.com/
[Docker]: https://docs.docker.com/engine/install/
[contracts]: ./contracts/
[jq]: https://jqlang.github.io/jq/
[methods]: ./methods/
[tested]: ./README.md#run-the-tests
[config]: ./script/config.toml
[forge-script-wallet-docs]: https://book.getfoundry.sh/reference/forge/forge-script#wallet-options---raw
1 change: 1 addition & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ out = "out"
libs = ["lib"]
test = "tests"
ffi = true
fs_permissions = [{ access = "read-write", path = "./"}]

# See more config options https://github.com/foundry-rs/foundry/tree/master/config
70 changes: 63 additions & 7 deletions script/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
pragma solidity ^0.8.20;

import {Script} from "forge-std/Script.sol";
import {console2} from "forge-std/console2.sol";
import "forge-std/Test.sol";
import {IRiscZeroVerifier} from "risc0/IRiscZeroVerifier.sol";
import {RiscZeroGroth16Verifier} from "risc0/groth16/RiscZeroGroth16Verifier.sol";
import {ControlID} from "risc0/groth16/ControlID.sol";
Expand All @@ -26,19 +26,75 @@ import {EvenNumber} from "../contracts/EvenNumber.sol";

/// @notice Deployment script for the RISC Zero starter project.
/// @dev Use the following environment variable to control the deployment:
/// * ETH_WALLET_PRIVATE_KEY private key of the wallet to be used for deployment.
/// * Set one of these two environment variables to control the deployment wallet:
/// * ETH_WALLET_PRIVATE_KEY private key of the wallet account.
/// * ETH_WALLET_ADDRESS address of the wallet account.
///
/// See the Foundry documentation for more information about Solidity scripts,
/// including information about wallet options.
///
/// See the Foundry documentation for more information about Solidity scripts.
/// https://book.getfoundry.sh/tutorials/solidity-scripting
/// https://book.getfoundry.sh/reference/forge/forge-script
contract EvenNumberDeploy is Script {
// Path to deployment config file, relative to the project root.
string constant CONFIG_FILE = "script/config.toml";

IRiscZeroVerifier verifier;

function run() external {
uint256 deployerKey = uint256(vm.envBytes32("ETH_WALLET_PRIVATE_KEY"));
// Read and log the chainID
uint256 chainId = block.chainid;
console2.log("You are deploying on ChainID %d", chainId);

// Read the config profile from the environment variable, or use the default for the chainId.
// Default is the first profile with a matching chainId field.
string memory config = vm.readFile(string.concat(vm.projectRoot(), "/", CONFIG_FILE));
string memory configProfile = vm.envOr("CONFIG_PROFILE", string(""));
if (bytes(configProfile).length == 0) {
string[] memory profileKeys = vm.parseTomlKeys(config, ".profile");
for (uint256 i = 0; i < profileKeys.length; i++) {
if (stdToml.readUint(config, string.concat(".profile.", profileKeys[i], ".chainId")) == chainId) {
configProfile = profileKeys[i];
break;
}
}
}

if (bytes(configProfile).length != 0) {
console2.log("Deploying using config profile:", configProfile);
string memory configProfileKey = string.concat(".profile.", configProfile);
address riscZeroVerifierAddress =
stdToml.readAddress(config, string.concat(configProfileKey, ".riscZeroVerifierAddress"));
// If set, use the predeployed verifier address found in the config.
verifier = IRiscZeroVerifier(riscZeroVerifierAddress);
}

// Determine the wallet to send transactions from.
uint256 deployerKey = uint256(vm.envOr("ETH_WALLET_PRIVATE_KEY", bytes32(0)));
address deployerAddr = address(0);
if (deployerKey != 0) {
// Check for conflicts in how the two environment variables are set.
address envAddr = vm.envOr("ETH_WALLET_ADDRESS", address(0));
require(
envAddr == address(0) || envAddr == vm.addr(deployerKey),
"conflicting settings from ETH_WALLET_PRIVATE_KEY and ETH_WALLET_ADDRESS"
);

vm.startBroadcast(deployerKey);
vm.startBroadcast(deployerKey);
} else {
deployerAddr = vm.envAddress("ETH_WALLET_ADDRESS");
vm.startBroadcast(deployerAddr);
}

IRiscZeroVerifier verifier = new RiscZeroGroth16Verifier(ControlID.CONTROL_ROOT, ControlID.BN254_CONTROL_ID);
console2.log("Deployed RiscZeroGroth16Verifier to", address(verifier));
// Deploy the verifier, if not already deployed.
if (address(verifier) == address(0)) {
verifier = new RiscZeroGroth16Verifier(ControlID.CONTROL_ROOT, ControlID.BN254_CONTROL_ID);
console2.log("Deployed RiscZeroGroth16Verifier to", address(verifier));
} else {
console2.log("Using IRiscZeroVerifier contract deployed at", address(verifier));
}

// Deploy the application contract.
EvenNumber evenNumber = new EvenNumber(verifier);
console2.log("Deployed EvenNumber to", address(evenNumber));

Expand Down
14 changes: 14 additions & 0 deletions script/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[profile.mainnet]
# RISC Zero Verifier contract deployed on mainnet (see https://dev.risczero.com/api/blockchain-integration/contracts/verifier#deployed-verifiers)
chainId = 1
riscZeroVerifierAddress = "0x8EaB2D97Dfce405A1692a21b3ff3A172d593D319"

[profile.sepolia]
# RISC Zero Verifier contract deployed on sepolia (see https://dev.risczero.com/api/blockchain-integration/contracts/verifier#deployed-verifiers)
chainId = 11155111
riscZeroVerifierAddress = "0x925d8331ddc0a1F0d96E68CF073DFE1d92b69187"

# You can add additional profiles here
# [profile.custom]
# chainId = 11155111
# riscZeroVerifierAddress =

0 comments on commit 0eefc99

Please sign in to comment.