From 261ab53037bd9034986997639c38167618d89e95 Mon Sep 17 00:00:00 2001 From: Mikhail <16622558+mmv08@users.noreply.github.com> Date: Fri, 10 Nov 2023 13:42:38 +0100 Subject: [PATCH] Add a GitHub action to validate an issue request to deploy a factory on a new network (#263) * Wip * Add github action to validate the github issue * Update .github/workflows/prepare-transaction.yml Co-authored-by: Nicholas Rodrigues Lordello * Add github action to validate the github issue * Export the script to a separate file * Export the script to a separate file --------- Co-authored-by: Nicholas Rodrigues Lordello --- .github/ISSUE_TEMPLATE/new_chain.yml | 45 +++++ .github/ISSUE_TEMPLATE/request_network.md | 14 -- .github/scripts/validate_new_chain_request.sh | 183 ++++++++++++++++++ .github/workflows/prepare-transaction.yml | 37 ++++ 4 files changed, 265 insertions(+), 14 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/new_chain.yml delete mode 100644 .github/ISSUE_TEMPLATE/request_network.md create mode 100644 .github/scripts/validate_new_chain_request.sh create mode 100644 .github/workflows/prepare-transaction.yml diff --git a/.github/ISSUE_TEMPLATE/new_chain.yml b/.github/ISSUE_TEMPLATE/new_chain.yml new file mode 100644 index 00000000..115e0b6d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/new_chain.yml @@ -0,0 +1,45 @@ +name: Request factory deployment to a new chain +description: Template to request a factory deployment to a new chain +title: "[New chain]: " +body: + - type: markdown + attributes: + value: Please fill the following form + - type: input + id: name + attributes: + label: Chain Name + description: Chain Name + validations: + required: true + - type: input + id: rpc_url + attributes: + label: RPC URL + description: RPC URL + validations: + required: true + - type: checkboxes + id: chainlist_url + attributes: + label: The chain must be added to https://chainlist.org/ + options: + - label: I confirm that the chain is added to chainlist + required: true + - type: checkboxes + id: prefunded + attributes: + label: After creating the issue, a bot will estimate the required pre-fund and post it in the comments. Please check this checkbox after you send the pre-fund. + options: + - label: I sent the pre-fund in accordance with Github Action's comment + - type: textarea + id: relevant + attributes: + label: Relevant information + description: Add relevant information like blockexplorer, any annotation + - type: markdown + attributes: + value: | + Please keep one network per issue. If you need to request a factory deployment to multiple networks, please create one issue per network.
+ After creating the issue, a GitHub Action will validate the issue description and post a comment with the result. If the validation passes, it will calculate the required prefund
+ and check if the deployer address is pre-funded. If the deployer address is not pre-funded, the comment will contain the required prefund and the deployer address.
diff --git a/.github/ISSUE_TEMPLATE/request_network.md b/.github/ISSUE_TEMPLATE/request_network.md deleted file mode 100644 index acd5007f..00000000 --- a/.github/ISSUE_TEMPLATE/request_network.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: Request new network -about: Request to add the deployment information for a new network ---- - -## Network information - -- Name: -- ChainId: -- RPC http/s address: -- Link to https://chainlist.org/ -- (Optional) Blockexplorer: -- [ ] I have run `RPC='http://my-rpc-address' yarn estimate` -- [ ] I have sent `requiredFunds` to `0xE1CB04A0fA36DdD16a06ea828007E35e1a3cBC37` diff --git a/.github/scripts/validate_new_chain_request.sh b/.github/scripts/validate_new_chain_request.sh new file mode 100644 index 00000000..5c61cc42 --- /dev/null +++ b/.github/scripts/validate_new_chain_request.sh @@ -0,0 +1,183 @@ +#!/usr/bin/env bash + + +# This script is used to validate a GitHub issue for a new chain request. +# What it does: +# 1. Extracts the RPC URL from the issue body +# 2. Extracts the chain ID from the RPC URL +# 3. Checks if the chain ID is in chainlist +# 4. Checks if the factory is already deployed +# 5. Checks if the deployer address is pre-funded +# +# If any of the above checks fails, the script will exit with an error code and set an environment variable +# `COMMENT_OUTPUT` with an error message. The GitHub action will then use this variable to post a comment. +# For the above reason, the script needs to be executed in the GitHub's action shell, for example: +# ``` +# . ./.github/scripts/validate_new_chain_request.sh +# ``` +# +# The script expects the following environment variables to be set: +# - `ISSUE_BODY` - the body of the issue +# - `FACTORY_ADDRESS` - the address of the factory contract +# - `FACTORY_DEPLOYER_ADDRESS` - the address of the factory deployer +# - `FACTORY_BYTECODE` - the bytecode of the factory contract + + +ERROR_MSG_RPC_FAILURE=\ +"**⛔️ Error:**
"\ +"Could not fetch the chain ID from the RPC URL.
"\ +"Either the RPC URL is missing, or the RPC is not responding.
"\ +"**Make sure your issue follows the issue template and includes the RPC URL.**
"\ +":sparkles: You can edit the issue to trigger the check again. :sparkles:" +ERROR_MSG_CHAINLIST_FAILURE=\ +"**⛔️ Error:**
"\ +"Couldn't find the chain in the chainlist. Please make sure it's added to the chainlist.
"\ +"For more information on how to add a chain, please refer to the [chainlist repository](https://github.com/ethereum-lists/chains).
"\ +":sparkles: You can edit the issue to trigger the check again. :sparkles:" +ERROR_MSG_PREFUND_CHECK=\ +"**⛔️ Error:**
"\ +"There was an error while estimating the deployment transaction and checking the pre-fund. Please make sure that the RPC URL is valid and reachable.
"\ +":sparkles: You can edit the issue to trigger the check again. :sparkles:" +SUCCESS_MSG=\ +"**✅ Success:**
"\ +"The issue description is valid:
"\ +"- The RPC URL is valid
"\ +"- The chain is in the chainlist
"\ +"- The deployer address is pre-funded
"\ +":sparkles: The team will be in touch with you soon :sparkles:" +ADDRESS_NOT_PREFUNDED_ERR_MSG() { + echo "**⛔️ Error:**
The deployer address is not pre-funded. Please send $1 wei to $FACTORY_DEPLOYER_ADDRESS and try again." +} +FACTORY_ALREADY_DEPLOYED_ERR_MSG="**⛔️ Error:**
The factory is already deployed. Please use the existing factory at $FACTORY_ADDRESS." + + +trim() { + # 3.5.3 Shell Parameter Expansion at https://www.gnu.org/software/bash/manual/bash.html + local var="$*" + # remove leading whitespace characters + var="${var#"${var%%[![:space:]]*}"}" + # remove trailing whitespace characters + var="${var%"${var##*[![:space:]]}"}" + echo "$var" +} + +rpc_url=$(echo "$ISSUE_BODY" | egrep -o 'https?://[^ ]+' -m 1 | head -1) + +if [ -z "$rpc_url" ]; then + echo "COMMENT_OUTPUT=$ERROR_MSG_RPC_FAILURE" >> $GITHUB_ENV + exit 1 +fi + +rpc_url="$(trim "$rpc_url")" +echo "Extracted RPC url: $rpc_url. Trying to get the chain id..." +response=$(curl "$rpc_url" --location --header \ + 'Content-Type: application/json' --data '{ + "jsonrpc": "2.0", + "method": "eth_chainId", + "params": [], + "id": 5413 +}') + + +if jq -e . >/dev/null 2>&1 <<< "$response"; then + chain_id=$(( $(echo "$response" | jq -r '.result') )) +else + echo "Failed to parse JSON, or got false/null" + echo "COMMENT_OUTPUT=$ERROR_MSG_RPC_FAILURE" >> $GITHUB_ENV + exit 1 +fi + + +factory_code=$(curl "$rpc_url" --location --header \ + 'Content-Type: application/json' --data '{ + "jsonrpc": "2.0", + "method": "eth_getCode", + "params": ["'"$FACTORY_ADDRESS"'", "latest"], + "id": "0x5afe" + }') + +if jq -e . >/dev/null 2>&1 <<< "$factory_code"; then + factory_code=$(jq -r '.result' <<< "$factory_code") + + if [ "$factory_code" != "0x" ]; then + echo "COMMENT_OUTPUT=$FACTORY_ALREADY_DEPLOYED_ERR_MSG" >> $GITHUB_ENV + exit 1 + fi +fi + +echo "$chain_id from the RPC URL is valid. Checking the chain in chainlist..." +chainlist_url="https://raw.githubusercontent.com/ethereum-lists/chains/master/_data/chains/eip155-$chain_id.json" + +chainlist_status_code=$(trim "$(curl -LI "$chainlist_url" -o /dev/null -w '%{http_code}\n' -s)") + +if [ "$chainlist_status_code" == "404" ]; then + echo "Chain $chain_id is not in chainlist." + echo "COMMENT_OUTPUT=$ERROR_MSG_CHAINLIST_FAILURE" >> $GITHUB_ENV + exit 1 +fi + +json_request='[ + { + "jsonrpc": "2.0", + "method": "eth_gasPrice", + "params": [], + "id": 1 + }, + { + "jsonrpc": "2.0", + "method": "eth_estimateGas", + "params": [ + { + "from": "'$FACTORY_DEPLOYER_ADDRESS'", + "data": "'$FACTORY_BYTECODE'" + } + ], + "id": 2 + } +]' + +response=$(curl "$rpc_url" --location --header 'Content-Type: application/json' --data "$json_request") + +if jq -e . >/dev/null 2>&1 <<< "$response"; then + gas_price=$(jq -r '.[0].result' <<< "$response") + echo "Current gas price: $gas_price" + gas_limit=$(jq -r '.[1].result' <<< "$response") + echo "Estimated deployment gas limit: $gas_limit" + + if [[ "$gas_price" == "null" || "$gas_limit" == "null" ]]; then + echo "COMMENT_OUTPUT=$ERROR_MSG_PREFUND_CHECK" >> $GITHUB_ENV + exit 1 + fi + + # We multiply the gas limit by 1.4, just like the deployment script does it + gas_limit=$(( gas_limit * 14 / 10 )) + expected_prefund=$((gas_limit * gas_price)) + + echo "Expected pre-fund: $expected_prefund" + + deployer_address_balance=$(curl "$rpc_url" --location --header \ + 'Content-Type: application/json' --data '{ + "jsonrpc": "2.0", + "method": "eth_getBalance", + "params": ["'$FACTORY_DEPLOYER_ADDRESS'", "latest"], + "id": 5413 + }') + + if jq -e . >/dev/null 2>&1 <<< "$deployer_address_balance"; then + deployer_address_balance=$(( $(echo "$deployer_address_balance" | jq -r '.result') )) + echo "Deployer address balance: $deployer_address_balance" + + if [ "$deployer_address_balance" -lt "$expected_prefund" ]; then + echo "COMMENT_OUTPUT=$(ADDRESS_NOT_PREFUNDED_ERR_MSG $expected_prefund)" >> $GITHUB_ENV + exit 1 + fi + else + echo "COMMENT_OUTPUT=$ERROR_MSG_PREFUND_CHECK" >> $GITHUB_ENV + exit 1 + fi +else + echo "COMMENT_OUTPUT=$ERROR_MSG_PREFUND_CHECK" >> $GITHUB_ENV + exit 1 +fi + +echo "COMMENT_OUTPUT=$SUCCESS_MSG" >> $GITHUB_ENV diff --git a/.github/workflows/prepare-transaction.yml b/.github/workflows/prepare-transaction.yml new file mode 100644 index 00000000..40fb4b4a --- /dev/null +++ b/.github/workflows/prepare-transaction.yml @@ -0,0 +1,37 @@ +name: "Validate the issue description and prepare the transaction" +on: + issues: + types: [opened, edited] +env: + ISSUE_BODY: ${{ github.event.issue.body }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NUMBER: ${{ github.event.issue.number }} + REPO: ${{ github.repository }} + FACTORY_ADDRESS: "0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7" + FACTORY_BYTECODE: "0x604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3" + FACTORY_DEPLOYER_ADDRESS: "0xE1CB04A0fA36DdD16a06ea828007E35e1a3cBC37" + +jobs: + prepareTransaction: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + sparse-checkout: | + .github/scripts/validate_new_chain_request.sh + sparse-checkout-cone-mode: false + + - name: Run the validation script + run: . ./.github/scripts/validate_new_chain_request.sh + env: + ISSUE_BODY: ${{ env.ISSUE_BODY }} + FACTORY_ADDRESS: ${{ env.FACTORY_ADDRESS }} + FACTORY_BYTECODE: ${{ env.FACTORY_BYTECODE }} + FACTORY_DEPLOYER_ADDRESS: ${{ env.FACTORY_DEPLOYER_ADDRESS }} + + - name: Post Comment to the Issue + if: always() + env: + COMMENT_OUTPUT: ${{ env.COMMENT_OUTPUT }} + run: | + gh issue comment "$NUMBER" --repo "$REPO" --body "$COMMENT_OUTPUT" --edit-last || gh issue comment "$NUMBER" --repo "$REPO" --body "$COMMENT_OUTPUT"