diff --git a/deployment-guide.md b/deployment-guide.md index ad624cb..2578091 100644 --- a/deployment-guide.md +++ b/deployment-guide.md @@ -116,7 +116,7 @@ You can deploy your contracts on the `Sepolia` testnet and run an end-to-end tes 3. Deploy your contract by running: ```bash - CONFIG_PROFILE=sepolia forge script script/Deploy.s.sol --rpc-url https://eth-sepolia.g.alchemy.com/v2/${ALCHEMY_API_KEY:?} --broadcast + forge script script/Deploy.s.sol --rpc-url https://eth-sepolia.g.alchemy.com/v2/${ALCHEMY_API_KEY:?} --broadcast ``` This command uses the `sepolia` profile defined in the [config][config] file, and should output something similar to: @@ -179,7 +179,7 @@ You can deploy your contract on Ethereum Mainnet as follows: 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_PRIVATE_KEY="YOUR_WALLET_PRIVATE_KEY" # the private hex-encoded key of your Mainnet wallet + export ETH_WALLET_ADDRESS="YOUR_WALLET_ADDRESS" # the account address you want to use for deployment ``` 2. Build your project: @@ -190,8 +190,11 @@ You can deploy your contract on Ethereum Mainnet as follows: 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 - CONFIG_PROFILE=mainnet forge script script/MainnetDeploy.s.sol --rpc-url https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY:?} --broadcast + 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: @@ -228,6 +231,10 @@ You can deploy your contract on Ethereum Mainnet as follows: 2. Publish a new state + > [!WARNING] + > 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 \ @@ -243,11 +250,12 @@ You can deploy your contract on Ethereum Mainnet as follows: ``` [Deploy to Ethereum Mainnet]: #deploy-your-project-on-ethereum-mainnet -[Deploy to a testnet]: #deploy-your-project-on-a-testnet [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 diff --git a/script/Deploy.s.sol b/script/Deploy.s.sol index 8801109..0d76455 100644 --- a/script/Deploy.s.sol +++ b/script/Deploy.s.sol @@ -26,39 +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 { - using stdToml for string; - + // Path to deployment config file, relative to the project root. string constant CONFIG_FILE = "script/config.toml"; - string constant DEFAULT_PROFILE = "DEFAULT_PROFILE"; + IRiscZeroVerifier verifier; function run() external { - // read and log the chainID + // Read and log the chainID uint256 chainId = block.chainid; console2.log("You are deploying on ChainID %d", chainId); - uint256 deployerKey = uint256(vm.envBytes32("ETH_WALLET_PRIVATE_KEY")); - - vm.startBroadcast(deployerKey); + // 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; + } + } + } - string memory configProfile = vm.envOr("CONFIG_PROFILE", DEFAULT_PROFILE); - if (keccak256(abi.encodePacked(configProfile)) != keccak256(abi.encodePacked(DEFAULT_PROFILE))) { - string memory config = vm.readFile(CONFIG_FILE); - string memory profile = string.concat(".profile.", configProfile); + if (bytes(configProfile).length != 0) { console2.log("Deploying using config profile:", configProfile); - address riscZeroVerifierAddress = config.readAddress(string.concat(profile, ".riscZeroVerifierAddress")); + 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); - console2.log("Using IRiscZeroVerifier contract deployed at", 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); } else { + deployerAddr = vm.envAddress("ETH_WALLET_ADDRESS"); + vm.startBroadcast(deployerAddr); + } + + // 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 IRiscZeroVerifier to", address(verifier)); + 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)); diff --git a/script/config.toml b/script/config.toml index a53ee20..9c97f14 100644 --- a/script/config.toml +++ b/script/config.toml @@ -1,11 +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" -[profile.custom] -# You can define a pre-deployed IRiscZeroVerifier contract here -# riscZeroVerifierAddress = \ No newline at end of file +# You can add additional profiles here +# [profile.custom] +# chainId = 11155111 +# riscZeroVerifierAddress =