diff --git a/.gitignore b/.gitignore index 4295dcff..ade1046b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ cache/ node_modules/ .env +.env.* remappings.txt broadcast/ src/test/sim/in/*.json @@ -12,3 +13,4 @@ src/test/sim/sims/*.t.sol docs/ coverage/ /solidity-metrics.html +dependencies/ diff --git a/.markdownlintignore b/.markdownlintignore index 18fc81f2..80422dc1 100644 --- a/.markdownlintignore +++ b/.markdownlintignore @@ -4,3 +4,4 @@ docs/ cache/ coverage/ lib/ +dependencies/ diff --git a/ROLES.md b/ROLES.md new file mode 100644 index 00000000..736b84b5 --- /dev/null +++ b/ROLES.md @@ -0,0 +1,83 @@ +# ROLES + +This document describes the roles that are used in the Olympus protocol. + +## Role Definitions + +| Role | Policy | Actions | +|------|----------|-------------| +| bondmanager_admin | BondManager | Create/close bond markets, set parameters | +| bridge_admin | CrossChainBridge | Allows configuring the CrossChainBridge | +| callback_admin | BondCallback | Administers the policy | +| callback_whitelist | BondCallback | Whitelists/blacklists tellers for callback | +| cooler_overseer | Clearinghouse | Allows activating the Clearinghouse | +| custodian | TreasuryCustodian | Deposit/withdraw reserves and grant/revoke approvals | +| distributor_admin | Distributor | Set reward rate, bounty, and other parameters | +| emergency_restart | Emergency | Reactivates the TRSRY and/or MINTR modules | +| emergency_shutdown | Clearinghouse | Allows shutting down the protocol in an emergency | +| emergency_shutdown | Emergency | Deactivates the TRSRY and/or MINTR modules | +| heart | Operator | Call the operate() function | +| heart | ReserveMigrator | Allows migrating reserves from one reserve token to another | +| heart | YieldRepurchaseFacility | Creates a new YRF market | +| heart_admin | Heart | Allows configuring heart parameters and activation/deactivation | +| loop_daddy | YieldRepurchaseFacility | Activate/deactivate the functionality | +| operator_admin | Operator | Activate/deactivate the functionality | +| operator_policy | Operator | Set spreads, threshold factor, and cushion factor | +| operator_reporter | Operator | Report bond purchases | +| poly_admin | pOLY | Allows migrating pOLY terms to another contract | + +## Role Allocations + +```json +{ + "0x0AE561226896dA978EaDA0Bec4a7d3CfAE04f506": [ // Current Operator contract + "callback_whitelist" + ], + "0x245cc372C84B3645Bf0Ffe6538620B04a217988B": [ // DAO MS + "operator_operate", + "operator_admin", + "callback_admin", + "price_admin", + "custodian", + "emergency_restart", + "bridge_admin", + "heart_admin", + "cooler_overseer", + "operator_policy", + "bondmanager_admin", + "loop_daddy" + ], + "0x73df08CE9dcC8d74d22F23282c4d49F13b4c795E": [ // Current BondCallback contract + "operator_reporter" + ], + "0x953EA3223d2dd3c1A91E9D6cca1bf7Af162C9c39": [ // OCG Timelock + "cooler_overseer", + "emergency_admin", + "emergency_shutdown", + "operator_admin", + "callback_admin", + "price_admin", + "custodian", + "emergency_restart", + "bridge_admin", + "heart_admin", + "operator_policy", + "loop_daddy", + "contract_registry_admin", + "loan_consolidator_admin" + ], + "0xda9fEDBcAF319Ecf8AB11fe874Fb1AbFc2181766": [ // pOly MS + "poly_admin" + ], + "0xa8A6ff2606b24F61AFA986381D8991DFcCCd2D55": [ // Emergency MS + "emergency_shutdown", + "emergency_admin" + ], + "0x39F6AA3d445e6Dd8eC232c6Bd589889A88E3034d": [ // Current Heart contract + "heart", + "operator_operate" + ] +} +``` + +The current role allocations can be determined by running the [role-viewer](https://github.com/OlympusDAO/role-viewer/) tool. diff --git a/foundry.toml b/foundry.toml index 5ad38205..dd8f3949 100644 --- a/foundry.toml +++ b/foundry.toml @@ -28,4 +28,10 @@ optimizer_runs = 10 chain_id = 1 [fuzz] -runs = 256 \ No newline at end of file +runs = 256 + +[soldeer] +remappings_generate = false + +[dependencies] +surl = { version = "1.0.0", git = "https://github.com/memester-xyz/surl.git", rev = "034c912ae9b5e707a5afd21f145b452ad8e800df" } diff --git a/remappings.txt b/remappings.txt index 7e14fdab..d3d7c251 100644 --- a/remappings.txt +++ b/remappings.txt @@ -27,3 +27,4 @@ openzeppelin-contracts/=lib/openzeppelin-contracts/ openzeppelin/=lib/forge-proposal-simulator/lib/openzeppelin-contracts/contracts/ solidity-code-metrics/=node_modules/solidity-code-metrics/ solidity-examples/=lib/solidity-examples/contracts/ +surl-1.0.0/=dependencies/surl-1.0.0/src/ diff --git a/shell/deploy.sh b/shell/deploy.sh index 66c43a81..616234e2 100755 --- a/shell/deploy.sh +++ b/shell/deploy.sh @@ -1,38 +1,68 @@ #!/bin/bash +# Deploys a sequence of contracts. +# # Usage: -# ./deploy.sh +# ./deploy.sh --sequence --broadcast --verify --resume --env +# +# Environment variables: +# RPC_URL +# PRIVATE_KEY +# GAS_PRICE +# ETHERSCAN_KEY (only needed if verify is true) +# VERIFIER_URL (only needed for a custom verifier or on a fork) -# Load environment variables, but respect overrides -curenv=$(declare -p -x) -source .env -eval "$curenv" +# Exit if any error occurs +set -e -# Get command-line arguments -DEPLOY_FILE=$1 -BROADCAST=${2:-false} -VERIFY=${3:-false} -RESUME=${4:-false} +# Iterate through named arguments +# Source: https://unix.stackexchange.com/a/388038 +while [ $# -gt 0 ]; do + if [[ $1 == *"--"* ]]; then + v="${1/--/}" + declare $v="$2" + fi + + shift +done + +# Get the name of the .env file or use the default +ENV_FILE=${env:-".env"} +echo "Sourcing environment variables from $ENV_FILE" + +# Load environment file +set -a # Automatically export all variables +source $ENV_FILE +set +a # Disable automatic export + +# Set sane defaults +BROADCAST=${broadcast:-false} +VERIFY=${verify:-false} +RESUME=${resume:-false} + +# Check if sequence is set +if [ -z "$sequence" ] +then + echo "No deployment sequence specified. Provide the relative path after the --sequence flag." + exit 1 +fi -# Check if DEPLOY_FILE is set -if [ -z "$DEPLOY_FILE" ] +# Check if the sequence file exists +if [ ! -f "$sequence" ] then - echo "No deploy file specified. Provide the relative path after the command." + echo "Deployment sequence ($sequence) not found. Provide the correct relative path after the --sequence flag." exit 1 fi -# Check if DEPLOY_FILE exists -if [ ! -f "$DEPLOY_FILE" ] +# Check if CHAIN is set +if [ -z "$CHAIN" ] then - echo "Deploy file ($DEPLOY_FILE) not found. Provide the correct relative path after the command." + echo "No chain specified. Specify the CHAIN in the $ENV_FILE file." exit 1 fi -echo "Deploying $DEPLOY_FILE" +echo "Deployment sequence: $sequence" echo "Chain: $CHAIN" -echo "Guardian: $GUARDIAN_ADDRESS" -echo "Policy: $POLICY_ADDRESS" -echo "Emergency: $EMERGENCY_ADDRESS" echo "Using RPC at URL: $RPC_URL" # Set BROADCAST_FLAG based on BROADCAST @@ -51,7 +81,7 @@ if [ "$VERIFY" = "true" ] || [ "$VERIFY" = "TRUE" ]; then # Check if ETHERSCAN_KEY is set if [ -z "$ETHERSCAN_KEY" ] then - echo "No Etherscan API key found. Provide the key in .env or disable verification." + echo "No Etherscan API key found. Provide the key in $ENV_FILE or disable verification." exit 1 fi @@ -79,7 +109,7 @@ fi # Deploy using script forge script ./src/scripts/deploy/DeployV2.sol:OlympusDeploy \ ---sig "deploy(string,string)()" $CHAIN $DEPLOY_FILE \ +--sig "deploy(string,string)()" $CHAIN $sequence \ --rpc-url $RPC_URL --private-key $PRIVATE_KEY --slow -vvv \ --with-gas-price $GAS_PRICE \ $BROADCAST_FLAG \ diff --git a/shell/full_install.sh b/shell/full_install.sh index 14157f33..5661e53f 100755 --- a/shell/full_install.sh +++ b/shell/full_install.sh @@ -24,5 +24,8 @@ cd lib/solidity-examples/ && git checkout a4954e5747baca5e7fd2b62c639e7600ad388a cd lib/solmate/ && git checkout fadb2e2778adbf01c80275bfb99e5c14969d964b && cd ../.. cd lib/forge-proposal-simulator && git checkout 864b357b650f9dc7b2fb1ae23562454815d51def && cd ../.. +echo "*** Running forge soldeer update" +forge soldeer update + echo "*** Running forge build" forge build diff --git a/soldeer.lock b/soldeer.lock new file mode 100644 index 00000000..a25fbe0e --- /dev/null +++ b/soldeer.lock @@ -0,0 +1,5 @@ +[[dependencies]] +name = "surl" +version = "1.0.0" +git = "https://github.com/memester-xyz/surl.git" +rev = "034c912ae9b5e707a5afd21f145b452ad8e800df" diff --git a/src/scripts/ops/OlyBatch.sol b/src/scripts/ops/OlyBatch.sol index 03a4dac1..9f6cf185 100644 --- a/src/scripts/ops/OlyBatch.sol +++ b/src/scripts/ops/OlyBatch.sol @@ -3,9 +3,12 @@ pragma solidity 0.8.15; import {BatchScript} from "./lib/BatchScript.sol"; import {stdJson} from "forge-std/StdJson.sol"; +import {console2} from "forge-std/console2.sol"; +import {Surl} from "surl-1.0.0/Surl.sol"; abstract contract OlyBatch is BatchScript { using stdJson for string; + using Surl for *; string internal env; string internal chain; @@ -81,4 +84,74 @@ abstract contract OlyBatch is BatchScript { } function loadEnv() internal virtual; + + function executeBatch(bool send_) internal override { + bool isTestnet = vm.envOr("TESTNET", false); + + if (isTestnet && send_) { + console2.log("Sending batch on testnet"); + _sendTestnetBatch(); + return; + } + + super.executeBatch(send_); + } + + function _sendTestnetBatch() private { + // Get the testnet RPC URL and access key + string memory TENDERLY_ACCOUNT_SLUG = vm.envString("TENDERLY_ACCOUNT_SLUG"); + string memory TENDERLY_PROJECT_SLUG = vm.envString("TENDERLY_PROJECT_SLUG"); + string memory TENDERLY_VNET_ID = vm.envString("TENDERLY_VNET_ID"); + string memory TENDERLY_ACCESS_KEY = vm.envString("TENDERLY_ACCESS_KEY"); + + // Iterate over the proposal actions and execute them + for (uint256 i; i < actionsTo.length; i++) { + console2.log("Preparing batch action ", i + 1); + + // Construct the API call + string[] memory headers = new string[](3); + headers[0] = "Accept: application/json"; + headers[1] = "Content-Type: application/json"; + headers[2] = string.concat("X-Access-Key: ", TENDERLY_ACCESS_KEY); + + string memory url = string.concat( + "https://api.tenderly.co/api/v1/account/", + TENDERLY_ACCOUNT_SLUG, + "/project/", + TENDERLY_PROJECT_SLUG, + "/vnets/", + TENDERLY_VNET_ID, + "/transactions" + ); + + // Execute the API call + // solhint-disable quotes + console2.log("Executing batch action ", i + 1); + (uint256 status, bytes memory response) = url.post( + headers, + string.concat( + "{", + '"callArgs": {', + '"from": "', + vm.toString(daoMS), + '", "to": "', + vm.toString(actionsTo[i]), + '", "gas": "0x7a1200", "gasPrice": "0x10", "value": "0x0", ', + '"data": "', + vm.toString(actionsData[i]), + '"', + "}}" + ) + ); + // solhint-enable quotes + + string memory responseString = string(response); + console2.log("Response: ", responseString); + + // If the response contains "error", exit + if (status >= 400 || vm.keyExists(responseString, ".error")) { + revert("Error executing batch action"); + } + } + } } diff --git a/src/scripts/ops/README.md b/src/scripts/ops/README.md new file mode 100644 index 00000000..5ff88abc --- /dev/null +++ b/src/scripts/ops/README.md @@ -0,0 +1,13 @@ +# Batch Scripts + +This directory contains batch scripts for the Olympus DAO multisig. + +## Fork Testing + +To run the scripts on a testnet/forked chain, provide the `--testnet` flag to the `batch.sh` script. This requires certain environment variables to be set, which are documented in the `batch.sh` file. + +For example: + +```bash +./batch.sh --contract ContractRegistryInstall --batch script1_install --broadcast true --testnet true --env .env.testnet +``` diff --git a/src/scripts/ops/batch.sh b/src/scripts/ops/batch.sh index 575a4cb7..10da1490 100644 --- a/src/scripts/ops/batch.sh +++ b/src/scripts/ops/batch.sh @@ -1,26 +1,72 @@ #!/bin/bash -# Arguments required for this script -# 1. String: File/Contract Name (should be the same) -# 2. String: Batch Name -# 3. Bool: Whether to send to STS or not (if false, just simulates the batch) +# Run a multisig batch +# +# Usage: +# ./batch.sh --contract --batch --broadcast --testnet --env +# +# Environment variables: +# RPC_URL +# SIGNER_ADDRESS +# TESTNET -# Load environment variables, but respect overrides -curenv=$(declare -p -x) -source .env -eval "$curenv" +# Exit if any error occurs +set -e -CONTRACT_NAME=$1 -BATCH_NAME=$2 -BROADCAST=$3 +# Iterate through named arguments +# Source: https://unix.stackexchange.com/a/388038 +while [ $# -gt 0 ]; do + if [[ $1 == *"--"* ]]; then + v="${1/--/}" + declare $v="$2" + fi -echo "Contract name: $CONTRACT_NAME" + shift +done -echo "Batch name: $BATCH_NAME" +# Get the name of the .env file or use the default +ENV_FILE=${env:-".env"} +echo "Sourcing environment variables from $ENV_FILE" -echo "Broadcasting: $BROADCAST" +# Load environment file +set -a # Automatically export all variables +source $ENV_FILE +set +a # Disable automatic export + +# Set sane defaults +BROADCAST=${broadcast:-false} +TESTNET=${testnet:-false} + +# Check if contract is set +if [ -z "$contract" ]; then + echo "No contract name provided. Provide the contract name after the --contract flag." + exit 1 +fi + +# Check if batch is set +if [ -z "$batch" ]; then + echo "No batch name provided. Provide the batch name after the --batch flag." + exit 1 +fi +# Check if RPC_URL is set +if [ -z "$RPC_URL" ]; then + echo "No RPC URL provided. Specify the RPC_URL in the $ENV_FILE file." + exit 1 +fi + +# Check if SIGNER_ADDRESS is set +if [ -z "$SIGNER_ADDRESS" ]; then + echo "No signer address provided. Specify the SIGNER_ADDRESS in the $ENV_FILE file." + exit 1 +fi + +echo "Contract name: $contract" +echo "Batch name: $batch" echo "Using RPC at URL: $RPC_URL" +echo "Using signer address: $SIGNER_ADDRESS" +echo "Broadcasting: $BROADCAST" +echo "Using testnet: $TESTNET" # Execute the batch -forge script ./src/scripts/ops/batches/$CONTRACT_NAME.sol:$CONTRACT_NAME --sig "$BATCH_NAME(bool)()" $BROADCAST --slow -vvv --sender $SIGNER_ADDRESS --rpc-url $RPC_URL \ No newline at end of file +TESTNET=$TESTNET forge script ./src/scripts/ops/batches/$contract.sol:$contract --sig "$batch(bool)()" $BROADCAST --slow -vvv --sender $SIGNER_ADDRESS --rpc-url $RPC_URL diff --git a/src/scripts/ops/lib/BatchScript.sol b/src/scripts/ops/lib/BatchScript.sol index 8e2c0857..baa7db2f 100644 --- a/src/scripts/ops/lib/BatchScript.sol +++ b/src/scripts/ops/lib/BatchScript.sol @@ -69,6 +69,9 @@ abstract contract BatchScript is Script { // Address to send transaction from address internal safe; + address[] internal actionsTo; + bytes[] internal actionsData; + enum Operation { CALL, DELEGATECALL @@ -128,6 +131,9 @@ abstract contract BatchScript is Script { vm.prank(safe); (bool success, bytes memory data) = to_.call(data_); if (success) { + actionsTo.push(to_); + actionsData.push(data_); + return data; } else { revert(string(data)); @@ -136,7 +142,7 @@ abstract contract BatchScript is Script { // Simulate then send the batch to the Safe API. If `send_` is `false`, the // batch will only be simulated. - function executeBatch(bool send_) internal { + function executeBatch(bool send_) internal virtual { _initialize(); Batch memory batch = _createBatch(safe); // _simulateBatch(safe, batch); diff --git a/src/scripts/proposals/README.md b/src/scripts/proposals/README.md new file mode 100644 index 00000000..9256843a --- /dev/null +++ b/src/scripts/proposals/README.md @@ -0,0 +1,33 @@ +# OCG Proposals + +This directory contains scripts for submitting proposals to the Olympus Governor. + +## Setup + +The OCG proposal must have a separate contract that inherits from `ProposalScript`. See the `ContractRegistryProposal` for an example. + +## Fork Testing + +It is possible to test proposal submission (and execution) on a forked chain. To do so, follow these steps: + +1. Create a fork of the chain you wish to test on. Tenderly will be used in the examples. +2. Create an environment file (e.g., `.env.tenderly`) and set the environment variables. + - `RPC_URL`: Your fork's RPC URL. + - `TENDERLY_ACCOUNT_SLUG`: Your Tenderly account slug. + - `TENDERLY_PROJECT_SLUG`: Your Tenderly project slug. + - `TENDERLY_VNET_ID`: Your Tenderly vNet ID. This is the random string in the URL of the testnet in the Tenderly dashboard. It is NOT the same as the random string in the `RPC_URL`. e.g. `https://dashboard.tenderly.co/{TENDERLY_ACCOUNT_SLUG}/{TENDERLY_PROJECT_SLUG}/testnet/{TENDERLY_VNET_ID}` + - `TENDERLY_ACCESS_KEY`: Your Tenderly access key. +3. Configure a wallet with `cast wallet` +4. Fund your chosen wallet with gOHM + - On Tenderly, this can be done using the "Fund Account" button in the dashboard. +5. Delegate your gOHM voting power to your wallet address. + - This can be done by running `./delegate.sh` with the appropriate arguments, or through the Tenderly dashboard. +6. Submit your proposal by running `./submitProposal.sh` with the appropriate arguments. +7. Alternatively, you can execute the proposal (as if the proposal has passed) by running `./executeOnTestnet.sh` with the appropriate arguments. + +## Mainnet + +1. Configure a wallet with `cast wallet` +2. Delegate your gOHM voting power to your wallet address. + - This can be done by running `./delegate.sh` with the appropriate arguments, or through the Tenderly dashboard. +3. Submit your proposal by running `./submitProposal.sh` with the appropriate arguments. diff --git a/src/scripts/proposals/delegate.sh b/src/scripts/proposals/delegate.sh new file mode 100644 index 00000000..dc5f96ee --- /dev/null +++ b/src/scripts/proposals/delegate.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +# This script delegates voting power to a delegate. +# +# Usage: src/scripts/proposals/delegate.sh --account --delegate --env +# +# Environment variables: +# RPC_URL + +# Exit if any error occurs +set -e + +# Iterate through named arguments +# Source: https://unix.stackexchange.com/a/388038 +while [ $# -gt 0 ]; do + if [[ $1 == *"--"* ]]; then + v="${1/--/}" + declare $v="$2" + fi + + shift +done + +# Get the name of the .env file or use the default +ENV_FILE=${env:-".env"} +echo "Sourcing environment variables from $ENV_FILE" + +# Load environment file +set -a # Automatically export all variables +source $ENV_FILE +set +a # Disable automatic export + +# Check if the RPC_URL was specified +if [ -z "$RPC_URL" ]; then + echo "Error: RPC_URL was not specified" + exit 1 +fi + +# Check if the forge account was specified +if [ -z "$account" ]; then + echo "Error: Forge account was not specified. Set up using 'cast wallet'." + exit 1 +fi + +# Check if the delegate was specified +if [ -z "$delegate" ]; then + echo "Error: Delegate was not specified" + exit 1 +fi + +echo "Using RPC at URL: $RPC_URL" +echo "Using forge account: $account" +echo "Delegating to delegate: $delegate" + +# Run the delegate command +# TODO this doesn't seem to work due to an error with cast call: +# > Error: invalid type: found string "mainnet", expected u64 +cast call 0x0ab87046fbb341d058f17cbc4c1133f25a20a52f "delegate(address)()" $delegate --chain mainnet --rpc-url $RPC_URL --account $account diff --git a/src/scripts/proposals/executeOnTestnet.sh b/src/scripts/proposals/executeOnTestnet.sh new file mode 100644 index 00000000..532038c6 --- /dev/null +++ b/src/scripts/proposals/executeOnTestnet.sh @@ -0,0 +1,92 @@ +#!/bin/bash + +# This script executes a proposal's actions on a testnet. +# +# Usage: src/scripts/proposals/executeOnTestnet.sh --file --contract --env +# +# Environment variables: +# TENDERLY_ACCOUNT_SLUG +# TENDERLY_PROJECT_SLUG +# TENDERLY_VNET_ID +# TENDERLY_ACCESS_KEY +# RPC_URL + +# Exit if any error occurs +set -e + +# Iterate through named arguments +# Source: https://unix.stackexchange.com/a/388038 +while [ $# -gt 0 ]; do + if [[ $1 == *"--"* ]]; then + v="${1/--/}" + declare $v="$2" + fi + + shift +done + +# Get the name of the .env file or use the default +ENV_FILE=${env:-".env"} +echo "Sourcing environment variables from $ENV_FILE" + +# Load environment file +set -a # Automatically export all variables +source $ENV_FILE +set +a # Disable automatic export + +# Check if the proposal file was specified +if [ -z "$file" ]; then + echo "Error: Proposal file was not specified" + exit 1 +fi + +# Check if the proposal file exists +if [ ! -f "$file" ]; then + echo "Error: Proposal file does not exist. Provide the correct relative path after the --file flag." + exit 1 +fi + +# Check if the contract name was specified +if [ -z "$contract" ]; then + echo "Error: Contract name was not specified" + exit 1 +fi + +# Check if the TENDERLY_ACCOUNT_SLUG was specified +if [ -z "$TENDERLY_ACCOUNT_SLUG" ]; then + echo "Error: TENDERLY_ACCOUNT_SLUG was not specified" + exit 1 +fi + +# Check if the TENDERLY_PROJECT_SLUG was specified +if [ -z "$TENDERLY_PROJECT_SLUG" ]; then + echo "Error: TENDERLY_PROJECT_SLUG was not specified" + exit 1 +fi + +# Check if the TENDERLY_VNET_ID was specified +if [ -z "$TENDERLY_VNET_ID" ]; then + echo "Error: TENDERLY_VNET_ID was not specified" + exit 1 +fi + +# Check if the TENDERLY_ACCESS_KEY was specified +if [ -z "$TENDERLY_ACCESS_KEY" ]; then + echo "Error: TENDERLY_ACCESS_KEY was not specified" + exit 1 +fi + +# Check if the RPC_URL was specified +if [ -z "$RPC_URL" ]; then + echo "Error: RPC_URL was not specified" + exit 1 +fi + +echo "Using proposal contract: $file:$contract" +echo "Using TENDERLY_ACCOUNT_SLUG: $TENDERLY_ACCOUNT_SLUG" +echo "Using TENDERLY_PROJECT_SLUG: $TENDERLY_PROJECT_SLUG" +echo "Using TENDERLY_VNET_ID: $TENDERLY_VNET_ID" +echo "Using RPC_URL: $RPC_URL" + +# Run the forge script +TENDERLY_ACCOUNT_SLUG=$TENDERLY_ACCOUNT_SLUG TENDERLY_PROJECT_SLUG=$TENDERLY_PROJECT_SLUG TENDERLY_VNET_ID=$TENDERLY_VNET_ID TENDERLY_ACCESS_KEY=$TENDERLY_ACCESS_KEY forge script $file:$contract --sig "executeOnTestnet()" --rpc-url $RPC_URL diff --git a/src/scripts/proposals/submitProposal.sh b/src/scripts/proposals/submitProposal.sh new file mode 100644 index 00000000..67437336 --- /dev/null +++ b/src/scripts/proposals/submitProposal.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +# This script submits a proposal to the governor. +# +# Usage: src/scripts/proposals/submitProposal.sh --file --contract --account --fork --broadcast --env +# +# Environment variables: +# RPC_URL + +# Exit if any error occurs +set -e + +# Iterate through named arguments +# Source: https://unix.stackexchange.com/a/388038 +while [ $# -gt 0 ]; do + if [[ $1 == *"--"* ]]; then + v="${1/--/}" + declare $v="$2" + fi + + shift +done + +# Get the name of the .env file or use the default +ENV_FILE=${env:-".env"} +echo "Sourcing environment variables from $ENV_FILE" + +# Load environment file +set -a # Automatically export all variables +source $ENV_FILE +set +a # Disable automatic export + +# Apply defaults to command-line arguments +FORK=${fork:-false} +BROADCAST=${broadcast:-false} + +# Check if the proposal file was specified +if [ -z "$file" ]; then + echo "Error: Proposal file was not specified" + exit 1 +fi + +# Check if the proposal file exists +if [ ! -f "$file" ]; then + echo "Error: Proposal file does not exist. Provide the correct relative path after the --file flag." + exit 1 +fi + +# Check if the contract name was specified +if [ -z "$contract" ]; then + echo "Error: Contract name was not specified" + exit 1 +fi + +# Check if the RPC_URL was specified +if [ -z "$RPC_URL" ]; then + echo "Error: RPC_URL was not specified" + exit 1 +fi + +# Check if the forge account was specified +if [ -z "$account" ]; then + echo "Error: Forge account was not specified. Set up using 'cast wallet'." + exit 1 +fi + +echo "Using proposal contract: $file:$contract" +echo "Using RPC at URL: $RPC_URL" +echo "Using forge account: $account" + +# Set the fork flag +FORK_FLAG="" +if [ "$FORK" = "true" ]; then + FORK_FLAG="--legacy" + echo "Fork: enabled" +else + echo "Fork: disabled" +fi + +# Set the broadcast flag +BROADCAST_FLAG="" +if [ "$BROADCAST" = "true" ]; then + BROADCAST_FLAG="--broadcast" + echo "Broadcast: enabled" +else + echo "Broadcast: disabled" +fi + +# Run the forge script +forge script $file:$contract -vvv --rpc-url $RPC_URL --account $account $FORK_FLAG $BROADCAST_FLAG