Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add mainnet deployment #119

Merged
merged 17 commits into from
Jun 26, 2024
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 =
Loading