diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 2adb8c4897..055dc5e277 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,6 +12,4 @@ updates: pull-request-branch-name: separator: "-" reviewers: - - "lazartravica" - - "Kourin1996" - - "zivkovicmilos" + - "0xPolygon/core-edge" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 10ef3db673..73592d30a1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,21 +3,26 @@ name: Build on: # yamllint disable-line rule:truthy workflow_dispatch: workflow_call: + # Map the workflow outputs to job outputs + outputs: + workflow_output: + description: "Build output" + value: ${{ jobs.go_build.outputs.build_output_failure }} jobs: go_build: name: Polygon Edge runs-on: ubuntu-latest + outputs: + build_output_failure: ${{ steps.edge_build_failure.outputs.build_output }} steps: - name: Checkout code uses: actions/checkout@v3 - with: - submodules: recursive - + - name: Setup Go environment uses: actions/setup-go@v3 with: - go-version: 1.18.x + go-version: 1.20.x - name: Build Polygon Edge run: go build -tags netgo -ldflags="-s -w -linkmode external -extldflags "-static" -X \"github.com/0xPolygon/polygon-edge/versioning.Version=${GITHUB_REF_NAME}\" -X \"github.com/0xPolygon/polygon-edge/versioning.Commit=${GITHUB_SHA}\"" && tar -czvf polygon-edge.tar.gz polygon-edge @@ -27,6 +32,11 @@ jobs: GOARC: amd64 GOOS: linux + - name: Build Polygon Edge Failed + if: failure() + id: edge_build_failure + run: echo "build_output=false" >> $GITHUB_OUTPUT + - name: 'Upload Artifact' uses: actions/upload-artifact@v3 with: @@ -41,10 +51,11 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v3 + - name: Setup Go environment uses: actions/setup-go@v3 with: - go-version: 1.18.x + go-version: 1.20.x - name: 'Reproduce builds' continue-on-error: true diff --git a/.github/workflows/deploy.devnet.eph.yml b/.github/workflows/deploy.devnet.eph.yml index a218d072e7..6c42348402 100644 --- a/.github/workflows/deploy.devnet.eph.yml +++ b/.github/workflows/deploy.devnet.eph.yml @@ -24,55 +24,6 @@ jobs: name: Build uses: ./.github/workflows/build.yml - test: - name: Test - uses: ./.github/workflows/test.yml - needs: build - secrets: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} - - container_image_build: - name: Build/Push Container Image - runs-on: ubuntu-latest - environment: devnet-ephemeral - needs: build - steps: - - name: Checkout repo - uses: actions/checkout@v3 - - - name: Download Polygon Edge Artifact - uses: actions/download-artifact@v3 - with: - name: polygon-edge - - run: tar -xvzf polygon-edge.tar.gz - - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v1-node16 - with: - role-to-assume: ${{ secrets.AWS_ROLE_ARN }} - aws-region: ${{ secrets.AWS_REGION }} - - - name: Login to Amazon ECR - id: login-ecr - uses: aws-actions/amazon-ecr-login@v1 - - - name: Build, tag, and push docker image to Amazon ECR - env: - REGISTRY: ${{ steps.login-ecr.outputs.registry }} - REPOSITORY: library/polygon-edge - IMAGE_TAG: ${{ github.sha }} - run: | - docker build -t $REGISTRY/$REPOSITORY:devnet-ephemeral -t $REGISTRY/$REPOSITORY:$IMAGE_TAG -f Dockerfile.release . - docker push $REGISTRY/$REPOSITORY:$IMAGE_TAG - docker push $REGISTRY/$REPOSITORY:devnet-ephemeral - deploy_eph_devnet: name: Deploy Ephemeral DevNet needs: build diff --git a/.github/workflows/deploy.devnet.yml b/.github/workflows/deploy.devnet.yml index b2ed712b92..22ca89706b 100644 --- a/.github/workflows/deploy.devnet.yml +++ b/.github/workflows/deploy.devnet.yml @@ -24,55 +24,6 @@ jobs: name: Build uses: ./.github/workflows/build.yml - test: - name: Test - uses: ./.github/workflows/test.yml - needs: build - secrets: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} - - container_image_build: - name: Build/Push Container Image - runs-on: ubuntu-latest - environment: devnet - needs: build - steps: - - name: Checkout repo - uses: actions/checkout@v3 - - - name: Download Polygon Edge Artifact - uses: actions/download-artifact@v3 - with: - name: polygon-edge - - run: tar -xvzf polygon-edge.tar.gz - - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v1-node16 - with: - role-to-assume: ${{ secrets.AWS_ROLE_ARN }} - aws-region: ${{ secrets.AWS_REGION }} - - - name: Login to Amazon ECR - id: login-ecr - uses: aws-actions/amazon-ecr-login@v1 - - - name: Build, tag, and push docker image to Amazon ECR - env: - REGISTRY: ${{ steps.login-ecr.outputs.registry }} - REPOSITORY: library/polygon-edge - IMAGE_TAG: ${{ github.sha }} - run: | - docker build -t $REGISTRY/$REPOSITORY:devnet -t $REGISTRY/$REPOSITORY:$IMAGE_TAG -f Dockerfile.release . - docker push $REGISTRY/$REPOSITORY:$IMAGE_TAG - docker push $REGISTRY/$REPOSITORY:devnet - deploy_devnet: name: Deploy DevNet needs: build diff --git a/.github/workflows/deploy.nightly.devnet.yml b/.github/workflows/deploy.nightly.devnet.yml new file mode 100644 index 0000000000..18faf0b469 --- /dev/null +++ b/.github/workflows/deploy.nightly.devnet.yml @@ -0,0 +1,278 @@ +--- + +name: Build Devnet +on: # yamllint disable-line rule:truthy + workflow_dispatch: + inputs: + environment: + description: The environment to run against + required: false + type: environment + workflow_call: + inputs: + environment: + description: The environment to run against + type: string + required: true + outputs: + workflow_output_loadtest1: + description: "Loadtest output" + value: ${{ jobs.loadtest1.outputs.loadtest_output_failure }} + workflow_output_loadtest2: + description: "Loadtest output" + value: ${{ jobs.loadtest2.outputs.loadtest_output_failure }} + secrets: + AWS_ROLE_ARN: + required: true + AWS_REGION: + required: true + TF_VAR_DEPLOYMENT_NAME: + required: true + TF_VAR_OWNER: + required: true + SLACK_PERFORMANCE_WEBHOOK_URL: + required: true + DD_API_KEY: + required: true + LOADTEST_MNEMONIC: + required: true + VAULT_PASSWORD_FILE: + required: true + +jobs: + build: + runs-on: ubuntu-latest + environment: ${{ inputs.environment }} + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + repository: maticnetwork/terraform-polygon-supernets + ref: main + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ secrets.AWS_ROLE_ARN }} + aws-region: ${{ secrets.AWS_REGION }} + - name: Install Terraform + uses: hashicorp/setup-terraform@v2.0.3 + with: + terraform_version: 1.4.5 + - name: Configure terraform for nightly build + run: | + sed 's/# backend "s3" {}/backend "s3" {}/' main.tf > main.tf.tmp && mv main.tf.tmp main.tf + - name: Terraform Init + id: init + run: terraform init -backend-config="bucket=polygon-edge-devnet-tf-states" -backend-config="key=state/${{ secrets.TF_VAR_DEPLOYMENT_NAME }}" -backend-config="region=${{ secrets.AWS_REGION }}" + - name: Terraform Validate + id: validate + run: terraform validate -no-color + continue-on-error: true + - name: Terraform Plan + id: plan + run: terraform plan -out=tfplan -no-color + env: + TF_VAR_deployment_name: ${{ secrets.TF_VAR_DEPLOYMENT_NAME }} + TF_VAR_owner: ${{ secrets.TF_VAR_OWNER }} + - name: Terraform Apply + id: apply + run: terraform apply -auto-approve tfplan + env: + TF_VAR_deployment_name: ${{ secrets.TF_VAR_DEPLOYMENT_NAME }} + TF_VAR_owner: ${{ secrets.TF_VAR_OWNER }} + - name: Retrieve state file from s3 + run: aws s3 cp s3://polygon-edge-devnet-tf-states/state/${{ secrets.TF_VAR_DEPLOYMENT_NAME }} state.json + - name: Configure private keys + run: | + terraform output pk_ansible > ~/devnet_private.key + chmod 600 ~/devnet_private.key + eval "$(ssh-agent)" + ssh-add ~/devnet_private.key + - name: Install ansible / botocore / boto3 + run: | + python3 -m pip install --user ansible + python3 -m pip install boto3 botocore + - name: Configure ansible for nightly build + working-directory: ansible + run: | + echo "${{ secrets.VAULT_PASSWORD_FILE }}" > password.txt + sed 's/devnet13/${{ secrets.TF_VAR_DEPLOYMENT_NAME }}/g' inventory/aws_ec2.yml > inventory/aws_ec2.yml.tmp && mv inventory/aws_ec2.yml.tmp inventory/aws_ec2.yml + sed 's/devnet13/${{ secrets.TF_VAR_DEPLOYMENT_NAME }}/g' local-extra-vars.yml > local-extra-vars.yml.tmp && mv local-extra-vars.yml.tmp local-extra-vars.yml + sed 's/edge_tag: .*/edge_tag: HEAD/g' local-extra-vars.yml > local-extra-vars.yml.tmp && mv local-extra-vars.yml.tmp local-extra-vars.yml + - name: Create script file + working-directory: ansible + run: | + cat > roles/edge/templates/bootstrap.sh <<'EOF' + #!/bin/bash -x + + main() { + mkdir /var/lib/bootstrap + pushd /var/lib/bootstrap + + {% for item in hostvars %} + {% if (hostvars[item].tags.Role == "fullnode" or hostvars[item].tags.Role == "validator") %} + polygon-edge polybft-secrets --data-dir {{ hostvars[item].tags["Name"] }} --json --insecure > {{ hostvars[item].tags["Name"] }}.json + {% endif %} + {% endfor %} + + BURN_CONTRACT_ADDRESS=0x0000000000000000000000000000000000000000 + + polygon-edge genesis \ + --consensus polybft \ + {% for item in hostvars %}{% if (hostvars[item].tags.Role == "fullnode" or hostvars[item].tags.Role == "validator") %} --bootnode /dns4/{{ hostvars[item].tags["Name"] }}/tcp/{{ edge_p2p_port }}/p2p/$(cat {{ hostvars[item].tags["Name"] }}.json | jq -r '.[0].node_id') {% endif %}{% endfor %} \ + {% for item in hostvars %}{% if (hostvars[item].tags.Role == "fullnode" or hostvars[item].tags.Role == "validator") %} --premine $(cat {{ hostvars[item].tags["Name"] }}.json | jq -r '.[0].address'):1000000000000000000000000 {% endif %}{% endfor %} \ + --premine {{ loadtest_account }}:1000000000000000000000000000 \ + --premine $BURN_CONTRACT_ADDRESS \ + --reward-wallet 0x0101010101010101010101010101010101010101:1000000000000000000000000000 \ + --premine 0xA39Fed214820cF843E2Bcd6cA1759257a530894B:1000000000000000000000000000 \ + --premine 0x181d9fEc79EC674DD3cB30dd9dd4188E737939FE:1000000000000000000000000000 \ + --premine 0x1AB8C3df809b85012a009c0264eb92dB04eD6EFa:1000000000000000000000000000 \ + --block-gas-limit {{ block_gas_limit }} \ + --block-time {{ block_time }}s \ + {% for item in hostvars %}{% if (hostvars[item].tags.Role == "validator") %} --validators /dns4/{{ hostvars[item].tags["Name"] }}/tcp/{{ edge_p2p_port }}/p2p/$(cat {{ hostvars[item].tags["Name"] }}.json | jq -r '.[0].node_id'):$(cat {{ hostvars[item].tags["Name"] }}.json | jq -r '.[0].address' | sed 's/^0x//'):$(cat {{ hostvars[item].tags["Name"] }}.json | jq -r '.[0].bls_pubkey') {% endif %}{% endfor %} \ + --epoch-size 10 \ + --native-token-config MyToken:MTK:18:true:0x0000000000000000000000000000000000001010 + + polygon-edge polybft stake-manager-deploy \ + --jsonrpc {{ rootchain_json_rpc }} \ + --test + + polygon-edge rootchain deploy \ + --stake-manager $(cat genesis.json | jq -r '.params.engine.polybft.bridge.stakeManagerAddr') \ + --stake-token $(cat genesis.json | jq -r '.params.engine.polybft.bridge.stakeTokenAddr') \ + --json-rpc {{ rootchain_json_rpc }} \ + --test + + polygon-edge rootchain fund \ + --stake-token $(cat genesis.json | jq -r '.params.engine.polybft.bridge.stakeTokenAddr') \ + --mint \ + --addresses $(cat validator-*.json | jq -r ".[].address" | paste -sd "," - | tr -d '\n') \ + --amounts $(for f in validator-*.json; do echo -n "1000000000000000000000000,"; done | sed 's/,$//') \ + --json-rpc {{ rootchain_json_rpc }} + + polygon-edge polybft whitelist-validators \ + --private-key aa75e9a7d427efc732f8e4f1a5b7646adcc61fd5bae40f80d13c8419c9f43d6d \ + --addresses $(cat validator-*.json | jq -r ".[].address" | paste -sd "," - | tr -d '\n') \ + --supernet-manager $(cat genesis.json | jq -r '.params.engine.polybft.bridge.customSupernetManagerAddr') \ + --jsonrpc {{ rootchain_json_rpc }} + + counter=1 + {% for item in hostvars %} + {% if (hostvars[item].tags.Role == "validator") %} + echo "Registering validator: ${counter}" + + polygon-edge polybft register-validator \ + --data-dir {{ hostvars[item].tags["Name"] }} \ + --supernet-manager $(cat genesis.json | jq -r '.params.engine.polybft.bridge.customSupernetManagerAddr') \ + --jsonrpc {{ rootchain_json_rpc }} + + polygon-edge polybft stake \ + --data-dir {{ hostvars[item].tags["Name"] }} \ + --amount 1000000000000000000000000 \ + --supernet-id $(cat genesis.json | jq -r '.params.engine.polybft.supernetID') \ + --stake-manager $(cat genesis.json | jq -r '.params.engine.polybft.bridge.stakeManagerAddr') \ + --stake-token $(cat genesis.json | jq -r '.params.engine.polybft.bridge.stakeTokenAddr') \ + --jsonrpc {{ rootchain_json_rpc }} + + ((counter++)) + {% endif %} + {% endfor %} + + {% for item in hostvars %} + {% if (hostvars[item].tags.Role == "validator") %} + {% endif %} + {% endfor %} + + polygon-edge polybft supernet \ + --private-key aa75e9a7d427efc732f8e4f1a5b7646adcc61fd5bae40f80d13c8419c9f43d6d \ + --supernet-manager $(cat genesis.json | jq -r '.params.engine.polybft.bridge.customSupernetManagerAddr') \ + --stake-manager $(cat genesis.json | jq -r '.params.engine.polybft.bridge.stakeManagerAddr') \ + --finalize-genesis-set \ + --enable-staking \ + --jsonrpc {{ rootchain_json_rpc }} + + tar czf {{ base_dn }}.tar.gz *.json *.private + popd + } + + main + + EOF + - name: Run Ansible + working-directory: ansible + run: | + ansible-inventory --graph + ansible-galaxy install -r requirements.yml + ansible-playbook --inventory inventory/aws_ec2.yml --vault-password-file=password.txt --extra-vars "@local-extra-vars.yml" site.yml + - name: Set rpc url value + id: url + run: | + terraform output -raw aws_lb_ext_domain | grep -o -E '^ext[^:]*' > rpc_url.txt + - uses: actions/upload-artifact@v3 + with: + name: rpc_url + path: rpc_url.txt + + loadtest1: + needs: build + uses: ./.github/workflows/loadtest.yml + name: Load Test Nightly Build - multiple_EOA + secrets: + SLACK_PERFORMANCE_WEBHOOK_URL: ${{ secrets.SLACK_PERFORMANCE_WEBHOOK_URL }} + LOADTEST_RPC_URL: "" # this is a workaround because of actions bug in passing output to another job + DD_API_KEY: ${{ secrets.DD_API_KEY }} + LOADTEST_MNEMONIC: ${{ secrets.LOADTEST_MNEMONIC }} + with: + runner: devnet + environment: ${{ inputs.environment }} + scenario: multiple_EOA + + loadtest2: + needs: loadtest1 + uses: ./.github/workflows/loadtest.yml + name: Load Test Nightly Build - multiple_ERC20 + secrets: + SLACK_PERFORMANCE_WEBHOOK_URL: ${{ secrets.SLACK_PERFORMANCE_WEBHOOK_URL }} + LOADTEST_RPC_URL: "" # this is a workaround because of actions bug in passing output to another job + DD_API_KEY: ${{ secrets.DD_API_KEY }} + LOADTEST_MNEMONIC: ${{ secrets.LOADTEST_MNEMONIC }} + with: + runner: devnet + environment: ${{ inputs.environment }} + scenario: multiple_ERC20 + + destroy_devnet: + needs: [loadtest1, loadtest2] + if: always() + name: Destroy Nightly Build + runs-on: ubuntu-latest + environment: ${{ inputs.environment }} + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + repository: maticnetwork/terraform-polygon-supernets + ref: main + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ secrets.AWS_ROLE_ARN }} + aws-region: ${{ secrets.AWS_REGION }} + - name: Install Terraform + uses: hashicorp/setup-terraform@v2.0.3 + with: + terraform_version: 1.4.5 + - name: Configure terraform for nightly build + run: | + sed 's/# backend "s3" {}/backend "s3" {}/' main.tf > main.tf.tmp && mv main.tf.tmp main.tf + - name: Terraform Init + id: init + run: terraform init -backend-config="bucket=polygon-edge-devnet-tf-states" -backend-config="key=state/${{ secrets.TF_VAR_DEPLOYMENT_NAME }}" -backend-config="region=${{ secrets.AWS_REGION }}" + - name: Retrieve state file from s3 + run: aws s3 cp s3://polygon-edge-devnet-tf-states/state/${{ secrets.TF_VAR_DEPLOYMENT_NAME }} state.json + - name: Terraform Destroy + id: destroy + run: terraform destroy -auto-approve -state=state.json + env: + TF_VAR_deployment_name: ${{ secrets.TF_VAR_DEPLOYMENT_NAME }} + TF_VAR_owner: ${{ secrets.TF_VAR_OWNER }} \ No newline at end of file diff --git a/.github/workflows/deploy.testnet.yml b/.github/workflows/deploy.testnet.yml index 09b31b715b..745776d196 100644 --- a/.github/workflows/deploy.testnet.yml +++ b/.github/workflows/deploy.testnet.yml @@ -23,55 +23,6 @@ jobs: uses: ./.github/workflows/build.yml name: Build - test: - uses: ./.github/workflows/test.yml - name: Test - needs: build - secrets: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} - - container_image_build: - name: Build/Push Container Image - runs-on: ubuntu-latest - environment: testnet - needs: build - steps: - - name: Checkout repo - uses: actions/checkout@v3 - - - name: Download Polygon Edge Artifact - uses: actions/download-artifact@v3 - with: - name: polygon-edge - - run: tar -xvzf polygon-edge.tar.gz - - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v1-node16 - with: - role-to-assume: ${{ secrets.AWS_ROLE_ARN }} - aws-region: ${{ secrets.AWS_REGION }} - - - name: Login to Amazon ECR - id: login-ecr - uses: aws-actions/amazon-ecr-login@v1 - - - name: Build, tag, and push docker image to Amazon ECR - env: - REGISTRY: ${{ steps.login-ecr.outputs.registry }} - REPOSITORY: library/polygon-edge - IMAGE_TAG: ${{ github.sha }} - run: | - docker build -t $REGISTRY/$REPOSITORY:testnet -t $REGISTRY/$REPOSITORY:$IMAGE_TAG -f Dockerfile.release . - docker push $REGISTRY/$REPOSITORY:$IMAGE_TAG - docker push $REGISTRY/$REPOSITORY:testnet - deploy_testnet: name: Update TestNet needs: build diff --git a/.github/workflows/e2e-polybft.yml b/.github/workflows/e2e-polybft.yml index e1e7b1c41b..85e51b261d 100644 --- a/.github/workflows/e2e-polybft.yml +++ b/.github/workflows/e2e-polybft.yml @@ -6,7 +6,12 @@ on: # yamllint disable-line rule:truthy - main - develop pull_request: + workflow_dispatch: workflow_call: + outputs: + workflow_output: + description: "E2E output" + value: ${{ jobs.build.outputs.e2e_output_failure }} jobs: build: @@ -14,16 +19,26 @@ jobs: env: E2E_TESTS: true E2E_LOGS: true - E2E_TESTS_TYPE: 'integration' CI_VERBOSE: true + outputs: + e2e_output_failure: ${{ steps.run_e2e_failure.outputs.test_output }} steps: - - uses: actions/checkout@v3 + - name: Checkout code + uses: actions/checkout@v3 + - name: Install Go uses: actions/setup-go@v3 with: - go-version: 1.18.x + go-version: 1.20.x + - name: Run tests run: make test-e2e-polybft + + - name: Run tests failed + if: failure() + id: run_e2e_failure + run: echo "test_output=false" >> $GITHUB_OUTPUT + - name: Archive test logs if: always() uses: actions/upload-artifact@v3 diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index e9b28f9401..d1db2650e8 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -1,11 +1,12 @@ --- name: E2E tests on: # yamllint disable-line rule:truthy - push: - branches: - - main - - develop - pull_request: + workflow_dispatch: + workflow_call: + outputs: + workflow_output: + description: "E2E IBFT output" + value: ${{ jobs.build.outputs.e2eibft_output_failure }} jobs: build: @@ -14,16 +15,27 @@ jobs: E2E_TESTS: true E2E_LOGS: true CI_VERBOSE: true + outputs: + e2eibft_output_failure: ${{ steps.run_e2eibft_failure.outputs.test_output }} steps: - - uses: actions/checkout@v3 + - name: Checkout code + uses: actions/checkout@v3 with: submodules: recursive + - name: Install Go uses: actions/setup-go@v3 with: - go-version: 1.18.x + go-version: 1.20.x + - name: Run tests run: make test-e2e + + - name: Run tests failed + if: failure() + id: run_e2eibft_failure + run: echo "test_output=false" >> $GITHUB_OUTPUT + - name: Archive test logs if: always() uses: actions/upload-artifact@v3 diff --git a/.github/workflows/fuzz-test.yml b/.github/workflows/fuzz-test.yml new file mode 100644 index 0000000000..d7fabfaa70 --- /dev/null +++ b/.github/workflows/fuzz-test.yml @@ -0,0 +1,38 @@ +--- +name: Fuzz tests +on: # yamllint disable-line rule:truthy + push: + branches: + - main + - develop + workflow_dispatch: + workflow_call: + outputs: + workflow_output: + description: "Fuzz output" + value: ${{ jobs.build.outputs.fuzz_output_failure }} + + +jobs: + fuzz_test: + name: Polygon Edge + runs-on: ubuntu-latest + outputs: + fuzz_output_failure: ${{ steps.run_fuzz_failure.outputs.test_output }} + steps: + - name: Setup Go + uses: actions/setup-go@v3 + with: + go-version: 1.20.x + + - name: Checkout Code + uses: actions/checkout@v3 + + - name: Run Fuzz Test + run: make fuzz-test + + - name: Run fuzz tests failed + if: failure() + id: run_fuzz_failure + run: echo "test_output=false" >> $GITHUB_OUTPUT + diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 9a1c351f25..292c1c19ec 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -2,13 +2,18 @@ name: Lint on: # yamllint disable-line rule:truthy push: - branches-ignore: - - 'develop' - - 'release/**' + branches: + - '*' tags-ignore: - 'v*' paths: - '**.go' + pull_request: + types: + - opened + - synchronize + - reopened + workflow_call: {} workflow_dispatch: {} @@ -19,10 +24,12 @@ jobs: - name: Install Go uses: actions/setup-go@v3 with: - go-version: 1.18.x + go-version: 1.20.x - name: Checkout code uses: actions/checkout@v3 - name: Lint uses: golangci/golangci-lint-action@v3 + with: + args: --timeout 10m --verbose diff --git a/.github/workflows/loadtest.yml b/.github/workflows/loadtest.yml index ff42c72bd2..281b8a62bc 100644 --- a/.github/workflows/loadtest.yml +++ b/.github/workflows/loadtest.yml @@ -1,147 +1,170 @@ --- - name: Load Test - on: # yamllint disable-line rule:truthy - workflow_dispatch: - inputs: - runner: - description: The runner to execute on - default: 'ubuntu-latest' - type: choice - options: - - ubuntu-latest - - devnet - - testnet - environment: - description: The environment to run against - required: false - type: environment - scenario: - default: 'simple' - description: The scenario to run - type: string - duration: - default: '2m' - description: Duration of the test - required: false - type: string - workflow_call: - inputs: - environment: - description: The environment to run against - type: string - required: true - runner: - required: true - type: string - description: The runner label to use - scenario: - required: true - description: The mode for the stress test - type: string - duration: - default: '2m' - description: Duration of the test - required: false - type: string - secrets: - SLACK_PERFORMANCE_WEBHOOK_URL: - required: true - DD_API_KEY: - required: true - LOADTEST_RPC_URL: - required: true - LOADTEST_MNEMONIC: - required: true +name: Load Test +on: # yamllint disable-line rule:truthy + workflow_dispatch: + inputs: + runner: + description: The runner to execute on + default: 'ubuntu-latest' + type: choice + options: + - ubuntu-latest + - devnet + - testnet + environment: + description: The environment to run against + required: false + type: environment + scenario: + default: 'simple' + description: The scenario to run + type: string + duration: + default: '2m' + description: Duration of the test + required: false + type: string + workflow_call: + inputs: + environment: + description: The environment to run against + type: string + required: true + runner: + required: true + type: string + description: The runner label to use + scenario: + required: true + description: The mode for the stress test + type: string + duration: + default: '2m' + description: Duration of the test + required: false + type: string + secrets: + SLACK_PERFORMANCE_WEBHOOK_URL: + required: true + DD_API_KEY: + required: true + LOADTEST_RPC_URL: + required: true + LOADTEST_MNEMONIC: + required: true - - jobs: - run_k6: - environment: ${{ inputs.environment }} - runs-on: ubuntu-latest - steps: - - name: Install Go - uses: actions/setup-go@v3 - with: - go-version: 1.18.x - - - name: Checkout code - uses: actions/checkout@v3 - - - uses: datadog/agent-github-action@v1.3 - with: - api_key: ${{ secrets.DD_API_KEY }} - - - name: Install xk6 - run: | - go install go.k6.io/xk6/cmd/xk6@latest - xk6 build --with github.com/distribworks/xk6-ethereum@5c6e782669953f1e5d1f44509e610fb2e3d22238 - - - name: Install JQ - run: | - mkdir -p $HOME/.local/bin - curl -sLo $HOME/.local/bin/jq https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64 && chmod +x $HOME/.local/bin/jq - echo "$HOME/.local/bin" >> $GITHUB_PATH +jobs: + run_k6: + environment: ${{ inputs.environment }} + runs-on: ubuntu-latest + outputs: + loadtest_output_failure: ${{ steps.run_k6_failure.outputs.test_output }} + steps: + - name: Install Go + uses: actions/setup-go@v3 + with: + go-version: 1.20.x - - id: k6 - name: Run scenario - run: | - ./k6 run --out statsd loadtest/scenarios/${{ inputs.scenario }}.js - echo "tps_avg=$(cat summary.json | jq -r '.metrics.ethereum_tps.values.avg')" >> $GITHUB_OUTPUT - echo "tps_max=$(cat summary.json | jq -r '.metrics.ethereum_tps.values.max')" >> $GITHUB_OUTPUT - echo "iterations=$(cat summary.json | jq -r '.metrics.iterations.values.count')" >> $GITHUB_OUTPUT - echo "block=$(cat summary.json | jq -r '.metrics.ethereum_block.values.count')" >> $GITHUB_OUTPUT - echo "ttm=$(cat summary.json | jq -r '.metrics.ethereum_time_to_mine.values.avg')" >> $GITHUB_OUTPUT - echo "gas_avg=$(cat summary.json | jq -r '.metrics.ethereum_gas_used.values.avg')" >> $GITHUB_OUTPUT - echo "gas_max=$(cat summary.json | jq -r '.metrics.ethereum_gas_used.values.max')" >> $GITHUB_OUTPUT - env: - K6_STATSD_ENABLE_TAGS: true - RPC_URL: ${{ secrets.LOADTEST_RPC_URL }} - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_PERFORMANCE_WEBHOOK_URL }} - LOADTEST_MNEMONIC: ${{ secrets.LOADTEST_MNEMONIC }} - LOADTEST_DURATION: ${{ inputs.duration }} - - - name: Notify Slack - uses: slackapi/slack-github-action@v1.23.0 - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_PERFORMANCE_WEBHOOK_URL }} - SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK - with: - payload: | - { - "blocks": [ - { - "type": "header", - "text": { - "type": "plain_text", - "text": "K6 Loadtest Results" - } - }, - { - "type": "section", - "text": { - "type": "mrkdwn", - "text": "*Scenario*: `${{ inputs.scenario }}`\n *Average TPS*: `${{ steps.k6.outputs.tps_avg }}`\n*Max TPS*: `${{ steps.k6.outputs.tps_max }}`\n*Transactions*: `${{ steps.k6.outputs.iterations }}`\n*Block Number*: `${{ steps.k6.outputs.block }}`\n*Time to Mine*: `${{ steps.k6.outputs.ttm }}`\n*Average Gas Used*: `${{ steps.k6.outputs.gas_avg }}`\n*Max Gas Used*: `${{ steps.k6.outputs.gas_max }}`" - } - }, - { - "type": "divider" - }, - { - "type": "context", - "elements": [ - { - "type": "mrkdwn", - "text": "Environment: `${{ inputs.environment }}`" - }, - { - "type": "mrkdwn", - "text": "JSON-RPC Endpoint: ${{ secrets.LOADTEST_RPC_URL }}" - }, - { - "type": "mrkdwn", - "text": "Workflow: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Results>" - } - ] - } - ] - } + - name: Checkout code + uses: actions/checkout@v3 + + - uses: datadog/agent-github-action@v1.3 + with: + api_key: ${{ secrets.DD_API_KEY }} + + - name: Install xk6 + run: | + go install go.k6.io/xk6/cmd/xk6@latest + xk6 build --with github.com/distribworks/xk6-ethereum@5c6e782669953f1e5d1f44509e610fb2e3d22238 + + - name: Install JQ + run: | + mkdir -p $HOME/.local/bin + curl -sLo $HOME/.local/bin/jq https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64 && chmod +x $HOME/.local/bin/jq + echo "$HOME/.local/bin" >> $GITHUB_PATH + + - name: Download artifact to get rpc url + env: + url: ${{ secrets.LOADTEST_RPC_URL }} + if: ${{ env.url == '' }} + uses: actions/download-artifact@v3 + with: + name: rpc_url + + - name: Set rpc_url + id: set_rpc_url + run: | + if [[ -z "${{ secrets.LOADTEST_RPC_URL }}" ]]; then + echo "rpc_url=http://$(cat rpc_url.txt)" >> $GITHUB_OUTPUT + else + echo "rpc_url=${{ secrets.LOADTEST_RPC_URL }}" >> $GITHUB_OUTPUT + fi + + - id: k6 + name: Run scenario + run: | + ./k6 run --out statsd loadtest/scenarios/${{ inputs.scenario }}.js + echo "tps_avg=$(cat summary.json | jq -r '.metrics.ethereum_tps.values.avg')" >> $GITHUB_OUTPUT + echo "tps_max=$(cat summary.json | jq -r '.metrics.ethereum_tps.values.max')" >> $GITHUB_OUTPUT + echo "iterations=$(cat summary.json | jq -r '.metrics.iterations.values.count')" >> $GITHUB_OUTPUT + echo "block=$(cat summary.json | jq -r '.metrics.ethereum_block.values.count')" >> $GITHUB_OUTPUT + echo "ttm=$(cat summary.json | jq -r '.metrics.ethereum_time_to_mine.values.avg')" >> $GITHUB_OUTPUT + echo "gas_avg=$(cat summary.json | jq -r '.metrics.ethereum_gas_used.values.avg')" >> $GITHUB_OUTPUT + echo "gas_max=$(cat summary.json | jq -r '.metrics.ethereum_gas_used.values.max')" >> $GITHUB_OUTPUT + env: + K6_STATSD_ENABLE_TAGS: true + RPC_URL: ${{ steps.set_rpc_url.outputs.rpc_url }} + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_PERFORMANCE_WEBHOOK_URL }} + LOADTEST_MNEMONIC: ${{ secrets.LOADTEST_MNEMONIC }} + LOADTEST_DURATION: ${{ inputs.duration }} + + - name: Run tests failed + if: failure() + id: run_k6_failure + run: echo "test_output=false" >> $GITHUB_OUTPUT + + - name: Notify Slack + uses: slackapi/slack-github-action@v1.23.0 + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_PERFORMANCE_WEBHOOK_URL }} + SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK + with: + payload: | + { + "blocks": [ + { + "type": "header", + "text": { + "type": "plain_text", + "text": "K6 Loadtest Results" + } + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "*Scenario*: `${{ inputs.scenario }}`\n *Average TPS*: `${{ steps.k6.outputs.tps_avg }}`\n*Max TPS*: `${{ steps.k6.outputs.tps_max }}`\n*Transactions*: `${{ steps.k6.outputs.iterations }}`\n*Block Number*: `${{ steps.k6.outputs.block }}`\n*Time to Mine*: `${{ steps.k6.outputs.ttm }}`\n*Average Gas Used*: `${{ steps.k6.outputs.gas_avg }}`\n*Max Gas Used*: `${{ steps.k6.outputs.gas_max }}`" + } + }, + { + "type": "divider" + }, + { + "type": "context", + "elements": [ + { + "type": "mrkdwn", + "text": "Environment: `${{ inputs.environment }}`" + }, + { + "type": "mrkdwn", + "text": "JSON-RPC Endpoint: ${{ steps.set_rpc_url.outputs.rpc_url }}" + }, + { + "type": "mrkdwn", + "text": "Workflow: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Results>" + } + ] + } + ] + } diff --git a/.github/workflows/manual.deploy.nightly.devnet.yml b/.github/workflows/manual.deploy.nightly.devnet.yml new file mode 100644 index 0000000000..22dd7d9a71 --- /dev/null +++ b/.github/workflows/manual.deploy.nightly.devnet.yml @@ -0,0 +1,31 @@ +--- +### This manually triggers the edge nightly build loadtest when pushed to jesse/nightly-loadtest-workflow + +name: Nightly DevNet Workflow (Manual) +on: # yamllint disable-line rule:truthy + push: + branches: + - jesse/fix-* + workflow_call: {} + workflow_dispatch: {} + +permissions: + id-token: write + contents: read + security-events: write + +jobs: + devnet: + name: Build Devnet + uses: ./.github/workflows/deploy.nightly.devnet.yml + secrets: + AWS_REGION: ${{ secrets.AWS_REGION }} + AWS_ROLE_ARN: ${{ secrets.AWS_ROLE_ARN }} + TF_VAR_DEPLOYMENT_NAME: ${{ secrets.TF_VAR_DEPLOYMENT_NAME }} + TF_VAR_OWNER: ${{ secrets.TF_VAR_OWNER }} + SLACK_PERFORMANCE_WEBHOOK_URL: ${{ secrets.SLACK_PERFORMANCE_WEBHOOK_URL }} + DD_API_KEY: ${{ secrets.DD_API_KEY }} + LOADTEST_MNEMONIC: ${{ secrets.LOADTEST_MNEMONIC }} + VAULT_PASSWORD_FILE: ${{ secrets.VAULT_PASSWORD_FILE }} + with: + environment: devnet diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 6932902913..7117dc25cf 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -1,10 +1,16 @@ --- name: Nightly Build -on: # yamllint disable-line rule:truthy +on: #yamllint disable-line rule:truthy + workflow_dispatch: schedule: # * is a special character in YAML so you have to quote this string - cron: '0 0 * * *' +permissions: + id-token: write + contents: read + security-events: write + jobs: build: name: Build @@ -19,12 +25,134 @@ jobs: SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} e2e: - name: Polybft E2E Tests + name: PolyBFT E2E Tests uses: ./.github/workflows/e2e-polybft.yml needs: build + e2eibft: + name: IBFT E2E Tests + uses: ./.github/workflows/e2e.yaml + needs: build + property: name: Polybft Property Tests uses: ./.github/workflows/property-polybft.yml needs: build - \ No newline at end of file + + fuzz: + name: Fuzz Tests + uses: ./.github/workflows/fuzz-test.yml + needs: build + + loadtest: + name: Build Devnet + uses: ./.github/workflows/deploy.nightly.devnet.yml + secrets: + AWS_REGION: ${{ secrets.AWS_REGION }} + AWS_ROLE_ARN: ${{ secrets.AWS_ROLE_ARN }} + TF_VAR_DEPLOYMENT_NAME: ${{ secrets.TF_VAR_DEPLOYMENT_NAME }} + TF_VAR_OWNER: ${{ secrets.TF_VAR_OWNER }} + SLACK_PERFORMANCE_WEBHOOK_URL: ${{ secrets.SLACK_PERFORMANCE_WEBHOOK_URL }} + DD_API_KEY: ${{ secrets.DD_API_KEY }} + LOADTEST_MNEMONIC: ${{ secrets.LOADTEST_MNEMONIC }} + VAULT_PASSWORD_FILE: ${{ secrets.VAULT_PASSWORD_FILE }} + with: + environment: devnet + + notification: + name: Nightly Notifications + runs-on: ubuntu-latest + needs: [build, test, e2e, e2eibft, property, fuzz, loadtest] + if: success() || failure() + steps: + - name: Notify Slack + uses: slackapi/slack-github-action@v1.23.0 + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_EDGE_GITHUB_URL }} + SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK + with: + payload: | + { + "blocks": [ + { + "type": "header", + "text": { + "type": "plain_text", + "text": "Nightly Build" + } + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "*Status* ${{ needs.build.outputs.workflow_output == '' && needs.test.outputs.workflow_output == '' && needs.property.outputs.workflow_output == '' && needs.e2e.outputs.workflow_output == '' && ':white_check_mark:' || ':x: `failed`' }}" + } + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "Build ${{ needs.build.outputs.workflow_output == '' && ':white_check_mark:' || ':x: `failed`' }}" + } + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "Unit tests ${{ needs.test.outputs.workflow_output == '' && ':white_check_mark:' || ':x: `failed`' }}" + } + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "Property tests ${{ needs.property.outputs.workflow_output == '' && ':white_check_mark:' || ':x: `failed`' }}" + } + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "E2E tests ${{ needs.e2e.outputs.workflow_output == '' && ':white_check_mark:' || ':x: `failed`' }}" + } + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "E2E IBFT tests ${{ needs.e2eibft.outputs.workflow_output == '' && ':white_check_mark:' || ':x: `failed`' }}" + } + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "Fuzz tests ${{ needs.fuzz.outputs.workflow_output == '' && ':white_check_mark:' || ':x: `failed`' }}" + } + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "Load tests (multiple_EOA) ${{ needs.loadtest.outputs.workflow_output_loadtest1 == '' && ':white_check_mark:' || ':x: `failed`' }}" + } + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "Load tests (multiple_ERC20) ${{ needs.loadtest.outputs.workflow_output_loadtest2 == '' && ':white_check_mark:' || ':x: `failed`' }}" + } + }, + { + "type": "divider" + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "Workflow: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Results>" + } + } + ] + } diff --git a/.github/workflows/property-polybft.yml b/.github/workflows/property-polybft.yml index 9c9e915829..fbb3706793 100644 --- a/.github/workflows/property-polybft.yml +++ b/.github/workflows/property-polybft.yml @@ -5,7 +5,12 @@ on: # yamllint disable-line rule:truthy branches: - main - develop + workflow_dispatch: workflow_call: + outputs: + workflow_output: + description: "Property output" + value: ${{ jobs.build.outputs.property_output_failure }} jobs: build: @@ -13,16 +18,26 @@ jobs: env: E2E_TESTS: true E2E_LOGS: true - E2E_TESTS_TYPE: 'property' CI_VERBOSE: true + outputs: + property_output_failure: ${{ steps.run_property_failure.outputs.test_output }} steps: - - uses: actions/checkout@v3 + - name: Checkout code + uses: actions/checkout@v3 + - name: Install Go uses: actions/setup-go@v3 with: - go-version: 1.18.x + go-version: 1.20.x + - name: Run tests run: make test-property-polybft + + - name: Run tests failed + if: failure() + id: run_property_failure + run: echo "test_output=false" >> $GITHUB_OUTPUT + - name: Archive test logs if: always() uses: actions/upload-artifact@v3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d6097c8924..7d865dbfe6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,6 +12,8 @@ on: # yamllint disable-line rule:truthy jobs: goreleaser: runs-on: ubuntu-latest + env: + DOCKER_CONFIG: $HOME/.docker steps: - name: Checkout uses: actions/checkout@v3 @@ -21,16 +23,23 @@ jobs: - name: Set up Go uses: actions/setup-go@v3 with: - go-version: 1.18.x + go-version: 1.20.x - name: Prepare id: prepare run: | TAG=${GITHUB_REF#refs/tags/} echo tag_name=${TAG} >> $GITHUB_OUTPUT + - name: Set up QEMU uses: docker/setup-qemu-action@v2 + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Run GoReleaser run: | docker run \ @@ -38,9 +47,8 @@ jobs: --privileged \ -e CGO_ENABLED=1 \ -e GITHUB_TOKEN \ - -e DOCKER_USERNAME \ - -e DOCKER_PASSWORD \ -e SLACK_WEBHOOK \ + -e DOCKER_CONFIG \ -v /var/run/docker.sock:/var/run/docker.sock \ -v `pwd`:/go/src/$(PACKAGE_NAME) \ -w /go/src/$(PACKAGE_NAME) \ @@ -48,10 +56,7 @@ jobs: --rm-dist --skip-validate env: PACKAGE_NAME: github.com/0xPolygon/polygon-edge - GOLANG_CROSS_VERSION: v1.18.3 + GOLANG_CROSS_VERSION: v1.20.5 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} VERSION: ${{ steps.prepare.outputs.tag_name }} - SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} - SLACK_CHANNEL: ${{ secrets.SLACK_CHANNEL }} - DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} - DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} + SLACK_WEBHOOK: ${{ secrets.SLACK_EDGE_GITHUB_URL }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d4973d7718..c592923467 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,16 +8,22 @@ on: # yamllint disable-line rule:truthy required: false SONAR_HOST_URL: required: false + outputs: + workflow_output: + description: "Unit tests output" + value: ${{ jobs.go_test.outputs.test_output_failure }} jobs: go_test: name: Polygon Edge runs-on: ubuntu-latest + outputs: + test_output_failure: ${{ steps.run_tests_failure.outputs.test_output }} steps: - name: Setup Go uses: actions/setup-go@v3 with: - go-version: 1.18.x + go-version: 1.20.x - name: Checkout Code uses: actions/checkout@v3 @@ -28,8 +34,13 @@ jobs: run: ./setup-ci.sh - name: Run Go Test - run: go test -coverprofile coverage.out -timeout 20m `go list ./... | grep -v e2e` - + run: make test + + - name: Run Go Test Failed + if: failure() + id: run_tests_failure + run: echo "test_output=false" >> $GITHUB_OUTPUT + # Triggering SonarQube analysis as results of it are required by Quality Gate check. - name: SonarQube Scan if: ${{ env.HAVE_SONAR_TOKEN == 'true' }} diff --git a/.gitmodules b/.gitmodules index 26a6e740c7..8315de1190 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,5 +5,3 @@ [submodule "core-contracts"] path = core-contracts url = https://github.com/0xPolygon/core-contracts - shallow = true - branch = feat-polybft-release diff --git a/.golangci.yml b/.golangci.yml index fe83dec3f4..d5cd6e9ba3 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -6,6 +6,8 @@ run: # default is true. Enables skipping of directories: # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ skip-dirs-use-default: true + skip-dirs: + - tests service: golangci-lint-version: 1.49.0 diff --git a/Makefile b/Makefile index d19530d4e7..8e23754b50 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,11 @@ generate-bsd-licenses: .PHONY: test test: - go test -coverprofile coverage.out -timeout=20m `go list ./... | grep -v e2e` + go test -coverprofile coverage.out -timeout 20m `go list ./... | grep -v e2e` + +.PHONY: fuzz-test +fuzz-test: + ./scripts/fuzzAll .PHONY: test-e2e test-e2e: @@ -54,13 +58,15 @@ test-e2e: test-e2e-polybft: # We can not build with race because of a bug in boltdb dependency go build -o artifacts/polygon-edge . - env EDGE_BINARY=${PWD}/artifacts/polygon-edge E2E_TESTS=true E2E_LOGS=true E2E_TESTS_TYPE=integration \ - go test -v -timeout=45m ./e2e-polybft/e2e/... + env EDGE_BINARY=${PWD}/artifacts/polygon-edge E2E_TESTS=true E2E_LOGS=true \ + go test -v -timeout=1h10m ./e2e-polybft/e2e/... +.PHONY: test-property-polybft test-property-polybft: # We can not build with race because of a bug in boltdb dependency go build -o artifacts/polygon-edge . - env EDGE_BINARY=${PWD}/artifacts/polygon-edge E2E_TESTS=true E2E_LOGS=true E2E_TESTS_TYPE=property go test -v -timeout=30m ./e2e-polybft/property/... + env EDGE_BINARY=${PWD}/artifacts/polygon-edge E2E_TESTS=true E2E_LOGS=true go test -v -timeout=30m ./e2e-polybft/property/... \ + -rapid.checks=10 .PHONY: compile-core-contracts compile-core-contracts: @@ -71,3 +77,15 @@ compile-core-contracts: generate-smart-contract-bindings: go run ./consensus/polybft/contractsapi/artifacts-gen/main.go go run ./consensus/polybft/contractsapi/bindings-gen/main.go + +.PHONY: run-docker +run-docker: + ./scripts/cluster polybft --docker + +.PHONY: stop-docker +stop-docker: + ./scripts/cluster polybft --docker stop + +.PHONY: destroy-docker +destroy-docker: + ./scripts/cluster polybft --docker destroy \ No newline at end of file diff --git a/README.md b/README.md index 232ecc973c..6d5e4ddbf3 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ ![Banner](.github/banner.jpg) -## Update: Edge v0.8 is here! +## Update: Edge v1.0.0 is here! -Developers at Polygon Labs have been hard at work gathering and incorporating community feedback into the Edge client and a new version of Edge, v0.8, is here with several new features! Check out the Release Notes included with the release to find out more! +Developers at Polygon Labs have been hard at work gathering and incorporating community feedback into the Edge client and a new version of Edge, v1.0.0, is here with several new features! Check out the Release Notes included with the release to find out more! ## Polygon Edge diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go index 6682c2b0a4..b3c749c306 100644 --- a/blockchain/blockchain.go +++ b/blockchain/blockchain.go @@ -1,9 +1,12 @@ package blockchain import ( + "encoding/json" "errors" "fmt" + "io/ioutil" "math/big" + "path/filepath" "sync" "sync/atomic" @@ -19,8 +22,14 @@ import ( ) const ( - BlockGasTargetDivisor uint64 = 1024 // The bound divisor of the gas limit, used in update calculations - defaultCacheSize int = 100 // The default size for Blockchain LRU cache structures + // defaultBaseFeeChangeDenom is the value to bound the amount the base fee can change between blocks. + defaultBaseFeeChangeDenom = 8 + + // blockGasTargetDivisor is the bound divisor of the gas limit, used in update calculations + blockGasTargetDivisor uint64 = 1024 + + // defaultCacheSize is the default size for Blockchain LRU cache structures + defaultCacheSize int = 100 ) var ( @@ -46,8 +55,8 @@ type Blockchain struct { executor Executor txSigner TxSigner - config *chain.Chain // Config containing chain information - genesis types.Hash // The hash of the genesis block + config *Config // Config containing chain information + genesis types.Hash // The hash of the genesis block headersCache *lru.Cache // LRU cache for the headers difficultyCache *lru.Cache // LRU cache for the difficulty @@ -63,8 +72,8 @@ type Blockchain struct { // any new fields from being added receiptsCache *lru.Cache // LRU cache for the block receipts - currentHeader atomic.Value // The current header - currentDifficulty atomic.Value // The current difficulty of the chain (total difficulty) + currentHeader atomic.Pointer[types.Header] // The current header + currentDifficulty atomic.Pointer[big.Int] // The current difficulty of the chain (total difficulty) stream *eventStream // Event subscriptions @@ -85,7 +94,7 @@ type Verifier interface { VerifyHeader(header *types.Header) error ProcessHeaders(headers []*types.Header) error GetBlockCreator(header *types.Header) (types.Address, error) - PreCommitState(header *types.Header, txn *state.Transition) error + PreCommitState(block *types.Block, txn *state.Transition) error } type Executor interface { @@ -101,6 +110,7 @@ type BlockResult struct { Root types.Hash Receipts []*types.Receipt TotalGas uint64 + Trace *types.Trace } // updateGasPriceAvg updates the rolling average value of the gas price @@ -185,7 +195,7 @@ func (b *Blockchain) GetAvgGasPrice() *big.Int { func NewBlockchain( logger hclog.Logger, db storage.Storage, - config *chain.Chain, + config *Config, consensus Verifier, executor Executor, txSigner TxSigner, @@ -249,7 +259,7 @@ func (b *Blockchain) ComputeGenesis() error { } // validate that the genesis file in storage matches the chain.Genesis - if b.genesis != b.config.Genesis.Hash() { + if b.genesis != b.config.Chain.Genesis.Hash() { return fmt.Errorf("genesis file does not match current genesis") } @@ -274,12 +284,12 @@ func (b *Blockchain) ComputeGenesis() error { b.setCurrentHeader(header, diff) } else { // empty storage, write the genesis - if err := b.writeGenesis(b.config.Genesis); err != nil { + if err := b.writeGenesis(b.config.Chain.Genesis); err != nil { return err } } - b.logger.Info("genesis", "hash", b.config.Genesis.Hash()) + b.logger.Info("genesis", "hash", b.config.Chain.Genesis.Hash()) return nil } @@ -306,27 +316,17 @@ func (b *Blockchain) setCurrentHeader(h *types.Header, diff *big.Int) { // Header returns the current header (atomic) func (b *Blockchain) Header() *types.Header { - header, ok := b.currentHeader.Load().(*types.Header) - if !ok { - return nil - } - - return header + return b.currentHeader.Load() } // CurrentTD returns the current total difficulty (atomic) func (b *Blockchain) CurrentTD() *big.Int { - td, ok := b.currentDifficulty.Load().(*big.Int) - if !ok { - return nil - } - - return td + return b.currentDifficulty.Load() } // Config returns the blockchain configuration func (b *Blockchain) Config() *chain.Params { - return b.config.Params + return b.config.Chain.Params } // GetHeader returns the block header using the hash @@ -378,7 +378,7 @@ func (b *Blockchain) calculateGasLimit(parentGasLimit uint64) uint64 { return blockGasTarget } - delta := parentGasLimit * 1 / BlockGasTargetDivisor + delta := parentGasLimit * 1 / blockGasTargetDivisor if parentGasLimit < blockGasTarget { // The gas limit is lower than the gas target, so it should // increase towards the target @@ -671,17 +671,17 @@ func (b *Blockchain) VerifyFinalizedBlock(block *types.Block) (*types.FullBlock, } // Do the initial block verification - receipts, err := b.verifyBlock(block) + blockResult, err := b.verifyBlock(block) if err != nil { return nil, err } - return &types.FullBlock{Block: block, Receipts: receipts}, nil + return &types.FullBlock{Block: block, Receipts: blockResult.Receipts, Trace: blockResult.Trace}, nil } // verifyBlock does the base (common) block verification steps by // verifying the block body as well as the parent information -func (b *Blockchain) verifyBlock(block *types.Block) ([]*types.Receipt, error) { +func (b *Blockchain) verifyBlock(block *types.Block) (*BlockResult, error) { // Make sure the block is present if block == nil { return nil, ErrNoBlock @@ -693,12 +693,7 @@ func (b *Blockchain) verifyBlock(block *types.Block) ([]*types.Receipt, error) { } // Make sure the block body data is valid - receipts, err := b.verifyBlockBody(block) - if err != nil { - return nil, err - } - - return receipts, nil + return b.verifyBlockBody(block) } // verifyBlockParent makes sure that the child block is in line @@ -756,7 +751,7 @@ func (b *Blockchain) verifyBlockParent(childBlock *types.Block) error { // - The trie roots match up (state, transactions, receipts, uncles) // - The receipts match up // - The execution result matches up -func (b *Blockchain) verifyBlockBody(block *types.Block) ([]*types.Receipt, error) { +func (b *Blockchain) verifyBlockBody(block *types.Block) (*BlockResult, error) { // Make sure the Uncles root matches up if hash := buildroot.CalculateUncleRoot(block.Uncles); hash != block.Header.Sha3Uncles { b.logger.Error(fmt.Sprintf( @@ -790,7 +785,7 @@ func (b *Blockchain) verifyBlockBody(block *types.Block) ([]*types.Receipt, erro return nil, fmt.Errorf("unable to verify block execution result, %w", err) } - return blockResult.Receipts, nil + return blockResult, nil } // verifyBlockResult verifies that the block transaction execution result @@ -840,11 +835,16 @@ func (b *Blockchain) executeBlockTransactions(block *types.Block) (*BlockResult, return nil, err } - if err := b.consensus.PreCommitState(header, txn); err != nil { + if err := b.consensus.PreCommitState(block, txn); err != nil { return nil, err } - _, root := txn.Commit() + _, trace, root, err := txn.Commit() + trace.ParentStateRoot = parent.StateRoot + + if err != nil { + return nil, fmt.Errorf("failed to commit the state changes: %w", err) + } // Append the receipts to the receipts cache b.receiptsCache.Add(header.Hash, txn.Receipts()) @@ -853,6 +853,7 @@ func (b *Blockchain) executeBlockTransactions(block *types.Block) (*BlockResult, Root: root, Receipts: txn.Receipts(), TotalGas: txn.TotalGas(), + Trace: trace, }, nil } @@ -891,6 +892,11 @@ func (b *Blockchain) WriteFullBlock(fblock *types.FullBlock, source string) erro return err } + // write the trace + if err := b.writeTrace(fblock.Trace, header.Number); err != nil { + return err + } + // update snapshot if err := b.consensus.ProcessHeaders([]*types.Header{header}); err != nil { return err @@ -1033,7 +1039,7 @@ func (b *Blockchain) updateGasPriceAvgWithBlock(block *types.Block) { gasPrices := make([]*big.Int, len(block.Transactions)) for i, transaction := range block.Transactions { - gasPrices[i] = transaction.GasPrice + gasPrices[i] = transaction.GetGasPrice(block.Header.BaseFee) } b.updateGasPriceAvg(gasPrices) @@ -1135,7 +1141,7 @@ func (b *Blockchain) verifyGasLimit(header *types.Header, parentHeader *types.He diff *= -1 } - limit := parentHeader.GasLimit / BlockGasTargetDivisor + limit := parentHeader.GasLimit / blockGasTargetDivisor if uint64(diff) > limit { return fmt.Errorf( "invalid gas limit, limit = %d, want %d +- %d", @@ -1280,6 +1286,22 @@ func (b *Blockchain) writeFork(header *types.Header) error { return nil } +// writeTrace writes the block trace to the file +func (b *Blockchain) writeTrace(trace *types.Trace, blockNumber uint64) error { + raw, err := json.Marshal(trace) + if err != nil { + return err + } + + consensusDir := filepath.Join(b.config.DataDir, "consensus") + if err := ioutil.WriteFile( + filepath.Join(consensusDir, fmt.Sprintf("trace_%d.json", blockNumber)), raw, 0600); err != nil { + return err + } + + return nil +} + // handleReorg handles a reorganization event func (b *Blockchain) handleReorg( evnt *Event, @@ -1414,3 +1436,37 @@ func (b *Blockchain) GetBlockByNumber(blockNumber uint64, full bool) (*types.Blo func (b *Blockchain) Close() error { return b.db.Close() } + +// CalculateBaseFee calculates the basefee of the header. +func (b *Blockchain) CalculateBaseFee(parent *types.Header) uint64 { + if !b.config.Chain.Params.Forks.IsActive(chain.London, parent.Number) { + return chain.GenesisBaseFee + } + + parentGasTarget := parent.GasLimit / b.config.Chain.Genesis.BaseFeeEM + + // If the parent gasUsed is the same as the target, the baseFee remains unchanged. + if parent.GasUsed == parentGasTarget { + return parent.BaseFee + } + + // If the parent block used more gas than its target, the baseFee should increase. + if parent.GasUsed > parentGasTarget { + gasUsedDelta := parent.GasUsed - parentGasTarget + baseFeeDelta := calcBaseFeeDelta(gasUsedDelta, parentGasTarget, parent.BaseFee) + + return parent.BaseFee + common.Max(baseFeeDelta, 1) + } + + // Otherwise, if the parent block used less gas than its target, the baseFee should decrease. + gasUsedDelta := parentGasTarget - parent.GasUsed + baseFeeDelta := calcBaseFeeDelta(gasUsedDelta, parentGasTarget, parent.BaseFee) + + return common.Max(parent.BaseFee-baseFeeDelta, 0) +} + +func calcBaseFeeDelta(gasUsedDelta, parentGasTarget, baseFee uint64) uint64 { + y := baseFee * gasUsedDelta / parentGasTarget + + return y / defaultBaseFeeChangeDenom +} diff --git a/blockchain/blockchain_test.go b/blockchain/blockchain_test.go index 1646c49660..50a99f1db1 100644 --- a/blockchain/blockchain_test.go +++ b/blockchain/blockchain_test.go @@ -955,7 +955,7 @@ func TestCalculateGasLimit(t *testing.T) { t.Fatalf("unable to construct the blockchain, %v", blockchainErr) } - b.config.Params = &chain.Params{ + b.config.Chain.Params = &chain.Params{ BlockGasTarget: tt.blockGasTarget, } @@ -1335,3 +1335,56 @@ func TestBlockchain_VerifyBlockBody(t *testing.T) { assert.ErrorIs(t, err, errUnableToExecute) }) } + +func TestBlockchain_CalculateBaseFee(t *testing.T) { + t.Parallel() + + tests := []struct { + blockNumber uint64 + parentBaseFee uint64 + parentGasLimit uint64 + parentGasUsed uint64 + expectedBaseFee uint64 + elasticityMultiplier uint64 + }{ + {6, chain.GenesisBaseFee, 20000000, 10000000, chain.GenesisBaseFee, 2}, // usage == target + {6, chain.GenesisBaseFee, 20000000, 10000000, 1125000000, 4}, // usage == target + {6, chain.GenesisBaseFee, 20000000, 9000000, 987500000, 2}, // usage below target + {6, chain.GenesisBaseFee, 20000000, 9000000, 1100000000, 4}, // usage below target + {6, chain.GenesisBaseFee, 20000000, 11000000, 1012500000, 2}, // usage above target + {6, chain.GenesisBaseFee, 20000000, 11000000, 1150000000, 4}, // usage above target + {6, chain.GenesisBaseFee, 20000000, 20000000, 1125000000, 2}, // usage full + {6, chain.GenesisBaseFee, 20000000, 20000000, 1375000000, 4}, // usage full + {6, chain.GenesisBaseFee, 20000000, 0, 875000000, 2}, // usage 0 + {6, chain.GenesisBaseFee, 20000000, 0, 875000000, 4}, // usage 0 + } + + for i, test := range tests { + test := test + + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + t.Parallel() + + blockchain := Blockchain{ + config: &Config{ + Chain: &chain.Chain{ + Params: &chain.Params{ + Forks: &chain.Forks{chain.London: chain.NewFork(5)}, + }, + Genesis: &chain.Genesis{BaseFeeEM: test.elasticityMultiplier}, + }, + }, + } + + parent := &types.Header{ + Number: test.blockNumber, + GasLimit: test.parentGasLimit, + GasUsed: test.parentGasUsed, + BaseFee: test.parentBaseFee, + } + + got := blockchain.CalculateBaseFee(parent) + assert.Equal(t, test.expectedBaseFee, got, fmt.Sprintf("expected %d, got %d", test.expectedBaseFee, got)) + }) + } +} diff --git a/blockchain/config.go b/blockchain/config.go new file mode 100644 index 0000000000..66f7a0d78c --- /dev/null +++ b/blockchain/config.go @@ -0,0 +1,9 @@ +package blockchain + +import "github.com/0xPolygon/polygon-edge/chain" + +// Config is the configuration for the blockchain +type Config struct { + Chain *chain.Chain // the reference to the chain configuration + DataDir string // the base data directory for the client +} diff --git a/blockchain/subscription.go b/blockchain/subscription.go index 34a147342f..145a727fa0 100644 --- a/blockchain/subscription.go +++ b/blockchain/subscription.go @@ -42,19 +42,7 @@ type subscription struct { // GetEventCh creates a new event channel, and returns it func (s *subscription) GetEventCh() chan *Event { - eventCh := make(chan *Event) - - go func() { - for { - evnt := s.GetEvent() - if evnt == nil { - return - } - eventCh <- evnt - } - }() - - return eventCh + return s.updateCh } // GetEvent returns the event from the subscription (BLOCKING) @@ -161,11 +149,7 @@ func (e *eventStream) newUpdateCh() chan *Event { e.Lock() defer e.Unlock() - ch := make(chan *Event, 1) - - if e.updateCh == nil { - e.updateCh = make([]chan *Event, 0) - } + ch := make(chan *Event, 5) e.updateCh = append(e.updateCh, ch) @@ -179,9 +163,6 @@ func (e *eventStream) push(event *Event) { // Notify the listeners for _, update := range e.updateCh { - select { - case update <- event: - default: - } + update <- event } } diff --git a/blockchain/subscription_test.go b/blockchain/subscription_test.go index 9e854a20a9..26acd59cf4 100644 --- a/blockchain/subscription_test.go +++ b/blockchain/subscription_test.go @@ -51,3 +51,61 @@ func TestSubscription(t *testing.T) { assert.Equal(t, event.NewChain[0].Number, caughtEventNum) } + +func TestSubscription_BufferedChannel_MultipleSubscriptions(t *testing.T) { + t.Parallel() + + var ( + e = &eventStream{} + wg sync.WaitGroup + numOfEvents = 100000 + numOfSubscriptions = 10 + ) + + subscriptions := make([]*subscription, numOfSubscriptions) + wg.Add(numOfSubscriptions) + + worker := func(id int, sub *subscription) { + updateCh := sub.GetEventCh() + caughtEvents := 0 + + defer wg.Done() + + for { + select { + case <-updateCh: + caughtEvents++ + if caughtEvents == numOfEvents { + return + } + case <-time.After(10 * time.Second): + t.Errorf("subscription %d did not caught all events", id) + } + } + } + + for i := 0; i < numOfSubscriptions; i++ { + sub := e.subscribe() + subscriptions[i] = sub + + go worker(i, sub) + } + + // Send the events to the channels + for i := 0; i < numOfEvents; i++ { + e.push(&Event{ + NewChain: []*types.Header{ + { + Number: uint64(i), + }, + }, + }) + } + + // Wait for the events to be processed + wg.Wait() + + for _, s := range subscriptions { + s.Close() + } +} diff --git a/blockchain/testing.go b/blockchain/testing.go index 2f3b510cd0..c8935ba5bf 100644 --- a/blockchain/testing.go +++ b/blockchain/testing.go @@ -97,13 +97,14 @@ func NewTestBlockchain(t *testing.T, headers []*types.Header) *Blockchain { Number: 0, GasLimit: 0, } + forksAvail := &chain.Forks{ + chain.EIP155: chain.NewFork(0), + chain.Homestead: chain.NewFork(0), + } config := &chain.Chain{ Genesis: genesis, Params: &chain.Params{ - Forks: &chain.Forks{ - EIP155: chain.NewFork(0), - Homestead: chain.NewFork(0), - }, + Forks: forksAvail, BlockGasTarget: defaultBlockGasTarget, }, } @@ -144,7 +145,7 @@ func NewMockBlockchain( var ( mockVerifier = &MockVerifier{} executor = &mockExecutor{} - config = &chain.Chain{ + chainConfig = &chain.Chain{ Genesis: &chain.Genesis{ Number: 0, GasLimit: 0, @@ -185,7 +186,7 @@ func NewMockBlockchain( return nil, errInvalidTypeAssertion } - callback(config) + callback(chainConfig) } // Execute the storage callback @@ -204,7 +205,7 @@ func NewMockBlockchain( db: mockStorage, consensus: mockVerifier, executor: executor, - config: config, + config: &Config{Chain: chainConfig}, stream: &eventStream{}, gpAverage: &gasPriceAverage{ price: big.NewInt(0), @@ -224,7 +225,7 @@ func NewMockBlockchain( type verifyHeaderDelegate func(*types.Header) error type processHeadersDelegate func([]*types.Header) error type getBlockCreatorDelegate func(*types.Header) (types.Address, error) -type preStateCommitDelegate func(*types.Header, *state.Transition) error +type preStateCommitDelegate func(*types.Block, *state.Transition) error type MockVerifier struct { verifyHeaderFn verifyHeaderDelegate @@ -269,9 +270,9 @@ func (m *MockVerifier) HookGetBlockCreator(fn getBlockCreatorDelegate) { m.getBlockCreatorFn = fn } -func (m *MockVerifier) PreCommitState(header *types.Header, txn *state.Transition) error { +func (m *MockVerifier) PreCommitState(block *types.Block, txn *state.Transition) error { if m.preStateCommitFn != nil { - return m.preStateCommitFn(header, txn) + return m.preStateCommitFn(block, txn) } return nil @@ -347,7 +348,7 @@ func newBlockChain(config *chain.Chain, executor Executor) (*Blockchain, error) return nil, err } - b, err := NewBlockchain(hclog.NewNullLogger(), db, config, &MockVerifier{}, executor, &mockSigner{}) + b, err := NewBlockchain(hclog.NewNullLogger(), db, &Config{Chain: config}, &MockVerifier{}, executor, &mockSigner{}) if err != nil { return nil, err } diff --git a/chain/chain.go b/chain/chain.go index 50bf41e1bc..64bed7f1f5 100644 --- a/chain/chain.go +++ b/chain/chain.go @@ -7,17 +7,28 @@ import ( "math/big" "os" + "github.com/hashicorp/go-multierror" + "github.com/umbracle/ethgo" + + "github.com/0xPolygon/polygon-edge/helper/common" "github.com/0xPolygon/polygon-edge/helper/hex" "github.com/0xPolygon/polygon-edge/types" - "github.com/hashicorp/go-multierror" ) -var ( +const ( + // GenesisBaseFeeEM is the initial base fee elasticity multiplier for EIP-1559 blocks. + GenesisBaseFeeEM = 2 + // GenesisGasLimit is the default gas limit of the Genesis block. GenesisGasLimit uint64 = 4712388 // GenesisDifficulty is the default difficulty of the Genesis block. - GenesisDifficulty = big.NewInt(131072) + GenesisDifficulty uint64 = 131072 +) + +var ( + // GenesisBaseFee is the initial base fee for EIP-1559 blocks. + GenesisBaseFee = ethgo.Gwei(1).Uint64() ) // Chain is the blockchain chain configuration @@ -30,8 +41,6 @@ type Chain struct { // Genesis specifies the header fields, state of a genesis block type Genesis struct { - Config *Params `json:"config"` - Nonce [8]byte `json:"nonce"` Timestamp uint64 `json:"timestamp"` ExtraData []byte `json:"extraData,omitempty"` @@ -40,6 +49,8 @@ type Genesis struct { Mixhash types.Hash `json:"mixHash"` Coinbase types.Address `json:"coinbase"` Alloc map[types.Address]*GenesisAccount `json:"alloc,omitempty"` + BaseFee uint64 `json:"baseFee"` + BaseFeeEM uint64 `json:"baseFeeEM"` // Override StateRoot types.Hash @@ -66,6 +77,7 @@ func (g *Genesis) GenesisHeader() *types.Header { ExtraData: g.ExtraData, GasLimit: g.GasLimit, GasUsed: g.GasUsed, + BaseFee: g.BaseFee, Difficulty: g.Difficulty, MixHash: g.Mixhash, Miner: g.Coinbase.Bytes(), @@ -81,7 +93,11 @@ func (g *Genesis) GenesisHeader() *types.Header { } if g.Difficulty == 0 { - head.Difficulty = GenesisDifficulty.Uint64() + head.Difficulty = GenesisDifficulty + } + + if g.BaseFee == 0 { + head.BaseFee = GenesisBaseFee } return head @@ -109,6 +125,8 @@ func (g *Genesis) MarshalJSON() ([]byte, error) { Number *string `json:"number,omitempty"` GasUsed *string `json:"gasUsed,omitempty"` ParentHash types.Hash `json:"parentHash"` + BaseFee *string `json:"baseFee"` + BaseFeeEM *string `json:"baseFeeEM"` } var enc Genesis @@ -119,6 +137,8 @@ func (g *Genesis) MarshalJSON() ([]byte, error) { enc.GasLimit = types.EncodeUint64(g.GasLimit) enc.Difficulty = types.EncodeUint64(g.Difficulty) + enc.BaseFee = types.EncodeUint64(g.BaseFee) + enc.BaseFeeEM = types.EncodeUint64(g.BaseFeeEM) enc.Mixhash = g.Mixhash enc.Coinbase = g.Coinbase @@ -153,6 +173,8 @@ func (g *Genesis) UnmarshalJSON(data []byte) error { Number *string `json:"number"` GasUsed *string `json:"gasUsed"` ParentHash *types.Hash `json:"parentHash"` + BaseFee *string `json:"baseFee"` + BaseFeeEM *string `json:"baseFeeEM"` } var dec Genesis @@ -166,14 +188,14 @@ func (g *Genesis) UnmarshalJSON(data []byte) error { err = multierror.Append(err, fmt.Errorf("%s: %w", field, subErr)) } - nonce, subErr := types.ParseUint64orHex(dec.Nonce) + nonce, subErr := common.ParseUint64orHex(dec.Nonce) if subErr != nil { parseError("nonce", subErr) } binary.BigEndian.PutUint64(g.Nonce[:], nonce) - g.Timestamp, subErr = types.ParseUint64orHex(dec.Timestamp) + g.Timestamp, subErr = common.ParseUint64orHex(dec.Timestamp) if subErr != nil { parseError("timestamp", subErr) } @@ -189,16 +211,26 @@ func (g *Genesis) UnmarshalJSON(data []byte) error { return fmt.Errorf("field 'gaslimit' is required") } - g.GasLimit, subErr = types.ParseUint64orHex(dec.GasLimit) + g.GasLimit, subErr = common.ParseUint64orHex(dec.GasLimit) if subErr != nil { parseError("gaslimit", subErr) } - g.Difficulty, subErr = types.ParseUint64orHex(dec.Difficulty) + g.Difficulty, subErr = common.ParseUint64orHex(dec.Difficulty) if subErr != nil { parseError("difficulty", subErr) } + g.BaseFee, subErr = common.ParseUint64orHex(dec.BaseFee) + if subErr != nil { + parseError("baseFee", subErr) + } + + g.BaseFeeEM, subErr = common.ParseUint64orHex(dec.BaseFeeEM) + if subErr != nil { + parseError("baseFeeEM", subErr) + } + if dec.Mixhash != nil { g.Mixhash = *dec.Mixhash } @@ -214,12 +246,12 @@ func (g *Genesis) UnmarshalJSON(data []byte) error { } } - g.Number, subErr = types.ParseUint64orHex(dec.Number) + g.Number, subErr = common.ParseUint64orHex(dec.Number) if subErr != nil { parseError("number", subErr) } - g.GasUsed, subErr = types.ParseUint64orHex(dec.GasUsed) + g.GasUsed, subErr = common.ParseUint64orHex(dec.GasUsed) if subErr != nil { parseError("gasused", subErr) } @@ -318,7 +350,7 @@ func (g *GenesisAccount) UnmarshalJSON(data []byte) error { parseError("balance", subErr) } - g.Nonce, subErr = types.ParseUint64orHex(dec.Nonce) + g.Nonce, subErr = common.ParseUint64orHex(dec.Nonce) if subErr != nil { parseError("nonce", subErr) @@ -361,13 +393,3 @@ func importChain(content []byte) (*Chain, error) { return chain, nil } - -// GetGenesisAccountBalance returns balance for genesis account based on its address (expressed in weis). -// If not found in provided allocations map, 0 is returned. -func GetGenesisAccountBalance(address types.Address, allocations map[types.Address]*GenesisAccount) (*big.Int, error) { - if genesisAcc, ok := allocations[address]; ok { - return genesisAcc.Balance, nil - } - - return nil, fmt.Errorf("genesis account %s is not found among genesis allocations", address) -} diff --git a/chain/chain_test.go b/chain/chain_test.go index db88298784..88568a019c 100644 --- a/chain/chain_test.go +++ b/chain/chain_test.go @@ -2,13 +2,11 @@ package chain import ( "encoding/json" - "fmt" "math/big" "reflect" "testing" "github.com/0xPolygon/polygon-edge/types" - "github.com/stretchr/testify/require" ) var emptyAddr types.Address @@ -152,48 +150,3 @@ func TestGenesisX(t *testing.T) { }) } } - -func TestGetGenesisAccountBalance(t *testing.T) { - t.Parallel() - - testAddr := types.Address{0x2} - cases := []struct { - name string - address types.Address - allocs map[types.Address]*GenesisAccount - expectedBalance *big.Int - shouldFail bool - }{ - { - name: "Query existing account", - address: testAddr, - allocs: map[types.Address]*GenesisAccount{ - testAddr: {Balance: big.NewInt(50)}, - }, - expectedBalance: big.NewInt(50), - shouldFail: false, - }, - { - name: "Query non-existing account", - address: testAddr, - allocs: nil, - expectedBalance: nil, - shouldFail: true, - }, - } - - for _, c := range cases { - c := c - t.Run(c.name, func(t *testing.T) { - t.Parallel() - - actualBalance, err := GetGenesisAccountBalance(c.address, c.allocs) - if c.shouldFail { - require.Equal(t, err.Error(), fmt.Errorf("genesis account %s is not found among genesis allocations", c.address).Error()) - } else { - require.NoError(t, err) - } - require.Equal(t, c.expectedBalance, actualBalance) - }) - } -} diff --git a/chain/params.go b/chain/params.go index df1ad6273e..7db1071d59 100644 --- a/chain/params.go +++ b/chain/params.go @@ -1,24 +1,40 @@ package chain import ( - "math/big" + "errors" + "sort" + "github.com/0xPolygon/polygon-edge/helper/common" "github.com/0xPolygon/polygon-edge/types" ) +var ( + // ErrBurnContractAddressMissing is the error when a contract address is not provided + ErrBurnContractAddressMissing = errors.New("burn contract address missing") +) + // Params are all the set of params for the chain type Params struct { Forks *Forks `json:"forks"` ChainID int64 `json:"chainID"` Engine map[string]interface{} `json:"engine"` - Whitelists *Whitelists `json:"whitelists,omitempty"` BlockGasTarget uint64 `json:"blockGasTarget"` - // AllowList configuration - ContractDeployerAllowList *AllowListConfig `json:"contractDeployerAllowListConfig,omitempty"` + // Access control configuration + ContractDeployerAllowList *AddressListConfig `json:"contractDeployerAllowList,omitempty"` + ContractDeployerBlockList *AddressListConfig `json:"contractDeployerBlockList,omitempty"` + TransactionsAllowList *AddressListConfig `json:"transactionsAllowList,omitempty"` + TransactionsBlockList *AddressListConfig `json:"transactionsBlockList,omitempty"` + BridgeAllowList *AddressListConfig `json:"bridgeAllowList,omitempty"` + BridgeBlockList *AddressListConfig `json:"bridgeBlockList,omitempty"` + + // Governance contract where the token will be sent to and burn in london fork + BurnContract map[uint64]types.Address `json:"burnContract"` + // Destination address to initialize default burn contract with + BurnContractDestinationAddress types.Address `json:"burnContractDestinationAddress,omitempty"` } -type AllowListConfig struct { +type AddressListConfig struct { // AdminAddresses is the list of the initial admin addresses AdminAddresses []types.Address `json:"adminAddresses,omitempty"` @@ -26,103 +42,119 @@ type AllowListConfig struct { EnabledAddresses []types.Address `json:"enabledAddresses,omitempty"` } -func (p *Params) GetEngine() string { - // We know there is already one - for k := range p.Engine { - return k - } +// CalculateBurnContract calculates burn contract address for the given block number +func (p *Params) CalculateBurnContract(block uint64) (types.Address, error) { + blocks := make([]uint64, 0, len(p.BurnContract)) - return "" -} + for startBlock := range p.BurnContract { + blocks = append(blocks, startBlock) + } -// Whitelists specifies supported whitelists -type Whitelists struct { - Deployment []types.Address `json:"deployment,omitempty"` -} + if len(blocks) == 0 { + return types.ZeroAddress, ErrBurnContractAddressMissing + } -// Forks specifies when each fork is activated -type Forks struct { - Homestead *Fork `json:"homestead,omitempty"` - Byzantium *Fork `json:"byzantium,omitempty"` - Constantinople *Fork `json:"constantinople,omitempty"` - Petersburg *Fork `json:"petersburg,omitempty"` - Istanbul *Fork `json:"istanbul,omitempty"` - London *Fork `json:"london,omitempty"` - EIP150 *Fork `json:"EIP150,omitempty"` - EIP158 *Fork `json:"EIP158,omitempty"` - EIP155 *Fork `json:"EIP155,omitempty"` -} + sort.Slice(blocks, func(i, j int) bool { + return blocks[i] < blocks[j] + }) -func (f *Forks) active(ff *Fork, block uint64) bool { - if ff == nil { - return false + for i := 0; i < len(blocks)-1; i++ { + if block >= blocks[i] && block < blocks[i+1] { + return p.BurnContract[blocks[i]], nil + } } - return ff.Active(block) + return p.BurnContract[blocks[len(blocks)-1]], nil } -func (f *Forks) IsHomestead(block uint64) bool { - return f.active(f.Homestead, block) -} +func (p *Params) GetEngine() string { + // We know there is already one + for k := range p.Engine { + return k + } -func (f *Forks) IsByzantium(block uint64) bool { - return f.active(f.Byzantium, block) + return "" } -func (f *Forks) IsConstantinople(block uint64) bool { - return f.active(f.Constantinople, block) -} +// predefined forks +const ( + Homestead = "homestead" + Byzantium = "byzantium" + Constantinople = "constantinople" + Petersburg = "petersburg" + Istanbul = "istanbul" + London = "london" + EIP150 = "EIP150" + EIP158 = "EIP158" + EIP155 = "EIP155" +) -func (f *Forks) IsPetersburg(block uint64) bool { - return f.active(f.Petersburg, block) -} +// Forks is map which contains all forks and their starting blocks from genesis +type Forks map[string]Fork -func (f *Forks) IsLondon(block uint64) bool { - return f.active(f.London, block) -} +// IsActive returns true if fork defined by name exists and defined for the block +func (f *Forks) IsActive(name string, block uint64) bool { + ff, exists := (*f)[name] -func (f *Forks) IsEIP150(block uint64) bool { - return f.active(f.EIP150, block) + return exists && ff.Active(block) } -func (f *Forks) IsEIP158(block uint64) bool { - return f.active(f.EIP158, block) +// SetFork adds/updates fork defined by name +func (f *Forks) SetFork(name string, value Fork) { + (*f)[name] = value } -func (f *Forks) IsEIP155(block uint64) bool { - return f.active(f.EIP155, block) +func (f *Forks) RemoveFork(name string) { + delete(*f, name) } +// At returns ForksInTime instance that shows which supported forks are enabled for the block func (f *Forks) At(block uint64) ForksInTime { return ForksInTime{ - Homestead: f.active(f.Homestead, block), - Byzantium: f.active(f.Byzantium, block), - Constantinople: f.active(f.Constantinople, block), - Petersburg: f.active(f.Petersburg, block), - Istanbul: f.active(f.Istanbul, block), - London: f.active(f.London, block), - EIP150: f.active(f.EIP150, block), - EIP158: f.active(f.EIP158, block), - EIP155: f.active(f.EIP155, block), + Homestead: f.IsActive(Homestead, block), + Byzantium: f.IsActive(Byzantium, block), + Constantinople: f.IsActive(Constantinople, block), + Petersburg: f.IsActive(Petersburg, block), + Istanbul: f.IsActive(Istanbul, block), + London: f.IsActive(London, block), + EIP150: f.IsActive(EIP150, block), + EIP158: f.IsActive(EIP158, block), + EIP155: f.IsActive(EIP155, block), } } -type Fork uint64 +// ForkParams hard-coded fork params +type ForkParams struct { + // MaxValidatorSetSize indicates the maximum size of validator set + MaxValidatorSetSize *uint64 `json:"maxValidatorSetSize,omitempty"` + + // EpochSize is size of epoch + EpochSize *uint64 `json:"epochSize,omitempty"` -func NewFork(n uint64) *Fork { - f := Fork(n) + // SprintSize is size of sprint + SprintSize *uint64 `json:"sprintSize,omitempty"` - return &f + // BlockTime is target frequency of blocks production + BlockTime *common.Duration `json:"blockTime,omitempty"` + + // BlockTimeDrift defines the time slot in which a new block can be created + BlockTimeDrift *uint64 `json:"blockTimeDrift,omitempty"` } -func (f Fork) Active(block uint64) bool { - return block >= uint64(f) +type Fork struct { + Block uint64 `json:"block"` + Params *ForkParams `json:"params,omitempty"` } -func (f Fork) Int() *big.Int { - return big.NewInt(int64(f)) +func NewFork(n uint64) Fork { + return Fork{Block: n} +} + +func (f Fork) Active(block uint64) bool { + return block >= f.Block } +// ForksInTime should contain all supported forks by current edge version type ForksInTime struct { Homestead, Byzantium, @@ -135,6 +167,7 @@ type ForksInTime struct { EIP155 bool } +// AllForksEnabled should contain all supported forks by current edge version var AllForksEnabled = &Forks{ Homestead: NewFork(0), EIP150: NewFork(0), diff --git a/chain/params_test.go b/chain/params_test.go index be27a2a4ad..775f5597f9 100644 --- a/chain/params_test.go +++ b/chain/params_test.go @@ -4,6 +4,10 @@ import ( "encoding/json" "reflect" "testing" + + "github.com/stretchr/testify/require" + + "github.com/0xPolygon/polygon-edge/types" ) func TestParamsForks(t *testing.T) { @@ -13,7 +17,7 @@ func TestParamsForks(t *testing.T) { }{ { input: `{ - "homestead": 1000 + "homestead": { "block": 1000 } }`, output: &Forks{ Homestead: NewFork(1000), @@ -54,3 +58,73 @@ func TestParamsForksInTime(t *testing.T) { expect("constantinople", ff.Constantinople, false) expect("eip150", ff.EIP150, false) } + +func TestParams_CalculateBurnContract(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + burnContract map[uint64]types.Address + block uint64 + want types.Address + wantErr bool + }{ + { + name: "no addresses in the list", + burnContract: map[uint64]types.Address{}, + block: 10, + want: types.ZeroAddress, + wantErr: true, + }, + { + name: "last address is used", + burnContract: map[uint64]types.Address{ + 15: types.StringToAddress("0x8888f1f195afa192cfee860698584c030f4c9db1"), + }, + block: 10, + want: types.StringToAddress("0x8888f1f195afa192cfee860698584c030f4c9db1"), + wantErr: false, + }, + { + name: "first address is used", + burnContract: map[uint64]types.Address{ + 5: types.StringToAddress("0x8888f1f195afa192cfee860698584c030f4c9db2"), + 15: types.StringToAddress("0x8888f1f195afa192cfee860698584c030f4c9db1"), + }, + block: 10, + want: types.StringToAddress("0x8888f1f195afa192cfee860698584c030f4c9db2"), + wantErr: false, + }, + { + name: "same block as key", + burnContract: map[uint64]types.Address{ + 5: types.StringToAddress("0x8888f1f195afa192cfee860698584c030f4c4db2"), + 10: types.StringToAddress("0x8888f1f195afa192cfee860698584c030f4c5db1"), + 15: types.StringToAddress("0x8888f1f195afa192cfee860698584c030f4c6db0"), + }, + block: 10, + want: types.StringToAddress("0x8888f1f195afa192cfee860698584c030f4c5db1"), + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + p := &Params{ + BurnContract: tt.burnContract, + } + + got, err := p.CalculateBurnContract(tt.block) + if tt.wantErr { + require.Error(t, err, "CalculateBurnContract() error = %v, wantErr %v", err, tt.wantErr) + } else { + require.NoError(t, err) + require.Equal(t, tt.want, got, "CalculateBurnContract() got = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/command/bridge/README.md b/command/bridge/README.md index b72e9037c2..db89ca9863 100644 --- a/command/bridge/README.md +++ b/command/bridge/README.md @@ -13,10 +13,11 @@ $ polygon-edge bridge deposit-erc20 \ --amounts \ --root-token \ --root-predicate \ - --json-rpc + --json-rpc + [--minter-key ] ``` -**Note:** for using test account provided by Geth dev instance, use `--test` flag. In that case `--sender-key` flag can be omitted and test account is used as a depositor. +**Note:** in case `minter-key` is provided, tokens are going to be minted to sender account. Note that provided minter private key must belong to the account which has minter role. ## Withdraw ERC20 @@ -27,9 +28,9 @@ $ polygon-edge bridge withdraw-erc20 \ --sender-key \ --receivers \ --amounts \ - --child-predicate \ + --child-predicate \ [--child-token ] \ - --json-rpc + --json-rpc ``` ## Exit diff --git a/command/bridge/bridge.go b/command/bridge/bridge.go index bf9d334f9d..2fd8ef2c30 100644 --- a/command/bridge/bridge.go +++ b/command/bridge/bridge.go @@ -3,9 +3,13 @@ package bridge import ( "github.com/spf13/cobra" - "github.com/0xPolygon/polygon-edge/command/bridge/deposit" + depositERC1155 "github.com/0xPolygon/polygon-edge/command/bridge/deposit/erc1155" + depositERC20 "github.com/0xPolygon/polygon-edge/command/bridge/deposit/erc20" + depositERC721 "github.com/0xPolygon/polygon-edge/command/bridge/deposit/erc721" "github.com/0xPolygon/polygon-edge/command/bridge/exit" - "github.com/0xPolygon/polygon-edge/command/bridge/withdraw" + withdrawERC1155 "github.com/0xPolygon/polygon-edge/command/bridge/withdraw/erc1155" + withdrawERC20 "github.com/0xPolygon/polygon-edge/command/bridge/withdraw/erc20" + withdrawERC721 "github.com/0xPolygon/polygon-edge/command/bridge/withdraw/erc721" ) // GetCommand creates "bridge" helper command @@ -22,10 +26,18 @@ func GetCommand() *cobra.Command { func registerSubcommands(baseCmd *cobra.Command) { baseCmd.AddCommand( - // bridge deposit - deposit.GetCommand(), - // bridge withdraw - withdraw.GetCommand(), + // bridge deposit-erc20 + depositERC20.GetCommand(), + // bridge deposit-erc721 + depositERC721.GetCommand(), + // bridge deposit-erc1155 + depositERC1155.GetCommand(), + // bridge withdraw-erc20 + withdrawERC20.GetCommand(), + // bridge withdraw-erc721 + withdrawERC721.GetCommand(), + // bridge withdraw-erc1155 + withdrawERC1155.GetCommand(), // bridge exit exit.GetCommand(), ) diff --git a/command/bridge/common/bridge_erc20_params.go b/command/bridge/common/bridge_erc20_params.go deleted file mode 100644 index 3840426f32..0000000000 --- a/command/bridge/common/bridge_erc20_params.go +++ /dev/null @@ -1,29 +0,0 @@ -package common - -import ( - "errors" -) - -const ( - SenderKeyFlag = "sender-key" - ReceiversFlag = "receivers" - AmountsFlag = "amounts" -) - -var ( - errInconsistentAccounts = errors.New("receivers and amounts must be equal length") -) - -type ERC20BridgeParams struct { - SenderKey string - Receivers []string - Amounts []string -} - -func (bp *ERC20BridgeParams) ValidateFlags() error { - if len(bp.Receivers) != len(bp.Amounts) { - return errInconsistentAccounts - } - - return nil -} diff --git a/command/bridge/common/params.go b/command/bridge/common/params.go new file mode 100644 index 0000000000..1bbb098dc7 --- /dev/null +++ b/command/bridge/common/params.go @@ -0,0 +1,264 @@ +package common + +import ( + "bytes" + "errors" + "fmt" + "math/big" + "strings" + + "github.com/spf13/cobra" + "github.com/umbracle/ethgo" + + cmdHelper "github.com/0xPolygon/polygon-edge/command/helper" + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" + "github.com/0xPolygon/polygon-edge/txrelayer" + "github.com/0xPolygon/polygon-edge/types" +) + +type TokenType int + +const ( + ERC20 TokenType = iota + ERC721 + ERC1155 +) + +const ( + SenderKeyFlag = "sender-key" + ReceiversFlag = "receivers" + AmountsFlag = "amounts" + TokenIDsFlag = "token-ids" + RootTokenFlag = "root-token" + RootPredicateFlag = "root-predicate" + ChildPredicateFlag = "child-predicate" + ChildTokenFlag = "child-token" + JSONRPCFlag = "json-rpc" + ChildChainMintableFlag = "child-chain-mintable" + + MinterKeyFlag = "minter-key" + MinterKeyFlagDesc = "minter key is the account which is able to mint tokens to sender account " + + "(if provided tokens are minted prior to depositing)" +) + +var ( + errInconsistentAmounts = errors.New("receivers and amounts must be equal length") + errInconsistentTokenIds = errors.New("receivers and token ids must be equal length") +) + +type BridgeParams struct { + SenderKey string + Receivers []string + TokenAddr string + PredicateAddr string + JSONRPCAddr string + ChildChainMintable bool +} + +// RegisterCommonFlags registers common bridge flags to a given command +func (p *BridgeParams) RegisterCommonFlags(cmd *cobra.Command) { + cmd.Flags().StringVar( + &p.SenderKey, + SenderKeyFlag, + "", + "hex encoded private key of the account which sends bridge transactions", + ) + + cmd.Flags().StringSliceVar( + &p.Receivers, + ReceiversFlag, + nil, + "receiving accounts addresses", + ) + + cmd.Flags().StringVar( + &p.JSONRPCAddr, + JSONRPCFlag, + txrelayer.DefaultRPCAddress, + "the JSON RPC endpoint", + ) + + cmd.Flags().BoolVar( + &p.ChildChainMintable, + ChildChainMintableFlag, + false, + "flag indicating whether tokens originate from child chain", + ) +} + +type ERC20BridgeParams struct { + *BridgeParams + Amounts []string +} + +func NewERC20BridgeParams() *ERC20BridgeParams { + return &ERC20BridgeParams{BridgeParams: &BridgeParams{}} +} + +func (bp *ERC20BridgeParams) Validate() error { + if len(bp.Receivers) != len(bp.Amounts) { + return errInconsistentAmounts + } + + return nil +} + +type ERC721BridgeParams struct { + *BridgeParams + TokenIDs []string +} + +func NewERC721BridgeParams() *ERC721BridgeParams { + return &ERC721BridgeParams{BridgeParams: &BridgeParams{}} +} + +func (bp *ERC721BridgeParams) Validate() error { + if len(bp.Receivers) != len(bp.TokenIDs) { + return errInconsistentTokenIds + } + + return nil +} + +type ERC1155BridgeParams struct { + *BridgeParams + Amounts []string + TokenIDs []string +} + +func NewERC1155BridgeParams() *ERC1155BridgeParams { + return &ERC1155BridgeParams{BridgeParams: &BridgeParams{}} +} + +func (bp *ERC1155BridgeParams) Validate() error { + if len(bp.Receivers) != len(bp.Amounts) { + return errInconsistentAmounts + } + + if len(bp.Receivers) != len(bp.TokenIDs) { + return errInconsistentTokenIds + } + + return nil +} + +// ExtractExitEventID tries to extract exit event id from provided receipt +func ExtractExitEventID(receipt *ethgo.Receipt) (*big.Int, error) { + var exitEvent contractsapi.L2StateSyncedEvent + for _, log := range receipt.Logs { + doesMatch, err := exitEvent.ParseLog(log) + if err != nil { + return nil, err + } + + if !doesMatch { + continue + } + + return exitEvent.ID, nil + } + + return nil, errors.New("failed to find exit event log") +} + +// ExtractChildTokenAddr extracts predicted deterministic child token address +func ExtractChildTokenAddr(receipt *ethgo.Receipt, childChainMintable bool) (*types.Address, error) { + var ( + l1TokenMapped contractsapi.TokenMappedEvent + l2TokenMapped contractsapi.L2MintableTokenMappedEvent + ) + + for _, log := range receipt.Logs { + if childChainMintable { + doesMatch, err := l2TokenMapped.ParseLog(log) + if err != nil { + return nil, err + } + + if !doesMatch { + continue + } + + return &l2TokenMapped.ChildToken, nil + } else { + doesMatch, err := l1TokenMapped.ParseLog(log) + if err != nil { + return nil, err + } + + if !doesMatch { + continue + } + + return &l1TokenMapped.ChildToken, nil + } + } + + return nil, nil +} + +type BridgeTxResult struct { + Sender string `json:"sender"` + Receivers []string `json:"receivers"` + ExitEventIDs []*big.Int `json:"exitEventIDs"` + Amounts []string `json:"amounts"` + TokenIDs []string `json:"tokenIds"` + BlockNumbers []uint64 `json:"blockNumbers"` + ChildTokenAddr *types.Address `json:"childTokenAddr"` + + Title string `json:"title"` +} + +func (r *BridgeTxResult) GetOutput() string { + var buffer bytes.Buffer + + vals := make([]string, 0, 7) + vals = append(vals, fmt.Sprintf("Sender|%s", r.Sender)) + vals = append(vals, fmt.Sprintf("Receivers|%s", strings.Join(r.Receivers, ", "))) + + if len(r.Amounts) > 0 { + vals = append(vals, fmt.Sprintf("Amounts|%s", strings.Join(r.Amounts, ", "))) + } + + if len(r.TokenIDs) > 0 { + vals = append(vals, fmt.Sprintf("Token Ids|%s", strings.Join(r.TokenIDs, ", "))) + } + + if len(r.ExitEventIDs) > 0 { + var buf bytes.Buffer + + for i, id := range r.ExitEventIDs { + buf.WriteString(id.String()) + + if i != len(r.ExitEventIDs)-1 { + buf.WriteString(", ") + } + } + + vals = append(vals, fmt.Sprintf("Exit Event IDs|%s", buf.String())) + } + + if len(r.BlockNumbers) > 0 { + var buf bytes.Buffer + + for i, blockNum := range r.BlockNumbers { + buf.WriteString(fmt.Sprintf("%d", blockNum)) + + if i != len(r.BlockNumbers)-1 { + buf.WriteString(", ") + } + } + + vals = append(vals, fmt.Sprintf("Inclusion Block Numbers|%s", buf.String())) + } + + if r.ChildTokenAddr != nil { + vals = append(vals, fmt.Sprintf("Child Token Address|%s", (*r.ChildTokenAddr).String())) + } + + _, _ = buffer.WriteString(fmt.Sprintf("\n[%s]\n", r.Title)) + _, _ = buffer.WriteString(cmdHelper.FormatKV(vals)) + _, _ = buffer.WriteString("\n") + + return buffer.String() +} diff --git a/command/bridge/deposit/deposit_erc20.go b/command/bridge/deposit/deposit_erc20.go deleted file mode 100644 index c85b6e0b11..0000000000 --- a/command/bridge/deposit/deposit_erc20.go +++ /dev/null @@ -1,327 +0,0 @@ -package deposit - -import ( - "bytes" - "fmt" - "math/big" - "strings" - - "github.com/spf13/cobra" - "github.com/umbracle/ethgo" - "golang.org/x/sync/errgroup" - - "github.com/0xPolygon/polygon-edge/command" - "github.com/0xPolygon/polygon-edge/command/bridge/common" - cmdHelper "github.com/0xPolygon/polygon-edge/command/helper" - "github.com/0xPolygon/polygon-edge/command/rootchain/helper" - "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" - "github.com/0xPolygon/polygon-edge/txrelayer" - "github.com/0xPolygon/polygon-edge/types" -) - -const ( - rootTokenFlag = "root-token" - rootPredicateFlag = "root-predicate" - jsonRPCFlag = "json-rpc" -) - -type depositERC20Params struct { - *common.ERC20BridgeParams - rootTokenAddr string - rootPredicateAddr string - jsonRPCAddress string - testMode bool -} - -var ( - // depositParams is abstraction for provided bridge parameter values - dp *depositERC20Params = &depositERC20Params{ERC20BridgeParams: &common.ERC20BridgeParams{}} -) - -// GetCommand returns the bridge deposit command -func GetCommand() *cobra.Command { - depositCmd := &cobra.Command{ - Use: "deposit-erc20", - Short: "Deposits ERC20 tokens from the root chain to the child chain", - PreRunE: runPreRun, - Run: runCommand, - } - - depositCmd.Flags().StringVar( - &dp.SenderKey, - common.SenderKeyFlag, - "", - "hex encoded private key of the account which sends rootchain deposit transactions", - ) - - depositCmd.Flags().StringSliceVar( - &dp.Receivers, - common.ReceiversFlag, - nil, - "receiving accounts addresses on child chain", - ) - - depositCmd.Flags().StringSliceVar( - &dp.Amounts, - common.AmountsFlag, - nil, - "amounts to send to receiving accounts", - ) - - depositCmd.Flags().StringVar( - &dp.rootTokenAddr, - rootTokenFlag, - "", - "root ERC20 token address", - ) - - depositCmd.Flags().StringVar( - &dp.rootPredicateAddr, - rootPredicateFlag, - "", - "root ERC20 token predicate address", - ) - - depositCmd.Flags().StringVar( - &dp.jsonRPCAddress, - jsonRPCFlag, - "http://127.0.0.1:8545", - "the JSON RPC root chain endpoint", - ) - - depositCmd.Flags().BoolVar( - &dp.testMode, - helper.TestModeFlag, - false, - "test indicates whether depositor is hardcoded test account "+ - "(in that case tokens are minted to it, so it is able to make deposits)", - ) - - _ = depositCmd.MarkFlagRequired(common.ReceiversFlag) - _ = depositCmd.MarkFlagRequired(common.AmountsFlag) - _ = depositCmd.MarkFlagRequired(rootTokenFlag) - _ = depositCmd.MarkFlagRequired(rootPredicateFlag) - - depositCmd.MarkFlagsMutuallyExclusive(helper.TestModeFlag, common.SenderKeyFlag) - - return depositCmd -} - -func runPreRun(cmd *cobra.Command, _ []string) error { - if err := dp.ValidateFlags(); err != nil { - return err - } - - return nil -} - -func runCommand(cmd *cobra.Command, _ []string) { - outputter := command.InitializeOutputter(cmd) - defer outputter.WriteOutput() - - depositorKey, err := helper.GetRootchainPrivateKey(dp.SenderKey) - if err != nil { - outputter.SetError(fmt.Errorf("failed to initialize depositor private key: %w", err)) - } - - depositorAddr := depositorKey.Address() - - txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(dp.jsonRPCAddress)) - if err != nil { - outputter.SetError(fmt.Errorf("failed to initialize rootchain tx relayer: %w", err)) - - return - } - - amounts := make([]*big.Int, len(dp.Amounts)) - aggregateAmount := new(big.Int) - - for i, amountRaw := range dp.Amounts { - amountRaw := amountRaw - - amount, err := types.ParseUint256orHex(&amountRaw) - if err != nil { - outputter.SetError(fmt.Errorf("failed to decode provided amount %s: %w", amount, err)) - - return - } - - amounts[i] = amount - aggregateAmount.Add(aggregateAmount, amount) - } - - if dp.testMode { - // mint tokens to depositor, so he is able to send them - mintTxn, err := createMintTxn(types.Address(depositorAddr), types.Address(depositorAddr), aggregateAmount) - if err != nil { - outputter.SetError(fmt.Errorf("mint transaction creation failed: %w", err)) - - return - } - - receipt, err := txRelayer.SendTransaction(mintTxn, depositorKey) - if err != nil { - outputter.SetError(fmt.Errorf("failed to send mint transaction to depositor %s", depositorAddr)) - - return - } - - if receipt.Status == uint64(types.ReceiptFailed) { - outputter.SetError(fmt.Errorf("failed to mint tokens to depositor %s", depositorAddr)) - - return - } - } - - // approve root erc20 predicate - approveTxn, err := createApproveERC20PredicateTxn(aggregateAmount, - types.StringToAddress(dp.rootPredicateAddr), - types.StringToAddress(dp.rootTokenAddr)) - if err != nil { - outputter.SetError(fmt.Errorf("failed to create root erc20 approve transaction: %w", err)) - - return - } - - receipt, err := txRelayer.SendTransaction(approveTxn, depositorKey) - if err != nil { - outputter.SetError(fmt.Errorf("failed to send root erc20 approve transaction")) - - return - } - - if receipt.Status == uint64(types.ReceiptFailed) { - outputter.SetError(fmt.Errorf("failed to approve root erc20 predicate")) - - return - } - - g, ctx := errgroup.WithContext(cmd.Context()) - - for i := range dp.Receivers { - receiver := dp.Receivers[i] - amount := amounts[i] - - g.Go(func() error { - select { - case <-ctx.Done(): - return ctx.Err() - default: - // deposit tokens - depositTxn, err := createDepositTxn(types.Address(depositorAddr), types.StringToAddress(receiver), amount) - if err != nil { - return fmt.Errorf("failed to create tx input: %w", err) - } - - receipt, err = txRelayer.SendTransaction(depositTxn, depositorKey) - if err != nil { - return fmt.Errorf("receiver: %s, amount: %s, error: %w", receiver, amount, err) - } - - if receipt.Status == uint64(types.ReceiptFailed) { - return fmt.Errorf("receiver: %s, amount: %s", receiver, amount) - } - - return nil - } - }) - } - - if err = g.Wait(); err != nil { - outputter.SetError(fmt.Errorf("sending deposit transactions to the rootchain failed: %w", err)) - - return - } - - outputter.SetCommandResult(&depositERC20Result{ - Sender: depositorAddr.String(), - Receivers: dp.Receivers, - Amounts: dp.Amounts, - }) -} - -// createDepositTxn encodes parameters for deposit function on rootchain predicate contract -func createDepositTxn(sender, receiver types.Address, amount *big.Int) (*ethgo.Transaction, error) { - depositToFn := &contractsapi.DepositToRootERC20PredicateFn{ - RootToken: types.StringToAddress(dp.rootTokenAddr), - Receiver: receiver, - Amount: amount, - } - - input, err := depositToFn.EncodeAbi() - if err != nil { - return nil, fmt.Errorf("failed to encode provided parameters: %w", err) - } - - addr := ethgo.Address(types.StringToAddress(dp.rootPredicateAddr)) - - return ðgo.Transaction{ - From: ethgo.Address(sender), - To: &addr, - Input: input, - }, nil -} - -// createMintTxn encodes parameters for mint function on rootchain token contract -func createMintTxn(sender, receiver types.Address, amount *big.Int) (*ethgo.Transaction, error) { - mintFn := &contractsapi.MintRootERC20Fn{ - To: receiver, - Amount: amount, - } - - input, err := mintFn.EncodeAbi() - if err != nil { - return nil, fmt.Errorf("failed to encode provided parameters: %w", err) - } - - addr := ethgo.Address(types.StringToAddress(dp.rootTokenAddr)) - - return ðgo.Transaction{ - From: ethgo.Address(sender), - To: &addr, - Input: input, - }, nil -} - -// createApproveERC20PredicateTxn sends approve transaction -// to ERC20 token for ERC20 predicate so that it is able to spend given tokens -func createApproveERC20PredicateTxn(amount *big.Int, - rootERC20Predicate, rootERC20Token types.Address) (*ethgo.Transaction, error) { - approveFnParams := &contractsapi.ApproveRootERC20Fn{ - Spender: rootERC20Predicate, - Amount: amount, - } - - input, err := approveFnParams.EncodeAbi() - if err != nil { - return nil, fmt.Errorf("failed to encode parameters for RootERC20.approve. error: %w", err) - } - - addr := ethgo.Address(rootERC20Token) - - return ðgo.Transaction{ - To: &addr, - Input: input, - }, nil -} - -type depositERC20Result struct { - Sender string `json:"sender"` - Receivers []string `json:"receivers"` - Amounts []string `json:"amounts"` -} - -func (r *depositERC20Result) GetOutput() string { - var buffer bytes.Buffer - - vals := make([]string, 0, 3) - vals = append(vals, fmt.Sprintf("Sender|%s", r.Sender)) - vals = append(vals, fmt.Sprintf("Receivers|%s", strings.Join(r.Receivers, ", "))) - vals = append(vals, fmt.Sprintf("Amounts|%s", strings.Join(r.Amounts, ", "))) - - buffer.WriteString("\n[DEPOSIT ERC20]\n") - buffer.WriteString(cmdHelper.FormatKV(vals)) - buffer.WriteString("\n") - - return buffer.String() -} diff --git a/command/bridge/deposit/erc1155/deposit_erc1155.go b/command/bridge/deposit/erc1155/deposit_erc1155.go new file mode 100644 index 0000000000..7cfaf8cb83 --- /dev/null +++ b/command/bridge/deposit/erc1155/deposit_erc1155.go @@ -0,0 +1,312 @@ +package erc1155 + +import ( + "fmt" + "math/big" + "strings" + + "github.com/spf13/cobra" + "github.com/umbracle/ethgo" + + "github.com/0xPolygon/polygon-edge/command" + "github.com/0xPolygon/polygon-edge/command/bridge/common" + "github.com/0xPolygon/polygon-edge/command/rootchain/helper" + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" + "github.com/0xPolygon/polygon-edge/txrelayer" + "github.com/0xPolygon/polygon-edge/types" +) + +type depositERC1155Params struct { + *common.ERC1155BridgeParams + minterKey string +} + +var ( + // depositParams is abstraction for provided bridge parameter values + dp *depositERC1155Params = &depositERC1155Params{ERC1155BridgeParams: common.NewERC1155BridgeParams()} +) + +// GetCommand returns the bridge deposit command +func GetCommand() *cobra.Command { + depositCmd := &cobra.Command{ + Use: "deposit-erc1155", + Short: "Deposits ERC 1155 tokens from the origin to the destination chain", + PreRunE: preRunCommand, + Run: runCommand, + } + + dp.RegisterCommonFlags(depositCmd) + + depositCmd.Flags().StringSliceVar( + &dp.Amounts, + common.AmountsFlag, + nil, + "amounts that are sent to the receivers accounts", + ) + + depositCmd.Flags().StringSliceVar( + &dp.TokenIDs, + common.TokenIDsFlag, + nil, + "token ids that are sent to the receivers accounts", + ) + + depositCmd.Flags().StringVar( + &dp.TokenAddr, + common.RootTokenFlag, + "", + "root ERC 1155 token address", + ) + + depositCmd.Flags().StringVar( + &dp.PredicateAddr, + common.RootPredicateFlag, + "", + "root ERC 1155 token predicate address", + ) + + depositCmd.Flags().StringVar( + &dp.minterKey, + common.MinterKeyFlag, + "", + common.MinterKeyFlagDesc, + ) + + _ = depositCmd.MarkFlagRequired(common.ReceiversFlag) + _ = depositCmd.MarkFlagRequired(common.AmountsFlag) + _ = depositCmd.MarkFlagRequired(common.TokenIDsFlag) + _ = depositCmd.MarkFlagRequired(common.RootTokenFlag) + _ = depositCmd.MarkFlagRequired(common.RootPredicateFlag) + + return depositCmd +} + +func preRunCommand(_ *cobra.Command, _ []string) error { + return dp.Validate() +} + +func runCommand(cmd *cobra.Command, _ []string) { + outputter := command.InitializeOutputter(cmd) + defer outputter.WriteOutput() + + depositorKey, err := helper.DecodePrivateKey(dp.SenderKey) + if err != nil { + outputter.SetError(fmt.Errorf("failed to initialize depositor private key: %w", err)) + } + + depositorAddr := depositorKey.Address() + + txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(dp.JSONRPCAddr)) + if err != nil { + outputter.SetError(fmt.Errorf("failed to initialize tx relayer: %w", err)) + + return + } + + amounts := make([]*big.Int, len(dp.Amounts)) + tokenIDs := make([]*big.Int, len(dp.TokenIDs)) + + for i := range dp.Receivers { + amountRaw := dp.Amounts[i] + tokenIDRaw := dp.TokenIDs[i] + + amount, err := types.ParseUint256orHex(&amountRaw) + if err != nil { + outputter.SetError(fmt.Errorf("failed to decode provided amount %s: %w", amountRaw, err)) + + return + } + + amounts[i] = amount + + tokenID, err := types.ParseUint256orHex(&tokenIDRaw) + if err != nil { + outputter.SetError(fmt.Errorf("failed to decode provided token id %s: %w", tokenIDRaw, err)) + + return + } + + tokenIDs[i] = tokenID + } + + if dp.minterKey != "" { + minterKey, err := helper.DecodePrivateKey(dp.minterKey) + if err != nil { + outputter.SetError(fmt.Errorf("invalid minter key provided: %w", err)) + + return + } + + // mint tokens to depositor, so he is able to send them + mintTxn, err := createMintTxn(types.Address(depositorAddr), types.Address(depositorAddr), amounts, tokenIDs) + if err != nil { + outputter.SetError(fmt.Errorf("mint transaction creation failed: %w", err)) + + return + } + + receipt, err := txRelayer.SendTransaction(mintTxn, minterKey) + if err != nil { + outputter.SetError(fmt.Errorf("failed to send mint transaction to depositor %s", depositorAddr)) + + return + } + + if receipt.Status == uint64(types.ReceiptFailed) { + outputter.SetError(fmt.Errorf("failed to mint tokens to depositor %s", depositorAddr)) + + return + } + } + + // approve root erc1155 predicate + approveTxn, err := createApproveERC1155PredicateTxn( + types.StringToAddress(dp.PredicateAddr), + types.StringToAddress(dp.TokenAddr)) + if err != nil { + outputter.SetError(fmt.Errorf("failed to create root erc 1155 approve transaction: %w", err)) + + return + } + + receipt, err := txRelayer.SendTransaction(approveTxn, depositorKey) + if err != nil { + outputter.SetError(fmt.Errorf("failed to send root erc 1155 approve transaction")) + + return + } + + if receipt.Status == uint64(types.ReceiptFailed) { + outputter.SetError(fmt.Errorf("failed to approve root erc 1155 predicate")) + + return + } + + receivers := make([]ethgo.Address, len(dp.Receivers)) + for i, receiverRaw := range dp.Receivers { + receivers[i] = ethgo.Address(types.StringToAddress(receiverRaw)) + } + + // deposit tokens + depositTxn, err := createDepositTxn(depositorAddr, receivers, amounts, tokenIDs) + if err != nil { + outputter.SetError(fmt.Errorf("failed to create tx input: %w", err)) + + return + } + + receipt, err = txRelayer.SendTransaction(depositTxn, depositorKey) + if err != nil { + outputter.SetError(fmt.Errorf("sending deposit transactions failed (receivers: %s, amount: %s): %w", + strings.Join(dp.Receivers, ", "), strings.Join(dp.Amounts, ", "), err)) + + return + } + + if receipt.Status == uint64(types.ReceiptFailed) { + outputter.SetError(fmt.Errorf("sending deposit transactions failed (receivers: %s, amounts: %s)", + strings.Join(dp.Receivers, ", "), strings.Join(dp.Amounts, ", "))) + + return + } + + res := &common.BridgeTxResult{ + Sender: depositorAddr.String(), + Receivers: dp.Receivers, + Amounts: dp.Amounts, + TokenIDs: dp.TokenIDs, + BlockNumbers: []uint64{receipt.BlockNumber}, + Title: "DEPOSIT ERC 1155", + } + + if dp.ChildChainMintable { + exitEventID, err := common.ExtractExitEventID(receipt) + if err != nil { + outputter.SetError(fmt.Errorf("failed to extract exit event: %w", err)) + + return + } + + res.ExitEventIDs = []*big.Int{exitEventID} + } + + // populate child token address if a token is mapped alongside with deposit + childToken, err := common.ExtractChildTokenAddr(receipt, dp.ChildChainMintable) + if err != nil { + outputter.SetError(fmt.Errorf("failed to extract child token address: %w", err)) + + return + } + + res.ChildTokenAddr = childToken + + outputter.SetCommandResult(res) +} + +// createDepositTxn encodes parameters for deposit function on rootchain predicate contract +func createDepositTxn(sender ethgo.Address, receivers []ethgo.Address, + amounts, tokenIDs []*big.Int) (*ethgo.Transaction, error) { + depositBatchFn := &contractsapi.DepositBatchRootERC1155PredicateFn{ + RootToken: types.StringToAddress(dp.TokenAddr), + Receivers: receivers, + TokenIDs: tokenIDs, + Amounts: amounts, + } + + input, err := depositBatchFn.EncodeAbi() + if err != nil { + return nil, fmt.Errorf("failed to encode provided parameters: %w", err) + } + + addr := ethgo.Address(types.StringToAddress(dp.PredicateAddr)) + + return ðgo.Transaction{ + From: sender, + To: &addr, + Input: input, + }, nil +} + +// createMintTxn encodes parameters for mint function on rootchain token contract +func createMintTxn(sender, receiver types.Address, amounts, tokenIDs []*big.Int) (*ethgo.Transaction, error) { + mintFn := &contractsapi.MintBatchRootERC1155Fn{ + To: receiver, + Amounts: amounts, + IDs: tokenIDs, + } + + input, err := mintFn.EncodeAbi() + if err != nil { + return nil, fmt.Errorf("failed to encode provided parameters: %w", err) + } + + addr := ethgo.Address(types.StringToAddress(dp.TokenAddr)) + + return ðgo.Transaction{ + From: ethgo.Address(sender), + To: &addr, + Input: input, + }, nil +} + +// createApproveERC1155PredicateTxn sends approve transaction +// to ERC1155 token for ERC1155 predicate so that it is able to spend given tokens +func createApproveERC1155PredicateTxn(rootERC1155Predicate, + rootERC1155Token types.Address) (*ethgo.Transaction, error) { + approveFnParams := &contractsapi.SetApprovalForAllRootERC1155Fn{ + Operator: rootERC1155Predicate, + Approved: true, + } + + input, err := approveFnParams.EncodeAbi() + if err != nil { + return nil, fmt.Errorf("failed to encode parameters for RootERC1155.setApprovalForAll. error: %w", err) + } + + addr := ethgo.Address(rootERC1155Token) + + return ðgo.Transaction{ + To: &addr, + Input: input, + }, nil +} diff --git a/command/bridge/deposit/erc20/deposit_erc20.go b/command/bridge/deposit/erc20/deposit_erc20.go new file mode 100644 index 0000000000..48efebecf8 --- /dev/null +++ b/command/bridge/deposit/erc20/deposit_erc20.go @@ -0,0 +1,284 @@ +package erc20 + +import ( + "fmt" + "math/big" + + "github.com/spf13/cobra" + "github.com/umbracle/ethgo" + "golang.org/x/sync/errgroup" + + "github.com/0xPolygon/polygon-edge/command" + "github.com/0xPolygon/polygon-edge/command/bridge/common" + "github.com/0xPolygon/polygon-edge/command/rootchain/helper" + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" + "github.com/0xPolygon/polygon-edge/txrelayer" + "github.com/0xPolygon/polygon-edge/types" +) + +type depositERC20Params struct { + *common.ERC20BridgeParams + minterKey string +} + +var ( + // depositParams is abstraction for provided bridge parameter values + dp *depositERC20Params = &depositERC20Params{ERC20BridgeParams: common.NewERC20BridgeParams()} +) + +// GetCommand returns the bridge deposit command +func GetCommand() *cobra.Command { + depositCmd := &cobra.Command{ + Use: "deposit-erc20", + Short: "Deposits ERC 20 tokens from the origin to the destination chain", + PreRunE: preRunCommand, + Run: runCommand, + } + + dp.RegisterCommonFlags(depositCmd) + + depositCmd.Flags().StringSliceVar( + &dp.Amounts, + common.AmountsFlag, + nil, + "amounts to send to receiving accounts", + ) + + depositCmd.Flags().StringVar( + &dp.TokenAddr, + common.RootTokenFlag, + "", + "root ERC 20 token address", + ) + + depositCmd.Flags().StringVar( + &dp.PredicateAddr, + common.RootPredicateFlag, + "", + "root ERC 20 token predicate address", + ) + + depositCmd.Flags().StringVar( + &dp.minterKey, + common.MinterKeyFlag, + "", + common.MinterKeyFlagDesc, + ) + + _ = depositCmd.MarkFlagRequired(common.ReceiversFlag) + _ = depositCmd.MarkFlagRequired(common.AmountsFlag) + _ = depositCmd.MarkFlagRequired(common.RootTokenFlag) + _ = depositCmd.MarkFlagRequired(common.RootPredicateFlag) + + return depositCmd +} + +func preRunCommand(cmd *cobra.Command, _ []string) error { + return dp.Validate() +} + +func runCommand(cmd *cobra.Command, _ []string) { + outputter := command.InitializeOutputter(cmd) + defer outputter.WriteOutput() + + depositorKey, err := helper.DecodePrivateKey(dp.SenderKey) + if err != nil { + outputter.SetError(fmt.Errorf("failed to initialize depositor private key: %w", err)) + } + + depositorAddr := depositorKey.Address() + + txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(dp.JSONRPCAddr)) + if err != nil { + outputter.SetError(fmt.Errorf("failed to initialize tx relayer: %w", err)) + + return + } + + amounts := make([]*big.Int, len(dp.Amounts)) + aggregateAmount := new(big.Int) + + for i, amountRaw := range dp.Amounts { + amountRaw := amountRaw + + amount, err := types.ParseUint256orHex(&amountRaw) + if err != nil { + outputter.SetError(fmt.Errorf("failed to decode provided amount %s: %w", amountRaw, err)) + + return + } + + amounts[i] = amount + aggregateAmount.Add(aggregateAmount, amount) + } + + if dp.minterKey != "" { + minterKey, err := helper.DecodePrivateKey(dp.minterKey) + if err != nil { + outputter.SetError(fmt.Errorf("invalid minter key provided: %w", err)) + + return + } + + // mint tokens to depositor, so he is able to send them + mintTxn, err := helper.CreateMintTxn(types.Address(depositorAddr), + types.StringToAddress(dp.TokenAddr), aggregateAmount) + if err != nil { + outputter.SetError(fmt.Errorf("mint transaction creation failed: %w", err)) + + return + } + + receipt, err := txRelayer.SendTransaction(mintTxn, minterKey) + if err != nil { + outputter.SetError(fmt.Errorf("failed to send mint transaction to depositor %s", depositorAddr)) + + return + } + + if receipt.Status == uint64(types.ReceiptFailed) { + outputter.SetError(fmt.Errorf("failed to mint tokens to depositor %s", depositorAddr)) + + return + } + } + + // approve erc20 predicate + approveTxn, err := helper.CreateApproveERC20Txn(aggregateAmount, + types.StringToAddress(dp.PredicateAddr), + types.StringToAddress(dp.TokenAddr)) + if err != nil { + outputter.SetError(fmt.Errorf("failed to create root erc 20 approve transaction: %w", err)) + + return + } + + receipt, err := txRelayer.SendTransaction(approveTxn, depositorKey) + if err != nil { + outputter.SetError(fmt.Errorf("failed to send root erc 20 approve transaction")) + + return + } + + if receipt.Status == uint64(types.ReceiptFailed) { + outputter.SetError(fmt.Errorf("failed to approve root erc 20 predicate")) + + return + } + + type bridgeTxData struct { + exitEventID *big.Int + blockNumber uint64 + childTokenAddr *types.Address + } + + g, ctx := errgroup.WithContext(cmd.Context()) + bridgeTxCh := make(chan bridgeTxData, len(dp.Receivers)) + exitEventIDs := make([]*big.Int, 0, len(dp.Receivers)) + blockNumbers := make([]uint64, 0, len(dp.Receivers)) + + for i := range dp.Receivers { + receiver := dp.Receivers[i] + amount := amounts[i] + + g.Go(func() error { + select { + case <-ctx.Done(): + return ctx.Err() + default: + // deposit tokens + depositTxn, err := createDepositTxn(types.Address(depositorAddr), types.StringToAddress(receiver), amount) + if err != nil { + return fmt.Errorf("failed to create tx input: %w", err) + } + + receipt, err = txRelayer.SendTransaction(depositTxn, depositorKey) + if err != nil { + return fmt.Errorf("receiver: %s, amount: %s, error: %w", receiver, amount, err) + } + + if receipt.Status == uint64(types.ReceiptFailed) { + return fmt.Errorf("receiver: %s, amount: %s", receiver, amount) + } + + var exitEventID *big.Int + + if dp.ChildChainMintable { + if exitEventID, err = common.ExtractExitEventID(receipt); err != nil { + return fmt.Errorf("failed to extract exit event: %w", err) + } + } + + // populate child token address if a token is mapped alongside with deposit + childToken, err := common.ExtractChildTokenAddr(receipt, dp.ChildChainMintable) + if err != nil { + return fmt.Errorf("failed to extract child token address: %w", err) + } + + // send aggregated data to channel if everything went ok + bridgeTxCh <- bridgeTxData{ + blockNumber: receipt.BlockNumber, + exitEventID: exitEventID, + childTokenAddr: childToken, + } + + return nil + } + }) + } + + if err = g.Wait(); err != nil { + outputter.SetError(fmt.Errorf("sending deposit transactions failed: %w", err)) + + return + } + + close(bridgeTxCh) + + var childToken *types.Address + + for x := range bridgeTxCh { + if x.exitEventID != nil { + exitEventIDs = append(exitEventIDs, x.exitEventID) + } + + blockNumbers = append(blockNumbers, x.blockNumber) + + if x.childTokenAddr != nil { + childToken = x.childTokenAddr + } + } + + outputter.SetCommandResult( + &common.BridgeTxResult{ + Sender: depositorAddr.String(), + Receivers: dp.Receivers, + Amounts: dp.Amounts, + ExitEventIDs: exitEventIDs, + ChildTokenAddr: childToken, + BlockNumbers: blockNumbers, + Title: "DEPOSIT ERC 20", + }) +} + +// createDepositTxn encodes parameters for deposit function on rootchain predicate contract +func createDepositTxn(sender, receiver types.Address, amount *big.Int) (*ethgo.Transaction, error) { + depositToFn := &contractsapi.DepositToRootERC20PredicateFn{ + RootToken: types.StringToAddress(dp.TokenAddr), + Receiver: receiver, + Amount: amount, + } + + input, err := depositToFn.EncodeAbi() + if err != nil { + return nil, fmt.Errorf("failed to encode provided parameters: %w", err) + } + + addr := ethgo.Address(types.StringToAddress(dp.PredicateAddr)) + + return ðgo.Transaction{ + From: ethgo.Address(sender), + To: &addr, + Input: input, + }, nil +} diff --git a/command/bridge/deposit/erc721/deposit_erc721.go b/command/bridge/deposit/erc721/deposit_erc721.go new file mode 100644 index 0000000000..0ba42f487c --- /dev/null +++ b/command/bridge/deposit/erc721/deposit_erc721.go @@ -0,0 +1,280 @@ +package deposit + +import ( + "fmt" + "math/big" + "strings" + + "github.com/0xPolygon/polygon-edge/command" + "github.com/0xPolygon/polygon-edge/command/bridge/common" + "github.com/0xPolygon/polygon-edge/command/rootchain/helper" + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" + "github.com/0xPolygon/polygon-edge/txrelayer" + "github.com/0xPolygon/polygon-edge/types" + "github.com/spf13/cobra" + "github.com/umbracle/ethgo" +) + +type depositERC721Params struct { + *common.ERC721BridgeParams + minterKey string +} + +var ( + dp *depositERC721Params = &depositERC721Params{ERC721BridgeParams: common.NewERC721BridgeParams()} +) + +func GetCommand() *cobra.Command { + depositCmd := &cobra.Command{ + Use: "deposit-erc721", + Short: "Deposits ERC721 tokens from the origin to the destination chain", + PreRunE: preRunCommand, + Run: runCommand, + } + + dp.RegisterCommonFlags(depositCmd) + + depositCmd.Flags().StringSliceVar( + &dp.TokenIDs, + common.TokenIDsFlag, + nil, + "token ids that are sent to the receivers accounts", + ) + + depositCmd.Flags().StringVar( + &dp.TokenAddr, + common.RootTokenFlag, + "", + "root ERC 721 token address", + ) + + depositCmd.Flags().StringVar( + &dp.PredicateAddr, + common.RootPredicateFlag, + "", + "root ERC 721 token predicate address", + ) + + depositCmd.Flags().StringVar( + &dp.minterKey, + common.MinterKeyFlag, + "", + common.MinterKeyFlagDesc, + ) + + _ = depositCmd.MarkFlagRequired(common.ReceiversFlag) + _ = depositCmd.MarkFlagRequired(common.TokenIDsFlag) + _ = depositCmd.MarkFlagRequired(common.RootTokenFlag) + _ = depositCmd.MarkFlagRequired(common.RootPredicateFlag) + + return depositCmd +} + +func preRunCommand(_ *cobra.Command, _ []string) error { + return dp.Validate() +} + +func runCommand(cmd *cobra.Command, _ []string) { + outputter := command.InitializeOutputter(cmd) + defer outputter.WriteOutput() + + depositorKey, err := helper.DecodePrivateKey(dp.SenderKey) + if err != nil { + outputter.SetError(fmt.Errorf("failed to initialize depositor private key: %w", err)) + } + + depositorAddr := depositorKey.Address() + + txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(dp.JSONRPCAddr)) + if err != nil { + outputter.SetError(fmt.Errorf("failed to initialize tx relayer: %w", err)) + + return + } + + receivers := make([]ethgo.Address, len(dp.Receivers)) + tokenIDs := make([]*big.Int, len(dp.Receivers)) + + for i, tokenIDRaw := range dp.TokenIDs { + tokenIDRaw := tokenIDRaw + + tokenID, err := types.ParseUint256orHex(&tokenIDRaw) + if err != nil { + outputter.SetError(fmt.Errorf("failed to decode provided token id %s: %w", tokenIDRaw, err)) + + return + } + + receivers[i] = ethgo.Address(types.StringToAddress(dp.Receivers[i])) + tokenIDs[i] = tokenID + } + + if dp.minterKey != "" { + minterKey, err := helper.DecodePrivateKey(dp.minterKey) + if err != nil { + outputter.SetError(fmt.Errorf("invalid minter key provided: %w", err)) + + return + } + + for i := 0; i < len(tokenIDs); i++ { + mintTxn, err := createMintTxn(types.Address(depositorAddr), types.Address(depositorAddr)) + if err != nil { + outputter.SetError(fmt.Errorf("mint transaction creation failed: %w", err)) + + return + } + + receipt, err := txRelayer.SendTransaction(mintTxn, minterKey) + if err != nil { + outputter.SetError(fmt.Errorf("failed to send mint transaction to depositor %s", depositorAddr)) + + return + } + + if receipt.Status == uint64(types.ReceiptFailed) { + outputter.SetError(fmt.Errorf("failed to mint tokens to depositor %s", depositorAddr)) + + return + } + } + } + + approveTxn, err := createApproveERC721PredicateTxn(types.StringToAddress(dp.PredicateAddr), + types.StringToAddress(dp.TokenAddr)) + if err != nil { + outputter.SetError(fmt.Errorf("failed to approve predicate: %w", err)) + + return + } + + receipt, err := txRelayer.SendTransaction(approveTxn, depositorKey) + if err != nil { + outputter.SetError(fmt.Errorf("failed to send root erc 721 approve transaction")) + + return + } + + if receipt.Status == uint64(types.ReceiptFailed) { + outputter.SetError(fmt.Errorf("failed to approve root erc 721 predicate")) + + return + } + + // deposit tokens + depositTxn, err := createDepositTxn(depositorAddr, receivers, tokenIDs) + if err != nil { + outputter.SetError(fmt.Errorf("failed to create tx input: %w", err)) + + return + } + + receipt, err = txRelayer.SendTransaction(depositTxn, depositorKey) + if err != nil { + outputter.SetError(fmt.Errorf("sending deposit transactions failed (receivers: %s, tokenIDs: %s): %w", + strings.Join(dp.Receivers, ", "), strings.Join(dp.TokenIDs, ", "), err)) + + return + } + + if receipt.Status == uint64(types.ReceiptFailed) { + outputter.SetError(fmt.Errorf("sending deposit transactions failed (receivers: %s, tokenIDs: %s)", + strings.Join(dp.Receivers, ", "), strings.Join(dp.TokenIDs, ", "))) + + return + } + + res := &common.BridgeTxResult{ + Sender: depositorAddr.String(), + Receivers: dp.Receivers, + TokenIDs: dp.TokenIDs, + BlockNumbers: []uint64{receipt.BlockNumber}, + Title: "DEPOSIT ERC 721", + } + + if dp.ChildChainMintable { + exitEventID, err := common.ExtractExitEventID(receipt) + if err != nil { + outputter.SetError(fmt.Errorf("failed to extract exit event: %w", err)) + + return + } + + res.ExitEventIDs = []*big.Int{exitEventID} + } + + // populate child token address if a token is mapped alongside with deposit + childToken, err := common.ExtractChildTokenAddr(receipt, dp.ChildChainMintable) + if err != nil { + outputter.SetError(fmt.Errorf("failed to extract child token address: %w", err)) + + return + } + + res.ChildTokenAddr = childToken + + outputter.SetCommandResult(res) +} + +// createDepositTxn encodes parameters for deposit fnction on rootchain predicate contract +func createDepositTxn(sender ethgo.Address, + receivers []ethgo.Address, tokenIDs []*big.Int) (*ethgo.Transaction, error) { + depositToRoot := &contractsapi.DepositBatchRootERC721PredicateFn{ + RootToken: types.StringToAddress(dp.TokenAddr), + Receivers: receivers, + TokenIDs: tokenIDs, + } + + input, err := depositToRoot.EncodeAbi() + if err != nil { + return nil, fmt.Errorf("failed to encode provided parameters: %w", err) + } + + addr := ethgo.Address(types.StringToAddress(dp.PredicateAddr)) + + return ðgo.Transaction{ + From: sender, + To: &addr, + Input: input, + }, nil +} + +// createMintTxn encodes parameters for mint function on rootchain token contract +func createMintTxn(sender, receiver types.Address) (*ethgo.Transaction, error) { + mintFn := &contractsapi.MintRootERC721Fn{ + To: receiver, + } + + input, err := mintFn.EncodeAbi() + if err != nil { + return nil, fmt.Errorf("failed to encode provided parameters: %w", err) + } + + addr := ethgo.Address(types.StringToAddress(dp.TokenAddr)) + + return ðgo.Transaction{ + From: ethgo.Address(sender), + To: &addr, + Input: input, + }, nil +} + +// createApproveERC721PredicateTxn sends approve transaction +func createApproveERC721PredicateTxn(rootERC721Predicate, rootERC721Token types.Address) (*ethgo.Transaction, error) { + approveFnParams := &contractsapi.SetApprovalForAllRootERC721Fn{ + Operator: rootERC721Predicate, + Approved: true, + } + + input, err := approveFnParams.EncodeAbi() + if err != nil { + return nil, fmt.Errorf("failed to encode parameters for RootERC721.approve. error: %w", err) + } + + addr := ethgo.Address(rootERC721Token) + + return ðgo.Transaction{ + To: &addr, + Input: input, + }, nil +} diff --git a/command/bridge/exit/exit.go b/command/bridge/exit/exit.go index 6b5b0fe659..dc74eef0d9 100644 --- a/command/bridge/exit/exit.go +++ b/command/bridge/exit/exit.go @@ -79,7 +79,7 @@ func GetCommand() *cobra.Command { exitCmd.Flags().StringVar( &ep.rootJSONRPCAddr, rootJSONRPCFlag, - "http://127.0.0.1:8545", + txrelayer.DefaultRPCAddress, "the JSON RPC root chain endpoint", ) @@ -107,7 +107,7 @@ func run(cmd *cobra.Command, _ []string) { outputter := command.InitializeOutputter(cmd) defer outputter.WriteOutput() - senderKey, err := helper.GetRootchainPrivateKey(ep.senderKey) + senderKey, err := helper.DecodePrivateKey(ep.senderKey) if err != nil { outputter.SetError(fmt.Errorf("failed to create wallet from private key: %w", err)) @@ -218,6 +218,7 @@ func createExitTxn(sender ethgo.Address, proof types.Proof) (*ethgo.Transaction, From: sender, To: &exitHelperAddr, Input: input, + Gas: txrelayer.DefaultGasLimit, } return txn, exitEvent, err diff --git a/command/bridge/withdraw/erc1155/withdraw_erc1155.go b/command/bridge/withdraw/erc1155/withdraw_erc1155.go new file mode 100644 index 0000000000..ab1ca84d38 --- /dev/null +++ b/command/bridge/withdraw/erc1155/withdraw_erc1155.go @@ -0,0 +1,193 @@ +package erc1155 + +import ( + "encoding/hex" + "fmt" + "math/big" + "strings" + + "github.com/spf13/cobra" + "github.com/umbracle/ethgo" + "github.com/umbracle/ethgo/wallet" + + "github.com/0xPolygon/polygon-edge/command" + "github.com/0xPolygon/polygon-edge/command/bridge/common" + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" + "github.com/0xPolygon/polygon-edge/contracts" + "github.com/0xPolygon/polygon-edge/txrelayer" + "github.com/0xPolygon/polygon-edge/types" +) + +var ( + wp *common.ERC1155BridgeParams = common.NewERC1155BridgeParams() +) + +// GetCommand returns the bridge withdraw command +func GetCommand() *cobra.Command { + withdrawCmd := &cobra.Command{ + Use: "withdraw-erc1155", + Short: "Withdraws ERC 1155 tokens from the destination to the origin chain", + PreRunE: preRunCommand, + Run: runCommand, + } + + wp.RegisterCommonFlags(withdrawCmd) + + withdrawCmd.Flags().StringSliceVar( + &wp.Amounts, + common.AmountsFlag, + nil, + "amounts that are sent to the receivers accounts", + ) + + withdrawCmd.Flags().StringSliceVar( + &wp.TokenIDs, + common.TokenIDsFlag, + nil, + "token ids that are sent to the receivers accounts", + ) + + withdrawCmd.Flags().StringVar( + &wp.PredicateAddr, + common.ChildPredicateFlag, + contracts.ChildERC1155PredicateContract.String(), + "ERC 1155 child chain predicate address", + ) + + withdrawCmd.Flags().StringVar( + &wp.TokenAddr, + common.ChildTokenFlag, + contracts.ChildERC1155Contract.String(), + "ERC 1155 child chain token address", + ) + + _ = withdrawCmd.MarkFlagRequired(common.ReceiversFlag) + _ = withdrawCmd.MarkFlagRequired(common.AmountsFlag) + _ = withdrawCmd.MarkFlagRequired(common.TokenIDsFlag) + + return withdrawCmd +} + +func preRunCommand(_ *cobra.Command, _ []string) error { + return wp.Validate() +} + +func runCommand(cmd *cobra.Command, _ []string) { + outputter := command.InitializeOutputter(cmd) + defer outputter.WriteOutput() + + senderKeyRaw, err := hex.DecodeString(wp.SenderKey) + if err != nil { + outputter.SetError(fmt.Errorf("failed to decode sender private key: %w", err)) + + return + } + + senderAccount, err := wallet.NewWalletFromPrivKey(senderKeyRaw) + if err != nil { + outputter.SetError(err) + + return + } + + txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(wp.JSONRPCAddr)) + if err != nil { + outputter.SetError(fmt.Errorf("could not create child chain tx relayer: %w", err)) + + return + } + + receivers := make([]ethgo.Address, len(wp.Receivers)) + amounts := make([]*big.Int, len(wp.Receivers)) + TokenIDs := make([]*big.Int, len(wp.Receivers)) + + for i, receiverRaw := range wp.Receivers { + receivers[i] = ethgo.Address(types.StringToAddress(receiverRaw)) + amountRaw := wp.Amounts[i] + tokenIDRaw := wp.TokenIDs[i] + + amount, err := types.ParseUint256orHex(&amountRaw) + if err != nil { + outputter.SetError(fmt.Errorf("failed to decode provided amount %s: %w", amountRaw, err)) + + return + } + + tokenID, err := types.ParseUint256orHex(&tokenIDRaw) + if err != nil { + outputter.SetError(fmt.Errorf("failed to decode provided token id %s: %w", amountRaw, err)) + + return + } + + amounts[i] = amount + TokenIDs[i] = tokenID + } + + // withdraw tokens transaction + txn, err := createWithdrawTxn(receivers, amounts, TokenIDs) + if err != nil { + outputter.SetError(fmt.Errorf("failed to create tx input: %w", err)) + + return + } + + receipt, err := txRelayer.SendTransaction(txn, senderAccount) + if err != nil { + outputter.SetError(fmt.Errorf("failed to send withdrawal transaction (receivers: %s, amounts: %s, token ids: %s): %w", + strings.Join(wp.Receivers, ", "), strings.Join(wp.Amounts, ", "), strings.Join(wp.TokenIDs, ", "), err)) + + return + } + + if receipt.Status == uint64(types.ReceiptFailed) { + outputter.SetError(fmt.Errorf("failed to execute withdrawal transaction (receivers: %s, amounts: %s, token ids: %s)", + strings.Join(wp.Receivers, ", "), strings.Join(wp.Amounts, ", "), strings.Join(wp.TokenIDs, ", "))) + + return + } + + res := &common.BridgeTxResult{ + Sender: senderAccount.Address().String(), + Receivers: wp.Receivers, + Amounts: wp.Amounts, + TokenIDs: wp.TokenIDs, + BlockNumbers: []uint64{receipt.BlockNumber}, + Title: "WITHDRAW ERC 1155", + } + + if !wp.ChildChainMintable { + exitEventID, err := common.ExtractExitEventID(receipt) + if err != nil { + outputter.SetError(fmt.Errorf("failed to extract exit event: %w", err)) + + return + } + + res.ExitEventIDs = []*big.Int{exitEventID} + } + + outputter.SetCommandResult(res) +} + +// createWithdrawTxn encodes parameters for withdraw function on child chain predicate contract +func createWithdrawTxn(receivers []ethgo.Address, amounts, TokenIDs []*big.Int) (*ethgo.Transaction, error) { + withdrawFn := &contractsapi.WithdrawBatchChildERC1155PredicateFn{ + ChildToken: types.StringToAddress(wp.TokenAddr), + Receivers: receivers, + Amounts: amounts, + TokenIDs: TokenIDs, + } + + input, err := withdrawFn.EncodeAbi() + if err != nil { + return nil, fmt.Errorf("failed to encode provided parameters: %w", err) + } + + addr := ethgo.Address(types.StringToAddress(wp.PredicateAddr)) + + return ðgo.Transaction{ + To: &addr, + Input: input, + }, nil +} diff --git a/command/bridge/withdraw/erc20/withdraw_erc20.go b/command/bridge/withdraw/erc20/withdraw_erc20.go new file mode 100644 index 0000000000..422f9365a8 --- /dev/null +++ b/command/bridge/withdraw/erc20/withdraw_erc20.go @@ -0,0 +1,171 @@ +package erc20 + +import ( + "encoding/hex" + "fmt" + "math/big" + + "github.com/spf13/cobra" + "github.com/umbracle/ethgo" + "github.com/umbracle/ethgo/wallet" + + "github.com/0xPolygon/polygon-edge/command" + "github.com/0xPolygon/polygon-edge/command/bridge/common" + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" + "github.com/0xPolygon/polygon-edge/contracts" + "github.com/0xPolygon/polygon-edge/txrelayer" + "github.com/0xPolygon/polygon-edge/types" +) + +var ( + wp *common.ERC20BridgeParams = common.NewERC20BridgeParams() +) + +// GetCommand returns the bridge withdraw command +func GetCommand() *cobra.Command { + withdrawCmd := &cobra.Command{ + Use: "withdraw-erc20", + Short: "Withdraws ERC 20 tokens from the destination to the origin chain", + PreRunE: preRunCommand, + Run: runCommand, + } + + wp.RegisterCommonFlags(withdrawCmd) + + withdrawCmd.Flags().StringSliceVar( + &wp.Amounts, + common.AmountsFlag, + nil, + "amounts to send to receiving accounts", + ) + + withdrawCmd.Flags().StringVar( + &wp.PredicateAddr, + common.ChildPredicateFlag, + contracts.ChildERC20PredicateContract.String(), + "child ERC 20 predicate address", + ) + + withdrawCmd.Flags().StringVar( + &wp.TokenAddr, + common.ChildTokenFlag, + contracts.NativeERC20TokenContract.String(), + "child ERC 20 token address", + ) + + _ = withdrawCmd.MarkFlagRequired(common.ReceiversFlag) + _ = withdrawCmd.MarkFlagRequired(common.AmountsFlag) + + return withdrawCmd +} + +func preRunCommand(_ *cobra.Command, _ []string) error { + return wp.Validate() +} + +func runCommand(cmd *cobra.Command, _ []string) { + outputter := command.InitializeOutputter(cmd) + defer outputter.WriteOutput() + + senderKeyRaw, err := hex.DecodeString(wp.SenderKey) + if err != nil { + outputter.SetError(fmt.Errorf("failed to decode sender private key: %w", err)) + + return + } + + senderAccount, err := wallet.NewWalletFromPrivKey(senderKeyRaw) + if err != nil { + outputter.SetError(err) + + return + } + + txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(wp.JSONRPCAddr)) + if err != nil { + outputter.SetError(fmt.Errorf("could not create destination chain tx relayer: %w", err)) + + return + } + + exitEventIDs := make([]*big.Int, 0, len(wp.Receivers)) + blockNumbers := make([]uint64, len(wp.Receivers)) + + for i := range wp.Receivers { + receiver := wp.Receivers[i] + amount := wp.Amounts[i] + + amountBig, err := types.ParseUint256orHex(&amount) + if err != nil { + outputter.SetError(fmt.Errorf("failed to decode provided amount %s: %w", amount, err)) + + return + } + + // withdraw tokens transaction + txn, err := createWithdrawTxn(types.StringToAddress(receiver), amountBig) + if err != nil { + outputter.SetError(fmt.Errorf("failed to create tx input: %w", err)) + + return + } + + receipt, err := txRelayer.SendTransaction(txn, senderAccount) + if err != nil { + outputter.SetError(fmt.Errorf("failed to send withdraw transaction (receiver: %s, amount: %s). error: %w)", + receiver, amount, err)) + + return + } + + if receipt.Status == uint64(types.ReceiptFailed) { + outputter.SetError(fmt.Errorf("failed to execute withdrawal (receiver: %s, amount: %s)", receiver, amount)) + + return + } + + if !wp.ChildChainMintable { + exitEventID, err := common.ExtractExitEventID(receipt) + if err != nil { + outputter.SetError(fmt.Errorf("failed to extract exit event: %w", err)) + + return + } + + exitEventIDs = append(exitEventIDs, exitEventID) + } + + blockNumbers[i] = receipt.BlockNumber + } + + outputter.SetCommandResult( + &common.BridgeTxResult{ + Sender: senderAccount.Address().String(), + Receivers: wp.Receivers, + Amounts: wp.Amounts, + ExitEventIDs: exitEventIDs, + BlockNumbers: blockNumbers, + Title: "WITHDRAW ERC 20", + }) +} + +// createWithdrawTxn encodes parameters for withdraw function on destination predicate contract +func createWithdrawTxn(receiver types.Address, amount *big.Int) (*ethgo.Transaction, error) { + withdrawToFn := &contractsapi.WithdrawToChildERC20PredicateFn{ + ChildToken: types.StringToAddress(wp.TokenAddr), + Receiver: receiver, + Amount: amount, + } + + input, err := withdrawToFn.EncodeAbi() + if err != nil { + return nil, fmt.Errorf("failed to encode provided parameters: %w", err) + } + + addr := ethgo.Address(types.StringToAddress(wp.PredicateAddr)) + + return ðgo.Transaction{ + To: &addr, + Input: input, + }, nil +} diff --git a/command/bridge/withdraw/erc721/withdraw_erc721.go b/command/bridge/withdraw/erc721/withdraw_erc721.go new file mode 100644 index 0000000000..1688b2aeab --- /dev/null +++ b/command/bridge/withdraw/erc721/withdraw_erc721.go @@ -0,0 +1,171 @@ +package withdraw + +import ( + "encoding/hex" + "fmt" + "math/big" + "strings" + + "github.com/0xPolygon/polygon-edge/command" + "github.com/0xPolygon/polygon-edge/command/bridge/common" + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" + "github.com/0xPolygon/polygon-edge/contracts" + "github.com/0xPolygon/polygon-edge/txrelayer" + "github.com/0xPolygon/polygon-edge/types" + "github.com/spf13/cobra" + "github.com/umbracle/ethgo" + "github.com/umbracle/ethgo/wallet" +) + +var ( + wp *common.ERC721BridgeParams = common.NewERC721BridgeParams() +) + +func GetCommand() *cobra.Command { + withdrawCmd := &cobra.Command{ + Use: "withdraw-erc721", + Short: "Withdraws ERC 721 tokens from the destination to the origin chain", + PreRunE: preRun, + Run: run, + } + + wp.RegisterCommonFlags(withdrawCmd) + + withdrawCmd.Flags().StringSliceVar( + &wp.TokenIDs, + common.TokenIDsFlag, + nil, + "tokens ids to send to receiving accounts", + ) + + withdrawCmd.Flags().StringVar( + &wp.PredicateAddr, + common.ChildPredicateFlag, + contracts.ChildERC721PredicateContract.String(), + "ERC 721 child chain predicate address", + ) + + withdrawCmd.Flags().StringVar( + &wp.TokenAddr, + common.ChildTokenFlag, + contracts.ChildERC721Contract.String(), + "ERC 721 child chain token address", + ) + + _ = withdrawCmd.MarkFlagRequired(common.SenderKeyFlag) + _ = withdrawCmd.MarkFlagRequired(common.ReceiversFlag) + _ = withdrawCmd.MarkFlagRequired(common.TokenIDsFlag) + + return withdrawCmd +} + +func preRun(_ *cobra.Command, _ []string) error { + return wp.Validate() +} + +func run(cmd *cobra.Command, _ []string) { + outputter := command.InitializeOutputter(cmd) + defer outputter.WriteOutput() + + senderKeyRaw, err := hex.DecodeString(wp.SenderKey) + if err != nil { + outputter.SetError(fmt.Errorf("failed to decode sender private key: %w", err)) + + return + } + + senderAccount, err := wallet.NewWalletFromPrivKey(senderKeyRaw) + if err != nil { + outputter.SetError(err) + + return + } + + txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(wp.JSONRPCAddr)) + if err != nil { + outputter.SetError(fmt.Errorf("could not create child chain tx relayer: %w", err)) + + return + } + + receivers := make([]ethgo.Address, len(wp.Receivers)) + tokenIDs := make([]*big.Int, len(wp.Receivers)) + + for i, tokenIDRaw := range wp.TokenIDs { + tokenIDRaw := tokenIDRaw + + tokenID, err := types.ParseUint256orHex(&tokenIDRaw) + if err != nil { + outputter.SetError(fmt.Errorf("failed to decode provided token id %s: %w", tokenIDRaw, err)) + + return + } + + receivers[i] = ethgo.Address(types.StringToAddress(wp.Receivers[i])) + tokenIDs[i] = tokenID + } + + txn, err := createWithdrawTxn(receivers, tokenIDs) + if err != nil { + outputter.SetError(fmt.Errorf("failed to create tx input: %w", err)) + + return + } + + receipt, err := txRelayer.SendTransaction(txn, senderAccount) + if err != nil { + outputter.SetError(fmt.Errorf("failed to send withdrawal transaction (receivers: %s, token ids: %s): %w", + strings.Join(wp.Receivers, ", "), strings.Join(wp.TokenIDs, ", "), err)) + + return + } + + if receipt.Status == uint64(types.ReceiptFailed) { + outputter.SetError(fmt.Errorf("failed to execute withdrawal transaction (receivers: %s, token ids: %s)", + strings.Join(wp.Receivers, ", "), strings.Join(wp.TokenIDs, ", "))) + + return + } + + res := &common.BridgeTxResult{ + Sender: senderAccount.Address().String(), + Receivers: wp.Receivers, + TokenIDs: wp.TokenIDs, + BlockNumbers: []uint64{receipt.BlockNumber}, + Title: "WITHDRAW ERC 721", + } + + if !wp.ChildChainMintable { + exitEventID, err := common.ExtractExitEventID(receipt) + if err != nil { + outputter.SetError(fmt.Errorf("failed to extract exit event: %w", err)) + + return + } + + res.ExitEventIDs = []*big.Int{exitEventID} + } + + outputter.SetCommandResult(res) +} + +// createWithdrawTxn encodes parameters for withdraw function on child chain predicate contract +func createWithdrawTxn(receivers []ethgo.Address, tokenIDs []*big.Int) (*ethgo.Transaction, error) { + withdrawToFn := &contractsapi.WithdrawBatchChildERC721PredicateFn{ + ChildToken: types.StringToAddress(wp.TokenAddr), + Receivers: receivers, + TokenIDs: tokenIDs, + } + + input, err := withdrawToFn.EncodeAbi() + if err != nil { + return nil, fmt.Errorf("failed to encode provided parameters: %w", err) + } + + addr := ethgo.Address(types.StringToAddress(wp.PredicateAddr)) + + return ðgo.Transaction{ + To: &addr, + Input: input, + }, nil +} diff --git a/command/bridge/withdraw/withdraw_erc20.go b/command/bridge/withdraw/withdraw_erc20.go deleted file mode 100644 index 6e00c63dbb..0000000000 --- a/command/bridge/withdraw/withdraw_erc20.go +++ /dev/null @@ -1,253 +0,0 @@ -package withdraw - -import ( - "bytes" - "encoding/hex" - "errors" - "fmt" - "math/big" - "strconv" - "strings" - - "github.com/spf13/cobra" - "github.com/umbracle/ethgo" - "github.com/umbracle/ethgo/wallet" - - "github.com/0xPolygon/polygon-edge/command" - "github.com/0xPolygon/polygon-edge/command/bridge/common" - cmdHelper "github.com/0xPolygon/polygon-edge/command/helper" - "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" - "github.com/0xPolygon/polygon-edge/contracts" - "github.com/0xPolygon/polygon-edge/txrelayer" - "github.com/0xPolygon/polygon-edge/types" -) - -const ( - jsonRPCFlag = "json-rpc" - childPredicateFlag = "child-predicate" - childTokenFlag = "child-token" -) - -type withdrawParams struct { - *common.ERC20BridgeParams - childPredicateAddr string - childTokenAddr string - jsonRPCAddress string -} - -var ( - wp *withdrawParams = &withdrawParams{ - ERC20BridgeParams: &common.ERC20BridgeParams{}, - } -) - -// GetCommand returns the bridge withdraw command -func GetCommand() *cobra.Command { - withdrawCmd := &cobra.Command{ - Use: "withdraw-erc20", - Short: "Withdraws tokens from the child chain to the root chain", - PreRunE: preRun, - Run: run, - } - - withdrawCmd.Flags().StringVar( - &wp.SenderKey, - common.SenderKeyFlag, - "", - "withdraw transaction sender hex-encoded private key", - ) - - withdrawCmd.Flags().StringSliceVar( - &wp.Receivers, - common.ReceiversFlag, - nil, - "receiving accounts addresses on the root chain", - ) - - withdrawCmd.Flags().StringSliceVar( - &wp.Amounts, - common.AmountsFlag, - nil, - "amounts to send to receiving accounts", - ) - - withdrawCmd.Flags().StringVar( - &wp.childPredicateAddr, - childPredicateFlag, - contracts.ChildERC20PredicateContract.String(), - "ERC20 child chain predicate address", - ) - - withdrawCmd.Flags().StringVar( - &wp.childTokenAddr, - childTokenFlag, - contracts.NativeERC20TokenContract.String(), - "ERC20 child chain token address", - ) - - withdrawCmd.Flags().StringVar( - &wp.jsonRPCAddress, - jsonRPCFlag, - "http://127.0.0.1:9545", - "the JSON RPC child chain endpoint", - ) - - _ = withdrawCmd.MarkFlagRequired(common.ReceiversFlag) - _ = withdrawCmd.MarkFlagRequired(common.AmountsFlag) - - return withdrawCmd -} - -func preRun(cmd *cobra.Command, _ []string) error { - if err := wp.ValidateFlags(); err != nil { - return err - } - - return nil -} - -func run(cmd *cobra.Command, _ []string) { - outputter := command.InitializeOutputter(cmd) - defer outputter.WriteOutput() - - senderKeyRaw, err := hex.DecodeString(wp.SenderKey) - if err != nil { - outputter.SetError(fmt.Errorf("failed to decode sender private key: %w", err)) - - return - } - - senderAccount, err := wallet.NewWalletFromPrivKey(senderKeyRaw) - if err != nil { - outputter.SetError(err) - - return - } - - txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(wp.jsonRPCAddress)) - if err != nil { - outputter.SetError(fmt.Errorf("could not create child chain tx relayer: %w", err)) - - return - } - - exitEventIDs := make([]string, len(wp.Receivers)) - blockNumbers := make([]string, len(wp.Receivers)) - - for i := range wp.Receivers { - receiver := wp.Receivers[i] - amount := wp.Amounts[i] - - amountBig, err := types.ParseUint256orHex(&amount) - if err != nil { - outputter.SetError(fmt.Errorf("failed to decode provided amount %s: %w", amount, err)) - - return - } - - // withdraw tokens transaction - txn, err := createWithdrawTxn(types.StringToAddress(receiver), amountBig) - if err != nil { - outputter.SetError(fmt.Errorf("failed to create tx input: %w", err)) - - return - } - - receipt, err := txRelayer.SendTransaction(txn, senderAccount) - if err != nil { - outputter.SetError(fmt.Errorf("receiver: %s, amount: %s, error: %w", receiver, amount, err)) - - return - } - - if receipt.Status == uint64(types.ReceiptFailed) { - outputter.SetError(fmt.Errorf("receiver: %s, amount: %s", receiver, amount)) - - return - } - - exitEventID, err := extractExitEventID(receipt) - if err != nil { - outputter.SetError(fmt.Errorf("failed to extract exit event: %w", err)) - - return - } - - exitEventIDs[i] = strconv.FormatUint(exitEventID.Uint64(), 10) - blockNumbers[i] = strconv.FormatUint(receipt.BlockNumber, 10) - } - - outputter.SetCommandResult( - &withdrawERC20Result{ - Sender: senderAccount.Address().String(), - Receivers: wp.Receivers, - Amounts: wp.Amounts, - ExitEventIDs: exitEventIDs, - BlockNumbers: blockNumbers, - }) -} - -// createWithdrawTxn encodes parameters for withdraw function on child chain predicate contract -func createWithdrawTxn(receiver types.Address, amount *big.Int) (*ethgo.Transaction, error) { - withdrawToFn := &contractsapi.WithdrawToChildERC20PredicateFn{ - ChildToken: types.StringToAddress(wp.childTokenAddr), - Receiver: receiver, - Amount: amount, - } - - input, err := withdrawToFn.EncodeAbi() - if err != nil { - return nil, fmt.Errorf("failed to encode provided parameters: %w", err) - } - - addr := ethgo.Address(types.StringToAddress(wp.childPredicateAddr)) - - return ðgo.Transaction{ - To: &addr, - Input: input, - }, nil -} - -// extractExitEventID tries to extract exit event id from provided receipt -func extractExitEventID(receipt *ethgo.Receipt) (*big.Int, error) { - var exitEvent contractsapi.L2StateSyncedEvent - for _, log := range receipt.Logs { - doesMatch, err := exitEvent.ParseLog(log) - if !doesMatch { - continue - } - - if err != nil { - return nil, err - } - - return exitEvent.ID, nil - } - - return nil, errors.New("failed to find exit event log") -} - -type withdrawERC20Result struct { - Sender string `json:"sender"` - Receivers []string `json:"receivers"` - Amounts []string `json:"amounts"` - ExitEventIDs []string `json:"exitEventIDs"` - BlockNumbers []string `json:"blockNumbers"` -} - -func (r *withdrawERC20Result) GetOutput() string { - var buffer bytes.Buffer - - vals := make([]string, 0, 5) - vals = append(vals, fmt.Sprintf("Sender|%s", r.Sender)) - vals = append(vals, fmt.Sprintf("Receivers|%s", strings.Join(r.Receivers, ", "))) - vals = append(vals, fmt.Sprintf("Amounts|%s", strings.Join(r.Amounts, ", "))) - vals = append(vals, fmt.Sprintf("Exit Event IDs|%s", strings.Join(r.ExitEventIDs, ", "))) - vals = append(vals, fmt.Sprintf("Inclusion Block Numbers|%s", strings.Join(r.BlockNumbers, ", "))) - - buffer.WriteString("\n[WITHDRAW ERC20]\n") - buffer.WriteString(cmdHelper.FormatKV(vals)) - buffer.WriteString("\n") - - return buffer.String() -} diff --git a/command/default.go b/command/default.go index 6ba242fa25..ab6af9d7d4 100644 --- a/command/default.go +++ b/command/default.go @@ -1,22 +1,26 @@ package command import ( - "github.com/0xPolygon/polygon-edge/server" "github.com/umbracle/ethgo" + + "github.com/0xPolygon/polygon-edge/chain" + "github.com/0xPolygon/polygon-edge/server" ) const ( - DefaultGenesisFileName = "genesis.json" - DefaultChainName = "polygon-edge" - DefaultChainID = 100 - DefaultConsensus = server.PolyBFTConsensus - DefaultGenesisGasUsed = 458752 // 0x70000 - DefaultGenesisGasLimit = 5242880 // 0x500000 + DefaultGenesisFileName = "genesis.json" + DefaultChainName = "polygon-edge" + DefaultChainID = 100 + DefaultConsensus = server.PolyBFTConsensus + DefaultGenesisGasUsed = 458752 // 0x70000 + DefaultGenesisGasLimit = 5242880 // 0x500000 + DefaultGenesisBaseFeeEM = chain.GenesisBaseFeeEM ) var ( DefaultStake = ethgo.Ether(1e6) DefaultPremineBalance = ethgo.Ether(1e6) + DefaultGenesisBaseFee = chain.GenesisBaseFee ) const ( diff --git a/command/genesis/genesis.go b/command/genesis/genesis.go index db737161d1..bf455956db 100644 --- a/command/genesis/genesis.go +++ b/command/genesis/genesis.go @@ -16,12 +16,10 @@ func GetCommand() *cobra.Command { genesisCmd := &cobra.Command{ Use: "genesis", Short: "Generates the genesis configuration file with the passed in parameters", - PreRunE: runPreRun, + PreRunE: preRunCommand, Run: runCommand, } - helper.RegisterGRPCAddressFlag(genesisCmd) - setFlags(genesisCmd) setLegacyFlags(genesisCmd) @@ -45,7 +43,7 @@ func setFlags(cmd *cobra.Command) { ¶ms.chainID, chainIDFlag, command.DefaultChainID, - "the ID of the chain", + "the ID of the chain (only used for IBFT consensus)", ) cmd.Flags().StringVar( @@ -60,7 +58,7 @@ func setFlags(cmd *cobra.Command) { premineFlag, []string{}, fmt.Sprintf( - "the premined accounts and balances (format:
:). Default premined balance: %d", + "the premined accounts and balances (format:
[:]). Default premined balance: %d", command.DefaultPremineBalance, ), ) @@ -72,6 +70,13 @@ func setFlags(cmd *cobra.Command) { "the maximum amount of gas used by all transactions in a block", ) + cmd.Flags().StringVar( + ¶ms.burnContract, + burnContractFlag, + "", + "the burn contract block and address (format: :
[:])", + ) + cmd.Flags().StringArrayVar( ¶ms.bootnodes, command.BootnodeFlag, @@ -150,19 +155,29 @@ func setFlags(cmd *cobra.Command) { // PolyBFT { cmd.Flags().StringVar( - ¶ms.manifestPath, - manifestPathFlag, - defaultManifestPath, - "the manifest file path, which contains genesis metadata", + ¶ms.validatorsPath, + validatorsPathFlag, + "./", + "root path containing polybft validators secrets", ) - cmd.Flags().IntVar( - ¶ms.validatorSetSize, - validatorSetSizeFlag, - defaultValidatorSetSize, - "the total number of validators", + cmd.Flags().StringVar( + ¶ms.validatorsPrefixPath, + validatorsPrefixFlag, + defaultValidatorPrefixPath, + "folder prefix names for polybft validators secrets", + ) + + cmd.Flags().StringArrayVar( + ¶ms.validators, + validatorsFlag, + []string{}, + "validators defined by user (format: ::)", ) + cmd.MarkFlagsMutuallyExclusive(validatorsFlag, validatorsPathFlag) + cmd.MarkFlagsMutuallyExclusive(validatorsFlag, validatorsPrefixFlag) + cmd.Flags().Uint64Var( ¶ms.sprintSize, sprintSizeFlag, @@ -177,13 +192,6 @@ func setFlags(cmd *cobra.Command) { "the predefined period which determines block creation frequency", ) - cmd.Flags().StringVar( - ¶ms.bridgeJSONRPCAddr, - bridgeFlag, - "", - "the rootchain JSON RPC endpoint", - ) - cmd.Flags().Uint64Var( ¶ms.epochReward, epochRewardFlag, @@ -191,15 +199,7 @@ func setFlags(cmd *cobra.Command) { "reward size for block sealing", ) - cmd.Flags().StringArrayVar( - ¶ms.eventTrackerStartBlocks, - trackerStartBlocksFlag, - []string{}, - "event tracker starting block configuration, which is specified per contract address "+ - "(format: :)", - ) - - //Regenesis flag that allows to start from non-empty database + // regenesis flag that allows to start from non-empty database cmd.Flags().StringVar( ¶ms.initialStateRoot, trieRootFlag, @@ -207,29 +207,121 @@ func setFlags(cmd *cobra.Command) { "trie root from the corresponding triedb", ) - cmd.Flags().BoolVar( - ¶ms.mintableNativeToken, - mintableTokenFlag, - false, - "flag indicate whether mintable or non-mintable native ERC20 token is deployed", + cmd.Flags().StringVar( + ¶ms.nativeTokenConfigRaw, + nativeTokenConfigFlag, + "", + "native token configuration, provided in the following format: "+ + "", + ) + + cmd.Flags().StringVar( + ¶ms.rewardTokenCode, + rewardTokenCodeFlag, + "", + "hex encoded reward token byte code", + ) + + cmd.Flags().StringVar( + ¶ms.rewardWallet, + rewardWalletFlag, + "", + "configuration of reward wallet in format ", + ) + + cmd.Flags().Uint64Var( + ¶ms.blockTimeDrift, + blockTimeDriftFlag, + defaultBlockTimeDrift, + "configuration for block time drift value (in seconds)", ) } - // Allow list + // Access Control Lists { cmd.Flags().StringArrayVar( ¶ms.contractDeployerAllowListAdmin, - contractDeployedAllowListAdminFlag, + contractDeployerAllowListAdminFlag, []string{}, "list of addresses to use as admin accounts in the contract deployer allow list", ) cmd.Flags().StringArrayVar( ¶ms.contractDeployerAllowListEnabled, - contractDeployedAllowListEnabledFlag, + contractDeployerAllowListEnabledFlag, []string{}, "list of addresses to enable by default in the contract deployer allow list", ) + + cmd.Flags().StringArrayVar( + ¶ms.contractDeployerBlockListAdmin, + contractDeployerBlockListAdminFlag, + []string{}, + "list of addresses to use as admin accounts in the contract deployer block list", + ) + + cmd.Flags().StringArrayVar( + ¶ms.contractDeployerBlockListEnabled, + contractDeployerBlockListEnabledFlag, + []string{}, + "list of addresses to enable by default in the contract deployer block list", + ) + + cmd.Flags().StringArrayVar( + ¶ms.transactionsAllowListAdmin, + transactionsAllowListAdminFlag, + []string{}, + "list of addresses to use as admin accounts in the transactions allow list", + ) + + cmd.Flags().StringArrayVar( + ¶ms.transactionsAllowListEnabled, + transactionsAllowListEnabledFlag, + []string{}, + "list of addresses to enable by default in the transactions allow list", + ) + + cmd.Flags().StringArrayVar( + ¶ms.transactionsBlockListAdmin, + transactionsBlockListAdminFlag, + []string{}, + "list of addresses to use as admin accounts in the transactions block list", + ) + + cmd.Flags().StringArrayVar( + ¶ms.transactionsBlockListEnabled, + transactionsBlockListEnabledFlag, + []string{}, + "list of addresses to enable by default in the transactions block list", + ) + + cmd.Flags().StringArrayVar( + ¶ms.bridgeAllowListAdmin, + bridgeAllowListAdminFlag, + []string{}, + "list of addresses to use as admin accounts in the bridge allow list", + ) + + cmd.Flags().StringArrayVar( + ¶ms.bridgeAllowListEnabled, + bridgeAllowListEnabledFlag, + []string{}, + "list of addresses to enable by default in the bridge allow list", + ) + + cmd.Flags().StringArrayVar( + ¶ms.bridgeBlockListAdmin, + bridgeBlockListAdminFlag, + []string{}, + "list of addresses to use as admin accounts in the bridge block list", + ) + + cmd.Flags().StringArrayVar( + ¶ms.bridgeBlockListEnabled, + bridgeBlockListEnabledFlag, + []string{}, + "list of addresses to enable by default in the bridge block list", + ) } } @@ -241,13 +333,13 @@ func setLegacyFlags(cmd *cobra.Command) { ¶ms.chainID, chainIDFlagLEGACY, command.DefaultChainID, - "the ID of the chain (not-applicable for Polybft consensus protocol as chain id is defined in manifest.json)", + "the ID of the chain", ) _ = cmd.Flags().MarkHidden(chainIDFlagLEGACY) } -func runPreRun(cmd *cobra.Command, _ []string) error { +func preRunCommand(cmd *cobra.Command, _ []string) error { if err := params.validateFlags(); err != nil { return err } diff --git a/command/genesis/params.go b/command/genesis/params.go index 7ba94efa8b..3524a6712f 100644 --- a/command/genesis/params.go +++ b/command/genesis/params.go @@ -3,6 +3,11 @@ package genesis import ( "errors" "fmt" + "math" + "math/big" + "os" + "strconv" + "strings" "time" "github.com/0xPolygon/polygon-edge/chain" @@ -11,6 +16,7 @@ import ( "github.com/0xPolygon/polygon-edge/consensus/ibft" "github.com/0xPolygon/polygon-edge/consensus/ibft/fork" "github.com/0xPolygon/polygon-edge/consensus/ibft/signer" + "github.com/0xPolygon/polygon-edge/consensus/polybft" "github.com/0xPolygon/polygon-edge/contracts/staking" stakingHelper "github.com/0xPolygon/polygon-edge/helper/staking" "github.com/0xPolygon/polygon-edge/server" @@ -19,17 +25,25 @@ import ( ) const ( - dirFlag = "dir" - nameFlag = "name" - premineFlag = "premine" - chainIDFlag = "chain-id" - epochSizeFlag = "epoch-size" - epochRewardFlag = "epoch-reward" - blockGasLimitFlag = "block-gas-limit" - posFlag = "pos" - minValidatorCount = "min-validator-count" - maxValidatorCount = "max-validator-count" - mintableTokenFlag = "mintable-native-token" + dirFlag = "dir" + nameFlag = "name" + premineFlag = "premine" + chainIDFlag = "chain-id" + epochSizeFlag = "epoch-size" + epochRewardFlag = "epoch-reward" + blockGasLimitFlag = "block-gas-limit" + burnContractFlag = "burn-contract" + posFlag = "pos" + minValidatorCount = "min-validator-count" + maxValidatorCount = "max-validator-count" + nativeTokenConfigFlag = "native-token-config" + rewardTokenCodeFlag = "reward-token-code" + rewardWalletFlag = "reward-wallet" + + defaultNativeTokenName = "Polygon" + defaultNativeTokenSymbol = "MATIC" + defaultNativeTokenDecimals = uint8(18) + minNativeTokenParamsNumber = 4 ) // Legacy flags that need to be preserved for running clients @@ -45,6 +59,9 @@ var ( errValidatorsNotSpecified = errors.New("validator information not specified") errUnsupportedConsensus = errors.New("specified consensusRaw not supported") errInvalidEpochSize = errors.New("epoch size must be greater than 1") + errInvalidTokenParams = errors.New("native token params were not submitted in proper format " + + "()") + errRewardWalletAmountZero = errors.New("reward wallet amount can not be zero or negative") ) type genesisParams struct { @@ -64,6 +81,8 @@ type genesisParams struct { blockGasLimit uint64 isPos bool + burnContract string + minNumValidators uint64 maxNumValidators uint64 @@ -78,20 +97,36 @@ type genesisParams struct { genesisConfig *chain.Chain // PolyBFT - manifestPath string - validatorSetSize int - sprintSize uint64 - blockTime time.Duration - bridgeJSONRPCAddr string - epochReward uint64 - eventTrackerStartBlocks []string + validatorsPath string + validatorsPrefixPath string + validators []string + sprintSize uint64 + blockTime time.Duration + epochReward uint64 + blockTimeDrift uint64 initialStateRoot string - // allowlist + // access lists contractDeployerAllowListAdmin []string contractDeployerAllowListEnabled []string - mintableNativeToken bool + contractDeployerBlockListAdmin []string + contractDeployerBlockListEnabled []string + transactionsAllowListAdmin []string + transactionsAllowListEnabled []string + transactionsBlockListAdmin []string + transactionsBlockListEnabled []string + bridgeAllowListAdmin []string + bridgeAllowListEnabled []string + bridgeBlockListAdmin []string + bridgeBlockListEnabled []string + + nativeTokenConfigRaw string + nativeTokenConfig *polybft.TokenConfig + + // rewards + rewardTokenCode string + rewardWallet string } func (p *genesisParams) validateFlags() error { @@ -107,6 +142,20 @@ func (p *genesisParams) validateFlags() error { return errValidatorsNotSpecified } + if p.isPolyBFTConsensus() { + if err := p.extractNativeTokenMetadata(); err != nil { + return err + } + + if err := p.validateBurnContract(); err != nil { + return err + } + + if err := p.validateRewardWallet(); err != nil { + return err + } + } + // Check if the genesis file already exists if generateError := verifyGenesisExistence(p.genesisPath); generateError != nil { return errors.New(generateError.GetMessage()) @@ -120,12 +169,15 @@ func (p *genesisParams) validateFlags() error { return errInvalidEpochSize } - // Validate min and max validators number - if err := command.ValidateMinMaxValidatorsNumber(p.minNumValidators, p.maxNumValidators); err != nil { - return err + // Validate validatorsPath only if validators information were not provided via CLI flag + if len(p.validators) == 0 { + if _, err := os.Stat(p.validatorsPath); err != nil { + return fmt.Errorf("invalid validators path ('%s') provided. Error: %w", p.validatorsPath, err) + } } - return nil + // Validate min and max validators number + return command.ValidateMinMaxValidatorsNumber(p.minNumValidators, p.maxNumValidators) } func (p *genesisParams) isIBFTConsensus() bool { @@ -296,6 +348,7 @@ func (p *genesisParams) initIBFTEngineMap(ibftType fork.IBFTType) { string(server.IBFTConsensus): map[string]interface{}{ fork.KeyType: ibftType, fork.KeyValidatorType: p.ibftValidatorType, + fork.KeyBlockTime: p.blockTime, ibft.KeyEpochSize: p.epochSize, }, } @@ -317,6 +370,12 @@ func (p *genesisParams) generateGenesis() error { } func (p *genesisParams) initGenesisConfig() error { + // Disable london hardfork if burn contract address is not provided + enabledForks := chain.AllForksEnabled + if !p.isBurnContractEnabled() { + enabledForks.RemoveFork(chain.London) + } + chainConfig := &chain.Chain{ Name: p.name, Genesis: &chain.Genesis{ @@ -328,12 +387,27 @@ func (p *genesisParams) initGenesisConfig() error { }, Params: &chain.Params{ ChainID: int64(p.chainID), - Forks: chain.AllForksEnabled, + Forks: enabledForks, Engine: p.consensusEngineConfig, }, Bootnodes: p.bootnodes, } + // burn contract can be set only for non mintable native token + if p.isBurnContractEnabled() { + chainConfig.Genesis.BaseFee = command.DefaultGenesisBaseFee + chainConfig.Genesis.BaseFeeEM = command.DefaultGenesisBaseFeeEM + chainConfig.Params.BurnContract = make(map[uint64]types.Address, 1) + + burnContractInfo, err := parseBurnContractInfo(p.burnContract) + if err != nil { + return err + } + + chainConfig.Params.BurnContract[burnContractInfo.BlockNumber] = burnContractInfo.Address + chainConfig.Params.BurnContractDestinationAddress = burnContractInfo.DestinationAddress + } + // Predeploy staking smart contract if needed if p.shouldPredeployStakingSC() { stakingAccount, err := p.predeployStakingSC() @@ -345,13 +419,13 @@ func (p *genesisParams) initGenesisConfig() error { } for _, premineRaw := range p.premine { - premineInfo, err := ParsePremineInfo(premineRaw) + premineInfo, err := parsePremineInfo(premineRaw) if err != nil { return err } - chainConfig.Genesis.Alloc[premineInfo.Address] = &chain.GenesisAccount{ - Balance: premineInfo.Amount, + chainConfig.Genesis.Alloc[premineInfo.address] = &chain.GenesisAccount{ + Balance: premineInfo.amount, } } @@ -380,6 +454,122 @@ func (p *genesisParams) predeployStakingSC() (*chain.GenesisAccount, error) { return stakingAccount, nil } +// validateRewardWallet validates reward wallet flag +func (p *genesisParams) validateRewardWallet() error { + if p.rewardWallet == "" { + return errors.New("reward wallet address must be defined") + } + + if p.rewardWallet == types.AddressToString(types.ZeroAddress) { + return errors.New("reward wallet address must not be zero address") + } + + premineInfo, err := parsePremineInfo(p.rewardWallet) + if err != nil { + return err + } + + if premineInfo.amount.Cmp(big.NewInt(0)) < 1 { + return errRewardWalletAmountZero + } + + return nil +} + +// validateBurnContract validates burn contract. If native token is mintable, +// burn contract flag must not be set. If native token is non mintable only one burn contract +// can be set and the specified address will be used to predeploy default EIP1559 burn contract. +func (p *genesisParams) validateBurnContract() error { + if p.isBurnContractEnabled() { + burnContractInfo, err := parseBurnContractInfo(p.burnContract) + if err != nil { + return fmt.Errorf("invalid burn contract info provided: %w", err) + } + + if p.nativeTokenConfig.IsMintable { + if burnContractInfo.Address != types.ZeroAddress { + return errors.New("only zero address is allowed as burn destination for mintable native token") + } + } else { + if burnContractInfo.Address == types.ZeroAddress { + return errors.New("it is not allowed to deploy burn contract to 0x0 address") + } + } + } + + return nil +} + +// isBurnContractEnabled returns true in case burn contract info is provided +func (p *genesisParams) isBurnContractEnabled() bool { + return p.burnContract != "" +} + +// extractNativeTokenMetadata parses provided native token metadata (such as name, symbol and decimals count) +func (p *genesisParams) extractNativeTokenMetadata() error { + if p.nativeTokenConfigRaw == "" { + p.nativeTokenConfig = &polybft.TokenConfig{ + Name: defaultNativeTokenName, + Symbol: defaultNativeTokenSymbol, + Decimals: defaultNativeTokenDecimals, + IsMintable: false, + Owner: types.ZeroAddress, + } + + return nil + } + + params := strings.Split(p.nativeTokenConfigRaw, ":") + if len(params) < minNativeTokenParamsNumber { + return errInvalidTokenParams + } + + // name + name := strings.TrimSpace(params[0]) + if name == "" { + return errInvalidTokenParams + } + + // symbol + symbol := strings.TrimSpace(params[1]) + if symbol == "" { + return errInvalidTokenParams + } + + // decimals + decimals, err := strconv.ParseUint(strings.TrimSpace(params[2]), 10, 8) + if err != nil || decimals > math.MaxUint8 { + return errInvalidTokenParams + } + + // is mintable native token used + isMintable, err := strconv.ParseBool(strings.TrimSpace(params[3])) + if err != nil { + return errInvalidTokenParams + } + + // in case it is mintable native token, it is expected to have 5 parameters provided + if isMintable && len(params) != minNativeTokenParamsNumber+1 { + return errInvalidTokenParams + } + + // owner address + owner := types.ZeroAddress + if isMintable { + owner = types.StringToAddress(strings.TrimSpace(params[4])) + } + + p.nativeTokenConfig = &polybft.TokenConfig{ + Name: name, + Symbol: symbol, + Decimals: uint8(decimals), + IsMintable: isMintable, + Owner: owner, + } + + return nil +} + func (p *genesisParams) getResult() command.CommandResult { return &GenesisResult{ Message: fmt.Sprintf("\nGenesis written to %s\n", p.genesisPath), diff --git a/command/genesis/params_test.go b/command/genesis/params_test.go new file mode 100644 index 0000000000..601db39b03 --- /dev/null +++ b/command/genesis/params_test.go @@ -0,0 +1,118 @@ +package genesis + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/0xPolygon/polygon-edge/consensus/polybft" + "github.com/0xPolygon/polygon-edge/types" +) + +func Test_extractNativeTokenMetadata(t *testing.T) { + t.Parallel() + + cases := []struct { + name string + rawConfig string + expectedCfg *polybft.TokenConfig + expectErr bool + }{ + { + name: "default token config", + rawConfig: "", + expectedCfg: &polybft.TokenConfig{ + Name: defaultNativeTokenName, + Symbol: defaultNativeTokenSymbol, + Decimals: defaultNativeTokenDecimals, + IsMintable: false, + Owner: types.ZeroAddress, + }, + expectErr: false, + }, + { + name: "not enough params provided", + rawConfig: "Test:TST:18", + expectErr: true, + }, + { + name: "empty name provided", + rawConfig: ":TST:18:false", + expectErr: true, + }, + { + name: "empty symbol provided", + rawConfig: "Test::18:false", + expectErr: true, + }, + { + name: "invalid decimals number provided", + rawConfig: "Test:TST:9999999999999999999999999999999999999999999999999999999999:false", + expectErr: true, + }, + { + name: "invalid mintable flag provided", + rawConfig: "Test:TST:18:bar", + expectErr: true, + }, + { + name: "mintable token not enough params provided", + rawConfig: "Test:TST:18:true", + expectErr: true, + }, + { + name: "non-mintable valid config", + rawConfig: "MyToken:MTK:9:false", + expectedCfg: &polybft.TokenConfig{ + Name: "MyToken", + Symbol: "MTK", + Decimals: 9, + IsMintable: false, + Owner: types.ZeroAddress, + }, + expectErr: false, + }, + { + name: "non-mintable token config, owner provided but ignored", + rawConfig: "MyToken:MTK:9:false:0x123456789", + expectedCfg: &polybft.TokenConfig{ + Name: "MyToken", + Symbol: "MTK", + Decimals: 9, + IsMintable: false, + Owner: types.ZeroAddress, + }, + expectErr: false, + }, + { + name: "mintable token valid config", + rawConfig: "MyMintToken:MMTK:9:true:0x123456789", + expectedCfg: &polybft.TokenConfig{ + Name: "MyMintToken", + Symbol: "MMTK", + Decimals: 9, + IsMintable: true, + Owner: types.StringToAddress("0x123456789"), + }, + expectErr: false, + }, + } + + for _, c := range cases { + c := c + t.Run(c.name, func(t *testing.T) { + t.Parallel() + + p := &genesisParams{nativeTokenConfigRaw: c.rawConfig} + err := p.extractNativeTokenMetadata() + + if c.expectErr { + require.Error(t, err) + require.Nil(t, p.nativeTokenConfig) + } else { + require.NoError(t, err) + require.Equal(t, c.expectedCfg, p.nativeTokenConfig) + } + }) + } +} diff --git a/command/genesis/polybft_params.go b/command/genesis/polybft_params.go index 561e68734f..b141788c44 100644 --- a/command/genesis/polybft_params.go +++ b/command/genesis/polybft_params.go @@ -1,107 +1,172 @@ package genesis import ( + "encoding/hex" "errors" "fmt" "math/big" + "path" "strings" "time" - "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" - "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi/artifact" + "github.com/multiformats/go-multiaddr" "github.com/0xPolygon/polygon-edge/chain" "github.com/0xPolygon/polygon-edge/command" "github.com/0xPolygon/polygon-edge/command/helper" - "github.com/0xPolygon/polygon-edge/consensus/polybft" - "github.com/0xPolygon/polygon-edge/consensus/polybft/bitmap" + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi/artifact" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/contracts" + "github.com/0xPolygon/polygon-edge/helper/common" "github.com/0xPolygon/polygon-edge/server" "github.com/0xPolygon/polygon-edge/types" ) const ( - manifestPathFlag = "manifest" - validatorSetSizeFlag = "validator-set-size" - sprintSizeFlag = "sprint-size" - blockTimeFlag = "block-time" - bridgeFlag = "bridge-json-rpc" - trackerStartBlocksFlag = "tracker-start-blocks" - trieRootFlag = "trieroot" - - defaultManifestPath = "./manifest.json" + validatorsFlag = "validators" + validatorsPathFlag = "validators-path" + validatorsPrefixFlag = "validators-prefix" + + defaultValidatorPrefixPath = "test-chain-" + + sprintSizeFlag = "sprint-size" + blockTimeFlag = "block-time" + trieRootFlag = "trieroot" + + blockTimeDriftFlag = "block-time-drift" + defaultEpochSize = uint64(10) defaultSprintSize = uint64(5) defaultValidatorSetSize = 100 defaultBlockTime = 2 * time.Second - defaultBridge = false defaultEpochReward = 1 - - contractDeployedAllowListAdminFlag = "contract-deployer-allow-list-admin" - contractDeployedAllowListEnabledFlag = "contract-deployer-allow-list-enabled" + defaultBlockTimeDrift = uint64(10) + + contractDeployerAllowListAdminFlag = "contract-deployer-allow-list-admin" + contractDeployerAllowListEnabledFlag = "contract-deployer-allow-list-enabled" + contractDeployerBlockListAdminFlag = "contract-deployer-block-list-admin" + contractDeployerBlockListEnabledFlag = "contract-deployer-block-list-enabled" + transactionsAllowListAdminFlag = "transactions-allow-list-admin" + transactionsAllowListEnabledFlag = "transactions-allow-list-enabled" + transactionsBlockListAdminFlag = "transactions-block-list-admin" + transactionsBlockListEnabledFlag = "transactions-block-list-enabled" + bridgeAllowListAdminFlag = "bridge-allow-list-admin" + bridgeAllowListEnabledFlag = "bridge-allow-list-enabled" + bridgeBlockListAdminFlag = "bridge-block-list-admin" + bridgeBlockListEnabledFlag = "bridge-block-list-enabled" bootnodePortStart = 30301 + + ecdsaAddressLength = 40 + blsKeyLength = 256 ) var ( errNoGenesisValidators = errors.New("genesis validators aren't provided") + errNoPremineAllowed = errors.New("native token is not mintable, so no premine is allowed " + + "except for zero address and reward wallet if native token is used as reward token") ) // generatePolyBftChainConfig creates and persists polybft chain configuration to the provided file path func (p *genesisParams) generatePolyBftChainConfig(o command.OutputFormatter) error { - // load manifest file - manifest, err := polybft.LoadManifest(p.manifestPath) + // populate premine balance map + premineBalances := make(map[types.Address]*premineInfo, len(p.premine)) + + for _, premine := range p.premine { + premineInfo, err := parsePremineInfo(premine) + if err != nil { + return fmt.Errorf("invalid balance amount provided '%s' : %w", premine, err) + } + + premineBalances[premineInfo.address] = premineInfo + } + + walletPremineInfo, err := parsePremineInfo(p.rewardWallet) if err != nil { - return fmt.Errorf("failed to load manifest file from provided path '%s': %w", p.manifestPath, err) + return fmt.Errorf("invalid reward wallet configuration provided '%s' : %w", p.rewardWallet, err) } - if len(manifest.GenesisValidators) == 0 { - return errNoGenesisValidators + if !p.nativeTokenConfig.IsMintable { + // validate premine map, no premine is allowed if token is not mintable, + // except for the reward wallet (if native token is used as reward token) and zero address + for a := range premineBalances { + if a != types.ZeroAddress && (p.rewardTokenCode != "" || a != walletPremineInfo.address) { + return errNoPremineAllowed + } + } } - eventTrackerStartBlock, err := parseTrackerStartBlocks(params.eventTrackerStartBlocks) - if err != nil { - return err + var ( + rewardTokenByteCode []byte + rewardTokenAddr = contracts.NativeERC20TokenContract + ) + + if p.rewardTokenCode == "" { + // native token is used as a reward token, and reward wallet is not a zero address + // so we need to add that address to premine map + premineBalances[walletPremineInfo.address] = walletPremineInfo + } else { + bytes, err := hex.DecodeString(p.rewardTokenCode) + if err != nil { + return fmt.Errorf("could not decode reward token byte code '%s' : %w", p.rewardTokenCode, err) + } + + rewardTokenByteCode = bytes + rewardTokenAddr = contracts.RewardTokenContract } - var bridge *polybft.BridgeConfig + initialValidators, err := p.getValidatorAccounts(premineBalances) + if err != nil { + return fmt.Errorf("failed to retrieve genesis validators: %w", err) + } - // populate bridge configuration - if p.bridgeJSONRPCAddr != "" && manifest.RootchainConfig != nil { - bridge = manifest.RootchainConfig.ToBridgeConfig() - bridge.JSONRPCEndpoint = p.bridgeJSONRPCAddr - bridge.EventTrackerStartBlocks = eventTrackerStartBlock + if len(initialValidators) == 0 { + return errNoGenesisValidators } if _, err := o.Write([]byte("[GENESIS VALIDATORS]\n")); err != nil { return err } - for _, v := range manifest.GenesisValidators { + for _, v := range initialValidators { if _, err := o.Write([]byte(fmt.Sprintf("%v\n", v))); err != nil { return err } } polyBftConfig := &polybft.PolyBFTConfig{ - InitialValidatorSet: manifest.GenesisValidators, - BlockTime: p.blockTime, + InitialValidatorSet: initialValidators, + BlockTime: common.Duration{Duration: p.blockTime}, EpochSize: p.epochSize, SprintSize: p.sprintSize, EpochReward: p.epochReward, // use 1st account as governance address - Governance: manifest.GenesisValidators[0].Address, - Bridge: bridge, - InitialTrieRoot: types.StringToHash(p.initialStateRoot), - MintableERC20Token: p.mintableNativeToken, + Governance: types.ZeroAddress, + InitialTrieRoot: types.StringToHash(p.initialStateRoot), + NativeTokenConfig: p.nativeTokenConfig, + MinValidatorSetSize: p.minNumValidators, + MaxValidatorSetSize: p.maxNumValidators, + RewardConfig: &polybft.RewardsConfig{ + TokenAddress: rewardTokenAddr, + WalletAddress: walletPremineInfo.address, + WalletAmount: walletPremineInfo.amount, + }, + BlockTimeDrift: p.blockTimeDrift, + } + + // Disable london hardfork if burn contract address is not provided + enabledForks := chain.AllForksEnabled + if !p.isBurnContractEnabled() { + enabledForks.RemoveFork(chain.London) } chainConfig := &chain.Chain{ Name: p.name, Params: &chain.Params{ - ChainID: manifest.ChainID, - Forks: chain.AllForksEnabled, + ChainID: int64(p.chainID), + Forks: enabledForks, Engine: map[string]interface{}{ string(server.PolyBFTConsensus): polyBftConfig, }, @@ -109,72 +174,48 @@ func (p *genesisParams) generatePolyBftChainConfig(o command.OutputFormatter) er Bootnodes: p.bootnodes, } - genesisValidators := make(map[types.Address]struct{}, len(manifest.GenesisValidators)) - totalStake := big.NewInt(0) + burnContractAddr := types.ZeroAddress - for _, validator := range manifest.GenesisValidators { - // populate premine info for validator accounts - genesisValidators[validator.Address] = struct{}{} - - // increment total stake - totalStake.Add(totalStake, validator.Stake) - } + if p.isBurnContractEnabled() { + chainConfig.Params.BurnContract = make(map[uint64]types.Address, 1) - // deploy genesis contracts - allocs, err := p.deployContracts(totalStake) - if err != nil { - return err - } - - premineInfos := make([]*PremineInfo, len(p.premine)) - premineValidatorsAddrs := []string{} - // premine non-validator - for i, premine := range p.premine { - premineInfo, err := ParsePremineInfo(premine) + burnContractInfo, err := parseBurnContractInfo(p.burnContract) if err != nil { return err } - // collect validators addresses which got premined, as it is an error - // genesis validators balances must be defined in manifest file and should not be changed in the genesis - if _, ok := genesisValidators[premineInfo.Address]; ok { - premineValidatorsAddrs = append(premineValidatorsAddrs, premineInfo.Address.String()) + if !p.nativeTokenConfig.IsMintable { + // burn contract can be specified on arbitrary address for non-mintable native tokens + burnContractAddr = burnContractInfo.Address + chainConfig.Params.BurnContract[burnContractInfo.BlockNumber] = burnContractAddr + chainConfig.Params.BurnContractDestinationAddress = burnContractInfo.DestinationAddress } else { - premineInfos[i] = premineInfo + // burnt funds are sent to zero address when dealing with mintable native tokens + chainConfig.Params.BurnContract[burnContractInfo.BlockNumber] = types.ZeroAddress } } - // if there are any premined validators in the genesis command, consider it as an error - if len(premineValidatorsAddrs) > 0 { - return fmt.Errorf("it is not allowed to override genesis validators balance outside from the manifest definition. "+ - "Validators which got premined: (%s)", strings.Join(premineValidatorsAddrs, ", ")) + // deploy genesis contracts + allocs, err := p.deployContracts(rewardTokenByteCode, polyBftConfig, chainConfig, burnContractAddr) + if err != nil { + return err } - // populate genesis validators balances - for _, validator := range manifest.GenesisValidators { - allocs[validator.Address] = &chain.GenesisAccount{ - Balance: validator.Balance, + // premine other accounts + for _, premine := range premineBalances { + // validators have already been premined, so no need to premine them again + if _, ok := allocs[premine.address]; ok { + continue } - } - // premine non-validator accounts - for _, premine := range premineInfos { - allocs[premine.Address] = &chain.GenesisAccount{ - Balance: premine.Amount, + allocs[premine.address] = &chain.GenesisAccount{ + Balance: premine.amount, } } - validatorMetadata := make([]*polybft.ValidatorMetadata, len(manifest.GenesisValidators)) - - for i, validator := range manifest.GenesisValidators { - // update balance of genesis validator, because it could be changed via premine flag - balance, err := chain.GetGenesisAccountBalance(validator.Address, allocs) - if err != nil { - return err - } - - validator.Balance = balance + validatorMetadata := make([]*validator.ValidatorMetadata, len(initialValidators)) + for i, validator := range initialValidators { // create validator metadata instance metadata, err := validator.ToValidatorMetadata() if err != nil { @@ -189,7 +230,7 @@ func (p *genesisParams) generatePolyBftChainConfig(o command.OutputFormatter) er } } - genesisExtraData, err := generateExtraDataPolyBft(validatorMetadata) + genesisExtraData, err := GenerateExtraDataPolyBft(validatorMetadata) if err != nil { return err } @@ -207,27 +248,78 @@ func (p *genesisParams) generatePolyBftChainConfig(o command.OutputFormatter) er if len(p.contractDeployerAllowListAdmin) != 0 { // only enable allow list if there is at least one address as **admin**, otherwise // the allow list could never be updated - chainConfig.Params.ContractDeployerAllowList = &chain.AllowListConfig{ + chainConfig.Params.ContractDeployerAllowList = &chain.AddressListConfig{ AdminAddresses: stringSliceToAddressSlice(p.contractDeployerAllowListAdmin), EnabledAddresses: stringSliceToAddressSlice(p.contractDeployerAllowListEnabled), } } + if len(p.contractDeployerBlockListAdmin) != 0 { + // only enable block list if there is at least one address as **admin**, otherwise + // the block list could never be updated + chainConfig.Params.ContractDeployerBlockList = &chain.AddressListConfig{ + AdminAddresses: stringSliceToAddressSlice(p.contractDeployerBlockListAdmin), + EnabledAddresses: stringSliceToAddressSlice(p.contractDeployerBlockListEnabled), + } + } + + if len(p.transactionsAllowListAdmin) != 0 { + // only enable allow list if there is at least one address as **admin**, otherwise + // the allow list could never be updated + chainConfig.Params.TransactionsAllowList = &chain.AddressListConfig{ + AdminAddresses: stringSliceToAddressSlice(p.transactionsAllowListAdmin), + EnabledAddresses: stringSliceToAddressSlice(p.transactionsAllowListEnabled), + } + } + + if len(p.transactionsBlockListAdmin) != 0 { + // only enable block list if there is at least one address as **admin**, otherwise + // the block list could never be updated + chainConfig.Params.TransactionsBlockList = &chain.AddressListConfig{ + AdminAddresses: stringSliceToAddressSlice(p.transactionsBlockListAdmin), + EnabledAddresses: stringSliceToAddressSlice(p.transactionsBlockListEnabled), + } + } + + if len(p.bridgeAllowListAdmin) != 0 { + // only enable allow list if there is at least one address as **admin**, otherwise + // the allow list could never be updated + chainConfig.Params.BridgeAllowList = &chain.AddressListConfig{ + AdminAddresses: stringSliceToAddressSlice(p.bridgeAllowListAdmin), + EnabledAddresses: stringSliceToAddressSlice(p.bridgeAllowListEnabled), + } + } + + if len(p.bridgeBlockListAdmin) != 0 { + // only enable block list if there is at least one address as **admin**, otherwise + // the block list could never be updated + chainConfig.Params.BridgeBlockList = &chain.AddressListConfig{ + AdminAddresses: stringSliceToAddressSlice(p.bridgeBlockListAdmin), + EnabledAddresses: stringSliceToAddressSlice(p.bridgeBlockListEnabled), + } + } + + if p.isBurnContractEnabled() { + // only populate base fee and base fee multiplier values if burn contract(s) + // is provided + chainConfig.Genesis.BaseFee = command.DefaultGenesisBaseFee + chainConfig.Genesis.BaseFeeEM = command.DefaultGenesisBaseFeeEM + } + return helper.WriteGenesisConfigToDisk(chainConfig, params.genesisPath) } -func (p *genesisParams) deployContracts(totalStake *big.Int) (map[types.Address]*chain.GenesisAccount, error) { +func (p *genesisParams) deployContracts( + rewardTokenByteCode []byte, + polybftConfig *polybft.PolyBFTConfig, + chainConfig *chain.Chain, + burnContractAddr types.Address) (map[types.Address]*chain.GenesisAccount, error) { type contractInfo struct { artifact *artifact.Artifact address types.Address } genesisContracts := []*contractInfo{ - { - // ChildValidatorSet contract - artifact: contractsapi.ChildValidatorSet, - address: contracts.ValidatorSetContract, - }, { // State receiver contract artifact: contractsapi.StateReceiver, @@ -239,9 +331,14 @@ func (p *genesisParams) deployContracts(totalStake *big.Int) (map[types.Address] address: contracts.ChildERC20Contract, }, { - // ChildERC20Predicate contract - artifact: contractsapi.ChildERC20Predicate, - address: contracts.ChildERC20PredicateContract, + // ChildERC721 token contract + artifact: contractsapi.ChildERC721, + address: contracts.ChildERC721Contract, + }, + { + // ChildERC1155 contract + artifact: contractsapi.ChildERC1155, + address: contracts.ChildERC1155Contract, }, { // BLS contract @@ -258,17 +355,119 @@ func (p *genesisParams) deployContracts(totalStake *big.Int) (map[types.Address] artifact: contractsapi.L2StateSender, address: contracts.L2StateSenderContract, }, + { + artifact: contractsapi.ValidatorSet, + address: contracts.ValidatorSetContract, + }, + { + artifact: contractsapi.RewardPool, + address: contracts.RewardPoolContract, + }, } - if !params.mintableNativeToken { + if !params.nativeTokenConfig.IsMintable { + genesisContracts = append(genesisContracts, + &contractInfo{ + artifact: contractsapi.NativeERC20, + address: contracts.NativeERC20TokenContract, + }) + + // burn contract can be set only for non-mintable native token. If burn contract is set, + // default EIP1559 contract will be deployed. + if p.isBurnContractEnabled() { + genesisContracts = append(genesisContracts, + &contractInfo{ + artifact: contractsapi.EIP1559Burn, + address: burnContractAddr, + }) + } + } else { + genesisContracts = append(genesisContracts, + &contractInfo{ + artifact: contractsapi.NativeERC20Mintable, + address: contracts.NativeERC20TokenContract, + }) + } + + if len(params.bridgeAllowListAdmin) != 0 || len(params.bridgeBlockListAdmin) != 0 { + // rootchain originated tokens predicates (with access lists) + genesisContracts = append(genesisContracts, + &contractInfo{ + artifact: contractsapi.ChildERC20PredicateACL, + address: contracts.ChildERC20PredicateContract, + }) + + genesisContracts = append(genesisContracts, + &contractInfo{ + artifact: contractsapi.ChildERC721PredicateACL, + address: contracts.ChildERC721PredicateContract, + }) + + genesisContracts = append(genesisContracts, + &contractInfo{ + artifact: contractsapi.ChildERC1155PredicateACL, + address: contracts.ChildERC1155PredicateContract, + }) + + // childchain originated tokens predicates (with access lists) + genesisContracts = append(genesisContracts, + &contractInfo{ + artifact: contractsapi.RootMintableERC20PredicateACL, + address: contracts.RootMintableERC20PredicateContract, + }) + + genesisContracts = append(genesisContracts, + &contractInfo{ + artifact: contractsapi.RootMintableERC721PredicateACL, + address: contracts.RootMintableERC721PredicateContract, + }) + genesisContracts = append(genesisContracts, - &contractInfo{artifact: contractsapi.NativeERC20, address: contracts.NativeERC20TokenContract}) + &contractInfo{ + artifact: contractsapi.RootMintableERC1155PredicateACL, + address: contracts.RootMintableERC1155PredicateContract, + }) } else { + // rootchain originated tokens predicates + genesisContracts = append(genesisContracts, + &contractInfo{ + artifact: contractsapi.ChildERC20Predicate, + address: contracts.ChildERC20PredicateContract, + }) + + genesisContracts = append(genesisContracts, + &contractInfo{ + artifact: contractsapi.ChildERC721Predicate, + address: contracts.ChildERC721PredicateContract, + }) + + genesisContracts = append(genesisContracts, + &contractInfo{ + artifact: contractsapi.ChildERC1155Predicate, + address: contracts.ChildERC1155PredicateContract, + }) + + // childchain originated tokens predicates + genesisContracts = append(genesisContracts, + &contractInfo{ + artifact: contractsapi.RootMintableERC20Predicate, + address: contracts.RootMintableERC20PredicateContract, + }) + + genesisContracts = append(genesisContracts, + &contractInfo{ + artifact: contractsapi.RootMintableERC721Predicate, + address: contracts.RootMintableERC721PredicateContract, + }) + genesisContracts = append(genesisContracts, - &contractInfo{artifact: contractsapi.NativeERC20Mintable, address: contracts.NativeERC20TokenContract}) + &contractInfo{ + artifact: contractsapi.RootMintableERC1155Predicate, + address: contracts.RootMintableERC1155PredicateContract, + }) } - allocations := make(map[types.Address]*chain.GenesisAccount, len(genesisContracts)) + allocations := make(map[types.Address]*chain.GenesisAccount, len(genesisContracts)+1) for _, contract := range genesisContracts { allocations[contract.address] = &chain.GenesisAccount{ @@ -277,22 +476,85 @@ func (p *genesisParams) deployContracts(totalStake *big.Int) (map[types.Address] } } - // ChildValidatorSet must have funds pre-allocated, because of withdrawal workflow - allocations[contracts.ValidatorSetContract].Balance = totalStake + if rewardTokenByteCode != nil { + // if reward token is provided in genesis then, add it to allocations + // to RewardTokenContract address and update Polybft config + allocations[contracts.RewardTokenContract] = &chain.GenesisAccount{ + Balance: big.NewInt(0), + Code: rewardTokenByteCode, + } + } return allocations, nil } -// generateExtraDataPolyBft populates Extra with specific fields required for polybft consensus protocol -func generateExtraDataPolyBft(validators []*polybft.ValidatorMetadata) ([]byte, error) { - delta := &polybft.ValidatorSetDelta{ - Added: validators, - Removed: bitmap.Bitmap{}, +// getValidatorAccounts gathers validator accounts info either from CLI or from provided local storage +func (p *genesisParams) getValidatorAccounts( + premineBalances map[types.Address]*premineInfo) ([]*validator.GenesisValidator, error) { + // populate validators premine info + if len(p.validators) > 0 { + validators := make([]*validator.GenesisValidator, len(p.validators)) + for i, val := range p.validators { + parts := strings.Split(val, ":") + if len(parts) != 3 { + return nil, fmt.Errorf("expected 3 parts provided in the following format "+ + ", but got %d part(s)", + len(parts)) + } + + if _, err := multiaddr.NewMultiaddr(parts[0]); err != nil { + return nil, fmt.Errorf("invalid P2P multi address '%s' provided: %w ", parts[0], err) + } + + trimmedAddress := strings.TrimPrefix(parts[1], "0x") + if len(trimmedAddress) != ecdsaAddressLength { + return nil, fmt.Errorf("invalid ECDSA address: %s", parts[1]) + } + + trimmedBLSKey := strings.TrimPrefix(parts[2], "0x") + if len(trimmedBLSKey) != blsKeyLength { + return nil, fmt.Errorf("invalid BLS key: %s", parts[2]) + } + + addr := types.StringToAddress(trimmedAddress) + validators[i] = &validator.GenesisValidator{ + MultiAddr: parts[0], + Address: addr, + BlsKey: trimmedBLSKey, + Balance: getPremineAmount(addr, premineBalances, big.NewInt(0)), + Stake: big.NewInt(0), + } + } + + return validators, nil + } + + validatorsPath := p.validatorsPath + if validatorsPath == "" { + validatorsPath = path.Dir(p.genesisPath) } - extra := polybft.Extra{Validators: delta, Checkpoint: &polybft.CheckpointData{}} + validators, err := ReadValidatorsByPrefix(validatorsPath, p.validatorsPrefixPath) + if err != nil { + return nil, err + } + + for _, v := range validators { + v.Balance = getPremineAmount(v.Address, premineBalances, big.NewInt(0)) + v.Stake = big.NewInt(0) + } + + return validators, nil +} + +// getPremineAmount retrieves amount from the premine map or if not provided, returns default amount +func getPremineAmount(addr types.Address, premineMap map[types.Address]*premineInfo, + defaultAmount *big.Int) *big.Int { + if premine, exists := premineMap[addr]; exists { + return premine.amount + } - return append(make([]byte, polybft.ExtraVanity), extra.MarshalRLPTo(nil)...), nil + return defaultAmount } func stringSliceToAddressSlice(addrs []string) []types.Address { diff --git a/command/genesis/utils.go b/command/genesis/utils.go index bef4153758..5e05603593 100644 --- a/command/genesis/utils.go +++ b/command/genesis/utils.go @@ -13,6 +13,8 @@ import ( "github.com/0xPolygon/polygon-edge/command" "github.com/0xPolygon/polygon-edge/consensus/polybft" + "github.com/0xPolygon/polygon-edge/consensus/polybft/bitmap" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" "github.com/0xPolygon/polygon-edge/secrets" "github.com/0xPolygon/polygon-edge/secrets/helper" @@ -62,13 +64,13 @@ func verifyGenesisExistence(genesisPath string) *GenesisGenError { return nil } -type PremineInfo struct { - Address types.Address - Amount *big.Int +type premineInfo struct { + address types.Address + amount *big.Int } -// ParsePremineInfo parses provided premine information and returns premine address and amount -func ParsePremineInfo(premineInfoRaw string) (*PremineInfo, error) { +// parsePremineInfo parses provided premine information and returns premine address and amount +func parsePremineInfo(premineInfoRaw string) (*premineInfo, error) { var ( address types.Address amount = command.DefaultPremineBalance @@ -90,7 +92,7 @@ func ParsePremineInfo(premineInfoRaw string) (*PremineInfo, error) { address = types.StringToAddress(premineInfoRaw) } - return &PremineInfo{Address: address, Amount: amount}, nil + return &premineInfo{address: address, amount: amount}, nil } // parseTrackerStartBlocks parses provided event tracker start blocks configuration. @@ -120,6 +122,46 @@ func parseTrackerStartBlocks(trackerStartBlocksRaw []string) (map[types.Address] return trackerStartBlocksConfig, nil } +// parseBurnContractInfo parses provided burn contract information and returns burn contract block and address +func parseBurnContractInfo(burnContractInfoRaw string) (*polybft.BurnContractInfo, error) { + // :
[:] + burnContractParts := strings.Split(burnContractInfoRaw, ":") + if len(burnContractParts) < 2 || len(burnContractParts) > 3 { + return nil, fmt.Errorf("expected format: :
[:]") + } + + blockRaw := burnContractParts[0] + + blockNum, err := types.ParseUint64orHex(&blockRaw) + if err != nil { + return nil, fmt.Errorf("failed to parse block number %s: %w", blockRaw, err) + } + + contractAddress := burnContractParts[1] + if err = types.IsValidAddress(contractAddress); err != nil { + return nil, fmt.Errorf("failed to parse contract address %s: %w", contractAddress, err) + } + + if len(burnContractParts) == 2 { + return &polybft.BurnContractInfo{ + BlockNumber: blockNum, + Address: types.StringToAddress(contractAddress), + DestinationAddress: types.ZeroAddress, + }, nil + } + + destinationAddress := burnContractParts[2] + if err = types.IsValidAddress(destinationAddress); err != nil { + return nil, fmt.Errorf("failed to parse burn destination address %s: %w", destinationAddress, err) + } + + return &polybft.BurnContractInfo{ + BlockNumber: blockNum, + Address: types.StringToAddress(contractAddress), + DestinationAddress: types.StringToAddress(destinationAddress), + }, nil +} + // GetValidatorKeyFiles returns file names which has validator secrets func GetValidatorKeyFiles(rootDir, filePrefix string) ([]string, error) { if rootDir == "" { @@ -158,27 +200,26 @@ func GetValidatorKeyFiles(rootDir, filePrefix string) ([]string, error) { } // ReadValidatorsByPrefix reads validators secrets on a given root directory and with given folder prefix -func ReadValidatorsByPrefix(dir, prefix string) ([]*polybft.Validator, error) { +func ReadValidatorsByPrefix(dir, prefix string) ([]*validator.GenesisValidator, error) { validatorKeyFiles, err := GetValidatorKeyFiles(dir, prefix) if err != nil { return nil, err } - validators := make([]*polybft.Validator, len(validatorKeyFiles)) + validators := make([]*validator.GenesisValidator, len(validatorKeyFiles)) for i, file := range validatorKeyFiles { path := filepath.Join(dir, file) - account, nodeID, blsSignature, err := getSecrets(path) + account, nodeID, err := getSecrets(path) if err != nil { return nil, err } - validators[i] = &polybft.Validator{ + validators[i] = &validator.GenesisValidator{ Address: types.Address(account.Ecdsa.Address()), BlsPrivateKey: account.Bls, BlsKey: hex.EncodeToString(account.Bls.PublicKey().Marshal()), - BlsSignature: blsSignature, MultiAddr: fmt.Sprintf("/ip4/%s/tcp/%d/p2p/%s", "127.0.0.1", bootnodePortStart+int64(i), nodeID), } } @@ -186,7 +227,7 @@ func ReadValidatorsByPrefix(dir, prefix string) ([]*polybft.Validator, error) { return validators, nil } -func getSecrets(directory string) (*wallet.Account, string, string, error) { +func getSecrets(directory string) (*wallet.Account, string, error) { baseConfig := &secrets.SecretsManagerParams{ Logger: hclog.NewNullLogger(), Extra: map[string]interface{}{ @@ -196,20 +237,30 @@ func getSecrets(directory string) (*wallet.Account, string, string, error) { localManager, err := local.SecretsManagerFactory(nil, baseConfig) if err != nil { - return nil, "", "", fmt.Errorf("unable to instantiate local secrets manager, %w", err) + return nil, "", fmt.Errorf("unable to instantiate local secrets manager, %w", err) } nodeID, err := helper.LoadNodeID(localManager) if err != nil { - return nil, "", "", err + return nil, "", err } account, err := wallet.NewAccountFromSecret(localManager) if err != nil { - return nil, "", "", err + return nil, "", err + } + + return account, nodeID, err +} + +// GenerateExtraDataPolyBft populates Extra with specific fields required for polybft consensus protocol +func GenerateExtraDataPolyBft(validators []*validator.ValidatorMetadata) ([]byte, error) { + delta := &validator.ValidatorSetDelta{ + Added: validators, + Removed: bitmap.Bitmap{}, } - blsSignature, err := helper.LoadBLSSignature(localManager) + extra := polybft.Extra{Validators: delta, Checkpoint: &polybft.CheckpointData{}} - return account, nodeID, blsSignature, err + return extra.MarshalRLPTo(nil), nil } diff --git a/command/helper/helper.go b/command/helper/helper.go index e19b25d441..82411528e3 100644 --- a/command/helper/helper.go +++ b/command/helper/helper.go @@ -4,6 +4,7 @@ import ( "encoding/json" "errors" "fmt" + "math/big" "net" "net/url" "time" @@ -250,3 +251,12 @@ func SetRequiredFlags(cmd *cobra.Command, requiredFlags []string) { _ = cmd.MarkFlagRequired(requiredFlag) } } + +func ParseAmount(amount string) (*big.Int, error) { + result, ok := new(big.Int).SetString(amount, 0) + if !ok || result.Cmp(big.NewInt(0)) <= 0 { + return nil, fmt.Errorf("amount %s should be numerical value greater than zero", amount) + } + + return result, nil +} diff --git a/command/ibft/switch/params.go b/command/ibft/switch/params.go index 2926008ad0..109e2f9bbf 100644 --- a/command/ibft/switch/params.go +++ b/command/ibft/switch/params.go @@ -403,6 +403,7 @@ func appendIBFTForks( Type: ibftType, ValidatorType: validatorType, From: common.JSONNumber{Value: from}, + BlockTime: lastFork.BlockTime, } switch ibftType { diff --git a/command/polybft/polybft_command.go b/command/polybft/polybft_command.go index 22b0c2f6fa..af5bed0800 100644 --- a/command/polybft/polybft_command.go +++ b/command/polybft/polybft_command.go @@ -1,13 +1,16 @@ package polybft import ( - "github.com/0xPolygon/polygon-edge/command/sidechain/registration" - "github.com/0xPolygon/polygon-edge/command/sidechain/staking" + "github.com/0xPolygon/polygon-edge/command/rootchain/registration" + "github.com/0xPolygon/polygon-edge/command/rootchain/staking" + "github.com/0xPolygon/polygon-edge/command/rootchain/supernet" + "github.com/0xPolygon/polygon-edge/command/rootchain/supernet/stakemanager" + "github.com/0xPolygon/polygon-edge/command/rootchain/validators" + "github.com/0xPolygon/polygon-edge/command/rootchain/whitelist" + "github.com/0xPolygon/polygon-edge/command/rootchain/withdraw" + "github.com/0xPolygon/polygon-edge/command/sidechain/rewards" "github.com/0xPolygon/polygon-edge/command/sidechain/unstaking" - "github.com/0xPolygon/polygon-edge/command/sidechain/validators" - - "github.com/0xPolygon/polygon-edge/command/sidechain/whitelist" - "github.com/0xPolygon/polygon-edge/command/sidechain/withdraw" + sidechainWithdraw "github.com/0xPolygon/polygon-edge/command/sidechain/withdraw" "github.com/spf13/cobra" ) @@ -18,12 +21,27 @@ func GetCommand() *cobra.Command { } polybftCmd.AddCommand( - staking.GetCommand(), + // sidechain (validator set) command to unstake on child chain unstaking.GetCommand(), + // sidechain (validator set) command to withdraw stake on child chain + sidechainWithdraw.GetCommand(), + // sidechain (reward pool) command to withdraw pending rewards + rewards.GetCommand(), + // rootchain (stake manager) command to withdraw stake withdraw.GetCommand(), + // rootchain (supernet manager) command that queries validator info validators.GetCommand(), + // rootchain (supernet manager) whitelist validator whitelist.GetCommand(), + // rootchain (supernet manager) register validator registration.GetCommand(), + // rootchain (stake manager) stake command + staking.GetCommand(), + // rootchain (supernet manager) command for finalizing genesis + // validator set and enabling staking + supernet.GetCommand(), + // rootchain command for deploying stake manager + stakemanager.GetCommand(), ) return polybftCmd diff --git a/command/polybftmanifest/manifest_init.go b/command/polybftmanifest/manifest_init.go deleted file mode 100644 index 5d22a09486..0000000000 --- a/command/polybftmanifest/manifest_init.go +++ /dev/null @@ -1,268 +0,0 @@ -package polybftmanifest - -import ( - "bytes" - "errors" - "fmt" - "math/big" - "os" - "path" - "strings" - - "github.com/0xPolygon/polygon-edge/command" - "github.com/0xPolygon/polygon-edge/command/genesis" - "github.com/0xPolygon/polygon-edge/consensus/polybft" - "github.com/0xPolygon/polygon-edge/types" - "github.com/multiformats/go-multiaddr" - "github.com/spf13/cobra" -) - -const ( - manifestPathFlag = "path" - premineValidatorsFlag = "premine-validators" - stakeFlag = "stake" - validatorsFlag = "validators" - validatorsPathFlag = "validators-path" - validatorsPrefixFlag = "validators-prefix" - chainIDFlag = "chain-id" - - defaultValidatorPrefixPath = "test-chain-" - defaultManifestPath = "./manifest.json" - - ecdsaAddressLength = 40 - blsKeyLength = 256 - blsSignatureLength = 128 -) - -var ( - params = &manifestInitParams{} -) - -func GetCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "manifest", - Short: "Initializes manifest file. It is applicable only to polybft consensus protocol.", - PreRunE: runPreRun, - Run: runCommand, - } - - setFlags(cmd) - - return cmd -} - -func runPreRun(_ *cobra.Command, _ []string) error { - return params.validateFlags() -} - -func setFlags(cmd *cobra.Command) { - cmd.Flags().StringVar( - ¶ms.manifestPath, - manifestPathFlag, - defaultManifestPath, - "the file path where manifest file is going to be stored", - ) - - cmd.Flags().StringVar( - ¶ms.validatorsPath, - validatorsPathFlag, - "./", - "root path containing polybft validator keys", - ) - - cmd.Flags().StringVar( - ¶ms.validatorsPrefixPath, - validatorsPrefixFlag, - defaultValidatorPrefixPath, - "folder prefix names for polybft validator keys", - ) - - cmd.Flags().StringArrayVar( - ¶ms.validators, - validatorsFlag, - []string{}, - "validators defined by user (format: :::)", - ) - - cmd.Flags().StringArrayVar( - ¶ms.premineValidators, - premineValidatorsFlag, - []string{}, - fmt.Sprintf( - "the premined validators and balances (format:
[:]). Default premined balance: %d", - command.DefaultPremineBalance, - ), - ) - - cmd.Flags().Int64Var( - ¶ms.chainID, - chainIDFlag, - command.DefaultChainID, - "the ID of the chain", - ) - - cmd.Flags().StringArrayVar( - ¶ms.stakes, - stakeFlag, - []string{}, - fmt.Sprintf( - "validators staked amount (format:
[:]). Default stake amount: %d", - command.DefaultStake, - ), - ) - - cmd.MarkFlagsMutuallyExclusive(validatorsFlag, validatorsPathFlag) - cmd.MarkFlagsMutuallyExclusive(validatorsFlag, validatorsPrefixFlag) -} - -func runCommand(cmd *cobra.Command, _ []string) { - outputter := command.InitializeOutputter(cmd) - defer outputter.WriteOutput() - - validators, err := params.getValidatorAccounts() - if err != nil { - outputter.SetError(fmt.Errorf("failed to get validator accounts: %w", err)) - - return - } - - manifest := &polybft.Manifest{GenesisValidators: validators, ChainID: params.chainID} - if err = manifest.Save(params.manifestPath); err != nil { - outputter.SetError(fmt.Errorf("failed to save manifest file '%s': %w", params.manifestPath, err)) - - return - } - - outputter.SetCommandResult(params.getResult()) -} - -type manifestInitParams struct { - manifestPath string - validatorsPath string - validatorsPrefixPath string - premineValidators []string - stakes []string - validators []string - chainID int64 -} - -func (p *manifestInitParams) validateFlags() error { - if _, err := os.Stat(p.validatorsPath); errors.Is(err, os.ErrNotExist) { - return fmt.Errorf("provided validators path '%s' doesn't exist", p.validatorsPath) - } - - return nil -} - -// getValidatorAccounts gathers validator accounts info either from CLI or from provided local storage -func (p *manifestInitParams) getValidatorAccounts() ([]*polybft.Validator, error) { - // populate validators premine info - premineMap := make(map[types.Address]*genesis.PremineInfo, len(p.premineValidators)) - stakeMap := make(map[types.Address]*genesis.PremineInfo, len(p.stakes)) - - for _, premine := range p.premineValidators { - premineInfo, err := genesis.ParsePremineInfo(premine) - if err != nil { - return nil, err - } - - premineMap[premineInfo.Address] = premineInfo - } - - for _, stake := range p.stakes { - stakeInfo, err := genesis.ParsePremineInfo(stake) - if err != nil { - return nil, fmt.Errorf("invalid stake amount provided '%s' : %w", stake, err) - } - - stakeMap[stakeInfo.Address] = stakeInfo - } - - if len(p.validators) > 0 { - validators := make([]*polybft.Validator, len(p.validators)) - for i, validator := range p.validators { - parts := strings.Split(validator, ":") - if len(parts) != 4 { - return nil, fmt.Errorf("expected 4 parts provided in the following format "+ - ", but got %d part(s)", - len(parts)) - } - - if _, err := multiaddr.NewMultiaddr(parts[0]); err != nil { - return nil, fmt.Errorf("invalid P2P multi address '%s' provided: %w ", parts[0], err) - } - - trimmedAddress := strings.TrimPrefix(parts[1], "0x") - if len(trimmedAddress) != ecdsaAddressLength { - return nil, fmt.Errorf("invalid ECDSA address: %s", parts[1]) - } - - trimmedBLSKey := strings.TrimPrefix(parts[2], "0x") - if len(trimmedBLSKey) != blsKeyLength { - return nil, fmt.Errorf("invalid BLS key: %s", parts[2]) - } - - if len(parts[3]) != blsSignatureLength { - return nil, fmt.Errorf("invalid BLS signature: %s", parts[3]) - } - - addr := types.StringToAddress(trimmedAddress) - validators[i] = &polybft.Validator{ - MultiAddr: parts[0], - Address: addr, - BlsKey: trimmedBLSKey, - BlsSignature: parts[3], - Balance: getPremineAmount(addr, premineMap, command.DefaultPremineBalance), - Stake: getPremineAmount(addr, stakeMap, command.DefaultStake), - } - } - - return validators, nil - } - - validatorsPath := p.validatorsPath - if validatorsPath == "" { - validatorsPath = path.Dir(p.manifestPath) - } - - validators, err := genesis.ReadValidatorsByPrefix(validatorsPath, p.validatorsPrefixPath) - if err != nil { - return nil, err - } - - for _, v := range validators { - v.Balance = getPremineAmount(v.Address, premineMap, command.DefaultPremineBalance) - v.Stake = getPremineAmount(v.Address, stakeMap, command.DefaultStake) - } - - return validators, nil -} - -// getPremineAmount retrieves amount from the premine map or if not provided, returns default amount -func getPremineAmount(addr types.Address, premineMap map[types.Address]*genesis.PremineInfo, - defaultAmount *big.Int) *big.Int { - if premine, exists := premineMap[addr]; exists { - return premine.Amount - } - - return defaultAmount -} - -func (p *manifestInitParams) getResult() command.CommandResult { - return &result{ - message: fmt.Sprintf("Manifest file written to %s\n", p.manifestPath), - } -} - -type result struct { - message string -} - -func (r *result) GetOutput() string { - var buffer bytes.Buffer - - buffer.WriteString("\n[MANIFEST INITIALIZATION SUCCESS]\n") - buffer.WriteString(r.message) - - return buffer.String() -} diff --git a/command/polybftsecrets/params.go b/command/polybftsecrets/params.go index f35d2bea13..ec521ecbfc 100644 --- a/command/polybftsecrets/params.go +++ b/command/polybftsecrets/params.go @@ -20,7 +20,6 @@ const ( networkFlag = "network" numFlag = "num" outputFlag = "output" - chainIDFlag = "chain-id" // maxInitNum is the maximum value for "num" flag maxInitNum = 30 @@ -40,8 +39,6 @@ type initParams struct { insecureLocalStore bool output bool - - chainID int64 } func (ip *initParams) validateFlags() error { @@ -119,13 +116,6 @@ func (ip *initParams) setFlags(cmd *cobra.Command) { false, "the flag indicating to output existing secrets", ) - - cmd.Flags().Int64Var( - &ip.chainID, - chainIDFlag, - command.DefaultChainID, - "the ID of the chain", - ) } func (ip *initParams) Execute() (Results, error) { @@ -196,19 +186,6 @@ func (ip *initParams) initKeys(secretsManager secrets.SecretsManager) ([]string, } generated = append(generated, secrets.ValidatorKey, secrets.ValidatorBLSKey) - } else { - a, err = wallet.NewAccountFromSecret(secretsManager) - if err != nil { - return generated, fmt.Errorf("error loading account: %w", err) - } - } - - if !secretsManager.HasSecret(secrets.ValidatorBLSSignature) { - if _, err = helper.InitValidatorBLSSignature(secretsManager, a, ip.chainID); err != nil { - return generated, fmt.Errorf("%w: error initializing validator-bls-signature", err) - } - - generated = append(generated, secrets.ValidatorBLSSignature) } } @@ -234,12 +211,6 @@ func (ip *initParams) getResult( res.Address = types.Address(account.Ecdsa.Address()) res.BLSPubkey = hex.EncodeToString(account.Bls.PublicKey().Marshal()) - s, err := secretsManager.GetSecret(secrets.ValidatorBLSSignature) - if err != nil { - return nil, err - } - - res.BLSSignature = string(s) res.Generated = strings.Join(generated, ", ") if ip.printPrivateKey { diff --git a/command/polybftsecrets/params_test.go b/command/polybftsecrets/params_test.go index 0671db3505..2d140973b6 100644 --- a/command/polybftsecrets/params_test.go +++ b/command/polybftsecrets/params_test.go @@ -29,7 +29,6 @@ func Test_initKeys(t *testing.T) { ip := &initParams{ generatesAccount: false, generatesNetwork: false, - chainID: 1, } _, err = ip.initKeys(sm) @@ -38,16 +37,14 @@ func Test_initKeys(t *testing.T) { assert.False(t, fileExists(path.Join(dir, "consensus/validator.key"))) assert.False(t, fileExists(path.Join(dir, "consensus/validator-bls.key"))) assert.False(t, fileExists(path.Join(dir, "libp2p/libp2p.key"))) - assert.False(t, fileExists(path.Join(dir, "consensus/validator.sig"))) ip.generatesAccount = true res, err := ip.initKeys(sm) require.NoError(t, err) - assert.Len(t, res, 3) + assert.Len(t, res, 2) assert.True(t, fileExists(path.Join(dir, "consensus/validator.key"))) assert.True(t, fileExists(path.Join(dir, "consensus/validator-bls.key"))) - assert.True(t, fileExists(path.Join(dir, "consensus/validator.sig"))) assert.False(t, fileExists(path.Join(dir, "libp2p/libp2p.key"))) ip.generatesNetwork = true @@ -83,7 +80,6 @@ func Test_getResult(t *testing.T) { generatesAccount: true, generatesNetwork: true, printPrivateKey: true, - chainID: 1, } _, err = ip.initKeys(sm) @@ -92,13 +88,7 @@ func Test_getResult(t *testing.T) { res, err := ip.getResult(sm, []string{}) require.NoError(t, err) - // Test BLS signature sir := res.(*SecretsInitResult) //nolint:forcetypeassert - ds, err := hex.DecodeString(sir.BLSSignature) - require.NoError(t, err) - - _, err = bls.UnmarshalSignature(ds) - require.NoError(t, err) // Test public key serialization privKey, err := hex.DecodeString(sir.PrivateKey) diff --git a/command/polybftsecrets/result.go b/command/polybftsecrets/result.go index 70adf2afd5..f3867312c3 100644 --- a/command/polybftsecrets/result.go +++ b/command/polybftsecrets/result.go @@ -28,7 +28,6 @@ type SecretsInitResult struct { NodeID string `json:"node_id"` PrivateKey string `json:"private_key"` BLSPrivateKey string `json:"bls_private_key"` - BLSSignature string `json:"bls_signature"` Insecure bool `json:"insecure"` Generated string `json:"generated"` } @@ -64,13 +63,6 @@ func (r *SecretsInitResult) GetOutput() string { ) } - if r.BLSSignature != "" { - vals = append( - vals, - fmt.Sprintf("BLS Signature|%s", r.BLSSignature), - ) - } - vals = append(vals, fmt.Sprintf("Node ID|%s", r.NodeID)) if r.Insecure { diff --git a/command/polybftsecrets/utils.go b/command/polybftsecrets/utils.go index 9507c0cb31..655f9b9e87 100644 --- a/command/polybftsecrets/utils.go +++ b/command/polybftsecrets/utils.go @@ -12,15 +12,18 @@ import ( const ( AccountDirFlag = "data-dir" AccountConfigFlag = "config" + PrivateKeyFlag = "private-key" + ChainIDFlag = "chain-id" AccountDirFlagDesc = "the directory for the Polygon Edge data if the local FS is used" AccountConfigFlagDesc = "the path to the SecretsManager config file, if omitted, the local FS secrets manager is used" + PrivateKeyFlagDesc = "hex-encoded private key of the account which executes rootchain commands" + ChainIDFlagDesc = "ID of child chain" ) // common errors for all polybft commands var ( ErrInvalidNum = fmt.Errorf("num flag value should be between 1 and %d", maxInitNum) - ErrInvalidConfig = errors.New("invalid secrets configuration") ErrInvalidParams = errors.New("no config file or data directory passed in") ErrUnsupportedType = errors.New("unsupported secrets manager") ErrSecureLocalStoreNotImplemented = errors.New( @@ -35,9 +38,7 @@ func GetSecretsManager(dataPath, configPath string, insecureLocalStore bool) (se if configPath != "" { secretsConfig, readErr := secrets.ReadConfig(configPath) if readErr != nil { - invalidConfigErr := ErrInvalidConfig.Error() - - return nil, fmt.Errorf("%s: %w", invalidConfigErr, readErr) + return nil, fmt.Errorf("invalid secrets configuration: %w", readErr) } if !secrets.SupportedServiceManager(secretsConfig.Type) { diff --git a/command/regenesis/howtotest.md b/command/regenesis/howtotest.md index 8a474a228c..6c0064cbae 100644 --- a/command/regenesis/howtotest.md +++ b/command/regenesis/howtotest.md @@ -1,166 +1,178 @@ -1) create cluster -```bash -scripts/cluster ibft -``` -2) check balance -```bash -curl -s -X POST --data '{"jsonrpc":"2.0", "method":"eth_getBalance", "params":["0x85da99c8a7c2c95964c8efd687e95e632fc533d6", "latest"], "id":1}' http://localhost:10002 - -{"jsonrpc":"2.0","id":1,"result":"0x3635c9adc5dea00000"} -``` - -3) get trie root -```bash -./polygon-edge regenesis getroot --rpc "http://localhost:10002" - -[Trie copy SUCCESS] -state root 0xf5ef1a28c82226effb90f4465180ec3469226747818579673f4be929f1cd8663 for block 38 - -``` - -4) make trie snapshot -```bash - -./polygon-edge regenesis --target-path ./trie_new --stateRoot 0xf5ef1a28c82226effb90f4465180ec3469226747818579673f4be929f1cd8663 --source-path ./test-chain-1/trie - -[Trie copy SUCCESS] - -``` - -5) remove old chain data -```bash -rm -rf test-chain-* -``` -6) create new validators -```bash -./polygon-edge polybft-secrets --insecure --data-dir test-chain- --num 4 - -[WARNING: INSECURE LOCAL SECRETS - SHOULD NOT BE RUN IN PRODUCTION] - -[SECRETS INIT] -Public key (address) = 0x467CaA6185461E4c518597dCE7DE497Fb98a5680 -BLS Public key = 197059fdc3a78bd4001d802481c5ff1d84870c0b37aef851c83522323bd80f6429751ddae63cf38d180a8d45a5b4bf5519f380d60d6eedf9ccd22c3f95fc5e3a1193155af6ff3ab9e2aea5beab3f52e5e364d2cb410d6108c92f9a8375aac73110b8526407691c7e92e5cfab984e9011202b0606dc2be942808554b848cce67b -Node ID = 16Uiu2HAmTN2YAviWyyG4A56Zz8gsVJhmksdojymS4pk54SZqVbGV - -[WARNING: INSECURE LOCAL SECRETS - SHOULD NOT BE RUN IN PRODUCTION] - -[SECRETS INIT] -Public key (address) = 0x33177bBAebcB20F8545864a83b9b6EE334e4f94D -BLS Public key = 12d82d172646703d298453cef6f4415ceab2052267d9ec300fd4742fa46fd8db0168b5e98372ae3efd52d647f9b356043163fc4f76182f1ef685faf5e53b1dba15b7d0d9cb9b7868592e02179255775618dbacafd384cffba95b647a5d84de9a27995bb8cc0766194f370ad5b274d1a53b9b8ab21a3dee2f4ee4f177f63fb1f0 -Node ID = 16Uiu2HAkvtXkr1Hsct3UGn19ULNb7jgzPvEPu6Fpdakco8P45648 - -[WARNING: INSECURE LOCAL SECRETS - SHOULD NOT BE RUN IN PRODUCTION] - -[SECRETS INIT] -Public key (address) = 0xf308dF858dA25c2e40485FfA2c037D98105FD254 -BLS Public key = 220efa87e71744f44e286230cf4ac95a419abdd6d33d1a578fee21387b841fa32184dd132c077adb8f46db0eb66333672e36b5f363778030475672defce0b5622bb0974424dd7babfdf722fe9eab75ab6e5e34e2ecfcea89420f757bf8adfeb7020f0f961ca946cdb2dde40413c5c0d48aa9f13182ec35b58c4052de466c0e25 -Node ID = 16Uiu2HAmJqYRtWGbepPjQMgWfXnFEkXuX4GKH8AdD1voTwHpKuFa - -[WARNING: INSECURE LOCAL SECRETS - SHOULD NOT BE RUN IN PRODUCTION] - -[SECRETS INIT] -Public key (address) = 0x7eC6b7fc98D988472AD1AC0cFcaC6DA993d865B0 -BLS Public key = 2b8188f4bc99a19d5476fc97d14e17231cfb80b205a9fc45261725edefb0195209d972e9c1ad7d3c52b8fa129637738a88203c92fe8aa70fd0998d00f6251cb403ee077ddb4192fac270fe321468fe209308ea7597288e2505ed819f551ed00510c61f3da60f6a83d6017cbaeb7590c44bd354415178bbb160701b12a72a35a6 -Node ID = 16Uiu2HAmEuYYyzQKpyVr2HVCG8Gqx5e5DLCi8LWY4TkFYvHYcWAq - -``` - -7) generate genesis manifest -```bash -./polygon-edge manifest -``` - -8) generate genesis file -```bash -./polygon-edge genesis --consensus polybft --validator-set-size=4 --bridge-json-rpc http://127.0.0.1:8545 \ ---block-gas-limit 10000000 \ ---epoch-size 10 --trieroot 0xf5ef1a28c82226effb90f4465180ec3469226747818579673f4be929f1cd8663 - -[GENESIS SUCCESS] -**** POLYBFT CONSENSUS PROTOCOL IS IN EXPERIMENTAL PHASE AND IS NOT FULLY PRODUCTION READY. YOU ARE USING IT AT YOUR OWN RISK. **** -Genesis written to ./genesis.json - -``` - -9) Try to start a new v0.7 chain -```bash - ./polygon-edge server --data-dir ./test-chain-1 --chain genesis.json --grpc-address :10000 --libp2p :30301 --jsonrpc :10002 --seal --log-level DEBUG & -./polygon-edge server --data-dir ./test-chain-2 --chain genesis.json --grpc-address :20000 --libp2p :30302 --jsonrpc :20002 --seal --log-level DEBUG & -./polygon-edge server --data-dir ./test-chain-3 --chain genesis.json --grpc-address :30000 --libp2p :30303 --jsonrpc :30002 --seal --log-level DEBUG & -./polygon-edge server --data-dir ./test-chain-4 --chain genesis.json --grpc-address :40000 --libp2p :30304 --jsonrpc :40002 --seal --log-level DEBUG & -wait - -[1] 2615 -[2] 2616 -[3] 2617 -[4] 2618 -2023-03-15T11:02:25.149+0400 [INFO] polygon.server: Data dir: path=./test-chain-1 -2023-03-15T11:02:25.149+0400 [DEBUG] polygon.server: DataDog profiler disabled, set DD_PROFILING_ENABLED env var to enable it. -2023-03-15T11:02:25.233+0400 [INFO] polygon.server: Data dir: path=./test-chain-3 -2023-03-15T11:02:25.251+0400 [DEBUG] polygon.server: DataDog profiler disabled, set DD_PROFILING_ENABLED env var to enable it. -invalid initial state root -[1] exit 1 ./polygon-edge server --data-dir ./test-chain-1 --chain genesis.json :10000 -2023-03-15T11:02:25.299+0400 [INFO] polygon.server: Data dir: path=./test-chain-2 -2023-03-15T11:02:25.302+0400 [DEBUG] polygon.server: DataDog profiler disabled, set DD_PROFILING_ENABLED env var to enable it. -2023-03-15T11:02:25.396+0400 [INFO] polygon.server: Data dir: path=./test-chain-4 -2023-03-15T11:02:25.413+0400 [DEBUG] polygon.server: DataDog profiler disabled, set DD_PROFILING_ENABLED env var to enable it. -invalid initial state root -[3] - exit 1 ./polygon-edge server --data-dir ./test-chain-3 --chain genesis.json :30000 -invalid initial state root -[2] - exit 1 ./polygon-edge server --data-dir ./test-chain-2 --chain genesis.json :20000 -invalid initial state root -[4] + exit 1 ./polygon-edge server --data-dir ./test-chain-4 --chain genesis.json :40000 -``` - -It fails, because we havent provided trie database with correct state trie. - -10) Copy snapshot trie to our data directory -```bash -rm -rf ./test-chain-1/trie -rm -rf ./test-chain-2/trie -rm -rf ./test-chain-3/trie -rm -rf ./test-chain-4/trie -cp -fR ./trie_new/ ./test-chain-1/trie/ -cp -fR ./trie_new/ ./test-chain-2/trie/ -cp -fR ./trie_new/ ./test-chain-3/trie/ -cp -fR ./trie_new/ ./test-chain-4/trie/ -``` - -11) run chain again -```bash - ./polygon-edge server --data-dir ./test-chain-1 --chain genesis.json --grpc-address :10000 --libp2p :30301 --jsonrpc :10002 --seal --log-level DEBUG & -./polygon-edge server --data-dir ./test-chain-2 --chain genesis.json --grpc-address :20000 --libp2p :30302 --jsonrpc :20002 --seal --log-level DEBUG & -./polygon-edge server --data-dir ./test-chain-3 --chain genesis.json --grpc-address :30000 --libp2p :30303 --jsonrpc :30002 --seal --log-level DEBUG & -./polygon-edge server --data-dir ./test-chain-4 --chain genesis.json --grpc-address :40000 --libp2p :30304 --jsonrpc :40002 --seal --log-level DEBUG & -wait - -[1] 2721 -[2] 2722 -[3] 2723 -[4] 2724 -2023-03-15T11:09:41.481+0400 [INFO] polygon.server: Data dir: path=./test-chain-2 -2023-03-15T11:09:41.481+0400 [DEBUG] polygon.server: DataDog profiler disabled, set DD_PROFILING_ENABLED env var to enable it. -2023-03-15T11:09:41.597+0400 [INFO] polygon.server: Data dir: path=./test-chain-1 -2023-03-15T11:09:41.597+0400 [DEBUG] polygon.server: DataDog profiler disabled, set DD_PROFILING_ENABLED env var to enable it. -2023-03-15T11:09:41.609+0400 [WARN] polygon: Initial state root checked and correct -2023-03-15T11:09:41.661+0400 [INFO] polygon.server: Data dir: path=./test-chain-4 -2023-03-15T11:09:41.661+0400 [DEBUG] polygon.server: DataDog profiler disabled, set DD_PROFILING_ENABLED env var to enable it. -2023-03-15T11:09:41.725+0400 [INFO] polygon.server: Data dir: path=./test-chain-3 -2023-03-15T11:09:41.725+0400 [DEBUG] polygon.server: DataDog profiler disabled, set DD_PROFILING_ENABLED env var to enable it. -2023-03-15T11:09:41.844+0400 [INFO] polygon.blockchain: genesis: hash=0x627b70a8abc294324808d9820015faa5e0616afca5fdc75528b03b703a461acd -2023-03-15T11:09:41.844+0400 [INFO] polygon.server.polybft: initializing polybft... -2023-03-15T11:09:41.951+0400 [WARN] polygon: Initial state root checked and correct -2023-03-15T11:09:42.101+0400 [WARN] polygon: Initial state root checked and correct -2023-03-15T11:09:42.254+0400 [WARN] polygon: Initial state root checked and correct -2023-03-15T11:09:42.445+0400 [INFO] polygon.blockchain: genesis: hash=0x627b70a8abc294324808d9820015faa5e0616afca5fdc75528b03b703a461acd -2023-03-15T11:09:42.445+0400 [INFO] polygon.server.polybft: initializing polybft... -2023-03-15T11:09:42.462+0400 [INFO] polygon.server.polybft.consensus_runtime: restartEpoch: block number=0 epoch=1 validators=4 firstBlockInEpoch=1 -... -``` - -12) check that balance of account on v0.6 is not 0 -```bash - curl -s -X POST --data '{"jsonrpc":"2.0", "method":"eth_getBalance", "params":["0x85da99c8a7c2c95964c8efd687e95e632fc533d6", "latest"], "id":1}' http://localhost:10002 - -{"jsonrpc":"2.0","id":1,"result":"0x3635c9adc5dea00000"}% -``` \ No newline at end of file +# Regenesis procedure + +This document outlines step necessary to perform a regenesis data migration. + +## Steps + +1. Create cluster + + ```bash + scripts/cluster ibft + ``` + +2. Check balance + + ```bash + curl -s -X POST --data '{"jsonrpc":"2.0", "method":"eth_getBalance", "params":["0x85da99c8a7c2c95964c8efd687e95e632fc533d6", "latest"], "id":1}' http://localhost:10002 + + {"jsonrpc":"2.0","id":1,"result":"0x3635c9adc5dea00000"} + ``` + +3. Get trie root + + ```bash + ./polygon-edge regenesis getroot --rpc "http://localhost:10002" + + [Trie copy SUCCESS] + state root 0xf5ef1a28c82226effb90f4465180ec3469226747818579673f4be929f1cd8663 for block 38 + ``` + +4. Make trie snapshot + + ```bash + ./polygon-edge regenesis --target-path ./trie_new --stateRoot 0xf5ef1a28c82226effb90f4465180ec3469226747818579673f4be929f1cd8663 --source-path ./test-chain-1/trie + + [Trie copy SUCCESS] + + ``` + +5. Remove old chain data + + ```bash + rm -rf test-chain-* + ``` + +6. Create new validators + + ```bash + ./polygon-edge polybft-secrets --insecure --data-dir test-chain- --num 4 + + [WARNING: INSECURE LOCAL SECRETS - SHOULD NOT BE RUN IN PRODUCTION] + + [SECRETS INIT] + Public key (address. = 0x467CaA6185461E4c518597dCE7DE497Fb98a5680 + BLS Public key = 197059fdc3a78bd4001d802481c5ff1d84870c0b37aef851c83522323bd80f6429751ddae63cf38d180a8d45a5b4bf5519f380d60d6eedf9ccd22c3f95fc5e3a1193155af6ff3ab9e2aea5beab3f52e5e364d2cb410d6108c92f9a8375aac73110b8526407691c7e92e5cfab984e9011202b0606dc2be942808554b848cce67b + Node ID = 16Uiu2HAmTN2YAviWyyG4A56Zz8gsVJhmksdojymS4pk54SZqVbGV + + [WARNING: INSECURE LOCAL SECRETS - SHOULD NOT BE RUN IN PRODUCTION] + + [SECRETS INIT] + Public key (address. = 0x33177bBAebcB20F8545864a83b9b6EE334e4f94D + BLS Public key = 12d82d172646703d298453cef6f4415ceab2052267d9ec300fd4742fa46fd8db0168b5e98372ae3efd52d647f9b356043163fc4f76182f1ef685faf5e53b1dba15b7d0d9cb9b7868592e02179255775618dbacafd384cffba95b647a5d84de9a27995bb8cc0766194f370ad5b274d1a53b9b8ab21a3dee2f4ee4f177f63fb1f0 + Node ID = 16Uiu2HAkvtXkr1Hsct3UGn19ULNb7jgzPvEPu6Fpdakco8P45648 + + [WARNING: INSECURE LOCAL SECRETS - SHOULD NOT BE RUN IN PRODUCTION] + + [SECRETS INIT] + Public key (address. = 0xf308dF858dA25c2e40485FfA2c037D98105FD254 + BLS Public key = 220efa87e71744f44e286230cf4ac95a419abdd6d33d1a578fee21387b841fa32184dd132c077adb8f46db0eb66333672e36b5f363778030475672defce0b5622bb0974424dd7babfdf722fe9eab75ab6e5e34e2ecfcea89420f757bf8adfeb7020f0f961ca946cdb2dde40413c5c0d48aa9f13182ec35b58c4052de466c0e25 + Node ID = 16Uiu2HAmJqYRtWGbepPjQMgWfXnFEkXuX4GKH8AdD1voTwHpKuFa + + [WARNING: INSECURE LOCAL SECRETS - SHOULD NOT BE RUN IN PRODUCTION] + + [SECRETS INIT] + Public key (address. = 0x7eC6b7fc98D988472AD1AC0cFcaC6DA993d865B0 + BLS Public key = 2b8188f4bc99a19d5476fc97d14e17231cfb80b205a9fc45261725edefb0195209d972e9c1ad7d3c52b8fa129637738a88203c92fe8aa70fd0998d00f6251cb403ee077ddb4192fac270fe321468fe209308ea7597288e2505ed819f551ed00510c61f3da60f6a83d6017cbaeb7590c44bd354415178bbb160701b12a72a35a6 + Node ID = 16Uiu2HAmEuYYyzQKpyVr2HVCG8Gqx5e5DLCi8LWY4TkFYvHYcWAq + + ``` + +7. Generate genesis file + + ```bash + ./polygon-edge genesis --consensus polybft \ + --block-gas-limit 10000000 \ + --epoch-size 10 --trieroot 0xf5ef1a28c82226effb90f4465180ec3469226747818579673f4be929f1cd8663 + + [GENESIS SUCCESS] + **** POLYBFT CONSENSUS PROTOCOL IS IN EXPERIMENTAL PHASE AND IS NOT FULLY PRODUCTION READY. YOU ARE USING IT AT YOUR OWN RISK. **** + Genesis written to ./genesis.json + + ``` + +8. Try to start a new v0.7 chain + + ```bash + ./polygon-edge server --data-dir ./test-chain-1 --chain genesis.json --grpc-address :10000 --libp2p :30301 --jsonrpc :10002 --seal --log-level DEBUG & + ./polygon-edge server --data-dir ./test-chain-2 --chain genesis.json --grpc-address :20000 --libp2p :30302 --jsonrpc :20002 --seal --log-level DEBUG & + ./polygon-edge server --data-dir ./test-chain-3 --chain genesis.json --grpc-address :30000 --libp2p :30303 --jsonrpc :30002 --seal --log-level DEBUG & + ./polygon-edge server --data-dir ./test-chain-4 --chain genesis.json --grpc-address :40000 --libp2p :30304 --jsonrpc :40002 --seal --log-level DEBUG & + wait + + [1] 2615 + [2] 2616 + [3] 2617 + [4] 2618 + 2023-03-15T11:02:25.149+0400 [INFO] polygon.server: Data dir: path=./test-chain-1 + 2023-03-15T11:02:25.149+0400 [DEBUG] polygon.server: DataDog profiler disabled, set DD_PROFILING_ENABLED env var to enable it. + 2023-03-15T11:02:25.233+0400 [INFO] polygon.server: Data dir: path=./test-chain-3 + 2023-03-15T11:02:25.251+0400 [DEBUG] polygon.server: DataDog profiler disabled, set DD_PROFILING_ENABLED env var to enable it. + invalid initial state root + [1] exit 1 ./polygon-edge server --data-dir ./test-chain-1 --chain genesis.json :10000 + 2023-03-15T11:02:25.299+0400 [INFO] polygon.server: Data dir: path=./test-chain-2 + 2023-03-15T11:02:25.302+0400 [DEBUG] polygon.server: DataDog profiler disabled, set DD_PROFILING_ENABLED env var to enable it. + 2023-03-15T11:02:25.396+0400 [INFO] polygon.server: Data dir: path=./test-chain-4 + 2023-03-15T11:02:25.413+0400 [DEBUG] polygon.server: DataDog profiler disabled, set DD_PROFILING_ENABLED env var to enable it. + invalid initial state root + [3] - exit 1 ./polygon-edge server --data-dir ./test-chain-3 --chain genesis.json :30000 + invalid initial state root + [2] - exit 1 ./polygon-edge server --data-dir ./test-chain-2 --chain genesis.json :20000 + invalid initial state root + [4] + exit 1 ./polygon-edge server --data-dir ./test-chain-4 --chain genesis.json :40000 + ``` + + It fails, because we havent provided trie database with correct state trie. + +9. Copy snapshot trie to our data directory + + ```bash + rm -rf ./test-chain-1/trie + rm -rf ./test-chain-2/trie + rm -rf ./test-chain-3/trie + rm -rf ./test-chain-4/trie + cp -fR ./trie_new/ ./test-chain-1/trie/ + cp -fR ./trie_new/ ./test-chain-2/trie/ + cp -fR ./trie_new/ ./test-chain-3/trie/ + cp -fR ./trie_new/ ./test-chain-4/trie/ + ``` + +10. Run chain again + + ```bash + ./polygon-edge server --data-dir ./test-chain-1 --chain genesis.json --grpc-address :10000 --libp2p :30301 --jsonrpc :10002 --seal --log-level DEBUG & + ./polygon-edge server --data-dir ./test-chain-2 --chain genesis.json --grpc-address :20000 --libp2p :30302 --jsonrpc :20002 --seal --log-level DEBUG & + ./polygon-edge server --data-dir ./test-chain-3 --chain genesis.json --grpc-address :30000 --libp2p :30303 --jsonrpc :30002 --seal --log-level DEBUG & + ./polygon-edge server --data-dir ./test-chain-4 --chain genesis.json --grpc-address :40000 --libp2p :30304 --jsonrpc :40002 --seal --log-level DEBUG & + wait + + [1] 2721 + [2] 2722 + [3] 2723 + [4] 2724 + 2023-03-15T11:09:41.481+0400 [INFO] polygon.server: Data dir: path=./test-chain-2 + 2023-03-15T11:09:41.481+0400 [DEBUG] polygon.server: DataDog profiler disabled, set DD_PROFILING_ENABLED env var to enable it. + 2023-03-15T11:09:41.597+0400 [INFO] polygon.server: Data dir: path=./test-chain-1 + 2023-03-15T11:09:41.597+0400 [DEBUG] polygon.server: DataDog profiler disabled, set DD_PROFILING_ENABLED env var to enable it. + 2023-03-15T11:09:41.609+0400 [WARN] polygon: Initial state root checked and correct + 2023-03-15T11:09:41.661+0400 [INFO] polygon.server: Data dir: path=./test-chain-4 + 2023-03-15T11:09:41.661+0400 [DEBUG] polygon.server: DataDog profiler disabled, set DD_PROFILING_ENABLED env var to enable it. + 2023-03-15T11:09:41.725+0400 [INFO] polygon.server: Data dir: path=./test-chain-3 + 2023-03-15T11:09:41.725+0400 [DEBUG] polygon.server: DataDog profiler disabled, set DD_PROFILING_ENABLED env var to enable it. + 2023-03-15T11:09:41.844+0400 [INFO] polygon.blockchain: genesis: hash=0x627b70a8abc294324808d9820015faa5e0616afca5fdc75528b03b703a461acd + 2023-03-15T11:09:41.844+0400 [INFO] polygon.server.polybft: initializing polybft... + 2023-03-15T11:09:41.951+0400 [WARN] polygon: Initial state root checked and correct + 2023-03-15T11:09:42.101+0400 [WARN] polygon: Initial state root checked and correct + 2023-03-15T11:09:42.254+0400 [WARN] polygon: Initial state root checked and correct + 2023-03-15T11:09:42.445+0400 [INFO] polygon.blockchain: genesis: hash=0x627b70a8abc294324808d9820015faa5e0616afca5fdc75528b03b703a461acd + 2023-03-15T11:09:42.445+0400 [INFO] polygon.server.polybft: initializing polybft... + 2023-03-15T11:09:42.462+0400 [INFO] polygon.server.polybft.consensus_runtime: restartEpoch: block number=0 epoch=1 validators=4 firstBlockInEpoch=1 + ... + ``` + +11. Check that balance of account on v0.6 is not 0 + + ```bash + curl -s -X POST --data '{"jsonrpc":"2.0", "method":"eth_getBalance", "params":["0x85da99c8a7c2c95964c8efd687e95e632fc533d6", "latest"], "id":1}' http://localhost:10002 + + {"jsonrpc":"2.0","id":1,"result":"0x3635c9adc5dea00000"}% + ``` diff --git a/command/root/root.go b/command/root/root.go index 958400825e..b52fb188cb 100644 --- a/command/root/root.go +++ b/command/root/root.go @@ -15,16 +15,15 @@ import ( "github.com/0xPolygon/polygon-edge/command/monitor" "github.com/0xPolygon/polygon-edge/command/peers" "github.com/0xPolygon/polygon-edge/command/polybft" - "github.com/0xPolygon/polygon-edge/command/polybftmanifest" "github.com/0xPolygon/polygon-edge/command/polybftsecrets" "github.com/0xPolygon/polygon-edge/command/regenesis" "github.com/0xPolygon/polygon-edge/command/rootchain" "github.com/0xPolygon/polygon-edge/command/secrets" "github.com/0xPolygon/polygon-edge/command/server" + "github.com/0xPolygon/polygon-edge/command/sidecar" "github.com/0xPolygon/polygon-edge/command/status" "github.com/0xPolygon/polygon-edge/command/txpool" "github.com/0xPolygon/polygon-edge/command/version" - "github.com/0xPolygon/polygon-edge/command/whitelist" ) type RootCommand struct { @@ -58,11 +57,10 @@ func (rc *RootCommand) registerSubCommands() { backup.GetCommand(), genesis.GetCommand(), server.GetCommand(), - whitelist.GetCommand(), license.GetCommand(), + sidecar.GetCommand(), polybftsecrets.GetCommand(), polybft.GetCommand(), - polybftmanifest.GetCommand(), bridge.GetCommand(), regenesis.GetCommand(), ) diff --git a/command/rootchain/README.md b/command/rootchain/README.md index 446e979af5..7e6b2ab8b4 100644 --- a/command/rootchain/README.md +++ b/command/rootchain/README.md @@ -4,7 +4,7 @@ Top level command for manipulating rootchain server. ## Start rootchain server -This command starts `ethereum/client-go` container which is basically geth node. +This command starts `ethereum/client-go` container which is Geth node started in dev mode. ```bash $ polygon-edge rootchain server @@ -17,7 +17,9 @@ This command funds the initialized accounts via `polygon-edge polybft-secrets` c ```bash $ polygon-edge rootchain fund --data-dir data-dir- --num 2 ``` -Or + +or + ```bash $ polygon-edge rootchain fund --data-dir data-dir-1 ``` @@ -27,10 +29,12 @@ $ polygon-edge rootchain fund --data-dir data-dir-1 This command deploys and initializes rootchain contracts. Transactions are being sent to given `--json-rpc` endpoint and are signed by private key provided by `--adminKey` flag. ```bash -$ polygon-edge rootchain init-contracts - --manifest - --deployer-key +$ polygon-edge rootchain deploy \ + --genesis \ + --deployer-key \ + --stake-manager \ + --stake-token \ --json-rpc ``` -**Note:** In case `test` flag is provided, it engages test mode, which uses predefined test account private key to send transactions to the rootchain. \ No newline at end of file +**Note:** In case `test` flag is provided, it engages test mode, which uses predefined test account private key to send transactions to the rootchain. diff --git a/command/rootchain/deploy/deploy.go b/command/rootchain/deploy/deploy.go new file mode 100644 index 0000000000..8f931815d6 --- /dev/null +++ b/command/rootchain/deploy/deploy.go @@ -0,0 +1,687 @@ +package deploy + +import ( + "context" + "errors" + "fmt" + + "github.com/spf13/cobra" + "github.com/umbracle/ethgo" + "github.com/umbracle/ethgo/jsonrpc" + "golang.org/x/sync/errgroup" + + "github.com/0xPolygon/polygon-edge/chain" + "github.com/0xPolygon/polygon-edge/command" + cmdHelper "github.com/0xPolygon/polygon-edge/command/helper" + "github.com/0xPolygon/polygon-edge/command/rootchain/helper" + "github.com/0xPolygon/polygon-edge/consensus/polybft" + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi/artifact" + bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" + "github.com/0xPolygon/polygon-edge/contracts" + "github.com/0xPolygon/polygon-edge/txrelayer" + "github.com/0xPolygon/polygon-edge/types" +) + +const ( + contractsDeploymentTitle = "[ROOTCHAIN - CONTRACTS DEPLOYMENT]" + + stateSenderName = "StateSender" + checkpointManagerName = "CheckpointManager" + blsName = "BLS" + bn256G2Name = "BN256G2" + exitHelperName = "ExitHelper" + rootERC20PredicateName = "RootERC20Predicate" + childERC20MintablePredicateName = "ChildERC20MintablePredicate" + rootERC20Name = "RootERC20" + erc20TemplateName = "ERC20Template" + rootERC721PredicateName = "RootERC721Predicate" + childERC721MintablePredicateName = "ChildERC721MintablePredicate" + erc721TemplateName = "ERC721Template" + rootERC1155PredicateName = "RootERC1155Predicate" + childERC1155MintablePredicateName = "ChildERC1155MintablePredicate" + erc1155TemplateName = "ERC1155Template" + customSupernetManagerName = "CustomSupernetManager" +) + +var ( + // params are the parameters of CLI command + params deployParams + + // consensusCfg contains consensus protocol configuration parameters + consensusCfg polybft.PolyBFTConfig + + // metadataPopulatorMap maps rootchain contract names to callback + // which populates appropriate field in the RootchainMetadata + metadataPopulatorMap = map[string]func(*polybft.RootchainConfig, types.Address){ + stateSenderName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { + rootchainConfig.StateSenderAddress = addr + }, + checkpointManagerName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { + rootchainConfig.CheckpointManagerAddress = addr + }, + blsName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { + rootchainConfig.BLSAddress = addr + }, + bn256G2Name: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { + rootchainConfig.BN256G2Address = addr + }, + exitHelperName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { + rootchainConfig.ExitHelperAddress = addr + }, + rootERC20PredicateName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { + rootchainConfig.RootERC20PredicateAddress = addr + }, + childERC20MintablePredicateName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { + rootchainConfig.ChildMintableERC20PredicateAddress = addr + }, + rootERC20Name: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { + rootchainConfig.RootNativeERC20Address = addr + }, + erc20TemplateName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { + rootchainConfig.ChildERC20Address = addr + }, + rootERC721PredicateName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { + rootchainConfig.RootERC721PredicateAddress = addr + }, + childERC721MintablePredicateName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { + rootchainConfig.ChildMintableERC721PredicateAddress = addr + }, + erc721TemplateName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { + rootchainConfig.ChildERC721Address = addr + }, + rootERC1155PredicateName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { + rootchainConfig.RootERC1155PredicateAddress = addr + }, + childERC1155MintablePredicateName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { + rootchainConfig.ChildMintableERC1155PredicateAddress = addr + }, + erc1155TemplateName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { + rootchainConfig.ChildERC1155Address = addr + }, + customSupernetManagerName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { + rootchainConfig.CustomSupernetManagerAddress = addr + }, + } + + // initializersMap maps rootchain contract names to initializer function callbacks + initializersMap = map[string]func(command.OutputFormatter, txrelayer.TxRelayer, + *polybft.RootchainConfig, ethgo.Key) error{ + customSupernetManagerName: func(fmt command.OutputFormatter, + relayer txrelayer.TxRelayer, + config *polybft.RootchainConfig, + key ethgo.Key) error { + initParams := &contractsapi.InitializeCustomSupernetManagerFn{ + NewStakeManager: config.StakeManagerAddress, + NewBls: config.BLSAddress, + NewStateSender: config.StateSenderAddress, + NewMatic: types.StringToAddress(params.stakeTokenAddr), + NewChildValidatorSet: contracts.ValidatorSetContract, + NewExitHelper: config.ExitHelperAddress, + NewDomain: bls.DomainValidatorSetString, + } + + return initContract(fmt, relayer, initParams, + config.CustomSupernetManagerAddress, customSupernetManagerName, key) + }, + exitHelperName: func(fmt command.OutputFormatter, + relayer txrelayer.TxRelayer, + config *polybft.RootchainConfig, + key ethgo.Key) error { + inputParams := &contractsapi.InitializeExitHelperFn{ + NewCheckpointManager: config.CheckpointManagerAddress, + } + + return initContract(fmt, relayer, inputParams, config.ExitHelperAddress, exitHelperName, key) + }, + rootERC20PredicateName: func(fmt command.OutputFormatter, + relayer txrelayer.TxRelayer, + config *polybft.RootchainConfig, + key ethgo.Key) error { + // map root native token on rootchain only if it is non-mintable on a childchain + nativeTokenRootAddr := types.ZeroAddress + if !consensusCfg.NativeTokenConfig.IsMintable { + nativeTokenRootAddr = config.RootNativeERC20Address + } + + inputParams := &contractsapi.InitializeRootERC20PredicateFn{ + NewStateSender: config.StateSenderAddress, + NewExitHelper: config.ExitHelperAddress, + NewChildERC20Predicate: contracts.ChildERC20PredicateContract, + NewChildTokenTemplate: contracts.ChildERC20Contract, + NativeTokenRootAddress: nativeTokenRootAddr, + } + + return initContract(fmt, relayer, inputParams, + config.RootERC20PredicateAddress, rootERC20PredicateName, key) + }, + childERC20MintablePredicateName: func(fmt command.OutputFormatter, + relayer txrelayer.TxRelayer, + config *polybft.RootchainConfig, + key ethgo.Key) error { + initParams := &contractsapi.InitializeChildMintableERC20PredicateFn{ + NewStateSender: config.StateSenderAddress, + NewExitHelper: config.ExitHelperAddress, + NewRootERC20Predicate: contracts.RootMintableERC20PredicateContract, + NewChildTokenTemplate: config.ChildERC20Address, + } + + return initContract(fmt, relayer, initParams, + config.ChildMintableERC20PredicateAddress, childERC20MintablePredicateName, key) + }, + rootERC721PredicateName: func(fmt command.OutputFormatter, + relayer txrelayer.TxRelayer, + config *polybft.RootchainConfig, + key ethgo.Key) error { + initParams := &contractsapi.InitializeRootERC721PredicateFn{ + NewStateSender: config.StateSenderAddress, + NewExitHelper: config.ExitHelperAddress, + NewChildERC721Predicate: contracts.ChildERC721PredicateContract, + NewChildTokenTemplate: contracts.ChildERC721Contract, + } + + return initContract(fmt, relayer, initParams, + config.RootERC721PredicateAddress, rootERC721PredicateName, key) + }, + childERC721MintablePredicateName: func(fmt command.OutputFormatter, + relayer txrelayer.TxRelayer, + config *polybft.RootchainConfig, + key ethgo.Key) error { + initParams := &contractsapi.InitializeChildMintableERC721PredicateFn{ + NewStateSender: config.StateSenderAddress, + NewExitHelper: config.ExitHelperAddress, + NewRootERC721Predicate: contracts.RootMintableERC721PredicateContract, + NewChildTokenTemplate: config.ChildERC721Address, + } + + return initContract(fmt, relayer, initParams, + config.ChildMintableERC721PredicateAddress, childERC721MintablePredicateName, key) + }, + rootERC1155PredicateName: func(fmt command.OutputFormatter, + relayer txrelayer.TxRelayer, + config *polybft.RootchainConfig, + key ethgo.Key) error { + initParams := &contractsapi.InitializeRootERC1155PredicateFn{ + NewStateSender: config.StateSenderAddress, + NewExitHelper: config.ExitHelperAddress, + NewChildERC1155Predicate: contracts.ChildERC1155PredicateContract, + NewChildTokenTemplate: contracts.ChildERC1155Contract, + } + + return initContract(fmt, relayer, initParams, + config.RootERC1155PredicateAddress, rootERC1155PredicateName, key) + }, + childERC1155MintablePredicateName: func(fmt command.OutputFormatter, + relayer txrelayer.TxRelayer, + config *polybft.RootchainConfig, + key ethgo.Key) error { + initParams := &contractsapi.InitializeChildMintableERC1155PredicateFn{ + NewStateSender: config.StateSenderAddress, + NewExitHelper: config.ExitHelperAddress, + NewRootERC1155Predicate: contracts.RootMintableERC1155PredicateContract, + NewChildTokenTemplate: config.ChildERC1155Address, + } + + return initContract(fmt, relayer, initParams, + config.ChildMintableERC1155PredicateAddress, childERC1155MintablePredicateName, key) + }, + } +) + +// GetCommand returns the rootchain deploy command +func GetCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "deploy", + Short: "Deploys and initializes required smart contracts on the rootchain", + PreRunE: preRunCommand, + Run: runCommand, + } + + cmd.Flags().StringVar( + ¶ms.genesisPath, + helper.GenesisPathFlag, + helper.DefaultGenesisPath, + helper.GenesisPathFlagDesc, + ) + + cmd.Flags().StringVar( + ¶ms.deployerKey, + deployerKeyFlag, + "", + "hex-encoded private key of the account which deploys rootchain contracts", + ) + + cmd.Flags().StringVar( + ¶ms.jsonRPCAddress, + jsonRPCFlag, + txrelayer.DefaultRPCAddress, + "the JSON RPC rootchain IP address", + ) + + cmd.Flags().StringVar( + ¶ms.rootERC20TokenAddr, + erc20AddrFlag, + "", + "existing root chain root native token address", + ) + + cmd.Flags().BoolVar( + ¶ms.isTestMode, + helper.TestModeFlag, + false, + "test indicates whether rootchain contracts deployer is hardcoded test account"+ + " (otherwise provided secrets are used to resolve deployer account)", + ) + + cmd.Flags().StringVar( + ¶ms.stakeTokenAddr, + helper.StakeTokenFlag, + "", + helper.StakeTokenFlagDesc, + ) + + cmd.Flags().StringVar( + ¶ms.stakeManagerAddr, + helper.StakeManagerFlag, + "", + helper.StakeManagerFlagDesc, + ) + + cmd.MarkFlagsMutuallyExclusive(helper.TestModeFlag, deployerKeyFlag) + _ = cmd.MarkFlagRequired(helper.StakeManagerFlag) + _ = cmd.MarkFlagRequired(helper.StakeTokenFlag) + + return cmd +} + +func preRunCommand(_ *cobra.Command, _ []string) error { + return params.validateFlags() +} + +func runCommand(cmd *cobra.Command, _ []string) { + outputter := command.InitializeOutputter(cmd) + defer outputter.WriteOutput() + + outputter.WriteCommandResult(&helper.MessageResult{ + Message: fmt.Sprintf("%s started... Rootchain JSON RPC address %s.", contractsDeploymentTitle, params.jsonRPCAddress), + }) + + chainConfig, err := chain.ImportFromFile(params.genesisPath) + if err != nil { + outputter.SetError(fmt.Errorf("failed to read chain configuration: %w", err)) + + return + } + + client, err := jsonrpc.NewClient(params.jsonRPCAddress) + if err != nil { + outputter.SetError(fmt.Errorf("failed to initialize JSON RPC client for provided IP address: %s: %w", + params.jsonRPCAddress, err)) + + return + } + + if consensusCfg.Bridge != nil { + code, err := client.Eth().GetCode(ethgo.Address(consensusCfg.Bridge.StateSenderAddr), ethgo.Latest) + if err != nil { + outputter.SetError(fmt.Errorf("failed to check if rootchain contracts are deployed: %w", err)) + + return + } else if code != "0x" { + outputter.SetCommandResult(&helper.MessageResult{ + Message: fmt.Sprintf("%s contracts are already deployed. Aborting.", contractsDeploymentTitle), + }) + + return + } + } + + rootchainCfg, supernetID, err := deployContracts(outputter, client, + chainConfig.Params.ChainID, consensusCfg.InitialValidatorSet, cmd.Context()) + if err != nil { + outputter.SetError(fmt.Errorf("failed to deploy rootchain contracts: %w", err)) + + return + } + + // populate bridge configuration + bridgeConfig := rootchainCfg.ToBridgeConfig() + if consensusCfg.Bridge != nil { + // only true if stake-manager-deploy command was executed + // users can still deploy stake manager manually + // only used for e2e tests + bridgeConfig.StakeTokenAddr = consensusCfg.Bridge.StakeTokenAddr + } + + consensusCfg.Bridge = bridgeConfig + + // set event tracker start blocks for rootchain contract(s) of interest + blockNum, err := client.Eth().BlockNumber() + if err != nil { + outputter.SetError(fmt.Errorf("failed to query rootchain latest block number: %w", err)) + + return + } + + consensusCfg.Bridge.EventTrackerStartBlocks = map[types.Address]uint64{ + rootchainCfg.StateSenderAddress: blockNum, + } + consensusCfg.SupernetID = supernetID + + // write updated consensus configuration + chainConfig.Params.Engine[polybft.ConsensusName] = consensusCfg + + if err := cmdHelper.WriteGenesisConfigToDisk(chainConfig, params.genesisPath); err != nil { + outputter.SetError(fmt.Errorf("failed to save chain configuration bridge data: %w", err)) + + return + } + + outputter.SetCommandResult(&helper.MessageResult{ + Message: fmt.Sprintf("%s finished. All contracts are successfully deployed and initialized.", + contractsDeploymentTitle), + }) +} + +// deployContracts deploys and initializes rootchain smart contracts +func deployContracts(outputter command.OutputFormatter, client *jsonrpc.Client, chainID int64, + initialValidators []*validator.GenesisValidator, cmdCtx context.Context) (*polybft.RootchainConfig, int64, error) { + txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithClient(client), txrelayer.WithWriter(outputter)) + if err != nil { + return nil, 0, fmt.Errorf("failed to initialize tx relayer: %w", err) + } + + deployerKey, err := helper.DecodePrivateKey(params.deployerKey) + if err != nil { + return nil, 0, fmt.Errorf("failed to initialize deployer key: %w", err) + } + + if params.isTestMode { + deployerAddr := deployerKey.Address() + txn := ðgo.Transaction{To: &deployerAddr, Value: ethgo.Ether(1)} + + if _, err = txRelayer.SendTransactionLocal(txn); err != nil { + return nil, 0, err + } + } + + type contractInfo struct { + name string + artifact *artifact.Artifact + } + + rootchainConfig := &polybft.RootchainConfig{ + JSONRPCAddr: params.jsonRPCAddress, + // update stake manager address in genesis in case if stake manager was deployed manually + StakeManagerAddress: types.StringToAddress(params.stakeManagerAddr), + } + + tokenContracts := []*contractInfo{} + + // deploy root ERC20 token only if non-mintable native token flavor is used on a child chain + if !consensusCfg.NativeTokenConfig.IsMintable { + if params.rootERC20TokenAddr != "" { + // use existing root chain ERC20 token + if err := populateExistingTokenAddr(client.Eth(), + params.rootERC20TokenAddr, rootERC20Name, rootchainConfig); err != nil { + return nil, 0, err + } + } else { + // deploy MockERC20 as a root chain root native token + tokenContracts = append(tokenContracts, + &contractInfo{name: rootERC20Name, artifact: contractsapi.RootERC20}) + } + } + + allContracts := []*contractInfo{ + { + name: stateSenderName, + artifact: contractsapi.StateSender, + }, + { + name: checkpointManagerName, + artifact: contractsapi.CheckpointManager, + }, + { + name: blsName, + artifact: contractsapi.BLS, + }, + { + name: bn256G2Name, + artifact: contractsapi.BLS256, + }, + { + name: exitHelperName, + artifact: contractsapi.ExitHelper, + }, + { + name: rootERC20PredicateName, + artifact: contractsapi.RootERC20Predicate, + }, + { + name: childERC20MintablePredicateName, + artifact: contractsapi.ChildMintableERC20Predicate, + }, + { + name: erc20TemplateName, + artifact: contractsapi.ChildERC20, + }, + { + name: rootERC721PredicateName, + artifact: contractsapi.RootERC721Predicate, + }, + { + name: childERC721MintablePredicateName, + artifact: contractsapi.ChildMintableERC721Predicate, + }, + { + name: erc721TemplateName, + artifact: contractsapi.ChildERC721, + }, + { + name: rootERC1155PredicateName, + artifact: contractsapi.RootERC1155Predicate, + }, + { + name: childERC1155MintablePredicateName, + artifact: contractsapi.ChildMintableERC1155Predicate, + }, + { + name: erc1155TemplateName, + artifact: contractsapi.ChildERC1155, + }, + { + name: customSupernetManagerName, + artifact: contractsapi.CustomSupernetManager, + }, + } + + allContracts = append(tokenContracts, allContracts...) + + g, ctx := errgroup.WithContext(cmdCtx) + results := make([]*deployContractResult, len(allContracts)) + + for i, contract := range allContracts { + i := i + contract := contract + + g.Go(func() error { + select { + case <-ctx.Done(): + return ctx.Err() + default: + txn := ðgo.Transaction{ + To: nil, // contract deployment + Input: contract.artifact.Bytecode, + } + + receipt, err := txRelayer.SendTransaction(txn, deployerKey) + if err != nil { + return fmt.Errorf("failed sending %s contract deploy transaction: %w", contract.name, err) + } + + if receipt == nil || receipt.Status != uint64(types.ReceiptSuccess) { + return fmt.Errorf("deployment of %s contract failed", contract.name) + } + + results[i] = newDeployContractsResult(contract.name, + types.Address(receipt.ContractAddress), + receipt.TransactionHash, + receipt.GasUsed) + + return nil + } + }) + } + + if err := g.Wait(); err != nil { + _, _ = outputter.Write([]byte("[ROOTCHAIN - DEPLOY] Successfully deployed the following contracts\n")) + + for _, result := range results { + if result != nil { + // In case an error happened, some of the indices may not be populated. + // Filter those out. + outputter.WriteCommandResult(result) + } + } + + return nil, 0, err + } + + for _, result := range results { + populatorFn, ok := metadataPopulatorMap[result.Name] + if !ok { + return nil, 0, fmt.Errorf("rootchain metadata populator not registered for contract '%s'", result.Name) + } + + populatorFn(rootchainConfig, result.Address) + + outputter.WriteCommandResult(result) + } + + g, ctx = errgroup.WithContext(cmdCtx) + + for _, contract := range allContracts { + contract := contract + + initializer, exists := initializersMap[contract.name] + if !exists { + continue + } + + g.Go(func() error { + select { + case <-cmdCtx.Done(): + return cmdCtx.Err() + default: + return initializer(outputter, txRelayer, rootchainConfig, deployerKey) + } + }) + } + + if err := g.Wait(); err != nil { + return nil, 0, err + } + + // register supernets manager on stake manager + supernetID, err := registerChainOnStakeManager(txRelayer, rootchainConfig, deployerKey) + if err != nil { + return nil, 0, err + } + + return rootchainConfig, supernetID, nil +} + +// populateExistingTokenAddr checks whether given token is deployed on the provided address. +// If it is, then its address is set to the rootchain config, otherwise an error is returned +func populateExistingTokenAddr(eth *jsonrpc.Eth, tokenAddr, tokenName string, + rootchainCfg *polybft.RootchainConfig) error { + addr := types.StringToAddress(tokenAddr) + + code, err := eth.GetCode(ethgo.Address(addr), ethgo.Latest) + if err != nil { + return fmt.Errorf("failed to check is %s token deployed: %w", tokenName, err) + } else if code == "0x" { + return fmt.Errorf("%s token is not deployed on provided address %s", tokenName, tokenAddr) + } + + populatorFn, ok := metadataPopulatorMap[tokenName] + if !ok { + return fmt.Errorf("root chain metadata populator not registered for contract '%s'", tokenName) + } + + populatorFn(rootchainCfg, addr) + + return nil +} + +// registerChainOnStakeManager registers child chain and its supernet manager on rootchain +func registerChainOnStakeManager(txRelayer txrelayer.TxRelayer, + rootchainCfg *polybft.RootchainConfig, deployerKey ethgo.Key) (int64, error) { + registerChainFn := &contractsapi.RegisterChildChainStakeManagerFn{ + Manager: rootchainCfg.CustomSupernetManagerAddress, + } + + encoded, err := registerChainFn.EncodeAbi() + if err != nil { + return 0, fmt.Errorf("failed to encode parameters for registering child chain on supernets. error: %w", err) + } + + receipt, err := helper.SendTransaction(txRelayer, ethgo.Address(rootchainCfg.StakeManagerAddress), + encoded, checkpointManagerName, deployerKey) + if err != nil { + return 0, err + } + + var ( + childChainRegisteredEvent contractsapi.ChildManagerRegisteredEvent + found bool + supernetID int64 + ) + + for _, log := range receipt.Logs { + doesMatch, err := childChainRegisteredEvent.ParseLog(log) + if err != nil { + return 0, err + } + + if !doesMatch { + continue + } + + supernetID = childChainRegisteredEvent.ID.Int64() + found = true + + break + } + + if !found { + return 0, errors.New("could not find a log that child chain was registered on stake manager") + } + + return supernetID, nil +} + +// initContract initializes arbitrary contract with given parameters deployed on a given address +func initContract(cmdOutput command.OutputFormatter, txRelayer txrelayer.TxRelayer, + initInputFn contractsapi.StateTransactionInput, contractAddr types.Address, + contractName string, deployerKey ethgo.Key) error { + input, err := initInputFn.EncodeAbi() + if err != nil { + return fmt.Errorf("failed to encode initialization params for %s.initialize. error: %w", + contractName, err) + } + + if _, err := helper.SendTransaction(txRelayer, ethgo.Address(contractAddr), + input, contractName, deployerKey); err != nil { + return err + } + + cmdOutput.WriteCommandResult( + &helper.MessageResult{ + Message: fmt.Sprintf("%s %s contract is initialized", contractsDeploymentTitle, contractName), + }) + + return nil +} diff --git a/command/rootchain/deploy/deploy_test.go b/command/rootchain/deploy/deploy_test.go new file mode 100644 index 0000000000..4381b8a476 --- /dev/null +++ b/command/rootchain/deploy/deploy_test.go @@ -0,0 +1,66 @@ +package deploy + +import ( + "context" + "os" + "testing" + + "github.com/stretchr/testify/require" + "github.com/umbracle/ethgo" + "github.com/umbracle/ethgo/jsonrpc" + "github.com/umbracle/ethgo/testutil" + + "github.com/0xPolygon/polygon-edge/command" + "github.com/0xPolygon/polygon-edge/command/rootchain/helper" + "github.com/0xPolygon/polygon-edge/consensus/polybft" + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" + "github.com/0xPolygon/polygon-edge/types" +) + +func TestDeployContracts_NoPanics(t *testing.T) { + t.Parallel() + + server := testutil.DeployTestServer(t, nil) + t.Cleanup(func() { + if err := os.RemoveAll(params.genesisPath); err != nil { + t.Fatal(err) + } + }) + + client, err := jsonrpc.NewClient(server.HTTPAddr()) + require.NoError(t, err) + + testKey, err := helper.DecodePrivateKey("") + require.NoError(t, err) + + receipt, err := server.Fund(testKey.Address()) + require.NoError(t, err) + require.Equal(t, uint64(types.ReceiptSuccess), receipt.Status) + + txn := ðgo.Transaction{ + To: nil, // contract deployment + Input: contractsapi.StakeManager.Bytecode, + } + + receipt, err = server.SendTxn(txn) + require.NoError(t, err) + require.Equal(t, uint64(types.ReceiptSuccess), receipt.Status) + + outputter := command.InitializeOutputter(GetCommand()) + params.stakeManagerAddr = receipt.ContractAddress.String() + params.stakeTokenAddr = types.StringToAddress("0x123456789").String() + consensusCfg = polybft.PolyBFTConfig{ + NativeTokenConfig: &polybft.TokenConfig{ + Name: "Test", + Symbol: "TST", + Decimals: 18, + IsMintable: false, + }, + } + + require.NotPanics(t, func() { + _, _, err = deployContracts(outputter, client, 1, []*validator.GenesisValidator{}, context.Background()) + }) + require.NoError(t, err) +} diff --git a/command/rootchain/deploy/params.go b/command/rootchain/deploy/params.go new file mode 100644 index 0000000000..45593b32aa --- /dev/null +++ b/command/rootchain/deploy/params.go @@ -0,0 +1,53 @@ +package deploy + +import ( + "errors" + "fmt" + "os" + + "github.com/0xPolygon/polygon-edge/consensus/polybft" +) + +const ( + deployerKeyFlag = "deployer-key" + jsonRPCFlag = "json-rpc" + erc20AddrFlag = "erc20-token" +) + +type deployParams struct { + genesisPath string + deployerKey string + jsonRPCAddress string + stakeTokenAddr string + rootERC20TokenAddr string + stakeManagerAddr string + isTestMode bool +} + +func (ip *deployParams) validateFlags() error { + var err error + + if _, err = os.Stat(ip.genesisPath); err != nil { + return fmt.Errorf("provided genesis path '%s' is invalid. Error: %w ", ip.genesisPath, err) + } + + consensusCfg, err = polybft.LoadPolyBFTConfig(ip.genesisPath) + if err != nil { + return err + } + + if consensusCfg.NativeTokenConfig == nil { + return errors.New("native token configuration is undefined") + } + + // when using mintable native token, child native token on root chain gets mapped automatically + if consensusCfg.NativeTokenConfig.IsMintable && ip.rootERC20TokenAddr != "" { + return errors.New("if child chain native token is mintable, root native token must not pre-exist on root chain") + } + + if params.stakeTokenAddr == "" { + return errors.New("stake token address is not provided") + } + + return nil +} diff --git a/command/rootchain/initcontracts/result.go b/command/rootchain/deploy/result.go similarity index 69% rename from command/rootchain/initcontracts/result.go rename to command/rootchain/deploy/result.go index b268b571dd..4fcdc040ab 100644 --- a/command/rootchain/initcontracts/result.go +++ b/command/rootchain/deploy/result.go @@ -1,4 +1,4 @@ -package initcontracts +package deploy import ( "bytes" @@ -13,13 +13,17 @@ type deployContractResult struct { Name string `json:"name"` Address types.Address `json:"address"` Hash types.Hash `json:"hash"` + GasUsed uint64 `json:"gasUsed"` } -func newDeployContractsResult(name string, address types.Address, hash ethgo.Hash) *deployContractResult { +func newDeployContractsResult(name string, + address types.Address, + hash ethgo.Hash, gasUsed uint64) *deployContractResult { return &deployContractResult{ Name: name, Address: address, Hash: types.BytesToHash(hash.Bytes()), + GasUsed: gasUsed, } } @@ -28,26 +32,14 @@ func (r deployContractResult) GetOutput() string { buffer.WriteString("\n[ROOTCHAIN - DEPLOY CONTRACT]\n") - vals := make([]string, 0, 3) + vals := make([]string, 0, 4) vals = append(vals, fmt.Sprintf("Name|%s", r.Name)) vals = append(vals, fmt.Sprintf("Contract (address)|%s", r.Address)) vals = append(vals, fmt.Sprintf("Transaction (hash)|%s", r.Hash)) + vals = append(vals, fmt.Sprintf("Transaction (gas used)|%d", r.GasUsed)) buffer.WriteString(helper.FormatKV(vals)) buffer.WriteString("\n") return buffer.String() } - -type messageResult struct { - Message string `json:"message"` -} - -func (r messageResult) GetOutput() string { - var buffer bytes.Buffer - - buffer.WriteString(r.Message) - buffer.WriteString("\n") - - return buffer.String() -} diff --git a/command/rootchain/fund/fund.go b/command/rootchain/fund/fund.go index 44113dc59a..30ec7695b8 100644 --- a/command/rootchain/fund/fund.go +++ b/command/rootchain/fund/fund.go @@ -2,28 +2,28 @@ package fund import ( "fmt" - "math/big" "github.com/spf13/cobra" "github.com/umbracle/ethgo" + "golang.org/x/sync/errgroup" "github.com/0xPolygon/polygon-edge/command" + "github.com/0xPolygon/polygon-edge/command/polybftsecrets" + "github.com/0xPolygon/polygon-edge/command/rootchain/helper" "github.com/0xPolygon/polygon-edge/txrelayer" "github.com/0xPolygon/polygon-edge/types" ) var ( - params fundParams - fundNumber int - jsonRPCAddress string + params fundParams ) // GetCommand returns the rootchain fund command func GetCommand() *cobra.Command { rootchainFundCmd := &cobra.Command{ Use: "fund", - Short: "Fund funds all the genesis addresses", - PreRunE: runPreRun, + Short: "Fund validator account with given tokens amount", + PreRunE: preRunCommand, Run: runCommand, } @@ -33,44 +33,50 @@ func GetCommand() *cobra.Command { } func setFlags(cmd *cobra.Command) { + cmd.Flags().StringSliceVar( + ¶ms.addresses, + addressesFlag, + nil, + "validator addresses", + ) + + cmd.Flags().StringSliceVar( + ¶ms.amounts, + amountsFlag, + nil, + "token amounts which is funded to validator on a root chain", + ) + cmd.Flags().StringVar( - ¶ms.dataDir, - dataDirFlag, - "", - "the directory for the Polygon Edge data if the local FS is used", + ¶ms.jsonRPCAddress, + jsonRPCFlag, + txrelayer.DefaultRPCAddress, + "the rootchain JSON RPC endpoint", ) cmd.Flags().StringVar( - ¶ms.configPath, - configFlag, + ¶ms.stakeTokenAddr, + helper.StakeTokenFlag, "", - "the path to the SecretsManager config file, "+ - "if omitted, the local FS secrets manager is used", + helper.StakeTokenFlagDesc, ) - cmd.Flags().IntVar( - &fundNumber, - numFlag, - 1, - "the flag indicating the number of accounts to be funded", + cmd.Flags().BoolVar( + ¶ms.mintStakeToken, + mintStakeTokenFlag, + false, + "indicates if stake token deployer should mint root tokens to given validators", ) cmd.Flags().StringVar( - &jsonRPCAddress, - jsonRPCFlag, - "http://127.0.0.1:8545", - "the JSON RPC rootchain IP address (e.g. http://127.0.0.1:8545)", + ¶ms.deployerPrivateKey, + polybftsecrets.PrivateKeyFlag, + "", + polybftsecrets.PrivateKeyFlagDesc, ) - - // Don't accept data-dir and config flags because they are related to different secrets managers. - // data-dir is about the local FS as secrets storage, config is about remote secrets manager. - cmd.MarkFlagsMutuallyExclusive(dataDirFlag, configFlag) - - // num flag should be used with data-dir flag only so it should not be used with config flag. - cmd.MarkFlagsMutuallyExclusive(numFlag, configFlag) } -func runPreRun(_ *cobra.Command, _ []string) error { +func preRunCommand(_ *cobra.Command, _ []string) error { return params.validateFlags() } @@ -78,66 +84,104 @@ func runCommand(cmd *cobra.Command, _ []string) { outputter := command.InitializeOutputter(cmd) defer outputter.WriteOutput() - paramsList := getParamsList() - resList := make(command.Results, len(paramsList)) - - txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(jsonRPCAddress)) + txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(params.jsonRPCAddress)) if err != nil { outputter.SetError(fmt.Errorf("failed to initialize tx relayer: %w", err)) return } - for i, params := range paramsList { - if err := params.initSecretsManager(); err != nil { - outputter.SetError(err) - - return - } - - validatorAcc, err := params.getValidatorAccount() - if err != nil { - outputter.SetError(err) - - return - } - - fundAddr := ethgo.Address(validatorAcc) - txn := ðgo.Transaction{ - To: &fundAddr, - Value: big.NewInt(1000000000000000000), - } + deployerKey, err := helper.DecodePrivateKey(params.deployerPrivateKey) + if err != nil { + outputter.SetError(fmt.Errorf("failed to initialize deployer private key: %w", err)) - receipt, err := txRelayer.SendTransactionLocal(txn) - if err != nil { - outputter.SetError(err) + return + } - return - } + var stakeTokenAddr types.Address - resList[i] = &result{ - ValidatorAddr: validatorAcc, - TxHash: types.Hash(receipt.TransactionHash), - } + if params.mintStakeToken { + stakeTokenAddr = types.StringToAddress(params.stakeTokenAddr) } - outputter.SetCommandResult(resList) -} - -// getParamsList creates a list of initParams with num elements. -// This function basically copies the given initParams but updating dataDir by applying an index. -func getParamsList() []fundParams { - if fundNumber == 1 { - return []fundParams{params} + results := make([]command.CommandResult, len(params.addresses)) + g, ctx := errgroup.WithContext(cmd.Context()) + + for i := 0; i < len(params.addresses); i++ { + i := i + + g.Go(func() error { + select { + case <-ctx.Done(): + return ctx.Err() + + default: + validatorAddr := types.StringToAddress(params.addresses[i]) + fundAddr := ethgo.Address(validatorAddr) + txn := ðgo.Transaction{ + To: &fundAddr, + Value: params.amountValues[i], + } + + var receipt *ethgo.Receipt + + if params.deployerPrivateKey != "" { + receipt, err = txRelayer.SendTransaction(txn, deployerKey) + } else { + receipt, err = txRelayer.SendTransactionLocal(txn) + } + + if err != nil { + return fmt.Errorf("failed to send fund validator '%s' transaction: %w", validatorAddr, err) + } + + if receipt.Status == uint64(types.ReceiptFailed) { + return fmt.Errorf("failed to fund validator '%s'", validatorAddr) + } + + if params.mintStakeToken { + // mint tokens to validator, so he is able to send them + mintTxn, err := helper.CreateMintTxn(validatorAddr, stakeTokenAddr, params.amountValues[i]) + if err != nil { + return fmt.Errorf("failed to create mint native tokens transaction for validator '%s'. err: %w", + validatorAddr, err) + } + + receipt, err := txRelayer.SendTransaction(mintTxn, deployerKey) + if err != nil { + return fmt.Errorf("failed to send mint native tokens transaction to validator '%s'. err: %w", validatorAddr, err) + } + + if receipt.Status == uint64(types.ReceiptFailed) { + return fmt.Errorf("failed to mint native tokens to validator '%s'", validatorAddr) + } + } + + results[i] = &result{ + ValidatorAddr: validatorAddr, + TxHash: types.Hash(receipt.TransactionHash), + IsMinted: params.mintStakeToken, + } + } + + return nil + }) } - paramsList := make([]fundParams, fundNumber) - for i := 1; i <= fundNumber; i++ { - paramsList[i-1] = fundParams{ - dataDir: fmt.Sprintf("%s%d", params.dataDir, i), - configPath: params.configPath, + if err := g.Wait(); err != nil { + outputter.SetError(err) + _, _ = outputter.Write([]byte("[ROOTCHAIN FUND] Successfully funded following accounts\n")) + + for _, result := range results { + if result != nil { + // In case an error happened, some of the indices may not be populated. + // Filter those out. + outputter.SetCommandResult(result) + } } + + return } - return paramsList + outputter.SetCommandResult(command.Results(results)) } diff --git a/command/rootchain/fund/params.go b/command/rootchain/fund/params.go index 8489cf7f11..4dd10f2edd 100644 --- a/command/rootchain/fund/params.go +++ b/command/rootchain/fund/params.go @@ -2,86 +2,59 @@ package fund import ( "errors" + "math/big" - "github.com/0xPolygon/polygon-edge/secrets" - "github.com/0xPolygon/polygon-edge/secrets/helper" + cmdhelper "github.com/0xPolygon/polygon-edge/command/helper" "github.com/0xPolygon/polygon-edge/types" ) const ( - dataDirFlag = "data-dir" - configFlag = "config" - numFlag = "num" - jsonRPCFlag = "json-rpc" + addressesFlag = "addresses" + amountsFlag = "amounts" + jsonRPCFlag = "json-rpc" + mintStakeTokenFlag = "mint" ) var ( - errInvalidConfig = errors.New("invalid secrets configuration") - errInvalidParams = errors.New("no config file or data directory passed in") - errUnsupportedType = errors.New("unsupported secrets manager") + errNoAddressesProvided = errors.New("no addresses provided") + errInconsistentLength = errors.New("validator addresses and amounts must be equal length") ) type fundParams struct { - dataDir string - configPath string - - secretsManager secrets.SecretsManager - secretsConfig *secrets.SecretsManagerConfig + addresses []string + amounts []string + stakeTokenAddr string + deployerPrivateKey string + mintStakeToken bool + jsonRPCAddress string + + amountValues []*big.Int } func (fp *fundParams) validateFlags() error { - if fp.dataDir == "" && fp.configPath == "" { - return errInvalidParams + if len(fp.addresses) == 0 { + return errNoAddressesProvided } - return nil -} - -func (fp *fundParams) hasConfigPath() bool { - return fp.configPath != "" -} + if len(fp.amounts) != len(fp.addresses) { + return errInconsistentLength + } -func (fp *fundParams) initSecretsManager() error { - var err error - if fp.hasConfigPath() { - if err = fp.parseConfig(); err != nil { + for _, addr := range fp.addresses { + if err := types.IsValidAddress(addr); err != nil { return err } - - fp.secretsManager, err = helper.InitCloudSecretsManager(fp.secretsConfig) - - return err - } - - return fp.initLocalSecretsManager() -} - -func (fp *fundParams) parseConfig() error { - secretsConfig, readErr := secrets.ReadConfig(fp.configPath) - if readErr != nil { - return errInvalidConfig - } - - if !secrets.SupportedServiceManager(secretsConfig.Type) { - return errUnsupportedType } - fp.secretsConfig = secretsConfig - - return nil -} + fp.amountValues = make([]*big.Int, len(fp.amounts)) + for i, amountRaw := range fp.amounts { + amountValue, err := cmdhelper.ParseAmount(amountRaw) + if err != nil { + return err + } -func (fp *fundParams) initLocalSecretsManager() error { - local, err := helper.SetupLocalSecretsManager(fp.dataDir) - if err != nil { - return err + fp.amountValues[i] = amountValue } - fp.secretsManager = local - return nil } - -func (fp *fundParams) getValidatorAccount() (types.Address, error) { - return helper.LoadValidatorAddress(fp.secretsManager) -} diff --git a/command/rootchain/fund/result.go b/command/rootchain/fund/result.go index 608cf64907..add7a63fa5 100644 --- a/command/rootchain/fund/result.go +++ b/command/rootchain/fund/result.go @@ -11,14 +11,16 @@ import ( type result struct { ValidatorAddr types.Address `json:"address"` TxHash types.Hash `json:"tx_hash"` + IsMinted bool `json:"mint"` } func (r *result) GetOutput() string { var buffer bytes.Buffer - vals := make([]string, 0, 2) + vals := make([]string, 0, 3) vals = append(vals, fmt.Sprintf("Validator (address)|%s", r.ValidatorAddr)) vals = append(vals, fmt.Sprintf("Transaction (hash)|%s", r.TxHash)) + vals = append(vals, fmt.Sprintf("Is minted|%v", r.IsMinted)) buffer.WriteString("\n[ROOTCHAIN FUND]\n") buffer.WriteString(helper.FormatKV(vals)) diff --git a/command/rootchain/helper/metadata.go b/command/rootchain/helper/metadata.go index 257d0cacf2..442d4b7854 100644 --- a/command/rootchain/helper/metadata.go +++ b/command/rootchain/helper/metadata.go @@ -1,32 +1,67 @@ package helper import ( + "bytes" "context" - "encoding/hex" "errors" "fmt" + "math/big" + "github.com/0xPolygon/polygon-edge/command/polybftsecrets" + "github.com/0xPolygon/polygon-edge/consensus/polybft" + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" + polybftWallet "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" + "github.com/0xPolygon/polygon-edge/contracts" + "github.com/0xPolygon/polygon-edge/helper/hex" + "github.com/0xPolygon/polygon-edge/txrelayer" + "github.com/0xPolygon/polygon-edge/types" dockertypes "github.com/docker/docker/api/types" "github.com/docker/docker/client" "github.com/umbracle/ethgo" "github.com/umbracle/ethgo/wallet" ) +//nolint:gosec const ( - testAccountPrivKey = "aa75e9a7d427efc732f8e4f1a5b7646adcc61fd5bae40f80d13c8419c9f43d6d" - TestModeFlag = "test" + TestAccountPrivKey = "aa75e9a7d427efc732f8e4f1a5b7646adcc61fd5bae40f80d13c8419c9f43d6d" + TestModeFlag = "test" + SupernetManagerFlag = "supernet-manager" + SupernetManagerFlagDesc = "address of supernet manager contract" + StakeManagerFlag = "stake-manager" + StakeManagerFlagDesc = "address of stake manager contract" + NativeRootTokenFlag = "native-root-token" + NativeRootTokenFlagDesc = "address of native root token" + GenesisPathFlag = "genesis" + GenesisPathFlagDesc = "genesis file path, which contains chain configuration" + DefaultGenesisPath = "./genesis.json" + StakeTokenFlag = "stake-token" + StakeTokenFlagDesc = "address of ERC20 token used for staking on rootchain" ) var ( ErrRootchainNotFound = errors.New("rootchain not found") ErrRootchainPortBind = errors.New("port 8545 is not bind with localhost") errTestModeSecrets = errors.New("rootchain test mode does not imply specifying secrets parameters") - rootchainAccountKey *wallet.Key + + rootchainAccountKey *wallet.Key ) -// GetRootchainPrivateKey initializes a private key from provided raw private key -func GetRootchainPrivateKey(rawKey string) (ethgo.Key, error) { - privateKeyRaw := testAccountPrivKey +type MessageResult struct { + Message string `json:"message"` +} + +func (r MessageResult) GetOutput() string { + var buffer bytes.Buffer + + buffer.WriteString(r.Message) + buffer.WriteString("\n") + + return buffer.String() +} + +// DecodePrivateKey decodes a private key from provided raw private key +func DecodePrivateKey(rawKey string) (ethgo.Key, error) { + privateKeyRaw := TestAccountPrivKey if rawKey != "" { privateKeyRaw = rawKey } @@ -87,3 +122,156 @@ func ReadRootchainIP() (string, error) { return fmt.Sprintf("http://%s:%s", ports[0].HostIP, ports[0].HostPort), nil } + +// GetECDSAKey returns the key based on provided parameters +// If private key is provided, it will return that key +// if not, it will return the key from the secrets manager +func GetECDSAKey(privateKey, accountDir, accountConfig string) (ethgo.Key, error) { + if privateKey != "" { + key, err := DecodePrivateKey(privateKey) + if err != nil { + return nil, fmt.Errorf("failed to initialize private key: %w", err) + } + + return key, nil + } + + secretsManager, err := polybftsecrets.GetSecretsManager(accountDir, accountConfig, true) + if err != nil { + return nil, err + } + + return polybftWallet.GetEcdsaFromSecret(secretsManager) +} + +// GetValidatorInfo queries SupernetManager smart contract on root +// and retrieves validator info for given address +func GetValidatorInfo(validatorAddr ethgo.Address, supernetManagerAddr, stakeManagerAddr types.Address, + chainID int64, txRelayer txrelayer.TxRelayer) (*polybft.ValidatorInfo, error) { + caller := ethgo.Address(contracts.SystemCaller) + getValidatorMethod := contractsapi.CustomSupernetManager.Abi.GetMethod("getValidator") + + encode, err := getValidatorMethod.Encode([]interface{}{validatorAddr}) + if err != nil { + return nil, err + } + + response, err := txRelayer.Call(caller, ethgo.Address(supernetManagerAddr), encode) + if err != nil { + return nil, err + } + + byteResponse, err := hex.DecodeHex(response) + if err != nil { + return nil, fmt.Errorf("unable to decode hex response, %w", err) + } + + decoded, err := getValidatorMethod.Outputs.Decode(byteResponse) + if err != nil { + return nil, err + } + + decodedOutputsMap, ok := decoded.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("could not convert decoded outputs to map") + } + + innerMap, ok := decodedOutputsMap["0"].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("could not convert decoded outputs map to inner map") + } + + //nolint:forcetypeassert + validatorInfo := &polybft.ValidatorInfo{ + Address: validatorAddr, + IsActive: innerMap["isActive"].(bool), + IsWhitelisted: innerMap["isWhitelisted"].(bool), + } + + stakeOfFn := &contractsapi.StakeOfStakeManagerFn{ + ID: new(big.Int).SetInt64(chainID), + Validator: types.Address(validatorAddr), + } + + encode, err = stakeOfFn.EncodeAbi() + if err != nil { + return nil, err + } + + response, err = txRelayer.Call(caller, ethgo.Address(stakeManagerAddr), encode) + if err != nil { + return nil, err + } + + stake, err := types.ParseUint256orHex(&response) + if err != nil { + return nil, err + } + + validatorInfo.Stake = stake + + return validatorInfo, nil +} + +// CreateMintTxn encodes parameters for mint function on rootchain token contract +func CreateMintTxn(receiver, erc20TokenAddr types.Address, amount *big.Int) (*ethgo.Transaction, error) { + mintFn := &contractsapi.MintRootERC20Fn{ + To: receiver, + Amount: amount, + } + + input, err := mintFn.EncodeAbi() + if err != nil { + return nil, fmt.Errorf("failed to encode provided parameters: %w", err) + } + + addr := ethgo.Address(erc20TokenAddr) + + return ðgo.Transaction{ + To: &addr, + Input: input, + }, nil +} + +// CreateApproveERC20Txn sends approve transaction +// to ERC20 token for spender so that it is able to spend given tokens +func CreateApproveERC20Txn(amount *big.Int, + spender, erc20TokenAddr types.Address) (*ethgo.Transaction, error) { + approveFnParams := &contractsapi.ApproveRootERC20Fn{ + Spender: spender, + Amount: amount, + } + + input, err := approveFnParams.EncodeAbi() + if err != nil { + return nil, fmt.Errorf("failed to encode parameters for RootERC20.approve. error: %w", err) + } + + addr := ethgo.Address(erc20TokenAddr) + + return ðgo.Transaction{ + To: &addr, + Input: input, + }, nil +} + +// SendTransaction sends provided transaction +func SendTransaction(txRelayer txrelayer.TxRelayer, addr ethgo.Address, input []byte, contractName string, + deployerKey ethgo.Key) (*ethgo.Receipt, error) { + txn := ðgo.Transaction{ + To: &addr, + Input: input, + } + + receipt, err := txRelayer.SendTransaction(txn, deployerKey) + if err != nil { + return nil, fmt.Errorf("failed to send transaction to %s contract (%s). error: %w", + contractName, txn.To.Address(), err) + } + + if receipt == nil || receipt.Status != uint64(types.ReceiptSuccess) { + return nil, fmt.Errorf("transaction execution failed on %s contract", contractName) + } + + return receipt, nil +} diff --git a/command/rootchain/initcontracts/init_contracts.go b/command/rootchain/initcontracts/init_contracts.go deleted file mode 100644 index faf6d943cc..0000000000 --- a/command/rootchain/initcontracts/init_contracts.go +++ /dev/null @@ -1,442 +0,0 @@ -package initcontracts - -import ( - "fmt" - "math/big" - - "github.com/spf13/cobra" - "github.com/umbracle/ethgo" - "github.com/umbracle/ethgo/jsonrpc" - - "github.com/0xPolygon/polygon-edge/command" - "github.com/0xPolygon/polygon-edge/command/rootchain/helper" - "github.com/0xPolygon/polygon-edge/consensus/polybft" - "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" - "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi/artifact" - "github.com/0xPolygon/polygon-edge/contracts" - "github.com/0xPolygon/polygon-edge/txrelayer" - "github.com/0xPolygon/polygon-edge/types" -) - -const ( - contractsDeploymentTitle = "[ROOTCHAIN - CONTRACTS DEPLOYMENT]" - - stateSenderName = "StateSender" - checkpointManagerName = "CheckpointManager" - blsName = "BLS" - bn256G2Name = "BN256G2" - exitHelperName = "ExitHelper" - rootERC20PredicateName = "RootERC20Predicate" - rootERC20Name = "RootERC20" - erc20TemplateName = "ERC20Template" -) - -var ( - params initContractsParams - - // metadataPopulatorMap maps rootchain contract names to callback - // which populates appropriate field in the RootchainMetadata - metadataPopulatorMap = map[string]func(*polybft.RootchainConfig, types.Address){ - stateSenderName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { - rootchainConfig.StateSenderAddress = addr - }, - checkpointManagerName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { - rootchainConfig.CheckpointManagerAddress = addr - }, - blsName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { - rootchainConfig.BLSAddress = addr - }, - bn256G2Name: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { - rootchainConfig.BN256G2Address = addr - }, - exitHelperName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { - rootchainConfig.ExitHelperAddress = addr - }, - rootERC20PredicateName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { - rootchainConfig.RootERC20PredicateAddress = addr - }, - rootERC20Name: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { - rootchainConfig.RootNativeERC20Address = addr - }, - erc20TemplateName: func(rootchainConfig *polybft.RootchainConfig, addr types.Address) { - rootchainConfig.ERC20TemplateAddress = addr - }, - } -) - -// GetCommand returns the rootchain init-contracts command -func GetCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "init-contracts", - Short: "Deploys and initializes required smart contracts on the rootchain", - PreRunE: runPreRun, - Run: runCommand, - } - - cmd.Flags().StringVar( - ¶ms.manifestPath, - manifestPathFlag, - defaultManifestPath, - "manifest file path, which contains metadata", - ) - - cmd.Flags().StringVar( - ¶ms.deployerKey, - deployerKeyFlag, - "", - "Hex encoded private key of the account which deploys rootchain contracts", - ) - - cmd.Flags().StringVar( - ¶ms.jsonRPCAddress, - jsonRPCFlag, - txrelayer.DefaultRPCAddress, - "the JSON RPC rootchain IP address", - ) - - cmd.Flags().StringVar( - ¶ms.rootERC20TokenAddr, - rootchainERC20Flag, - "", - "existing root chain ERC20 token address", - ) - - cmd.Flags().BoolVar( - ¶ms.isTestMode, - helper.TestModeFlag, - false, - "test indicates whether rootchain contracts deployer is hardcoded test account"+ - " (otherwise provided secrets are used to resolve deployer account)", - ) - - cmd.MarkFlagsMutuallyExclusive(helper.TestModeFlag, deployerKeyFlag) - - return cmd -} - -func runPreRun(_ *cobra.Command, _ []string) error { - return params.validateFlags() -} - -func runCommand(cmd *cobra.Command, _ []string) { - outputter := command.InitializeOutputter(cmd) - defer outputter.WriteOutput() - - outputter.WriteCommandResult(&messageResult{ - Message: fmt.Sprintf("%s started...", contractsDeploymentTitle), - }) - - client, err := jsonrpc.NewClient(params.jsonRPCAddress) - if err != nil { - outputter.SetError(fmt.Errorf("failed to initialize JSON RPC client for provided IP address: %s: %w", - params.jsonRPCAddress, err)) - - return - } - - manifest, err := polybft.LoadManifest(params.manifestPath) - if err != nil { - outputter.SetError(fmt.Errorf("failed to read manifest: %w", err)) - - return - } - - if manifest.RootchainConfig != nil { - code, err := client.Eth().GetCode(ethgo.Address(manifest.RootchainConfig.StateSenderAddress), ethgo.Latest) - if err != nil { - outputter.SetError(fmt.Errorf("failed to check if rootchain contracts are deployed: %w", err)) - - return - } else if code != "0x" { - outputter.SetCommandResult(&messageResult{ - Message: fmt.Sprintf("%s contracts are already deployed. Aborting.", contractsDeploymentTitle), - }) - - return - } - } - - if err := deployContracts(outputter, client, manifest); err != nil { - outputter.SetError(fmt.Errorf("failed to deploy rootchain contracts: %w", err)) - - return - } - - outputter.SetCommandResult(&messageResult{ - Message: fmt.Sprintf("%s finished. All contracts are successfully deployed and initialized.", - contractsDeploymentTitle), - }) -} - -func deployContracts(outputter command.OutputFormatter, client *jsonrpc.Client, - manifest *polybft.Manifest) error { - // if the bridge contract is not created, we have to deploy all the contracts - txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithClient(client)) - if err != nil { - return fmt.Errorf("failed to initialize tx relayer: %w", err) - } - - deployerKey, err := helper.GetRootchainPrivateKey(params.deployerKey) - if err != nil { - return fmt.Errorf("failed to initialize deployer key: %w", err) - } - - if params.isTestMode { - deployerAddr := deployerKey.Address() - txn := ðgo.Transaction{To: &deployerAddr, Value: big.NewInt(1000000000000000000)} - - _, err = txRelayer.SendTransactionLocal(txn) - if err != nil { - return err - } - } - - type contractInfo struct { - name string - artifact *artifact.Artifact - } - - deployContracts := []*contractInfo{ - { - name: "StateSender", - artifact: contractsapi.StateSender, - }, - { - name: "CheckpointManager", - artifact: contractsapi.CheckpointManager, - }, - { - name: "BLS", - artifact: contractsapi.BLS, - }, - { - name: "BN256G2", - artifact: contractsapi.BLS256, - }, - { - name: "ExitHelper", - artifact: contractsapi.ExitHelper, - }, - { - name: "RootERC20Predicate", - artifact: contractsapi.RootERC20Predicate, - }, - { - name: "ERC20Template", - artifact: contractsapi.ChildERC20, - }, - } - rootchainConfig := &polybft.RootchainConfig{} - manifest.RootchainConfig = rootchainConfig - - if params.rootERC20TokenAddr != "" { - // use existing root chain ERC20 token - addr := types.StringToAddress(params.rootERC20TokenAddr) - - code, err := client.Eth().GetCode(ethgo.Address(addr), ethgo.Latest) - if err != nil { - return fmt.Errorf("failed to check is root chain ERC20 token deployed: %w", err) - } else if code == "0x" { - return fmt.Errorf("root chain ERC20 token is not deployed on provided address %s", params.rootERC20TokenAddr) - } - - populatorFn, ok := metadataPopulatorMap["RootERC20"] - if !ok { - return fmt.Errorf("root chain metadata populator not registered for contract 'RootERC20'") - } - - populatorFn(manifest.RootchainConfig, addr) - } else { - // deploy MockERC20 as default root chain ERC20 token - deployContracts = append(deployContracts, &contractInfo{name: "RootERC20", artifact: contractsapi.RootERC20}) - } - - for _, contract := range deployContracts { - txn := ðgo.Transaction{ - To: nil, // contract deployment - Input: contract.artifact.Bytecode, - } - - receipt, err := txRelayer.SendTransaction(txn, deployerKey) - if err != nil { - return err - } - - if receipt == nil || receipt.Status != uint64(types.ReceiptSuccess) { - return fmt.Errorf("deployment of %s contract failed", contract.name) - } - - contractAddr := types.Address(receipt.ContractAddress) - - populatorFn, ok := metadataPopulatorMap[contract.name] - if !ok { - return fmt.Errorf("rootchain metadata populator not registered for contract '%s'", contract.name) - } - - populatorFn(manifest.RootchainConfig, contractAddr) - - outputter.WriteCommandResult(newDeployContractsResult(contract.name, contractAddr, receipt.TransactionHash)) - } - - if err := manifest.Save(params.manifestPath); err != nil { - return fmt.Errorf("failed to save manifest data: %w", err) - } - - // init CheckpointManager - if err := initializeCheckpointManager(outputter, txRelayer, manifest, deployerKey); err != nil { - return err - } - - outputter.WriteCommandResult(&messageResult{ - Message: fmt.Sprintf("%s %s contract is initialized", contractsDeploymentTitle, checkpointManagerName), - }) - - // init ExitHelper - if err := initializeExitHelper(txRelayer, rootchainConfig, deployerKey); err != nil { - return err - } - - outputter.WriteCommandResult(&messageResult{ - Message: fmt.Sprintf("%s %s contract is initialized", contractsDeploymentTitle, exitHelperName), - }) - - // init RootERC20Predicate - if err := initializeRootERC20Predicate(txRelayer, rootchainConfig, deployerKey); err != nil { - return err - } - - outputter.WriteCommandResult(&messageResult{ - Message: fmt.Sprintf("%s %s contract is initialized", contractsDeploymentTitle, rootERC20PredicateName), - }) - - return nil -} - -// initializeCheckpointManager invokes initialize function on "CheckpointManager" smart contract -func initializeCheckpointManager( - o command.OutputFormatter, - txRelayer txrelayer.TxRelayer, - manifest *polybft.Manifest, - deployerKey ethgo.Key) error { - validatorSet, err := validatorSetToABISlice(o, manifest.GenesisValidators) - if err != nil { - return fmt.Errorf("failed to convert validators to map: %w", err) - } - - initialize := contractsapi.InitializeCheckpointManagerFn{ - ChainID_: big.NewInt(manifest.ChainID), - NewBls: manifest.RootchainConfig.BLSAddress, - NewBn256G2: manifest.RootchainConfig.BN256G2Address, - NewValidatorSet: validatorSet, - } - - initCheckpointInput, err := initialize.EncodeAbi() - if err != nil { - return fmt.Errorf("failed to encode parameters for CheckpointManager.initialize. error: %w", err) - } - - addr := ethgo.Address(manifest.RootchainConfig.CheckpointManagerAddress) - txn := ðgo.Transaction{ - To: &addr, - Input: initCheckpointInput, - } - - return sendTransaction(txRelayer, txn, checkpointManagerName, deployerKey) -} - -// initializeExitHelper invokes initialize function on "ExitHelper" smart contract -func initializeExitHelper(txRelayer txrelayer.TxRelayer, rootchainConfig *polybft.RootchainConfig, - deployerKey ethgo.Key) error { - input, err := contractsapi.ExitHelper.Abi.GetMethod("initialize"). - Encode([]interface{}{rootchainConfig.CheckpointManagerAddress}) - if err != nil { - return fmt.Errorf("failed to encode parameters for ExitHelper.initialize. error: %w", err) - } - - addr := ethgo.Address(rootchainConfig.ExitHelperAddress) - txn := ðgo.Transaction{ - To: &addr, - Input: input, - } - - return sendTransaction(txRelayer, txn, exitHelperName, deployerKey) -} - -// initializeRootERC20Predicate invokes initialize function on "RootERC20Predicate" smart contract -func initializeRootERC20Predicate(txRelayer txrelayer.TxRelayer, rootchainConfig *polybft.RootchainConfig, - deployerKey ethgo.Key) error { - rootERC20PredicateParams := &contractsapi.InitializeRootERC20PredicateFn{ - NewStateSender: rootchainConfig.StateSenderAddress, - NewExitHelper: rootchainConfig.ExitHelperAddress, - NewChildERC20Predicate: contracts.ChildERC20PredicateContract, - NewChildTokenTemplate: rootchainConfig.ERC20TemplateAddress, - NativeTokenRootAddress: rootchainConfig.RootNativeERC20Address, - } - - input, err := rootERC20PredicateParams.EncodeAbi() - if err != nil { - return fmt.Errorf("failed to encode parameters for RootERC20Predicate.initialize. error: %w", err) - } - - addr := ethgo.Address(rootchainConfig.RootERC20PredicateAddress) - txn := ðgo.Transaction{ - To: &addr, - Input: input, - } - - return sendTransaction(txRelayer, txn, rootERC20PredicateName, deployerKey) -} - -// sendTransaction sends provided transaction -func sendTransaction(txRelayer txrelayer.TxRelayer, txn *ethgo.Transaction, contractName string, - deployerKey ethgo.Key) error { - receipt, err := txRelayer.SendTransaction(txn, deployerKey) - if err != nil { - return fmt.Errorf("failed to send transaction to %s contract (%s). error: %w", contractName, txn.To.Address(), err) - } - - if receipt == nil || receipt.Status != uint64(types.ReceiptSuccess) { - return fmt.Errorf("transaction execution failed on %s contract", contractName) - } - - return nil -} - -// validatorSetToABISlice converts given validators to generic map -// which is used for ABI encoding validator set being sent to the rootchain contract -func validatorSetToABISlice(o command.OutputFormatter, - validators []*polybft.Validator) ([]*contractsapi.Validator, error) { - accSet := make(polybft.AccountSet, len(validators)) - - if _, err := o.Write([]byte(fmt.Sprintf("%s [VALIDATORS]\n", contractsDeploymentTitle))); err != nil { - return nil, err - } - - for i, validator := range validators { - if _, err := o.Write([]byte(fmt.Sprintf("%v\n", validator))); err != nil { - return nil, err - } - - blsKey, err := validator.UnmarshalBLSPublicKey() - if err != nil { - return nil, err - } - - accSet[i] = &polybft.ValidatorMetadata{ - Address: validator.Address, - BlsKey: blsKey, - VotingPower: new(big.Int).Set(validator.Stake), - } - } - - hash, err := accSet.Hash() - if err != nil { - return nil, err - } - - if _, err := o.Write([]byte(fmt.Sprintf("%s Validators hash: %s\n", contractsDeploymentTitle, hash))); err != nil { - return nil, err - } - - return accSet.ToAPIBinding(), nil -} diff --git a/command/rootchain/initcontracts/init_contracts_test.go b/command/rootchain/initcontracts/init_contracts_test.go deleted file mode 100644 index 60aeaa9a52..0000000000 --- a/command/rootchain/initcontracts/init_contracts_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package initcontracts - -import ( - "os" - "testing" - - "github.com/0xPolygon/polygon-edge/command" - "github.com/0xPolygon/polygon-edge/command/rootchain/helper" - "github.com/0xPolygon/polygon-edge/consensus/polybft" - "github.com/stretchr/testify/require" - "github.com/umbracle/ethgo/jsonrpc" - "github.com/umbracle/ethgo/testutil" -) - -func TestDeployContracts_NoPanics(t *testing.T) { - t.Parallel() - - server := testutil.DeployTestServer(t, nil) - t.Cleanup(func() { - err := os.RemoveAll(params.manifestPath) - if err != nil { - t.Fatal(err) - } - }) - - client, err := jsonrpc.NewClient(server.HTTPAddr()) - require.NoError(t, err) - - testKey, err := helper.GetRootchainPrivateKey("") - require.NoError(t, err) - - receipt, err := server.Fund(testKey.Address()) - require.NoError(t, err) - require.Equal(t, uint64(1), receipt.Status) - - outputter := command.InitializeOutputter(GetCommand()) - - require.NotPanics(t, func() { - err = deployContracts(outputter, client, &polybft.Manifest{}) - }) - require.NoError(t, err) -} diff --git a/command/rootchain/initcontracts/params.go b/command/rootchain/initcontracts/params.go deleted file mode 100644 index 2258396ff9..0000000000 --- a/command/rootchain/initcontracts/params.go +++ /dev/null @@ -1,32 +0,0 @@ -package initcontracts - -import ( - "errors" - "fmt" - "os" -) - -const ( - manifestPathFlag = "manifest" - deployerKeyFlag = "deployer-key" - jsonRPCFlag = "json-rpc" - rootchainERC20Flag = "rootchain-erc20" - - defaultManifestPath = "./manifest.json" -) - -type initContractsParams struct { - manifestPath string - deployerKey string - jsonRPCAddress string - rootERC20TokenAddr string - isTestMode bool -} - -func (ip *initContractsParams) validateFlags() error { - if _, err := os.Stat(ip.manifestPath); errors.Is(err, os.ErrNotExist) { - return fmt.Errorf("provided manifest path '%s' doesn't exist", ip.manifestPath) - } - - return nil -} diff --git a/command/rootchain/registration/params.go b/command/rootchain/registration/params.go new file mode 100644 index 0000000000..faa1cd61ff --- /dev/null +++ b/command/rootchain/registration/params.go @@ -0,0 +1,45 @@ +package registration + +import ( + "bytes" + "fmt" + + "github.com/0xPolygon/polygon-edge/command/helper" + sidechainHelper "github.com/0xPolygon/polygon-edge/command/sidechain" +) + +type registerParams struct { + accountDir string + accountConfig string + supernetManagerAddress string + jsonRPC string +} + +func (rp *registerParams) validateFlags() error { + // validate jsonrpc address + _, err := helper.ParseJSONRPCAddress(rp.jsonRPC) + if err != nil { + return fmt.Errorf("failed to parse json rpc address. Error: %w", err) + } + + return sidechainHelper.ValidateSecretFlags(rp.accountDir, rp.accountConfig) +} + +type registerResult struct { + validatorAddress string + koskSignature string +} + +func (rr registerResult) GetOutput() string { + var buffer bytes.Buffer + + buffer.WriteString("\n[VALIDATOR REGISTRATION]\n") + + vals := make([]string, 0, 2) + vals = append(vals, fmt.Sprintf("Validator Address|%s", rr.validatorAddress)) + vals = append(vals, fmt.Sprintf("KOSK Signature|%s", rr.koskSignature)) + buffer.WriteString(helper.FormatKV(vals)) + buffer.WriteString("\n") + + return buffer.String() +} diff --git a/command/sidechain/registration/register_validator.go b/command/rootchain/registration/register_validator.go similarity index 55% rename from command/sidechain/registration/register_validator.go rename to command/rootchain/registration/register_validator.go index 7518d846a9..fcc89a95aa 100644 --- a/command/sidechain/registration/register_validator.go +++ b/command/rootchain/registration/register_validator.go @@ -8,28 +8,22 @@ import ( "github.com/0xPolygon/polygon-edge/command" "github.com/0xPolygon/polygon-edge/command/helper" "github.com/0xPolygon/polygon-edge/command/polybftsecrets" + rootHelper "github.com/0xPolygon/polygon-edge/command/rootchain/helper" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" - "github.com/0xPolygon/polygon-edge/contracts" - "github.com/0xPolygon/polygon-edge/secrets" "github.com/0xPolygon/polygon-edge/txrelayer" "github.com/0xPolygon/polygon-edge/types" "github.com/spf13/cobra" "github.com/umbracle/ethgo" ) -var ( - stakeManager = contracts.ValidatorSetContract - stakeFn = contractsapi.ChildValidatorSet.Abi.Methods["stake"] -) - var params registerParams func GetCommand() *cobra.Command { registerCmd := &cobra.Command{ Use: "register-validator", - Short: "Registers and stake an enlisted validator", + Short: "registers a whitelisted validator to supernet manager on rootchain", PreRunE: runPreRun, RunE: runCommand, } @@ -55,17 +49,10 @@ func setFlags(cmd *cobra.Command) { ) cmd.Flags().StringVar( - ¶ms.stake, - stakeFlag, + ¶ms.supernetManagerAddress, + rootHelper.SupernetManagerFlag, "", - "stake represents amount which is going to be staked by the new validator account", - ) - - cmd.Flags().Int64Var( - ¶ms.chainID, - chainIDFlag, - command.DefaultChainID, - "the ID of the chain", + rootHelper.SupernetManagerFlagDesc, ) helper.RegisterJSONRPCFlag(cmd) @@ -92,27 +79,24 @@ func runCommand(cmd *cobra.Command, _ []string) error { return err } - newValidatorAccount, err := wallet.NewAccountFromSecret(secretsManager) + rootChainID, err := txRelayer.Client().Eth().ChainID() if err != nil { return err } - sRaw, err := secretsManager.GetSecret(secrets.ValidatorBLSSignature) - if err != nil { - return err - } - - sb, err := hex.DecodeString(string(sRaw)) + newValidatorAccount, err := wallet.NewAccountFromSecret(secretsManager) if err != nil { return err } - blsSignature, err := bls.UnmarshalSignature(sb) + koskSignature, err := bls.MakeKOSKSignature( + newValidatorAccount.Bls, newValidatorAccount.Address(), + rootChainID.Int64(), bls.DomainValidatorSet, types.StringToAddress(params.supernetManagerAddress)) if err != nil { return err } - receipt, err := registerValidator(txRelayer, newValidatorAccount, blsSignature) + receipt, err := registerValidator(txRelayer, newValidatorAccount, koskSignature) if err != nil { return err } @@ -124,20 +108,25 @@ func runCommand(cmd *cobra.Command, _ []string) error { result := ®isterResult{} foundLog := false - var newValidatorEvent contractsapi.NewValidatorEvent + var validatorRegisteredEvent contractsapi.ValidatorRegisteredEvent for _, log := range receipt.Logs { - doesMatch, err := newValidatorEvent.ParseLog(log) + doesMatch, err := validatorRegisteredEvent.ParseLog(log) + if err != nil { + return err + } + if !doesMatch { continue } + koskSignatureRaw, err := koskSignature.Marshal() if err != nil { return err } - result.validatorAddress = newValidatorEvent.Validator.String() - result.stakeResult = "No stake parameters have been submitted" - result.amount = 0 + result.koskSignature = hex.EncodeToString(koskSignatureRaw) + result.validatorAddress = validatorRegisteredEvent.Validator.String() + foundLog = true break @@ -147,74 +136,11 @@ func runCommand(cmd *cobra.Command, _ []string) error { return fmt.Errorf("could not find an appropriate log in receipt that registration happened") } - if params.stake != "" { - receipt, err = stake(txRelayer, newValidatorAccount) - if err != nil { - result.stakeResult = fmt.Sprintf("Failed to execute stake transaction: %s", err.Error()) - } else { - populateStakeResults(receipt, result) - } - } - outputter.WriteCommandResult(result) return nil } -func stake(sender txrelayer.TxRelayer, account *wallet.Account) (*ethgo.Receipt, error) { - if stakeFn == nil { - return nil, errors.New("failed to create stake ABI function") - } - - input, err := stakeFn.Encode([]interface{}{}) - if err != nil { - return nil, err - } - - stake, err := types.ParseUint256orHex(¶ms.stake) - if err != nil { - return nil, err - } - - txn := ðgo.Transaction{ - Input: input, - To: (*ethgo.Address)(&stakeManager), - Value: stake, - } - - return sender.SendTransaction(txn, account.Ecdsa) -} - -func populateStakeResults(receipt *ethgo.Receipt, result *registerResult) { - if receipt.Status != uint64(types.ReceiptSuccess) { - result.stakeResult = "Stake transaction failed" - - return - } - - // check the logs to verify stake - var stakedEvent contractsapi.StakedEvent - for _, log := range receipt.Logs { - doesMatch, err := stakedEvent.ParseLog(log) - if !doesMatch { - continue - } - - if err != nil { - result.stakeResult = "Failed to parse stake log" - - return - } - - result.amount = stakedEvent.Amount.Uint64() - result.stakeResult = "Stake succeeded" - - return - } - - result.stakeResult = "Could not find an appropriate log in receipt that stake happened" -} - func registerValidator(sender txrelayer.TxRelayer, account *wallet.Account, signature *bls.Signature) (*ethgo.Receipt, error) { sigMarshal, err := signature.ToBigInt() @@ -222,7 +148,7 @@ func registerValidator(sender txrelayer.TxRelayer, account *wallet.Account, return nil, fmt.Errorf("register validator failed: %w", err) } - registerFn := &contractsapi.RegisterChildValidatorSetFn{ + registerFn := &contractsapi.RegisterCustomSupernetManagerFn{ Signature: sigMarshal, Pubkey: account.Bls.PublicKey().ToBigInt(), } @@ -232,9 +158,10 @@ func registerValidator(sender txrelayer.TxRelayer, account *wallet.Account, return nil, fmt.Errorf("register validator failed: %w", err) } + supernetAddr := ethgo.Address(types.StringToAddress(params.supernetManagerAddress)) txn := ðgo.Transaction{ Input: input, - To: (*ethgo.Address)(&stakeManager), + To: &supernetAddr, } return sender.SendTransaction(txn, account.Ecdsa) diff --git a/command/rootchain/rootchain.go b/command/rootchain/rootchain.go index 2d7fa00f62..c49a8fcd73 100644 --- a/command/rootchain/rootchain.go +++ b/command/rootchain/rootchain.go @@ -3,8 +3,8 @@ package rootchain import ( "github.com/spf13/cobra" + "github.com/0xPolygon/polygon-edge/command/rootchain/deploy" "github.com/0xPolygon/polygon-edge/command/rootchain/fund" - "github.com/0xPolygon/polygon-edge/command/rootchain/initcontracts" "github.com/0xPolygon/polygon-edge/command/rootchain/server" ) @@ -15,18 +15,14 @@ func GetCommand() *cobra.Command { Short: "Top level rootchain helper command.", } - registerSubcommands(rootchainCmd) - - return rootchainCmd -} - -func registerSubcommands(baseCmd *cobra.Command) { - baseCmd.AddCommand( - // rootchain fund - fund.GetCommand(), + rootchainCmd.AddCommand( // rootchain server server.GetCommand(), - // init-contracts - initcontracts.GetCommand(), + // rootchain deploy + deploy.GetCommand(), + // rootchain fund + fund.GetCommand(), ) + + return rootchainCmd } diff --git a/command/rootchain/staking/params.go b/command/rootchain/staking/params.go new file mode 100644 index 0000000000..e56ec6bcbe --- /dev/null +++ b/command/rootchain/staking/params.go @@ -0,0 +1,57 @@ +package staking + +import ( + "bytes" + "fmt" + "math/big" + + "github.com/0xPolygon/polygon-edge/command/helper" + sidechainHelper "github.com/0xPolygon/polygon-edge/command/sidechain" +) + +var supernetIDFlag = "supernet-id" + +type stakeParams struct { + accountDir string + accountConfig string + stakeManagerAddr string + stakeTokenAddr string + jsonRPC string + supernetID int64 + amount string + + amountValue *big.Int +} + +func (sp *stakeParams) validateFlags() (err error) { + if sp.amountValue, err = helper.ParseAmount(sp.amount); err != nil { + return err + } + + // validate jsonrpc address + if _, err := helper.ParseJSONRPCAddress(sp.jsonRPC); err != nil { + return fmt.Errorf("failed to parse json rpc address. Error: %w", err) + } + + return sidechainHelper.ValidateSecretFlags(sp.accountDir, sp.accountConfig) +} + +type stakeResult struct { + validatorAddress string + amount *big.Int +} + +func (sr stakeResult) GetOutput() string { + var buffer bytes.Buffer + + buffer.WriteString("\n[VALIDATOR STAKE]\n") + + vals := make([]string, 0, 2) + vals = append(vals, fmt.Sprintf("Validator Address|%s", sr.validatorAddress)) + vals = append(vals, fmt.Sprintf("Amount Staked|%d", sr.amount)) + + buffer.WriteString(helper.FormatKV(vals)) + buffer.WriteString("\n") + + return buffer.String() +} diff --git a/command/sidechain/staking/stake.go b/command/rootchain/staking/stake.go similarity index 56% rename from command/sidechain/staking/stake.go rename to command/rootchain/staking/stake.go index 6ed251793d..f195d4aeb6 100644 --- a/command/sidechain/staking/stake.go +++ b/command/rootchain/staking/stake.go @@ -8,9 +8,9 @@ import ( "github.com/0xPolygon/polygon-edge/command" "github.com/0xPolygon/polygon-edge/command/helper" "github.com/0xPolygon/polygon-edge/command/polybftsecrets" + rootHelper "github.com/0xPolygon/polygon-edge/command/rootchain/helper" sidechainHelper "github.com/0xPolygon/polygon-edge/command/sidechain" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" - "github.com/0xPolygon/polygon-edge/contracts" "github.com/0xPolygon/polygon-edge/txrelayer" "github.com/0xPolygon/polygon-edge/types" "github.com/spf13/cobra" @@ -24,7 +24,7 @@ var ( func GetCommand() *cobra.Command { stakeCmd := &cobra.Command{ Use: "stake", - Short: "Stakes the amount sent for validator or delegates its stake to another account", + Short: "Stakes the amount sent for validator on rootchain", PreRunE: runPreRun, RunE: runCommand, } @@ -50,28 +50,34 @@ func setFlags(cmd *cobra.Command) { polybftsecrets.AccountConfigFlagDesc, ) - cmd.Flags().BoolVar( - ¶ms.self, - sidechainHelper.SelfFlag, - false, - "indicates if its a self stake action", + cmd.Flags().StringVar( + ¶ms.stakeManagerAddr, + rootHelper.StakeManagerFlag, + "", + rootHelper.StakeManagerFlagDesc, ) - cmd.Flags().Uint64Var( + cmd.Flags().StringVar( ¶ms.amount, sidechainHelper.AmountFlag, + "", + "amount to stake", + ) + + cmd.Flags().Int64Var( + ¶ms.supernetID, + supernetIDFlag, 0, - "amount to stake or delegate to another account", + "ID of supernet provided by stake manager on supernet registration", ) cmd.Flags().StringVar( - ¶ms.delegateAddress, - delegateAddressFlag, + ¶ms.stakeTokenAddr, + rootHelper.StakeTokenFlag, "", - "account address to which stake should be delegated", + rootHelper.StakeTokenFlagDesc, ) - cmd.MarkFlagsMutuallyExclusive(sidechainHelper.SelfFlag, delegateAddressFlag) cmd.MarkFlagsMutuallyExclusive(polybftsecrets.AccountDirFlag, polybftsecrets.AccountConfigFlag) } @@ -96,30 +102,39 @@ func runCommand(cmd *cobra.Command, _ []string) error { return err } - var encoded []byte - if params.self { - encoded, err = contractsapi.ChildValidatorSet.Abi.Methods["stake"].Encode([]interface{}{}) - if err != nil { - return err - } - } else { - delegateToAddress := types.StringToAddress(params.delegateAddress) - encoded, err = contractsapi.ChildValidatorSet.Abi.Methods["delegate"].Encode( - []interface{}{ethgo.Address(delegateToAddress), false}) - if err != nil { - return err - } + approveTxn, err := rootHelper.CreateApproveERC20Txn(params.amountValue, + types.StringToAddress(params.stakeManagerAddr), types.StringToAddress(params.stakeTokenAddr)) + if err != nil { + return err } + receipt, err := txRelayer.SendTransaction(approveTxn, validatorAccount.Ecdsa) + if err != nil { + return err + } + + if receipt.Status == uint64(types.ReceiptFailed) { + return fmt.Errorf("approve transaction failed on block %d", receipt.BlockNumber) + } + + stakeFn := contractsapi.StakeForStakeManagerFn{ + ID: new(big.Int).SetInt64(params.supernetID), + Amount: params.amountValue, + } + + encoded, err := stakeFn.EncodeAbi() + if err != nil { + return err + } + + stakeManagerAddr := ethgo.Address(types.StringToAddress(params.stakeManagerAddr)) txn := ðgo.Transaction{ - From: validatorAccount.Ecdsa.Address(), - Input: encoded, - To: (*ethgo.Address)(&contracts.ValidatorSetContract), - Value: new(big.Int).SetUint64(params.amount), - GasPrice: sidechainHelper.DefaultGasPrice, + From: validatorAccount.Ecdsa.Address(), + Input: encoded, + To: &stakeManagerAddr, } - receipt, err := txRelayer.SendTransaction(txn, validatorAccount.Ecdsa) + receipt, err = txRelayer.SendTransaction(txn, validatorAccount.Ecdsa) if err != nil { return err } @@ -133,42 +148,30 @@ func runCommand(cmd *cobra.Command, _ []string) error { } var ( - stakedEvent contractsapi.StakedEvent - delegatedEvent contractsapi.DelegatedEvent - foundLog bool + stakeAddedEvent contractsapi.StakeAddedEvent + foundLog bool ) // check the logs to check for the result for _, log := range receipt.Logs { - doesMatch, err := stakedEvent.ParseLog(log) + doesMatch, err := stakeAddedEvent.ParseLog(log) if err != nil { return err } - if doesMatch { // its a stake function call - result.isSelfStake = true - result.amount = stakedEvent.Amount.Uint64() - foundLog = true - - break - } - - doesMatch, err = delegatedEvent.ParseLog(log) - if err != nil { - return err + if !doesMatch { + continue } - if doesMatch { - result.amount = delegatedEvent.Amount.Uint64() - result.delegatedTo = delegatedEvent.Validator.String() - foundLog = true + result.amount = stakeAddedEvent.Amount + result.validatorAddress = stakeAddedEvent.Validator.String() + foundLog = true - break - } + break } if !foundLog { - return fmt.Errorf("could not find an appropriate log in receipt that stake or delegate happened") + return fmt.Errorf("could not find an appropriate log in receipt that stake happened") } outputter.WriteCommandResult(result) diff --git a/command/rootchain/supernet/params.go b/command/rootchain/supernet/params.go new file mode 100644 index 0000000000..04c36fec39 --- /dev/null +++ b/command/rootchain/supernet/params.go @@ -0,0 +1,69 @@ +package supernet + +import ( + "bytes" + "fmt" + "os" + + "github.com/0xPolygon/polygon-edge/command/helper" + sidechainHelper "github.com/0xPolygon/polygon-edge/command/sidechain" +) + +const ( + finalizeGenesisSetFlag = "finalize-genesis-set" + enableStakingFlag = "enable-staking" +) + +type supernetParams struct { + accountDir string + accountConfig string + privateKey string + jsonRPC string + supernetManagerAddress string + stakeManagerAddress string + genesisPath string + finalizeGenesisSet bool + enableStaking bool +} + +func (sp *supernetParams) validateFlags() error { + if sp.privateKey == "" { + return sidechainHelper.ValidateSecretFlags(sp.accountDir, sp.accountConfig) + } + + if _, err := os.Stat(sp.genesisPath); err != nil { + return fmt.Errorf("provided genesis path '%s' is invalid. Error: %w ", sp.genesisPath, err) + } + + // validate jsonrpc address + _, err := helper.ParseJSONRPCAddress(sp.jsonRPC) + + return err +} + +type supernetResult struct { + isGenesisSetFinalized bool + isStakingEnabled bool +} + +func (sr supernetResult) GetOutput() string { + var ( + buffer bytes.Buffer + vals []string + ) + + buffer.WriteString("\n[SUPERNET COMMAND]\n") + + if sr.isGenesisSetFinalized { + vals = append(vals, "Genesis validator set finalized on supernet manager") + } + + if sr.isStakingEnabled { + vals = append(vals, "Staking enabled on supernet manager") + } + + buffer.WriteString(helper.FormatKV(vals)) + buffer.WriteString("\n") + + return buffer.String() +} diff --git a/command/rootchain/supernet/stakemanager/params.go b/command/rootchain/supernet/stakemanager/params.go new file mode 100644 index 0000000000..c62aa0d9c0 --- /dev/null +++ b/command/rootchain/supernet/stakemanager/params.go @@ -0,0 +1,34 @@ +package stakemanager + +import ( + "fmt" + "os" + + "github.com/0xPolygon/polygon-edge/command/helper" + sidechainHelper "github.com/0xPolygon/polygon-edge/command/sidechain" +) + +type stakeManagerDeployParams struct { + accountDir string + accountConfig string + privateKey string + jsonRPC string + genesisPath string + stakeTokenAddress string + isTestMode bool +} + +func (s *stakeManagerDeployParams) validateFlags() error { + if !s.isTestMode && s.privateKey == "" { + return sidechainHelper.ValidateSecretFlags(s.accountDir, s.accountConfig) + } + + if _, err := os.Stat(s.genesisPath); err != nil { + return fmt.Errorf("provided genesis path '%s' is invalid. Error: %w ", s.genesisPath, err) + } + + // validate jsonrpc address + _, err := helper.ParseJSONRPCAddress(s.jsonRPC) + + return err +} diff --git a/command/rootchain/supernet/stakemanager/stake_manager_deploy.go b/command/rootchain/supernet/stakemanager/stake_manager_deploy.go new file mode 100644 index 0000000000..d82746c77f --- /dev/null +++ b/command/rootchain/supernet/stakemanager/stake_manager_deploy.go @@ -0,0 +1,266 @@ +package stakemanager + +import ( + "fmt" + + "github.com/0xPolygon/polygon-edge/chain" + "github.com/0xPolygon/polygon-edge/command" + "github.com/0xPolygon/polygon-edge/command/helper" + "github.com/0xPolygon/polygon-edge/command/polybftsecrets" + rootHelper "github.com/0xPolygon/polygon-edge/command/rootchain/helper" + "github.com/0xPolygon/polygon-edge/consensus/polybft" + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi/artifact" + "github.com/0xPolygon/polygon-edge/txrelayer" + "github.com/0xPolygon/polygon-edge/types" + "github.com/spf13/cobra" + "github.com/umbracle/ethgo" + "golang.org/x/sync/errgroup" +) + +var params stakeManagerDeployParams + +func GetCommand() *cobra.Command { + registerCmd := &cobra.Command{ + Use: "stake-manager-deploy", + Short: "Command for deploying stake manager contract on rootchain", + PreRunE: runPreRun, + RunE: runCommand, + } + + setFlags(registerCmd) + + return registerCmd +} + +func runPreRun(cmd *cobra.Command, _ []string) error { + params.jsonRPC = helper.GetJSONRPCAddress(cmd) + + return params.validateFlags() +} + +func setFlags(cmd *cobra.Command) { + cmd.Flags().StringVar( + ¶ms.accountDir, + polybftsecrets.AccountDirFlag, + "", + polybftsecrets.AccountDirFlagDesc, + ) + + cmd.Flags().StringVar( + ¶ms.accountConfig, + polybftsecrets.AccountConfigFlag, + "", + polybftsecrets.AccountConfigFlagDesc, + ) + + cmd.Flags().StringVar( + ¶ms.privateKey, + polybftsecrets.PrivateKeyFlag, + "", + polybftsecrets.PrivateKeyFlagDesc, + ) + + cmd.Flags().StringVar( + ¶ms.genesisPath, + rootHelper.GenesisPathFlag, + rootHelper.DefaultGenesisPath, + rootHelper.GenesisPathFlagDesc, + ) + + cmd.Flags().StringVar( + ¶ms.stakeTokenAddress, + rootHelper.StakeTokenFlag, + "", + rootHelper.StakeTokenFlagDesc, + ) + + cmd.Flags().BoolVar( + ¶ms.isTestMode, + rootHelper.TestModeFlag, + false, + "indicates if command is run in test mode. If test mode is used contract will be deployed using test account "+ + "and a test stake ERC20 token will be deployed to be used for staking", + ) + + cmd.MarkFlagsMutuallyExclusive(polybftsecrets.AccountDirFlag, polybftsecrets.AccountConfigFlag) + cmd.MarkFlagsMutuallyExclusive(polybftsecrets.PrivateKeyFlag, polybftsecrets.AccountConfigFlag) + cmd.MarkFlagsMutuallyExclusive(polybftsecrets.PrivateKeyFlag, polybftsecrets.AccountDirFlag) + cmd.MarkFlagsMutuallyExclusive(rootHelper.TestModeFlag, polybftsecrets.PrivateKeyFlag) + cmd.MarkFlagsMutuallyExclusive(rootHelper.TestModeFlag, polybftsecrets.AccountConfigFlag) + cmd.MarkFlagsMutuallyExclusive(rootHelper.TestModeFlag, polybftsecrets.AccountDirFlag) + cmd.MarkFlagsMutuallyExclusive(rootHelper.TestModeFlag, rootHelper.StakeTokenFlag) + + helper.RegisterJSONRPCFlag(cmd) +} + +func runCommand(cmd *cobra.Command, _ []string) error { + outputter := command.InitializeOutputter(cmd) + defer outputter.WriteOutput() + + var ( + deployerKey ethgo.Key + err error + ) + + if params.isTestMode { + deployerKey, err = rootHelper.DecodePrivateKey("") + } else { + deployerKey, err = rootHelper.GetECDSAKey(params.privateKey, params.accountDir, params.accountConfig) + } + + if err != nil { + return fmt.Errorf("faield to get deployer key: %w", err) + } + + txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(params.jsonRPC)) + if err != nil { + return fmt.Errorf("deploying stake manager failed: %w", err) + } + + if params.isTestMode { + // fund deployer so that he can deploy contracts + deployerAddr := deployerKey.Address() + txn := ðgo.Transaction{To: &deployerAddr, Value: ethgo.Ether(1)} + + if _, err = txRelayer.SendTransactionLocal(txn); err != nil { + return fmt.Errorf("faield to send local transaction: %w", err) + } + } + + var ( + stakeManagerAddress types.Address + stakeTokenAddress = types.StringToAddress(params.stakeTokenAddress) + g, ctx = errgroup.WithContext(cmd.Context()) + ) + + g.Go(func() error { + select { + case <-ctx.Done(): + return ctx.Err() + default: + // deploy stake manager + contractAddress, err := deployContract(txRelayer, deployerKey, + contractsapi.StakeManager, "StakeManager") + if err != nil { + return err + } + + outputter.WriteCommandResult(&rootHelper.MessageResult{ + Message: "[STAKEMANAGER - DEPLOY] Successfully deployed StakeManager contract", + }) + + stakeManagerAddress = contractAddress + + return nil + } + }) + + if params.isTestMode { + g.Go(func() error { + select { + case <-ctx.Done(): + return ctx.Err() + default: + // this is only used for testing, we are deploying a test ERC20 token to use for staking + // this should not be used in production + // deploy stake manager + contractAddress, err := deployContract(txRelayer, deployerKey, + contractsapi.RootERC20, "MockERC20StakeToken") + if err != nil { + return err + } + + outputter.WriteCommandResult(&rootHelper.MessageResult{ + Message: "[STAKEMANAGER - DEPLOY] Successfully deployed MockERC20StakeToken contract", + }) + + stakeTokenAddress = contractAddress + + return nil + } + }) + } + + if err := g.Wait(); err != nil { + return err + } + + // initialize stake manager + if err := initializeStakeManager(outputter, txRelayer, + stakeManagerAddress, stakeTokenAddress, deployerKey); err != nil { + return fmt.Errorf("could not initialize stake manager contract. Error: %w", err) + } + + // update stake manager address in genesis + chainConfig, err := chain.ImportFromFile(params.genesisPath) + if err != nil { + return fmt.Errorf("failed to read chain configuration: %w", err) + } + + consensusConfig, err := polybft.GetPolyBFTConfig(chainConfig) + if err != nil { + return fmt.Errorf("failed to retrieve consensus configuration: %w", err) + } + + if consensusConfig.Bridge == nil { + consensusConfig.Bridge = &polybft.BridgeConfig{} + } + + consensusConfig.Bridge.StakeManagerAddr = stakeManagerAddress + consensusConfig.Bridge.StakeTokenAddr = stakeTokenAddress + + // write updated chain configuration + chainConfig.Params.Engine[polybft.ConsensusName] = consensusConfig + + if err = helper.WriteGenesisConfigToDisk(chainConfig, params.genesisPath); err != nil { + return fmt.Errorf("failed to save chain configuration bridge data: %w", err) + } + + return nil +} + +// initializeStakeManager invokes initialize function on StakeManager contract +func initializeStakeManager(cmdOutput command.OutputFormatter, + txRelayer txrelayer.TxRelayer, + stakeManagerAddress types.Address, + stakeTokenAddress types.Address, + deployerKey ethgo.Key) error { + initFn := &contractsapi.InitializeStakeManagerFn{NewMatic: stakeTokenAddress} + + input, err := initFn.EncodeAbi() + if err != nil { + return err + } + + if _, err := rootHelper.SendTransaction(txRelayer, ethgo.Address(stakeManagerAddress), + input, "StakeManager", deployerKey); err != nil { + return err + } + + cmdOutput.WriteCommandResult(&rootHelper.MessageResult{ + Message: "[STAKEMANAGER - DEPLOY] StakeManager contract is initialized", + }) + + return nil +} + +func deployContract(txRelayer txrelayer.TxRelayer, deployerKey ethgo.Key, + artifact *artifact.Artifact, contractName string) (types.Address, error) { + txn := ðgo.Transaction{ + To: nil, // contract deployment + Input: artifact.Bytecode, + } + + receipt, err := txRelayer.SendTransaction(txn, deployerKey) + if err != nil { + return types.ZeroAddress, + fmt.Errorf("failed sending %s contract deploy transaction: %w", contractName, err) + } + + if receipt == nil || receipt.Status != uint64(types.ReceiptSuccess) { + return types.ZeroAddress, fmt.Errorf("deployment of %s contract failed", contractName) + } + + return types.Address(receipt.ContractAddress), nil +} diff --git a/command/rootchain/supernet/supernet.go b/command/rootchain/supernet/supernet.go new file mode 100644 index 0000000000..40f2ba7270 --- /dev/null +++ b/command/rootchain/supernet/supernet.go @@ -0,0 +1,332 @@ +package supernet + +import ( + "fmt" + "math/big" + "strings" + + "github.com/0xPolygon/polygon-edge/chain" + "github.com/0xPolygon/polygon-edge/command" + "github.com/0xPolygon/polygon-edge/command/genesis" + "github.com/0xPolygon/polygon-edge/command/helper" + "github.com/0xPolygon/polygon-edge/command/polybftsecrets" + rootHelper "github.com/0xPolygon/polygon-edge/command/rootchain/helper" + "github.com/0xPolygon/polygon-edge/consensus/polybft" + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" + "github.com/0xPolygon/polygon-edge/txrelayer" + "github.com/0xPolygon/polygon-edge/types" + "github.com/spf13/cobra" + "github.com/umbracle/ethgo" +) + +var params supernetParams + +func GetCommand() *cobra.Command { + registerCmd := &cobra.Command{ + Use: "supernet", + Short: "Supernet initialization & finalization command", + PreRunE: runPreRun, + RunE: runCommand, + } + + setFlags(registerCmd) + + return registerCmd +} + +func runPreRun(cmd *cobra.Command, _ []string) error { + params.jsonRPC = helper.GetJSONRPCAddress(cmd) + + return params.validateFlags() +} + +func setFlags(cmd *cobra.Command) { + cmd.Flags().StringVar( + ¶ms.accountDir, + polybftsecrets.AccountDirFlag, + "", + polybftsecrets.AccountDirFlagDesc, + ) + + cmd.Flags().StringVar( + ¶ms.accountConfig, + polybftsecrets.AccountConfigFlag, + "", + polybftsecrets.AccountConfigFlagDesc, + ) + + cmd.Flags().StringVar( + ¶ms.privateKey, + polybftsecrets.PrivateKeyFlag, + "", + polybftsecrets.PrivateKeyFlagDesc, + ) + + cmd.Flags().StringVar( + ¶ms.genesisPath, + rootHelper.GenesisPathFlag, + rootHelper.DefaultGenesisPath, + rootHelper.GenesisPathFlagDesc, + ) + + cmd.Flags().StringVar( + ¶ms.supernetManagerAddress, + rootHelper.SupernetManagerFlag, + "", + rootHelper.SupernetManagerFlagDesc, + ) + + cmd.Flags().StringVar( + ¶ms.stakeManagerAddress, + rootHelper.StakeManagerFlag, + "", + rootHelper.StakeManagerFlagDesc, + ) + + cmd.Flags().BoolVar( + ¶ms.finalizeGenesisSet, + finalizeGenesisSetFlag, + false, + "indicates if genesis validator set should be finalized on rootchain", + ) + + cmd.Flags().BoolVar( + ¶ms.enableStaking, + enableStakingFlag, + false, + "indicates if staking will be enabled after finalization of genesis validators on rootchain", + ) + + cmd.MarkFlagsMutuallyExclusive(polybftsecrets.AccountDirFlag, polybftsecrets.AccountConfigFlag) + cmd.MarkFlagsMutuallyExclusive(polybftsecrets.PrivateKeyFlag, polybftsecrets.AccountConfigFlag) + cmd.MarkFlagsMutuallyExclusive(polybftsecrets.PrivateKeyFlag, polybftsecrets.AccountDirFlag) + + helper.RegisterJSONRPCFlag(cmd) +} + +func runCommand(cmd *cobra.Command, _ []string) error { + outputter := command.InitializeOutputter(cmd) + defer outputter.WriteOutput() + + ownerKey, err := rootHelper.GetECDSAKey(params.privateKey, params.accountDir, params.accountConfig) + if err != nil { + return err + } + + txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(params.jsonRPC)) + if err != nil { + return fmt.Errorf("enlist validator failed: %w", err) + } + + supernetAddr := ethgo.Address(types.StringToAddress(params.supernetManagerAddress)) + + if params.finalizeGenesisSet { + encoded, err := contractsapi.CustomSupernetManager.Abi.Methods["finalizeGenesis"].Encode([]interface{}{}) + if err != nil { + return err + } + + txn := ðgo.Transaction{ + From: ownerKey.Address(), + Input: encoded, + To: &supernetAddr, + } + + if _, err = txRelayer.Call(ownerKey.Address(), supernetAddr, encoded); err == nil { + receipt, err := txRelayer.SendTransaction(txn, ownerKey) + if err != nil { + return fmt.Errorf("finalizing genesis validator set failed. Error: %w", err) + } + + if receipt.Status == uint64(types.ReceiptFailed) { + return fmt.Errorf("finalizing genesis validator set transaction failed on block %d", receipt.BlockNumber) + } + } else if !strings.Contains(err.Error(), "execution reverted: GenesisLib: already finalized") { + return err + } + + chainConfig, err := chain.ImportFromFile(params.genesisPath) + if err != nil { + return fmt.Errorf("failed to read chain configuration: %w", err) + } + + consensusConfig, err := polybft.GetPolyBFTConfig(chainConfig) + if err != nil { + return fmt.Errorf("failed to retrieve consensus configuration: %w", err) + } + + stakeManager := types.StringToAddress(params.stakeManagerAddress) + callerAddr := types.Address(ownerKey.Address()) + + validatorMetadata := make([]*validator.ValidatorMetadata, len(consensusConfig.InitialValidatorSet)) + + // update Stake field of validators in genesis file + // based on their finalized stake on rootchain + for i, v := range consensusConfig.InitialValidatorSet { + finalizedStake, err := getFinalizedStake(callerAddr, v.Address, stakeManager, + consensusConfig.SupernetID, txRelayer) + if err != nil { + return fmt.Errorf("could not get finalized stake for validator: %v. Error: %w", v.Address, err) + } + + v.Stake = finalizedStake + + metadata, err := v.ToValidatorMetadata() + if err != nil { + return err + } + + validatorMetadata[i] = metadata + } + + // update the voting power in genesis block extra + // based on finalized stake on rootchain + genesisExtraData, err := genesis.GenerateExtraDataPolyBft(validatorMetadata) + if err != nil { + return err + } + + chainConfig.Genesis.ExtraData = genesisExtraData + chainConfig.Params.Engine[polybft.ConsensusName] = consensusConfig + + // save updated stake and genesis extra to genesis file on disk + if err := helper.WriteGenesisConfigToDisk(chainConfig, params.genesisPath); err != nil { + return fmt.Errorf("failed to save chain configuration bridge data: %w", err) + } + + // initialize CheckpointManager contract since it needs to have a valid VotingPowers of validators + if err := initializeCheckpointManager(outputter, txRelayer, + consensusConfig, chainConfig.Params.ChainID, ownerKey); err != nil { + return fmt.Errorf("could not initialize CheckpointManager with finalized genesis validator set: %w", err) + } + } + + if params.enableStaking { + encoded, err := contractsapi.CustomSupernetManager.Abi.Methods["enableStaking"].Encode([]interface{}{}) + if err != nil { + return err + } + + txn := ðgo.Transaction{ + From: ownerKey.Address(), + Input: encoded, + To: &supernetAddr, + } + + receipt, err := txRelayer.SendTransaction(txn, ownerKey) + if err != nil { + return fmt.Errorf("enabling staking on supernet manager failed. Error: %w", err) + } + + if receipt.Status == uint64(types.ReceiptFailed) { + return fmt.Errorf("enable staking transaction failed on block %d", receipt.BlockNumber) + } + } + + result := &supernetResult{ + isGenesisSetFinalized: params.finalizeGenesisSet, + isStakingEnabled: params.enableStaking, + } + + outputter.WriteCommandResult(result) + + return nil +} + +// geFinalizedStake returns finalized stake of given validator for given supernet on StakeManager +func getFinalizedStake(owner, validator, stakeManager types.Address, chainID int64, + txRelayer txrelayer.TxRelayer) (*big.Int, error) { + stakeOfFn := &contractsapi.StakeOfStakeManagerFn{ + Validator: validator, + ID: new(big.Int).SetInt64(chainID), + } + + encode, err := stakeOfFn.EncodeAbi() + if err != nil { + return nil, err + } + + response, err := txRelayer.Call(ethgo.Address(owner), ethgo.Address(stakeManager), encode) + if err != nil { + return nil, err + } + + return types.ParseUint256orHex(&response) +} + +// validatorSetToABISlice converts given validators to generic map +// which is used for ABI encoding validator set being sent to the rootchain contract +func validatorSetToABISlice(o command.OutputFormatter, + validators []*validator.GenesisValidator) ([]*contractsapi.Validator, error) { + accSet := make(validator.AccountSet, len(validators)) + + if _, err := o.Write([]byte("[VALIDATORS - CHECKPOINT MANAGER] \n")); err != nil { + return nil, err + } + + for i, val := range validators { + if _, err := o.Write([]byte(fmt.Sprintf("%v\n", val))); err != nil { + return nil, err + } + + blsKey, err := val.UnmarshalBLSPublicKey() + if err != nil { + return nil, err + } + + accSet[i] = &validator.ValidatorMetadata{ + Address: val.Address, + BlsKey: blsKey, + VotingPower: new(big.Int).Set(val.Stake), + } + } + + hash, err := accSet.Hash() + if err != nil { + return nil, err + } + + if _, err := o.Write([]byte( + fmt.Sprintf("[VALIDATORS - CHECKPOINT MANAGER] Validators hash: %s\n", hash))); err != nil { + return nil, err + } + + return accSet.ToAPIBinding(), nil +} + +// initializeCheckpointManager initializes CheckpointManager contract on rootchain +// based on finalized stake (voting power) of genesis validators on root +func initializeCheckpointManager(outputter command.OutputFormatter, + txRelayer txrelayer.TxRelayer, + consensusConfig polybft.PolyBFTConfig, chainID int64, + deployerKey ethgo.Key) error { + validatorSet, err := validatorSetToABISlice(outputter, consensusConfig.InitialValidatorSet) + if err != nil { + return fmt.Errorf("failed to convert validators to map: %w", err) + } + + initParams := &contractsapi.InitializeCheckpointManagerFn{ + ChainID_: big.NewInt(chainID), + NewBls: consensusConfig.Bridge.BLSAddress, + NewBn256G2: consensusConfig.Bridge.BN256G2Address, + NewValidatorSet: validatorSet, + } + + input, err := initParams.EncodeAbi() + if err != nil { + return fmt.Errorf("failed to encode initialization params for CheckpointManager.initialize. error: %w", err) + } + + if _, err := rootHelper.SendTransaction(txRelayer, ethgo.Address(consensusConfig.Bridge.CheckpointManagerAddr), + input, "CheckpointManager", deployerKey); err != nil { + return err + } + + outputter.WriteCommandResult( + &rootHelper.MessageResult{ + Message: fmt.Sprintf("CheckpointManager contract is initialized"), + }) + + return nil +} diff --git a/command/rootchain/validators/params.go b/command/rootchain/validators/params.go new file mode 100644 index 0000000000..cd2dab159e --- /dev/null +++ b/command/rootchain/validators/params.go @@ -0,0 +1,46 @@ +package validators + +import ( + "bytes" + "fmt" + + "github.com/0xPolygon/polygon-edge/command/helper" + sidechainHelper "github.com/0xPolygon/polygon-edge/command/sidechain" +) + +type validatorInfoParams struct { + accountDir string + accountConfig string + jsonRPC string + supernetManagerAddress string + stakeManagerAddress string + chainID int64 +} + +func (v *validatorInfoParams) validateFlags() error { + return sidechainHelper.ValidateSecretFlags(v.accountDir, v.accountConfig) +} + +type validatorsInfoResult struct { + address string + stake uint64 + active bool + whitelisted bool +} + +func (vr validatorsInfoResult) GetOutput() string { + var buffer bytes.Buffer + + buffer.WriteString("\n[VALIDATOR INFO]\n") + + vals := make([]string, 4) + vals[0] = fmt.Sprintf("Validator Address|%s", vr.address) + vals[1] = fmt.Sprintf("Stake|%v", vr.stake) + vals[2] = fmt.Sprintf("Is Whitelisted|%v", vr.whitelisted) + vals[3] = fmt.Sprintf("Is Active|%v", vr.active) + + buffer.WriteString(helper.FormatKV(vals)) + buffer.WriteString("\n") + + return buffer.String() +} diff --git a/command/sidechain/validators/validator_info.go b/command/rootchain/validators/validator_info.go similarity index 65% rename from command/sidechain/validators/validator_info.go rename to command/rootchain/validators/validator_info.go index d6af0a050a..94c1a7108b 100644 --- a/command/sidechain/validators/validator_info.go +++ b/command/rootchain/validators/validator_info.go @@ -6,8 +6,10 @@ import ( "github.com/0xPolygon/polygon-edge/command" "github.com/0xPolygon/polygon-edge/command/helper" "github.com/0xPolygon/polygon-edge/command/polybftsecrets" + rootHelper "github.com/0xPolygon/polygon-edge/command/rootchain/helper" sidechainHelper "github.com/0xPolygon/polygon-edge/command/sidechain" "github.com/0xPolygon/polygon-edge/txrelayer" + "github.com/0xPolygon/polygon-edge/types" "github.com/spf13/cobra" ) @@ -44,6 +46,27 @@ func setFlags(cmd *cobra.Command) { polybftsecrets.AccountConfigFlagDesc, ) + cmd.Flags().StringVar( + ¶ms.supernetManagerAddress, + rootHelper.SupernetManagerFlag, + "", + rootHelper.SupernetManagerFlagDesc, + ) + + cmd.Flags().StringVar( + ¶ms.stakeManagerAddress, + rootHelper.StakeManagerFlag, + "", + rootHelper.StakeManagerFlagDesc, + ) + + cmd.Flags().Int64Var( + ¶ms.chainID, + polybftsecrets.ChainIDFlag, + 0, + polybftsecrets.ChainIDFlagDesc, + ) + cmd.MarkFlagsMutuallyExclusive(polybftsecrets.AccountDirFlag, polybftsecrets.AccountConfigFlag) } @@ -68,19 +91,20 @@ func runCommand(cmd *cobra.Command, _ []string) error { } validatorAddr := validatorAccount.Ecdsa.Address() + supernetManagerAddr := types.StringToAddress(params.supernetManagerAddress) + stakeManagerAddr := types.StringToAddress(params.stakeManagerAddress) - validatorInfo, err := sidechainHelper.GetValidatorInfo(validatorAddr, txRelayer) + validatorInfo, err := rootHelper.GetValidatorInfo(validatorAddr, + supernetManagerAddr, stakeManagerAddr, params.chainID, txRelayer) if err != nil { return fmt.Errorf("failed to get validator info for %s: %w", validatorAddr, err) } outputter.WriteCommandResult(&validatorsInfoResult{ - address: validatorInfo.Address.String(), - stake: validatorInfo.Stake.Uint64(), - totalStake: validatorInfo.TotalStake.Uint64(), - commission: validatorInfo.Commission.Uint64(), - withdrawableRewards: validatorInfo.WithdrawableRewards.Uint64(), - active: validatorInfo.Active, + address: validatorInfo.Address.String(), + stake: validatorInfo.Stake.Uint64(), + active: validatorInfo.IsActive, + whitelisted: validatorInfo.IsWhitelisted, }) return nil diff --git a/command/rootchain/whitelist/params.go b/command/rootchain/whitelist/params.go new file mode 100644 index 0000000000..85c68d9ffd --- /dev/null +++ b/command/rootchain/whitelist/params.go @@ -0,0 +1,62 @@ +package whitelist + +import ( + "bytes" + "errors" + "fmt" + + "github.com/0xPolygon/polygon-edge/command/helper" + sidechainHelper "github.com/0xPolygon/polygon-edge/command/sidechain" +) + +const ( + newValidatorAddressesFlag = "addresses" +) + +var ( + errNoNewValidatorsProvided = errors.New("no new validators addresses provided") +) + +type whitelistParams struct { + accountDir string + accountConfig string + privateKey string + jsonRPC string + newValidatorAddresses []string + supernetManagerAddress string +} + +func (ep *whitelistParams) validateFlags() error { + if len(ep.newValidatorAddresses) == 0 { + return errNoNewValidatorsProvided + } + + if ep.privateKey == "" { + return sidechainHelper.ValidateSecretFlags(ep.accountDir, ep.accountConfig) + } + + // validate jsonrpc address + _, err := helper.ParseJSONRPCAddress(ep.jsonRPC) + + return err +} + +type whitelistResult struct { + newValidatorAddresses []string +} + +func (wr whitelistResult) GetOutput() string { + var buffer bytes.Buffer + + buffer.WriteString("\n[WHITELIST VALIDATORS]\n") + + vals := make([]string, len(wr.newValidatorAddresses)) + for i, addr := range wr.newValidatorAddresses { + vals[i] = fmt.Sprintf("Validator address|%s", addr) + } + + buffer.WriteString(helper.FormatKV(vals)) + buffer.WriteString("\n") + + return buffer.String() +} diff --git a/command/rootchain/whitelist/whitelist_validators.go b/command/rootchain/whitelist/whitelist_validators.go new file mode 100644 index 0000000000..6b6fbc1638 --- /dev/null +++ b/command/rootchain/whitelist/whitelist_validators.go @@ -0,0 +1,156 @@ +package whitelist + +import ( + "fmt" + "time" + + "github.com/0xPolygon/polygon-edge/command" + "github.com/0xPolygon/polygon-edge/command/helper" + "github.com/0xPolygon/polygon-edge/command/polybftsecrets" + rootHelper "github.com/0xPolygon/polygon-edge/command/rootchain/helper" + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" + "github.com/0xPolygon/polygon-edge/txrelayer" + "github.com/0xPolygon/polygon-edge/types" + "github.com/spf13/cobra" + "github.com/umbracle/ethgo" +) + +var params whitelistParams + +func GetCommand() *cobra.Command { + registerCmd := &cobra.Command{ + Use: "whitelist-validators", + Short: "whitelist new validators", + PreRunE: runPreRun, + RunE: runCommand, + } + + setFlags(registerCmd) + + return registerCmd +} + +func setFlags(cmd *cobra.Command) { + cmd.Flags().StringVar( + ¶ms.accountDir, + polybftsecrets.AccountDirFlag, + "", + polybftsecrets.AccountDirFlagDesc, + ) + + cmd.Flags().StringVar( + ¶ms.accountConfig, + polybftsecrets.AccountConfigFlag, + "", + polybftsecrets.AccountConfigFlagDesc, + ) + + cmd.Flags().StringVar( + ¶ms.privateKey, + polybftsecrets.PrivateKeyFlag, + "", + polybftsecrets.PrivateKeyFlagDesc, + ) + + cmd.Flags().StringSliceVar( + ¶ms.newValidatorAddresses, + newValidatorAddressesFlag, + []string{}, + "account addresses of a possible validators", + ) + + cmd.Flags().StringVar( + ¶ms.supernetManagerAddress, + rootHelper.SupernetManagerFlag, + "", + rootHelper.SupernetManagerFlagDesc, + ) + + cmd.MarkFlagsMutuallyExclusive(polybftsecrets.AccountDirFlag, polybftsecrets.AccountConfigFlag) + cmd.MarkFlagsMutuallyExclusive(polybftsecrets.PrivateKeyFlag, polybftsecrets.AccountConfigFlag) + cmd.MarkFlagsMutuallyExclusive(polybftsecrets.PrivateKeyFlag, polybftsecrets.AccountDirFlag) + + helper.RegisterJSONRPCFlag(cmd) +} + +func runPreRun(cmd *cobra.Command, _ []string) error { + params.jsonRPC = helper.GetJSONRPCAddress(cmd) + + return params.validateFlags() +} + +func runCommand(cmd *cobra.Command, _ []string) error { + outputter := command.InitializeOutputter(cmd) + defer outputter.WriteOutput() + + ecdsaKey, err := rootHelper.GetECDSAKey(params.privateKey, params.accountDir, params.accountConfig) + if err != nil { + return err + } + + txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(params.jsonRPC), + txrelayer.WithReceiptTimeout(150*time.Millisecond)) + if err != nil { + return fmt.Errorf("whitelist validator failed. Could not create tx relayer: %w", err) + } + + whitelistFn := &contractsapi.WhitelistValidatorsCustomSupernetManagerFn{ + Validators_: stringSliceToAddressSlice(params.newValidatorAddresses), + } + + encoded, err := whitelistFn.EncodeAbi() + if err != nil { + return fmt.Errorf("whitelist validator failed. Could not abi encode whitelist function: %w", err) + } + + supernetAddr := ethgo.Address(types.StringToAddress(params.supernetManagerAddress)) + txn := ðgo.Transaction{ + From: ecdsaKey.Address(), + Input: encoded, + To: &supernetAddr, + } + + receipt, err := txRelayer.SendTransaction(txn, ecdsaKey) + if err != nil { + return fmt.Errorf("whitelist validator failed %w", err) + } + + if receipt.Status == uint64(types.ReceiptFailed) { + return fmt.Errorf("whitelist validator transaction failed on block %d", receipt.BlockNumber) + } + + var ( + whitelistEvent contractsapi.AddedToWhitelistEvent + result = &whitelistResult{} + ) + + for _, log := range receipt.Logs { + doesMatch, err := whitelistEvent.ParseLog(log) + if !doesMatch { + continue + } + + if err != nil { + return err + } + + result.newValidatorAddresses = append(result.newValidatorAddresses, whitelistEvent.Validator.String()) + } + + if len(result.newValidatorAddresses) != len(params.newValidatorAddresses) { + return fmt.Errorf("whitelist of validators did not pass successfully") + } + + outputter.WriteCommandResult(result) + + return nil +} + +func stringSliceToAddressSlice(addrs []string) []ethgo.Address { + res := make([]ethgo.Address, len(addrs)) + for indx, addr := range addrs { + res[indx] = ethgo.Address(types.StringToAddress(addr)) + } + + return res +} diff --git a/command/rootchain/withdraw/params.go b/command/rootchain/withdraw/params.go new file mode 100644 index 0000000000..71c481a5b6 --- /dev/null +++ b/command/rootchain/withdraw/params.go @@ -0,0 +1,55 @@ +package withdraw + +import ( + "bytes" + "fmt" + "math/big" + + "github.com/0xPolygon/polygon-edge/command/helper" + sidechainHelper "github.com/0xPolygon/polygon-edge/command/sidechain" +) + +var ( + addressToFlag = "to" +) + +type withdrawParams struct { + accountDir string + accountConfig string + jsonRPC string + stakeManagerAddr string + addressTo string + amount string + + amountValue *big.Int +} + +func (v *withdrawParams) validateFlags() (err error) { + if v.amountValue, err = helper.ParseAmount(v.amount); err != nil { + return err + } + + return sidechainHelper.ValidateSecretFlags(v.accountDir, v.accountConfig) +} + +type withdrawResult struct { + validatorAddress string + amount uint64 + withdrawnTo string +} + +func (wr withdrawResult) GetOutput() string { + var buffer bytes.Buffer + + buffer.WriteString("\n[WITHDRAWN AMOUNT]\n") + + vals := make([]string, 0, 3) + vals = append(vals, fmt.Sprintf("Validator Address|%s", wr.validatorAddress)) + vals = append(vals, fmt.Sprintf("Amount Withdrawn|%v", wr.amount)) + vals = append(vals, fmt.Sprintf("Withdrawn To|%s", wr.withdrawnTo)) + + buffer.WriteString(helper.FormatKV(vals)) + buffer.WriteString("\n") + + return buffer.String() +} diff --git a/command/sidechain/whitelist/whitelist_validator.go b/command/rootchain/withdraw/withdraw.go similarity index 53% rename from command/sidechain/whitelist/whitelist_validator.go rename to command/rootchain/withdraw/withdraw.go index 0a1c43811f..d64478eeaf 100644 --- a/command/sidechain/whitelist/whitelist_validator.go +++ b/command/rootchain/withdraw/withdraw.go @@ -1,4 +1,4 @@ -package whitelist +package withdraw import ( "fmt" @@ -7,28 +7,28 @@ import ( "github.com/0xPolygon/polygon-edge/command" "github.com/0xPolygon/polygon-edge/command/helper" "github.com/0xPolygon/polygon-edge/command/polybftsecrets" + rootHelper "github.com/0xPolygon/polygon-edge/command/rootchain/helper" sidechainHelper "github.com/0xPolygon/polygon-edge/command/sidechain" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" - "github.com/0xPolygon/polygon-edge/contracts" "github.com/0xPolygon/polygon-edge/txrelayer" "github.com/0xPolygon/polygon-edge/types" "github.com/spf13/cobra" "github.com/umbracle/ethgo" ) -var params whitelistParams +var params withdrawParams func GetCommand() *cobra.Command { - registerCmd := &cobra.Command{ - Use: "whitelist-validator", - Short: "whitelist a new validator", + withdrawCmd := &cobra.Command{ + Use: "withdraw-root", + Short: "Withdraws sender's withdrawable amount to specified address on the root chain", PreRunE: runPreRun, RunE: runCommand, } - setFlags(registerCmd) + setFlags(withdrawCmd) - return registerCmd + return withdrawCmd } func setFlags(cmd *cobra.Command) { @@ -47,10 +47,24 @@ func setFlags(cmd *cobra.Command) { ) cmd.Flags().StringVar( - ¶ms.newValidatorAddress, - newValidatorAddressFlag, + ¶ms.addressTo, + addressToFlag, "", - "account address of a possible validator", + "address where to withdraw withdrawable amount", + ) + + cmd.Flags().StringVar( + ¶ms.stakeManagerAddr, + rootHelper.StakeManagerFlag, + "", + rootHelper.StakeManagerFlagDesc, + ) + + cmd.Flags().StringVar( + ¶ms.amount, + sidechainHelper.AmountFlag, + "", + "amount to withdraw", ) cmd.MarkFlagsMutuallyExclusive(polybftsecrets.AccountDirFlag, polybftsecrets.AccountConfigFlag) @@ -67,50 +81,54 @@ func runCommand(cmd *cobra.Command, _ []string) error { outputter := command.InitializeOutputter(cmd) defer outputter.WriteOutput() - ownerAccount, err := sidechainHelper.GetAccount(params.accountDir, params.accountConfig) + validatorAccount, err := sidechainHelper.GetAccount(params.accountDir, params.accountConfig) if err != nil { - return fmt.Errorf("enlist validator failed: %w", err) + return err } txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(params.jsonRPC), txrelayer.WithReceiptTimeout(150*time.Millisecond)) if err != nil { - return fmt.Errorf("enlist validator failed: %w", err) + return err } - whitelistFn := &contractsapi.AddToWhitelistChildValidatorSetFn{ - WhitelistAddreses: []ethgo.Address{ethgo.Address(types.StringToAddress(params.newValidatorAddress))}, + withdrawFn := &contractsapi.WithdrawStakeStakeManagerFn{ + To: types.StringToAddress(params.addressTo), + Amount: params.amountValue, } - encoded, err := whitelistFn.EncodeAbi() + encoded, err := withdrawFn.EncodeAbi() if err != nil { - return fmt.Errorf("enlist validator failed: %w", err) + return err } + stakeManagerAddr := ethgo.Address(types.StringToAddress(params.stakeManagerAddr)) txn := ðgo.Transaction{ - From: ownerAccount.Ecdsa.Address(), - Input: encoded, - To: (*ethgo.Address)(&contracts.ValidatorSetContract), - GasPrice: sidechainHelper.DefaultGasPrice, + From: validatorAccount.Ecdsa.Address(), + Input: encoded, + To: &stakeManagerAddr, } - receipt, err := txRelayer.SendTransaction(txn, ownerAccount.Ecdsa) + receipt, err := txRelayer.SendTransaction(txn, validatorAccount.Ecdsa) if err != nil { - return fmt.Errorf("enlist validator failed %w", err) + return err } if receipt.Status == uint64(types.ReceiptFailed) { - return fmt.Errorf("enlist validator transaction failed on block %d", receipt.BlockNumber) + return fmt.Errorf("withdraw transaction failed on block %d", receipt.BlockNumber) + } + + result := &withdrawResult{ + validatorAddress: validatorAccount.Ecdsa.Address().String(), } var ( - whitelistEvent contractsapi.AddedToWhitelistEvent - result = &enlistResult{} - foundLog = false + withdrawalEvent contractsapi.StakeWithdrawnEvent + foundLog bool ) for _, log := range receipt.Logs { - doesMatch, err := whitelistEvent.ParseLog(log) + doesMatch, err := withdrawalEvent.ParseLog(log) if !doesMatch { continue } @@ -119,14 +137,15 @@ func runCommand(cmd *cobra.Command, _ []string) error { return err } - result.newValidatorAddress = whitelistEvent.Validator.String() + result.amount = withdrawalEvent.Amount.Uint64() + result.withdrawnTo = withdrawalEvent.Recipient.String() foundLog = true break } if !foundLog { - return fmt.Errorf("could not find an appropriate log in receipt that enlistment happened") + return fmt.Errorf("could not find an appropriate log in receipt that withdrawal happened") } outputter.WriteCommandResult(result) diff --git a/command/server/config/config.go b/command/server/config/config.go index 65b22424cf..4d4beb2f12 100644 --- a/command/server/config/config.go +++ b/command/server/config/config.go @@ -25,12 +25,12 @@ type Config struct { TxPool *TxPool `json:"tx_pool" yaml:"tx_pool"` LogLevel string `json:"log_level" yaml:"log_level"` RestoreFile string `json:"restore_file" yaml:"restore_file"` - BlockTime uint64 `json:"block_time_s" yaml:"block_time_s"` Headers *Headers `json:"headers" yaml:"headers"` LogFilePath string `json:"log_to" yaml:"log_to"` JSONRPCBatchRequestLimit uint64 `json:"json_rpc_batch_request_limit" yaml:"json_rpc_batch_request_limit"` JSONRPCBlockRangeLimit uint64 `json:"json_rpc_block_range_limit" yaml:"json_rpc_block_range_limit"` JSONLogFormat bool `json:"json_log_format" yaml:"json_log_format"` + CorsAllowedOrigins []string `json:"cors_allowed_origins" yaml:"cors_allowed_origins"` Relayer bool `json:"relayer" yaml:"relayer"` NumBlockConfirmations uint64 `json:"num_block_confirmations" yaml:"num_block_confirmations"` @@ -65,9 +65,6 @@ type Headers struct { } const ( - // DefaultBlockTime minimum block generation time in seconds - DefaultBlockTime uint64 = 2 - // BlockTimeMultiplierForTimeout Multiplier to get IBFT timeout from block time // timeout is calculated when IBFT timeout is not specified BlockTimeMultiplierForTimeout uint64 = 5 @@ -111,7 +108,6 @@ func DefaultConfig() *Config { }, LogLevel: "INFO", RestoreFile: "", - BlockTime: DefaultBlockTime, Headers: &Headers{ AccessControlAllowOrigins: []string{"*"}, }, diff --git a/command/server/init.go b/command/server/init.go index f7e9a8e069..353fbf9bde 100644 --- a/command/server/init.go +++ b/command/server/init.go @@ -19,7 +19,6 @@ import ( ) var ( - errInvalidBlockTime = errors.New("invalid block time specified") errDataDirectoryUndefined = errors.New("data directory not defined") ) @@ -50,10 +49,6 @@ func (p *serverParams) initRawParams() error { return err } - if err := p.initBlockTime(); err != nil { - return err - } - if p.isDevMode { p.initDevMode() } @@ -66,14 +61,6 @@ func (p *serverParams) initRawParams() error { return p.initAddresses() } -func (p *serverParams) initBlockTime() error { - if p.rawConfig.BlockTime < 1 { - return errInvalidBlockTime - } - - return nil -} - func (p *serverParams) initDataDirLocation() error { if p.rawConfig.DataDir == "" { return errDataDirectoryUndefined diff --git a/command/server/params.go b/command/server/params.go index ea5e09dc79..67beee7600 100644 --- a/command/server/params.go +++ b/command/server/params.go @@ -33,7 +33,6 @@ const ( blockGasTargetFlag = "block-gas-target" secretsConfigFlag = "secrets-config" restoreFlag = "restore" - blockTimeFlag = "block-time" devIntervalFlag = "dev-interval" devFlag = "dev" corsOriginFlag = "access-control-allow-origins" @@ -82,8 +81,6 @@ type serverParams struct { devInterval uint64 isDevMode bool - corsAllowedOrigins []string - ibftBaseTimeoutLegacy uint64 genesisConfig *chain.Chain @@ -152,7 +149,7 @@ func (p *serverParams) generateConfig() *server.Config { Chain: p.genesisConfig, JSONRPC: &server.JSONRPC{ JSONRPCAddr: p.jsonRPCAddress, - AccessControlAllowOrigin: p.corsAllowedOrigins, + AccessControlAllowOrigin: p.rawConfig.CorsAllowedOrigins, BatchLengthLimit: p.rawConfig.JSONRPCBatchRequestLimit, BlockRangeLimit: p.rawConfig.JSONRPCBlockRangeLimit, }, @@ -179,7 +176,6 @@ func (p *serverParams) generateConfig() *server.Config { MaxAccountEnqueued: p.rawConfig.TxPool.MaxAccountEnqueued, SecretsManager: p.secretsConfig, RestoreFile: p.getRestoreFilePath(), - BlockTime: p.rawConfig.BlockTime, LogLevel: hclog.LevelFromString(p.rawConfig.LogLevel), JSONLogFormat: p.rawConfig.JSONLogFormat, LogFilePath: p.logFileLocation, diff --git a/command/server/server.go b/command/server/server.go index 90253583a7..b7fa6dbf2d 100644 --- a/command/server/server.go +++ b/command/server/server.go @@ -57,7 +57,7 @@ func setFlags(cmd *cobra.Command) { ¶ms.configPath, configFlag, "", - "the path to the CLI config. Supports .json and .hcl", + "the path to the CLI config. Supports .json, .hcl, .yaml, .yml", ) cmd.Flags().StringVar( @@ -185,15 +185,8 @@ func setFlags(cmd *cobra.Command) { "maximum number of enqueued transactions per account", ) - cmd.Flags().Uint64Var( - ¶ms.rawConfig.BlockTime, - blockTimeFlag, - defaultConfig.BlockTime, - "minimum block time in seconds (at least 1s)", - ) - cmd.Flags().StringArrayVar( - ¶ms.corsAllowedOrigins, + ¶ms.rawConfig.CorsAllowedOrigins, corsOriginFlag, defaultConfig.Headers.AccessControlAllowOrigins, "the CORS header indicating whether any JSON-RPC response can be shared with the specified origin", diff --git a/command/sidecar/sidecar.go b/command/sidecar/sidecar.go new file mode 100644 index 0000000000..55050244bb --- /dev/null +++ b/command/sidecar/sidecar.go @@ -0,0 +1,110 @@ +package sidecar + +import ( + "context" + "encoding/json" + "fmt" + "time" + + "github.com/0xPolygon/polygon-edge/command" + "github.com/0xPolygon/polygon-edge/command/helper" + "github.com/0xPolygon/polygon-edge/server/proto" + "github.com/0xPolygon/polygon-edge/types" + "github.com/spf13/cobra" + "google.golang.org/protobuf/types/known/emptypb" +) + +func GetCommand() *cobra.Command { + sidecarCmd := &cobra.Command{ + Use: "sidecar", + Short: "Runs the sidecar middleware application", + Run: func(cmd *cobra.Command, args []string) { + outputter := command.InitializeOutputter(cmd) + + addr := helper.GetGRPCAddress(cmd) + + sidecar, err := newSidecar(addr, outputter) + if err != nil { + outputter.SetError(err) + + return + } + + if err = helper.HandleSignals(sidecar.Close, outputter); err != nil { + outputter.SetError(err) + + return + } + }, + } + + helper.RegisterGRPCAddressFlag(sidecarCmd) + + return sidecarCmd +} + +type sidecar struct { + clt proto.SystemClient + closeCh chan struct{} +} + +func newSidecar(grpcAddress string, outputter command.OutputFormatter) (*sidecar, error) { + client, err := helper.GetSystemClientConnection(grpcAddress) + if err != nil { + return nil, err + } + + s := &sidecar{ + clt: client, + closeCh: make(chan struct{}), + } + + go s.run(outputter) + + return s, nil +} + +func (s *sidecar) run(outputter command.OutputFormatter) { + lastBlock := int64(0) + + for { + status, err := s.clt.GetStatus(context.Background(), &emptypb.Empty{}) + if err != nil { + outputter.SetError(err) + + return + } + + if lastBlock == status.Current.Number { + continue + } + + traceResp, err := s.clt.GetTrace(context.Background(), &proto.GetTraceRequest{Number: uint64(status.Current.Number)}) + if err != nil { + outputter.SetError(err) + + return + } + + var trace *types.Trace + if err := json.Unmarshal(traceResp.Trace, &trace); err != nil { + outputter.SetError(err) + + return + } + + fmt.Println("-----") + fmt.Println(trace.AccountTrie) + fmt.Println(trace.StorageTrie) + + select { + case <-time.After(500 * time.Millisecond): + case <-s.closeCh: + return + } + } +} + +func (s *sidecar) Close() { + close(s.closeCh) +} diff --git a/command/sidechain/helper.go b/command/sidechain/helper.go index 5c2c717140..969489c7f4 100644 --- a/command/sidechain/helper.go +++ b/command/sidechain/helper.go @@ -3,25 +3,21 @@ package sidechain import ( "errors" "fmt" - "math/big" "os" "github.com/0xPolygon/polygon-edge/command/polybftsecrets" + rootHelper "github.com/0xPolygon/polygon-edge/command/rootchain/helper" "github.com/0xPolygon/polygon-edge/consensus/polybft" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" "github.com/0xPolygon/polygon-edge/contracts" - "github.com/0xPolygon/polygon-edge/helper/hex" "github.com/0xPolygon/polygon-edge/txrelayer" "github.com/0xPolygon/polygon-edge/types" "github.com/umbracle/ethgo" ) const ( - SelfFlag = "self" AmountFlag = "amount" - - DefaultGasPrice = 1879048192 // 0x70000000 ) func CheckIfDirectoryExist(dir string) error { @@ -60,65 +56,34 @@ func GetAccountFromDir(accountDir string) (*wallet.Account, error) { return GetAccount(accountDir, "") } -// GetValidatorInfo queries ChildValidatorSet smart contract and retrieves validator info for given address -func GetValidatorInfo(validatorAddr ethgo.Address, txRelayer txrelayer.TxRelayer) (*polybft.ValidatorInfo, error) { - getValidatorMethod := contractsapi.ChildValidatorSet.Abi.GetMethod("getValidator") - - encode, err := getValidatorMethod.Encode([]interface{}{validatorAddr}) - if err != nil { - return nil, err - } - - response, err := txRelayer.Call(ethgo.Address(contracts.SystemCaller), - ethgo.Address(contracts.ValidatorSetContract), encode) +// GetValidatorInfo queries CustomSupernetManager, StakeManager and RewardPool smart contracts +// to retrieve validator info for given address +func GetValidatorInfo(validatorAddr ethgo.Address, supernetManager, stakeManager types.Address, + chainID int64, rootRelayer, childRelayer txrelayer.TxRelayer) (*polybft.ValidatorInfo, error) { + validatorInfo, err := rootHelper.GetValidatorInfo(validatorAddr, supernetManager, stakeManager, + chainID, rootRelayer) if err != nil { return nil, err } - byteResponse, err := hex.DecodeHex(response) - if err != nil { - return nil, fmt.Errorf("unable to decode hex response, %w", err) - } + withdrawableFn := contractsapi.RewardPool.Abi.GetMethod("pendingRewards") - decoded, err := getValidatorMethod.Outputs.Decode(byteResponse) + encode, err := withdrawableFn.Encode([]interface{}{validatorAddr}) if err != nil { return nil, err } - decodedOutputsMap, ok := decoded.(map[string]interface{}) - if !ok { - return nil, fmt.Errorf("could not convert decoded outputs to map") - } - - return &polybft.ValidatorInfo{ - Address: validatorAddr.Address(), - Stake: decodedOutputsMap["stake"].(*big.Int), //nolint:forcetypeassert - TotalStake: decodedOutputsMap["totalStake"].(*big.Int), //nolint:forcetypeassert - Commission: decodedOutputsMap["commission"].(*big.Int), //nolint:forcetypeassert - WithdrawableRewards: decodedOutputsMap["withdrawableRewards"].(*big.Int), //nolint:forcetypeassert - Active: decodedOutputsMap["active"].(bool), //nolint:forcetypeassert - }, nil -} - -// GetDelegatorReward queries delegator reward for given validator and delegator addresses -func GetDelegatorReward(validatorAddr ethgo.Address, delegatorAddr ethgo.Address, - txRelayer txrelayer.TxRelayer) (*big.Int, error) { - input, err := contractsapi.ChildValidatorSet.Abi.Methods["getDelegatorReward"].Encode( - []interface{}{validatorAddr, delegatorAddr}) + response, err := childRelayer.Call(ethgo.ZeroAddress, ethgo.Address(contracts.RewardPoolContract), encode) if err != nil { - return nil, fmt.Errorf("failed to encode input parameters for getDelegatorReward fn: %w", err) + return nil, err } - response, err := txRelayer.Call(ethgo.Address(contracts.SystemCaller), - ethgo.Address(contracts.ValidatorSetContract), input) + withdrawableRewards, err := types.ParseUint256orHex(&response) if err != nil { return nil, err } - delegatorReward, err := types.ParseUint256orHex(&response) - if err != nil { - return nil, fmt.Errorf("unable to decode hex response, %w", err) - } + validatorInfo.WithdrawableRewards = withdrawableRewards - return delegatorReward, nil + return validatorInfo, nil } diff --git a/command/sidechain/registration/params.go b/command/sidechain/registration/params.go deleted file mode 100644 index bc6f5cc2bd..0000000000 --- a/command/sidechain/registration/params.go +++ /dev/null @@ -1,62 +0,0 @@ -package registration - -import ( - "bytes" - "fmt" - - "github.com/0xPolygon/polygon-edge/command/helper" - sidechainHelper "github.com/0xPolygon/polygon-edge/command/sidechain" - "github.com/0xPolygon/polygon-edge/types" -) - -const ( - stakeFlag = "stake" - chainIDFlag = "chain-id" -) - -type registerParams struct { - accountDir string - accountConfig string - jsonRPC string - stake string - chainID int64 -} - -func (rp *registerParams) validateFlags() error { - if err := sidechainHelper.ValidateSecretFlags(rp.accountDir, rp.accountConfig); err != nil { - return err - } - - if rp.stake != "" { - _, err := types.ParseUint256orHex(&rp.stake) - if err != nil { - return fmt.Errorf("provided stake '%s' isn't valid", rp.stake) - } - } - - return nil -} - -type registerResult struct { - validatorAddress string - stakeResult string - amount uint64 -} - -func (rr registerResult) GetOutput() string { - var buffer bytes.Buffer - - var vals []string - - buffer.WriteString("\n[REGISTRATION]\n") - - vals = make([]string, 0, 3) - vals = append(vals, fmt.Sprintf("Validator Address|%s", rr.validatorAddress)) - vals = append(vals, fmt.Sprintf("Staking Result|%s", rr.stakeResult)) - vals = append(vals, fmt.Sprintf("Amount Staked|%v", rr.amount)) - - buffer.WriteString(helper.FormatKV(vals)) - buffer.WriteString("\n") - - return buffer.String() -} diff --git a/command/sidechain/rewards/params.go b/command/sidechain/rewards/params.go new file mode 100644 index 0000000000..6672bff096 --- /dev/null +++ b/command/sidechain/rewards/params.go @@ -0,0 +1,39 @@ +package rewards + +import ( + "bytes" + "fmt" + + "github.com/0xPolygon/polygon-edge/command/helper" + sidechainHelper "github.com/0xPolygon/polygon-edge/command/sidechain" +) + +type withdrawRewardsParams struct { + accountDir string + accountConfig string + jsonRPC string +} + +type withdrawRewardResult struct { + validatorAddress string + rewardAmount uint64 +} + +func (w *withdrawRewardsParams) validateFlags() error { + return sidechainHelper.ValidateSecretFlags(w.accountDir, w.accountConfig) +} + +func (wr withdrawRewardResult) GetOutput() string { + var buffer bytes.Buffer + + buffer.WriteString("\n[WITHDRAW REWARDS]\n") + + vals := make([]string, 0, 2) + vals = append(vals, fmt.Sprintf("Validator Address|%s", wr.validatorAddress)) + vals = append(vals, fmt.Sprintf("Amount Withdrawn|%v", wr.rewardAmount)) + + buffer.WriteString(helper.FormatKV(vals)) + buffer.WriteString("\n") + + return buffer.String() +} diff --git a/command/sidechain/rewards/rewards.go b/command/sidechain/rewards/rewards.go new file mode 100644 index 0000000000..b46c1fd45d --- /dev/null +++ b/command/sidechain/rewards/rewards.go @@ -0,0 +1,120 @@ +package rewards + +import ( + "fmt" + "time" + + "github.com/0xPolygon/polygon-edge/command" + "github.com/0xPolygon/polygon-edge/command/helper" + "github.com/0xPolygon/polygon-edge/command/polybftsecrets" + sidechainHelper "github.com/0xPolygon/polygon-edge/command/sidechain" + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" + "github.com/0xPolygon/polygon-edge/contracts" + "github.com/0xPolygon/polygon-edge/txrelayer" + "github.com/0xPolygon/polygon-edge/types" + "github.com/spf13/cobra" + "github.com/umbracle/ethgo" +) + +var params withdrawRewardsParams + +func GetCommand() *cobra.Command { + unstakeCmd := &cobra.Command{ + Use: "withdraw-rewards", + Short: "Withdraws pending rewards on child chain for given validator", + PreRunE: runPreRun, + RunE: runCommand, + } + + helper.RegisterJSONRPCFlag(unstakeCmd) + setFlags(unstakeCmd) + + return unstakeCmd +} + +func setFlags(cmd *cobra.Command) { + cmd.Flags().StringVar( + ¶ms.accountDir, + polybftsecrets.AccountDirFlag, + "", + polybftsecrets.AccountDirFlagDesc, + ) + + cmd.Flags().StringVar( + ¶ms.accountConfig, + polybftsecrets.AccountConfigFlag, + "", + polybftsecrets.AccountConfigFlagDesc, + ) + + cmd.MarkFlagsMutuallyExclusive(polybftsecrets.AccountDirFlag, polybftsecrets.AccountConfigFlag) +} + +func runPreRun(cmd *cobra.Command, _ []string) error { + params.jsonRPC = helper.GetJSONRPCAddress(cmd) + + return params.validateFlags() +} + +func runCommand(cmd *cobra.Command, _ []string) error { + outputter := command.InitializeOutputter(cmd) + defer outputter.WriteOutput() + + validatorAccount, err := sidechainHelper.GetAccount(params.accountDir, params.accountConfig) + if err != nil { + return err + } + + validatorAddr := validatorAccount.Ecdsa.Address() + rewardPoolAddr := ethgo.Address(contracts.RewardPoolContract) + + txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(params.jsonRPC), + txrelayer.WithReceiptTimeout(150*time.Millisecond)) + if err != nil { + return err + } + + encoded, err := contractsapi.RewardPool.Abi.Methods["pendingRewards"].Encode([]interface{}{validatorAddr}) + if err != nil { + return err + } + + response, err := txRelayer.Call(validatorAddr, rewardPoolAddr, encoded) + if err != nil { + return err + } + + amount, err := types.ParseUint256orHex(&response) + if err != nil { + return err + } + + encoded, err = contractsapi.RewardPool.Abi.Methods["withdrawReward"].Encode([]interface{}{}) + if err != nil { + return err + } + + txn := ðgo.Transaction{ + From: validatorAddr, + Input: encoded, + To: &rewardPoolAddr, + } + + receipt, err := txRelayer.SendTransaction(txn, validatorAccount.Ecdsa) + if err != nil { + return err + } + + if receipt.Status != uint64(types.ReceiptSuccess) { + return fmt.Errorf("withdraw transaction failed on block: %d", receipt.BlockNumber) + } + + result := &withdrawRewardResult{ + validatorAddress: validatorAccount.Ecdsa.Address().String(), + rewardAmount: amount.Uint64(), + } + + outputter.WriteCommandResult(result) + + return nil +} diff --git a/command/sidechain/staking/params.go b/command/sidechain/staking/params.go deleted file mode 100644 index 118edb8b37..0000000000 --- a/command/sidechain/staking/params.go +++ /dev/null @@ -1,59 +0,0 @@ -package staking - -import ( - "bytes" - "fmt" - - "github.com/0xPolygon/polygon-edge/command/helper" - sidechainHelper "github.com/0xPolygon/polygon-edge/command/sidechain" -) - -var ( - delegateAddressFlag = "delegate" -) - -type stakeParams struct { - accountDir string - accountConfig string - jsonRPC string - amount uint64 - self bool - delegateAddress string -} - -func (v *stakeParams) validateFlags() error { - return sidechainHelper.ValidateSecretFlags(v.accountDir, v.accountConfig) -} - -type stakeResult struct { - validatorAddress string - isSelfStake bool - amount uint64 - delegatedTo string -} - -func (sr stakeResult) GetOutput() string { - var buffer bytes.Buffer - - var vals []string - - if sr.isSelfStake { - buffer.WriteString("\n[SELF STAKE]\n") - - vals = make([]string, 0, 2) - vals = append(vals, fmt.Sprintf("Validator Address|%s", sr.validatorAddress)) - vals = append(vals, fmt.Sprintf("Amount Staked|%v", sr.amount)) - } else { - buffer.WriteString("\n[DELEGATED AMOUNT]\n") - - vals = make([]string, 0, 3) - vals = append(vals, fmt.Sprintf("Validator Address|%s", sr.validatorAddress)) - vals = append(vals, fmt.Sprintf("Amount Delegated|%v", sr.amount)) - vals = append(vals, fmt.Sprintf("Delegated To|%s", sr.delegatedTo)) - } - - buffer.WriteString(helper.FormatKV(vals)) - buffer.WriteString("\n") - - return buffer.String() -} diff --git a/command/sidechain/unstaking/params.go b/command/sidechain/unstaking/params.go index 695b260235..4cd0620211 100644 --- a/command/sidechain/unstaking/params.go +++ b/command/sidechain/unstaking/params.go @@ -3,6 +3,7 @@ package unstaking import ( "bytes" "fmt" + "math/big" "github.com/0xPolygon/polygon-edge/command/helper" sidechainHelper "github.com/0xPolygon/polygon-edge/command/sidechain" @@ -13,44 +14,35 @@ var ( ) type unstakeParams struct { - accountDir string - accountConfig string - jsonRPC string - amount uint64 - self bool - undelegateAddress string + accountDir string + accountConfig string + jsonRPC string + amount string + + amountValue *big.Int } -func (v *unstakeParams) validateFlags() error { +func (v *unstakeParams) validateFlags() (err error) { + if v.amountValue, err = helper.ParseAmount(v.amount); err != nil { + return err + } + return sidechainHelper.ValidateSecretFlags(v.accountDir, v.accountConfig) } type unstakeResult struct { validatorAddress string - isSelfUnstake bool amount uint64 - undelegatedFrom string } func (ur unstakeResult) GetOutput() string { var buffer bytes.Buffer - var vals []string + buffer.WriteString("\n[UNSTAKE]\n") - if ur.isSelfUnstake { - buffer.WriteString("\n[SELF UNSTAKE]\n") - - vals = make([]string, 0, 2) - vals = append(vals, fmt.Sprintf("Validator Address|%s", ur.validatorAddress)) - vals = append(vals, fmt.Sprintf("Amount Unstaked|%v", ur.amount)) - } else { - buffer.WriteString("\n[UNDELEGATED AMOUNT]\n") - - vals = make([]string, 0, 3) - vals = append(vals, fmt.Sprintf("Validator Address|%s", ur.validatorAddress)) - vals = append(vals, fmt.Sprintf("Amount Undelegated|%v", ur.amount)) - vals = append(vals, fmt.Sprintf("Undelegated From|%s", ur.undelegatedFrom)) - } + vals := make([]string, 0, 2) + vals = append(vals, fmt.Sprintf("Validator Address|%s", ur.validatorAddress)) + vals = append(vals, fmt.Sprintf("Amount Unstaked|%v", ur.amount)) buffer.WriteString(helper.FormatKV(vals)) buffer.WriteString("\n") diff --git a/command/sidechain/unstaking/unstake.go b/command/sidechain/unstaking/unstake.go index 57ecc7172c..f62fab1c80 100644 --- a/command/sidechain/unstaking/unstake.go +++ b/command/sidechain/unstaking/unstake.go @@ -47,28 +47,13 @@ func setFlags(cmd *cobra.Command) { polybftsecrets.AccountConfigFlagDesc, ) - cmd.Flags().BoolVar( - ¶ms.self, - sidechainHelper.SelfFlag, - false, - "indicates if its a self unstake action", - ) - - cmd.Flags().Uint64Var( + cmd.Flags().StringVar( ¶ms.amount, sidechainHelper.AmountFlag, - 0, - "amount to unstake or undelegate amount from validator", - ) - - cmd.Flags().StringVar( - ¶ms.undelegateAddress, - undelegateAddressFlag, "", - "account address from which amount will be undelegated", + "amount to unstake from validator", ) - cmd.MarkFlagsMutuallyExclusive(sidechainHelper.SelfFlag, undelegateAddressFlag) cmd.MarkFlagsMutuallyExclusive(polybftsecrets.AccountDirFlag, polybftsecrets.AccountConfigFlag) } @@ -93,25 +78,19 @@ func runCommand(cmd *cobra.Command, _ []string) error { return err } - var encoded []byte - if params.self { - encoded, err = contractsapi.ChildValidatorSet.Abi.Methods["unstake"].Encode([]interface{}{params.amount}) - if err != nil { - return err - } - } else { - encoded, err = contractsapi.ChildValidatorSet.Abi.Methods["undelegate"].Encode( - []interface{}{ethgo.HexToAddress(params.undelegateAddress), params.amount}) - if err != nil { - return err - } + unstakeFn := &contractsapi.UnstakeValidatorSetFn{ + Amount: params.amountValue, + } + + encoded, err := unstakeFn.EncodeAbi() + if err != nil { + return err } txn := ðgo.Transaction{ - From: validatorAccount.Ecdsa.Address(), - Input: encoded, - To: (*ethgo.Address)(&contracts.ValidatorSetContract), - GasPrice: sidechainHelper.DefaultGasPrice, + From: validatorAccount.Ecdsa.Address(), + Input: encoded, + To: (*ethgo.Address)(&contracts.ValidatorSetContract), } receipt, err := txRelayer.SendTransaction(txn, validatorAccount.Ecdsa) @@ -119,51 +98,36 @@ func runCommand(cmd *cobra.Command, _ []string) error { return err } - if receipt.Status == uint64(types.ReceiptFailed) { - return fmt.Errorf("unstake transaction failed on block %d", receipt.BlockNumber) + if receipt.Status != uint64(types.ReceiptSuccess) { + return fmt.Errorf("unstake transaction failed on block: %d", receipt.BlockNumber) } + var ( + withdrawalRegisteredEvent contractsapi.WithdrawalRegisteredEvent + foundLog bool + ) + result := &unstakeResult{ validatorAddress: validatorAccount.Ecdsa.Address().String(), } - var ( - unstakedEvent contractsapi.UnstakedEvent - undelegatedEvent contractsapi.UndelegatedEvent - foundLog bool - ) - // check the logs to check for the result for _, log := range receipt.Logs { - doesMatch, err := unstakedEvent.ParseLog(log) - if err != nil { - return err - } - - if doesMatch { // its an unstake function call - result.isSelfUnstake = true - result.amount = unstakedEvent.Amount.Uint64() - foundLog = true - - break - } - - doesMatch, err = undelegatedEvent.ParseLog(log) + doesMatch, err := withdrawalRegisteredEvent.ParseLog(log) if err != nil { return err } if doesMatch { - result.amount = undelegatedEvent.Amount.Uint64() - result.undelegatedFrom = undelegatedEvent.Validator.String() foundLog = true + result.amount = withdrawalRegisteredEvent.Amount.Uint64() break } } if !foundLog { - return fmt.Errorf("could not find an appropriate log in receipt that unstake or undelegate happened") + return fmt.Errorf("could not find an appropriate log in receipt that unstake happened (withdrawal registered)") } outputter.WriteCommandResult(result) diff --git a/command/sidechain/validators/params.go b/command/sidechain/validators/params.go deleted file mode 100644 index a69f077d77..0000000000 --- a/command/sidechain/validators/params.go +++ /dev/null @@ -1,47 +0,0 @@ -package validators - -import ( - "bytes" - "fmt" - - "github.com/0xPolygon/polygon-edge/command/helper" - sidechainHelper "github.com/0xPolygon/polygon-edge/command/sidechain" -) - -type validatorInfoParams struct { - accountDir string - accountConfig string - jsonRPC string -} - -func (v *validatorInfoParams) validateFlags() error { - return sidechainHelper.ValidateSecretFlags(v.accountDir, v.accountConfig) -} - -type validatorsInfoResult struct { - address string - stake uint64 - totalStake uint64 - commission uint64 - withdrawableRewards uint64 - active bool -} - -func (vr validatorsInfoResult) GetOutput() string { - var buffer bytes.Buffer - - buffer.WriteString("\n[VALIDATOR INFO]\n") - - vals := make([]string, 0, 5) - vals = append(vals, fmt.Sprintf("Validator Address|%s", vr.address)) - vals = append(vals, fmt.Sprintf("Self Stake|%v", vr.stake)) - vals = append(vals, fmt.Sprintf("Total Stake|%v", vr.totalStake)) - vals = append(vals, fmt.Sprintf("Withdrawable Rewards|%v", vr.withdrawableRewards)) - vals = append(vals, fmt.Sprintf("Commission|%v", vr.commission)) - vals = append(vals, fmt.Sprintf("Is Active|%v", vr.active)) - - buffer.WriteString(helper.FormatKV(vals)) - buffer.WriteString("\n") - - return buffer.String() -} diff --git a/command/sidechain/whitelist/params.go b/command/sidechain/whitelist/params.go deleted file mode 100644 index 50dddcf5bc..0000000000 --- a/command/sidechain/whitelist/params.go +++ /dev/null @@ -1,43 +0,0 @@ -package whitelist - -import ( - "bytes" - "fmt" - - "github.com/0xPolygon/polygon-edge/command/helper" - sidechainHelper "github.com/0xPolygon/polygon-edge/command/sidechain" -) - -var ( - newValidatorAddressFlag = "address" -) - -type whitelistParams struct { - accountDir string - accountConfig string - jsonRPC string - newValidatorAddress string -} - -func (ep *whitelistParams) validateFlags() error { - return sidechainHelper.ValidateSecretFlags(ep.accountDir, ep.accountConfig) -} - -type enlistResult struct { - newValidatorAddress string -} - -func (er enlistResult) GetOutput() string { - var buffer bytes.Buffer - - var vals []string - - buffer.WriteString("\n[ENLIST VALIDATOR]\n") - - vals = append(vals, fmt.Sprintf("Validator Address|%s", er.newValidatorAddress)) - - buffer.WriteString(helper.FormatKV(vals)) - buffer.WriteString("\n") - - return buffer.String() -} diff --git a/command/sidechain/withdraw/params.go b/command/sidechain/withdraw/params.go index c51f2e8bf7..a3ffecceee 100644 --- a/command/sidechain/withdraw/params.go +++ b/command/sidechain/withdraw/params.go @@ -3,41 +3,39 @@ package withdraw import ( "bytes" "fmt" + "math/big" "github.com/0xPolygon/polygon-edge/command/helper" sidechainHelper "github.com/0xPolygon/polygon-edge/command/sidechain" ) -var ( - addressToFlag = "to" -) - type withdrawParams struct { accountDir string accountConfig string jsonRPC string - addressTo string } -func (v *withdrawParams) validateFlags() error { - return sidechainHelper.ValidateSecretFlags(v.accountDir, v.accountConfig) +func (w *withdrawParams) validateFlags() error { + return sidechainHelper.ValidateSecretFlags(w.accountDir, w.accountConfig) } type withdrawResult struct { validatorAddress string - amount uint64 - withdrawnTo string + amount *big.Int + exitEventID *big.Int + blockNumber uint64 } -func (wr withdrawResult) GetOutput() string { +func (r *withdrawResult) GetOutput() string { var buffer bytes.Buffer - buffer.WriteString("\n[WITHDRAWN AMOUNT]\n") + buffer.WriteString("\n[WITHDRAWAL]\n") - vals := make([]string, 0, 3) - vals = append(vals, fmt.Sprintf("Validator Address|%s", wr.validatorAddress)) - vals = append(vals, fmt.Sprintf("Amount Withdrawn|%v", wr.amount)) - vals = append(vals, fmt.Sprintf("Withdrawn To|%s", wr.withdrawnTo)) + vals := make([]string, 0, 4) + vals = append(vals, fmt.Sprintf("Validator Address|%s", r.validatorAddress)) + vals = append(vals, fmt.Sprintf("Amount Withdrawn|%d", r.amount)) + vals = append(vals, fmt.Sprintf("Exit Event ID|%d", r.exitEventID)) + vals = append(vals, fmt.Sprintf("Inclusion Block Number|%d", r.blockNumber)) buffer.WriteString(helper.FormatKV(vals)) buffer.WriteString("\n") diff --git a/command/sidechain/withdraw/withdraw.go b/command/sidechain/withdraw/withdraw.go index 2271716786..a93ec6da23 100644 --- a/command/sidechain/withdraw/withdraw.go +++ b/command/sidechain/withdraw/withdraw.go @@ -5,6 +5,7 @@ import ( "time" "github.com/0xPolygon/polygon-edge/command" + "github.com/0xPolygon/polygon-edge/command/bridge/common" "github.com/0xPolygon/polygon-edge/command/helper" "github.com/0xPolygon/polygon-edge/command/polybftsecrets" sidechainHelper "github.com/0xPolygon/polygon-edge/command/sidechain" @@ -19,16 +20,17 @@ import ( var params withdrawParams func GetCommand() *cobra.Command { - withdrawCmd := &cobra.Command{ - Use: "withdraw", - Short: "Withdraws sender's withdrawable amount to specified address", + unstakeCmd := &cobra.Command{ + Use: "withdraw-child", + Short: "Withdraws pending withdrawals on child chain for given validator", PreRunE: runPreRun, RunE: runCommand, } - setFlags(withdrawCmd) + helper.RegisterJSONRPCFlag(unstakeCmd) + setFlags(unstakeCmd) - return withdrawCmd + return unstakeCmd } func setFlags(cmd *cobra.Command) { @@ -46,15 +48,7 @@ func setFlags(cmd *cobra.Command) { polybftsecrets.AccountConfigFlagDesc, ) - cmd.Flags().StringVar( - ¶ms.addressTo, - addressToFlag, - "", - "address where to withdraw withdrawable amount", - ) - cmd.MarkFlagsMutuallyExclusive(polybftsecrets.AccountDirFlag, polybftsecrets.AccountConfigFlag) - helper.RegisterJSONRPCFlag(cmd) } func runPreRun(cmd *cobra.Command, _ []string) error { @@ -78,17 +72,15 @@ func runCommand(cmd *cobra.Command, _ []string) error { return err } - encoded, err := contractsapi.ChildValidatorSet.Abi.Methods["withdraw"].Encode( - []interface{}{ethgo.HexToAddress(params.addressTo)}) + encoded, err := contractsapi.ValidatorSet.Abi.Methods["withdraw"].Encode([]interface{}{}) if err != nil { return err } txn := ðgo.Transaction{ - From: validatorAccount.Ecdsa.Address(), - Input: encoded, - To: (*ethgo.Address)(&contracts.ValidatorSetContract), - GasPrice: sidechainHelper.DefaultGasPrice, + From: validatorAccount.Ecdsa.Address(), + Input: encoded, + To: (*ethgo.Address)(&contracts.ValidatorSetContract), } receipt, err := txRelayer.SendTransaction(txn, validatorAccount.Ecdsa) @@ -96,12 +88,8 @@ func runCommand(cmd *cobra.Command, _ []string) error { return err } - if receipt.Status == uint64(types.ReceiptFailed) { - return fmt.Errorf("withdraw transaction failed on block %d", receipt.BlockNumber) - } - - result := &withdrawResult{ - validatorAddress: validatorAccount.Ecdsa.Address().String(), + if receipt.Status != uint64(types.ReceiptSuccess) { + return fmt.Errorf("withdraw transaction failed on block: %d", receipt.BlockNumber) } var ( @@ -109,28 +97,36 @@ func runCommand(cmd *cobra.Command, _ []string) error { foundLog bool ) + // check the logs to check for the result for _, log := range receipt.Logs { doesMatch, err := withdrawalEvent.ParseLog(log) - if !doesMatch { - continue - } - if err != nil { return err } - result.amount = withdrawalEvent.Amount.Uint64() - result.withdrawnTo = withdrawalEvent.To.String() - foundLog = true + if doesMatch { + foundLog = true - break + break + } } if !foundLog { - return fmt.Errorf("could not find an appropriate log in receipt that withdrawal happened") + return fmt.Errorf("could not find an appropriate log in receipt that withdraw happened on ValidatorSet") + } + + exitEventID, err := common.ExtractExitEventID(receipt) + if err != nil { + return fmt.Errorf("withdrawal failed: %w", err) } - outputter.WriteCommandResult(result) + outputter.WriteCommandResult( + &withdrawResult{ + validatorAddress: validatorAccount.Ecdsa.Address().String(), + amount: withdrawalEvent.Amount, + exitEventID: exitEventID, + blockNumber: receipt.BlockNumber, + }) return nil } diff --git a/command/whitelist/deployment/deployment.go b/command/whitelist/deployment/deployment.go deleted file mode 100644 index 0a350481c2..0000000000 --- a/command/whitelist/deployment/deployment.go +++ /dev/null @@ -1,66 +0,0 @@ -package deployment - -import ( - "fmt" - - "github.com/0xPolygon/polygon-edge/command" - "github.com/spf13/cobra" -) - -func GetCommand() *cobra.Command { - deploymentCmd := &cobra.Command{ - Use: "deployment", - Short: "Top level command for updating smart contract deployment whitelist. Only accepts subcommands", - PreRunE: runPreRun, - Run: runCommand, - } - - setFlags(deploymentCmd) - - return deploymentCmd -} - -func setFlags(cmd *cobra.Command) { - cmd.Flags().StringVar( - ¶ms.genesisPath, - chainFlag, - fmt.Sprintf("./%s", command.DefaultGenesisFileName), - "the genesis file to update", - ) - cmd.Flags().StringArrayVar( - ¶ms.addAddressRaw, - addAddressFlag, - []string{}, - "adds a new address to the contract deployment whitelist", - ) - - cmd.Flags().StringArrayVar( - ¶ms.removeAddressRaw, - removeAddressFlag, - []string{}, - "removes a new address from the contract deployment whitelist", - ) -} - -func runPreRun(_ *cobra.Command, _ []string) error { - return params.initRawParams() -} - -func runCommand(cmd *cobra.Command, _ []string) { - outputter := command.InitializeOutputter(cmd) - defer outputter.WriteOutput() - - if err := params.updateGenesisConfig(); err != nil { - outputter.SetError(err) - - return - } - - if err := params.overrideGenesisConfig(); err != nil { - outputter.SetError(err) - - return - } - - outputter.SetCommandResult(params.getResult()) -} diff --git a/command/whitelist/deployment/params.go b/command/whitelist/deployment/params.go deleted file mode 100644 index 6d7f4619b4..0000000000 --- a/command/whitelist/deployment/params.go +++ /dev/null @@ -1,162 +0,0 @@ -package deployment - -import ( - "fmt" - "os" - - "github.com/0xPolygon/polygon-edge/chain" - "github.com/0xPolygon/polygon-edge/command" - "github.com/0xPolygon/polygon-edge/command/helper" - "github.com/0xPolygon/polygon-edge/helper/config" - "github.com/0xPolygon/polygon-edge/types" -) - -const ( - chainFlag = "chain" - addAddressFlag = "add" - removeAddressFlag = "remove" -) - -var ( - params = &deploymentParams{} -) - -type deploymentParams struct { - // raw addresses, entered by CLI commands - addAddressRaw []string - removeAddressRaw []string - - // addresses, converted from raw addresses - addAddresses []types.Address - removeAddresses []types.Address - - // genesis file - genesisPath string - genesisConfig *chain.Chain - - // deployment whitelist from genesis configuration - whitelist []types.Address -} - -func (p *deploymentParams) initRawParams() error { - // convert raw addresses to appropriate format - if err := p.initRawAddresses(); err != nil { - return err - } - - // init genesis configuration - if err := p.initChain(); err != nil { - return err - } - - return nil -} - -func (p *deploymentParams) initRawAddresses() error { - // convert addresses to be added from string to type.Address - p.addAddresses = unmarshallRawAddresses(p.addAddressRaw) - - // convert addresses to be removed from string to type.Address - p.removeAddresses = unmarshallRawAddresses(p.removeAddressRaw) - - return nil -} - -func (p *deploymentParams) initChain() error { - // import genesis configuration - cc, err := chain.Import(p.genesisPath) - if err != nil { - return fmt.Errorf( - "failed to load chain config from %s: %w", - p.genesisPath, - err, - ) - } - - // set genesis configuration - p.genesisConfig = cc - - return nil -} - -func (p *deploymentParams) updateGenesisConfig() error { - // Fetch contract deployment whitelist from genesis config - deploymentWhitelist, err := config.GetDeploymentWhitelist(p.genesisConfig) - if err != nil { - return err - } - - doesExist := map[types.Address]bool{} - - for _, a := range deploymentWhitelist { - doesExist[a] = true - } - - for _, a := range p.addAddresses { - doesExist[a] = true - } - - for _, a := range p.removeAddresses { - doesExist[a] = false - } - - newDeploymentWhitelist := make([]types.Address, 0) - - for addr, exists := range doesExist { - if exists { - newDeploymentWhitelist = append(newDeploymentWhitelist, addr) - } - } - - // Set whitelist in genesis configuration - whitelistConfig := config.GetWhitelist(p.genesisConfig) - - if whitelistConfig == nil { - whitelistConfig = &chain.Whitelists{} - } - - whitelistConfig.Deployment = newDeploymentWhitelist - p.genesisConfig.Params.Whitelists = whitelistConfig - - // Save whitelist for result - p.whitelist = newDeploymentWhitelist - - return nil -} - -func (p *deploymentParams) overrideGenesisConfig() error { - // Remove the current genesis configuration from the disk - if err := os.Remove(p.genesisPath); err != nil { - return err - } - - // Save the new genesis configuration - if err := helper.WriteGenesisConfigToDisk( - p.genesisConfig, - p.genesisPath, - ); err != nil { - return err - } - - return nil -} - -func (p *deploymentParams) getResult() command.CommandResult { - result := &DeploymentResult{ - AddAddresses: p.addAddresses, - RemoveAddresses: p.removeAddresses, - Whitelist: p.whitelist, - } - - return result -} - -func unmarshallRawAddresses(addresses []string) []types.Address { - marshalledAddresses := make([]types.Address, len(addresses)) - - for indx, address := range addresses { - marshalledAddresses[indx] = types.StringToAddress(address) - } - - return marshalledAddresses -} diff --git a/command/whitelist/deployment/result.go b/command/whitelist/deployment/result.go deleted file mode 100644 index 17ce4dbba3..0000000000 --- a/command/whitelist/deployment/result.go +++ /dev/null @@ -1,32 +0,0 @@ -package deployment - -import ( - "bytes" - "fmt" - - "github.com/0xPolygon/polygon-edge/types" -) - -type DeploymentResult struct { - AddAddresses []types.Address `json:"addAddress,omitempty"` - RemoveAddresses []types.Address `json:"removeAddress,omitempty"` - Whitelist []types.Address `json:"whitelist"` -} - -func (r *DeploymentResult) GetOutput() string { - var buffer bytes.Buffer - - buffer.WriteString("\n[CONTRACT DEPLOYMENT WHITELIST]\n\n") - - if len(r.AddAddresses) != 0 { - buffer.WriteString(fmt.Sprintf("Added addresses: %s,\n", r.AddAddresses)) - } - - if len(r.RemoveAddresses) != 0 { - buffer.WriteString(fmt.Sprintf("Removed addresses: %s,\n", r.RemoveAddresses)) - } - - buffer.WriteString(fmt.Sprintf("Contract deployment whitelist : %s,\n", r.Whitelist)) - - return buffer.String() -} diff --git a/command/whitelist/show/params.go b/command/whitelist/show/params.go deleted file mode 100644 index acc55ab6c7..0000000000 --- a/command/whitelist/show/params.go +++ /dev/null @@ -1,72 +0,0 @@ -package show - -import ( - "fmt" - - "github.com/0xPolygon/polygon-edge/chain" - "github.com/0xPolygon/polygon-edge/command" - "github.com/0xPolygon/polygon-edge/helper/config" - "github.com/0xPolygon/polygon-edge/types" -) - -const ( - chainFlag = "chain" -) - -var ( - params = &showParams{} -) - -type showParams struct { - // genesis file path - genesisPath string - - // deployment whitelist - whitelists Whitelists -} - -type Whitelists struct { - deployment []types.Address -} - -func (p *showParams) initRawParams() error { - // init genesis configuration - if err := p.initWhitelists(); err != nil { - return err - } - - return nil -} - -func (p *showParams) initWhitelists() error { - // import genesis configuration - genesisConfig, err := chain.Import(p.genesisPath) - if err != nil { - return fmt.Errorf( - "failed to load chain config from %s: %w", - p.genesisPath, - err, - ) - } - - // fetch whitelists - deploymentWhitelist, err := config.GetDeploymentWhitelist(genesisConfig) - if err != nil { - return err - } - - // set whitelists - p.whitelists = Whitelists{ - deployment: deploymentWhitelist, - } - - return nil -} - -func (p *showParams) getResult() command.CommandResult { - result := &ShowResult{ - Whitelists: p.whitelists, - } - - return result -} diff --git a/command/whitelist/show/result.go b/command/whitelist/show/result.go deleted file mode 100644 index fbbba91c1e..0000000000 --- a/command/whitelist/show/result.go +++ /dev/null @@ -1,20 +0,0 @@ -package show - -import ( - "bytes" - "fmt" -) - -type ShowResult struct { - Whitelists Whitelists -} - -func (r *ShowResult) GetOutput() string { - var buffer bytes.Buffer - - buffer.WriteString("\n[WHITELISTS]\n\n") - - buffer.WriteString(fmt.Sprintf("Contract deployment whitelist : %s,\n", r.Whitelists.deployment)) - - return buffer.String() -} diff --git a/command/whitelist/show/show.go b/command/whitelist/show/show.go deleted file mode 100644 index 43113aa46c..0000000000 --- a/command/whitelist/show/show.go +++ /dev/null @@ -1,41 +0,0 @@ -package show - -import ( - "fmt" - - "github.com/0xPolygon/polygon-edge/command" - "github.com/spf13/cobra" -) - -func GetCommand() *cobra.Command { - showCmd := &cobra.Command{ - Use: "show", - Short: "Displays whitelist information", - PreRunE: runPreRun, - Run: runCommand, - } - - setFlags(showCmd) - - return showCmd -} - -func setFlags(cmd *cobra.Command) { - cmd.Flags().StringVar( - ¶ms.genesisPath, - chainFlag, - fmt.Sprintf("./%s", command.DefaultGenesisFileName), - "the genesis file to update", - ) -} - -func runPreRun(_ *cobra.Command, _ []string) error { - return params.initRawParams() -} - -func runCommand(cmd *cobra.Command, _ []string) { - outputter := command.InitializeOutputter(cmd) - defer outputter.WriteOutput() - - outputter.SetCommandResult(params.getResult()) -} diff --git a/command/whitelist/whitelist.go b/command/whitelist/whitelist.go deleted file mode 100644 index 42376252f7..0000000000 --- a/command/whitelist/whitelist.go +++ /dev/null @@ -1,25 +0,0 @@ -package whitelist - -import ( - "github.com/0xPolygon/polygon-edge/command/whitelist/deployment" - "github.com/0xPolygon/polygon-edge/command/whitelist/show" - "github.com/spf13/cobra" -) - -func GetCommand() *cobra.Command { - whitelistCmd := &cobra.Command{ - Use: "whitelist", - Short: "Top level command for modifying the Polygon Edge whitelists within the config. Only accepts subcommands.", - } - - registerSubcommands(whitelistCmd) - - return whitelistCmd -} - -func registerSubcommands(baseCmd *cobra.Command) { - baseCmd.AddCommand( - deployment.GetCommand(), - show.GetCommand(), - ) -} diff --git a/consensus/consensus.go b/consensus/consensus.go index c5b49de855..9532d801f4 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -29,7 +29,7 @@ type Consensus interface { GetBlockCreator(header *types.Header) (types.Address, error) // PreCommitState a hook to be called before finalizing state transition on inserting block - PreCommitState(header *types.Header, txn *state.Transition) error + PreCommitState(block *types.Block, txn *state.Transition) error // GetSyncProgression retrieves the current sync progression, if any GetSyncProgression() *progress.Progression @@ -37,6 +37,9 @@ type Consensus interface { // GetBridgeProvider returns an instance of BridgeDataProvider GetBridgeProvider() BridgeDataProvider + // FilterExtra filters extra data in header that is not a part of block hash + FilterExtra(extra []byte) ([]byte, error) + // Initialize initializes the consensus (e.g. setup data) Initialize() error diff --git a/consensus/dev/dev.go b/consensus/dev/dev.go index 79a2053f62..8e09dde42c 100644 --- a/consensus/dev/dev.go +++ b/consensus/dev/dev.go @@ -1,7 +1,10 @@ package dev import ( + "encoding/json" "fmt" + "io/ioutil" + "path/filepath" "time" "github.com/0xPolygon/polygon-edge/blockchain" @@ -29,6 +32,8 @@ type Dev struct { blockchain *blockchain.Blockchain executor *state.Executor + + dataDir string } // Factory implements the base factory method @@ -44,6 +49,7 @@ func Factory( blockchain: params.Blockchain, executor: params.Executor, txpool: params.TxPool, + dataDir: params.Config.Path, } rawInterval, ok := params.Config.Config["interval"] @@ -109,10 +115,10 @@ type transitionInterface interface { Write(txn *types.Transaction) error } -func (d *Dev) writeTransactions(gasLimit uint64, transition transitionInterface) []*types.Transaction { +func (d *Dev) writeTransactions(baseFee, gasLimit uint64, transition transitionInterface) []*types.Transaction { var successful []*types.Transaction - d.txpool.Prepare() + d.txpool.Prepare(baseFee) for { tx := d.txpool.Peek() @@ -120,7 +126,7 @@ func (d *Dev) writeTransactions(gasLimit uint64, transition transitionInterface) break } - if tx.ExceedsBlockGasLimit(gasLimit) { + if tx.Gas > gasLimit { d.txpool.Drop(tx) continue @@ -167,7 +173,10 @@ func (d *Dev) writeNewBlock(parent *types.Header) error { return err } + baseFee := d.blockchain.CalculateBaseFee(parent) + header.GasLimit = gasLimit + header.BaseFee = baseFee miner, err := d.GetBlockCreator(header) if err != nil { @@ -180,10 +189,28 @@ func (d *Dev) writeNewBlock(parent *types.Header) error { return err } - txns := d.writeTransactions(gasLimit, transition) + txns := d.writeTransactions(baseFee, gasLimit, transition) // Commit the changes - _, root := transition.Commit() + _, trace, root, err := transition.Commit() + if err != nil { + return fmt.Errorf("failed to commit the state changes: %w", err) + } + + trace.ParentStateRoot = parent.StateRoot + + // write the trace + { + raw, err := json.Marshal(trace) + if err != nil { + return err + } + + if err := ioutil.WriteFile( + filepath.Join(d.dataDir, fmt.Sprintf("trace_%d", header.Number))+".json", raw, 0600); err != nil { + return err + } + } // Update the header header.StateRoot = root @@ -229,7 +256,7 @@ func (d *Dev) GetBlockCreator(header *types.Header) (types.Address, error) { } // PreCommitState a hook to be called before finalizing state transition on inserting block -func (d *Dev) PreCommitState(_header *types.Header, _txn *state.Transition) error { +func (d *Dev) PreCommitState(_ *types.Block, _ *state.Transition) error { return nil } @@ -246,3 +273,7 @@ func (d *Dev) Close() error { func (d *Dev) GetBridgeProvider() consensus.BridgeDataProvider { return nil } + +func (d *Dev) FilterExtra(extra []byte) ([]byte, error) { + return extra, nil +} diff --git a/consensus/dummy/dummy.go b/consensus/dummy/dummy.go index fafc2dc6d6..4f552f535b 100644 --- a/consensus/dummy/dummy.go +++ b/consensus/dummy/dummy.go @@ -61,7 +61,7 @@ func (d *Dummy) GetBlockCreator(header *types.Header) (types.Address, error) { } // PreCommitState a hook to be called before finalizing state transition on inserting block -func (d *Dummy) PreCommitState(_header *types.Header, _txn *state.Transition) error { +func (d *Dummy) PreCommitState(_ *types.Block, _ *state.Transition) error { return nil } @@ -79,6 +79,10 @@ func (d *Dummy) GetBridgeProvider() consensus.BridgeDataProvider { return nil } +func (d *Dummy) FilterExtra(extra []byte) ([]byte, error) { + return extra, nil +} + func (d *Dummy) run() { d.logger.Info("started") // do nothing diff --git a/consensus/ibft/consensus_backend.go b/consensus/ibft/consensus_backend.go index 2e875d35ef..b30aeaca2c 100644 --- a/consensus/ibft/consensus_backend.go +++ b/consensus/ibft/consensus_backend.go @@ -2,7 +2,11 @@ package ibft import ( "context" + "encoding/json" "fmt" + "io/ioutil" + "math/big" + "path/filepath" "time" "github.com/0xPolygon/go-ibft/messages" @@ -139,39 +143,21 @@ func (i *backendIBFT) MaximumFaultyNodes() uint64 { return uint64(CalcMaxFaultyNodes(i.currentValidators)) } -func (i *backendIBFT) HasQuorum( - blockNumber uint64, - messages []*proto.Message, - msgType proto.MessageType, -) bool { - validators, err := i.forkManager.GetValidators(blockNumber) +// DISCLAIMER: IBFT will be deprecated so we set 1 as a voting power to all validators +func (i *backendIBFT) GetVotingPowers(height uint64) (map[string]*big.Int, error) { + validators, err := i.forkManager.GetValidators(height) if err != nil { - i.logger.Error( - "failed to get validators when calculation quorum", - "height", blockNumber, - "err", err, - ) - - return false + return nil, err } - quorum := i.quorumSize(blockNumber)(validators) + result := make(map[string]*big.Int, validators.Len()) - switch msgType { - case proto.MessageType_PREPREPARE: - return len(messages) > 0 - case proto.MessageType_PREPARE: - // two cases -> first message is MessageType_PREPREPARE, and other -> MessageType_PREPREPARE is not included - if len(messages) > 0 && messages[0].Type == proto.MessageType_PREPREPARE { - return len(messages) >= quorum - } - - return len(messages) >= quorum-1 - case proto.MessageType_COMMIT, proto.MessageType_ROUND_CHANGE: - return len(messages) >= quorum - default: - return false + for index := 0; index < validators.Len(); index++ { + strAddress := types.AddressToString(validators.At(uint64(index)).Addr()) + result[strAddress] = big.NewInt(1) // set 1 as voting power to everyone } + + return result, nil } // buildBlock builds the block, based on the passed in snapshot and parent header @@ -195,6 +181,9 @@ func (i *backendIBFT) buildBlock(parent *types.Header) (*types.Block, error) { return nil, err } + // calculate base fee + baseFee := i.blockchain.CalculateBaseFee(parent) + header.GasLimit = gasLimit if err := i.currentHooks.ModifyHeader(header, i.currentSigner.Address()); err != nil { @@ -223,16 +212,38 @@ func (i *backendIBFT) buildBlock(parent *types.Header) (*types.Block, error) { txs := i.writeTransactions( writeCtx, + baseFee, gasLimit, header.Number, transition, ) - if err := i.PreCommitState(header, transition); err != nil { + // provide dummy block instance to the PreCommitState + // (for the IBFT consensus, it is correct to have just a header, as only it is used) + if err := i.PreCommitState(&types.Block{Header: header}, transition); err != nil { return nil, err } - _, root := transition.Commit() + _, trace, root, err := transition.Commit() + if err != nil { + return nil, fmt.Errorf("failed to commit the state changes: %w", err) + } + + trace.ParentStateRoot = parent.StateRoot + + // write the trace + { + raw, err := json.Marshal(trace) + if err != nil { + return nil, err + } + + if err := ioutil.WriteFile( + filepath.Join(i.config.Path, fmt.Sprintf("trace_%d", header.Number))+".json", raw, 0600); err != nil { + return nil, err + } + } + header.StateRoot = root header.GasUsed = transition.TotalGas() @@ -300,11 +311,11 @@ type txExeResult struct { type transitionInterface interface { Write(txn *types.Transaction) error - WriteFailedReceipt(txn *types.Transaction) error } func (i *backendIBFT) writeTransactions( writeCtx context.Context, + baseFee, gasLimit, blockNumber uint64, transition transitionInterface, @@ -331,7 +342,7 @@ func (i *backendIBFT) writeTransactions( ) }() - i.txpool.Prepare() + i.txpool.Prepare(baseFee) write: for { @@ -379,18 +390,9 @@ func (i *backendIBFT) writeTransaction( return nil, false } - if tx.ExceedsBlockGasLimit(gasLimit) { + if tx.Gas > gasLimit { i.txpool.Drop(tx) - if err := transition.WriteFailedReceipt(tx); err != nil { - i.logger.Error( - fmt.Sprintf( - "unable to write failed receipt for transaction %s", - tx.Hash, - ), - ) - } - // continue processing return &txExeResult{tx, fail}, true } diff --git a/consensus/ibft/fork/fork.go b/consensus/ibft/fork/fork.go index cf6a4c4090..9d5695a680 100644 --- a/consensus/ibft/fork/fork.go +++ b/consensus/ibft/fork/fork.go @@ -13,10 +13,12 @@ const ( KeyType = "type" KeyTypes = "types" KeyValidatorType = "validator_type" + KeyBlockTime = "blockTime" ) var ( ErrUndefinedIBFTConfig = errors.New("IBFT config is not defined") + errInvalidBlockTime = errors.New("invalid block time provided") ) // IBFT Fork represents setting in params.engine.ibft of genesis.json @@ -26,6 +28,7 @@ type IBFTFork struct { Deployment *common.JSONNumber `json:"deployment,omitempty"` From common.JSONNumber `json:"from"` To *common.JSONNumber `json:"to,omitempty"` + BlockTime *common.Duration `json:"blockTime,omitempty"` // PoA Validators validators.Validators `json:"validators,omitempty"` @@ -42,6 +45,7 @@ func (f *IBFTFork) UnmarshalJSON(data []byte) error { Deployment *common.JSONNumber `json:"deployment,omitempty"` From common.JSONNumber `json:"from"` To *common.JSONNumber `json:"to,omitempty"` + BlockTime *common.Duration `json:"blockTime,omitempty"` Validators interface{} `json:"validators,omitempty"` MaxValidatorCount *common.JSONNumber `json:"maxValidatorCount,omitempty"` MinValidatorCount *common.JSONNumber `json:"minValidatorCount,omitempty"` @@ -55,6 +59,7 @@ func (f *IBFTFork) UnmarshalJSON(data []byte) error { f.Deployment = raw.Deployment f.From = raw.From f.To = raw.To + f.BlockTime = raw.BlockTime f.MaxValidatorCount = raw.MaxValidatorCount f.MinValidatorCount = raw.MinValidatorCount @@ -74,11 +79,7 @@ func (f *IBFTFork) UnmarshalJSON(data []byte) error { return err } - if err := json.Unmarshal(validatorsBytes, f.Validators); err != nil { - return err - } - - return nil + return json.Unmarshal(validatorsBytes, f.Validators) } // GetIBFTForks returns IBFT fork configurations from chain config @@ -98,6 +99,20 @@ func GetIBFTForks(ibftConfig map[string]interface{}) (IBFTForks, error) { } } + var blockTime *common.Duration = nil + + blockTimeGeneric, ok := ibftConfig[KeyBlockTime] + if ok { + blockTimeRaw, err := json.Marshal(blockTimeGeneric) + if err != nil { + return nil, errInvalidBlockTime + } + + if err := json.Unmarshal(blockTimeRaw, &blockTime); err != nil { + return nil, errInvalidBlockTime + } + } + return IBFTForks{ { Type: typ, @@ -105,6 +120,7 @@ func GetIBFTForks(ibftConfig map[string]interface{}) (IBFTForks, error) { ValidatorType: validatorType, From: common.JSONNumber{Value: 0}, To: nil, + BlockTime: blockTime, }, }, nil } diff --git a/consensus/ibft/fork/fork_test.go b/consensus/ibft/fork/fork_test.go index 3c8cf358cb..f77e6c5f91 100644 --- a/consensus/ibft/fork/fork_test.go +++ b/consensus/ibft/fork/fork_test.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "testing" + "time" "github.com/0xPolygon/polygon-edge/helper/common" testHelper "github.com/0xPolygon/polygon-edge/helper/tests" @@ -62,6 +63,7 @@ func TestIBFTForkUnmarshalJSON(t *testing.T) { data: fmt.Sprintf(`{ "type": "%s", "validator_type": "%s", + "blockTime": %d, "validators": [ { "Address": "%s" @@ -72,8 +74,9 @@ func TestIBFTForkUnmarshalJSON(t *testing.T) { ], "from": %d, "to": %d - }`, + }`, PoA, validators.ECDSAValidatorType, + 3000000000, types.StringToAddress("1"), types.StringToAddress("2"), 16, 20, ), @@ -86,6 +89,7 @@ func TestIBFTForkUnmarshalJSON(t *testing.T) { validators.NewECDSAValidator(types.StringToAddress("1")), validators.NewECDSAValidator(types.StringToAddress("2")), ), + BlockTime: &common.Duration{Duration: 3 * time.Second}, MaxValidatorCount: nil, MinValidatorCount: nil, }, diff --git a/consensus/ibft/fork/hooks_test.go b/consensus/ibft/fork/hooks_test.go index e650b3ee8a..db5869a557 100644 --- a/consensus/ibft/fork/hooks_test.go +++ b/consensus/ibft/fork/hooks_test.go @@ -279,6 +279,9 @@ func newTestTransition( ex := state.NewExecutor(&chain.Params{ Forks: chain.AllForksEnabled, + BurnContract: map[uint64]types.Address{ + 0: types.ZeroAddress, + }, }, st, hclog.NewNullLogger()) rootHash, err := ex.WriteGenesis(nil, types.Hash{}) diff --git a/consensus/ibft/ibft.go b/consensus/ibft/ibft.go index 4be216f3d1..5e388e4d4f 100644 --- a/consensus/ibft/ibft.go +++ b/consensus/ibft/ibft.go @@ -34,16 +34,15 @@ const ( ) var ( - ErrInvalidHookParam = errors.New("invalid IBFT hook param passed in") - ErrProposerSealByNonValidator = errors.New("proposer seal by non-validator") - ErrInvalidMixHash = errors.New("invalid mixhash") - ErrInvalidSha3Uncles = errors.New("invalid sha3 uncles") - ErrWrongDifficulty = errors.New("wrong difficulty") - ErrParentCommittedSealsNotFound = errors.New("parent committed seals not found") + ErrInvalidHookParam = errors.New("invalid IBFT hook param passed in") + ErrProposerSealByNonValidator = errors.New("proposer seal by non-validator") + ErrInvalidMixHash = errors.New("invalid mixhash") + ErrInvalidSha3Uncles = errors.New("invalid sha3 uncles") + ErrWrongDifficulty = errors.New("wrong difficulty") ) type txPoolInterface interface { - Prepare() + Prepare(uint64) Length() uint64 Peek() *types.Transaction Pop(tx *types.Transaction) @@ -491,10 +490,10 @@ func (i *backendIBFT) GetBlockCreator(header *types.Header) (types.Address, erro } // PreCommitState a hook to be called before finalizing state transition on inserting block -func (i *backendIBFT) PreCommitState(header *types.Header, txn *state.Transition) error { - hooks := i.forkManager.GetHooks(header.Number) +func (i *backendIBFT) PreCommitState(block *types.Block, txn *state.Transition) error { + hooks := i.forkManager.GetHooks(block.Number()) - return hooks.PreCommitState(header, txn) + return hooks.PreCommitState(block.Header, txn) } // GetEpoch returns the current epoch @@ -552,6 +551,11 @@ func (i *backendIBFT) GetBridgeProvider() consensus.BridgeDataProvider { return nil } +// FilterExtra is the implementation of Consensus interface +func (i *backendIBFT) FilterExtra(extra []byte) ([]byte, error) { + return extra, nil +} + // updateCurrentModules updates Signer, Hooks, and Validators // that are used at specified height // by fetching from ForkManager diff --git a/consensus/polybft/README.md b/consensus/polybft/README.md index 303db1927c..5336609bfa 100644 --- a/consensus/polybft/README.md +++ b/consensus/polybft/README.md @@ -3,90 +3,134 @@ Polybft is a consensus protocol, which runs [go-ibft](https://github.com/0xPolygon/go-ibft) consensus engine. -It has native support for running bridge, which enables running cross-chain transactions with Ethereum-compatible blockchains. +It has a native support for running bridge, which enables running cross-chain transactions with Ethereum-compatible blockchains. ## Setup local testing environment -### Precondition - 1. Build binary ```bash - go build -o polygon-edge . + $ go build -o polygon-edge . ``` 2. Init secrets - this command is used to generate account secrets (ECDSA, BLS as well as P2P networking node id). `--data-dir` denotes folder prefix names and `--num` how many accounts need to be created. **This command is for testing purposes only.** ```bash - polygon-edge polybft-secrets --data-dir test-chain- --num 4 + $ polygon-edge polybft-secrets --data-dir test-chain- --num 4 ``` -3. Start rootchain server - rootchain server is a Geth instance running in dev mode, which simulates Ethereum network. **This command is for testing purposes only.** +3. Create chain configuration - this command creates chain configuration, which is needed to run a blockchain. + It contains initial validator set as well and there are two ways to specify it: + + - all the validators information are present in local storage of single host and therefore directory if provided using `--validators-path` flag and validators folder prefix names using `--validators-prefix` flag + - for reward distribution to work, user must define a reward wallet address with its balance. Wallet address is used to distribute reward tokens from that address to validators that signed blocks in that epoch. ```bash - polygon-edge rootchain server + $ polygon-edge genesis --block-gas-limit 10000000 --epoch-size 10 \ + [--validators-path ./] [--validators-prefix test-chain-] \ + [--consensus polybft] \ + [--reward-wallet adress:amount] ``` -4. Generate manifest file - manifest file contains public validator information as well as bridge configuration. It is intermediary file, which is later used for genesis specification generation as well as rootchain contracts deployment. - - There are two ways to provide validators information: - - - all the validators information are present in local storage of single host and therefore directory if provided using `--validators-path` flag and validators folder prefix names using `--validators-prefix` flag - - ```bash - polygon-edge manifest [--validators-path ./] [--validators-prefix test-chain-] - [--path ./manifest.json] [--premine-validators 100] - ``` - - - validators information are scafollded on multiple hosts and therefore necessary information are supplied using `--validators` flag. Validator information needs to be supplied in the strictly following format: - `:::`. + - validators information are scafollded on multiple hosts and therefore necessary information are supplied using `--validators` flag. Validator information needs to be supplied in the strictly following format: + `:::`. **Note:** when specifying validators via validators flag, entire multi address must be specified. - ```bash - polygon-edge manifest + ```bash + $ polygon-edge genesis --block-gas-limit 10000000 --epoch-size 10 \ --validators /ip4/127.0.0.1/tcp/30301/p2p/16Uiu2HAmV5hqAp77untfJRorxqKmyUxgaVn8YHFjBJm9gKMms3mr:0xDcBe0024206ec42b0Ef4214Ac7B71aeae1A11af0:1cf134e02c6b2afb2ceda50bf2c9a01da367ac48f7783ee6c55444e1cab418ec0f52837b90a4d8cf944814073fc6f2bd96f35366a3846a8393e3cb0b19197cde23e2b40c6401fa27ff7d0c36779d9d097d1393cab6fc1d332f92fb3df850b78703b2989d567d1344e219f0667a1863f52f7663092276770cf513f9704b5351c4:11b18bde524f4b02258a8d196b687f8d8e9490d536718666dc7babca14eccb631c238fb79aa2b44a5a4dceccad2dd797f537008dda185d952226a814c1acf7c2 [--validators /ip4/127.0.0.1/tcp/30302/p2p/16Uiu2HAmGmidRQY5BGJPGVRF8p1pYFdfzuf1StHzXGLDizuxJxex:0x2da750eD4AE1D5A7F7c996Faec592F3d44060e90:088d92c25b5f278750534e8a902da604a1aa39b524b4511f5f47c3a386374ca3031b667beb424faef068a01cee3428a1bc8c1c8bab826f30a1ee03fbe90cb5f01abcf4abd7af3bbe83eaed6f82179b9cbdc417aad65d919b802d91c2e1aaefec27ba747158bc18a0556e39bfc9175c099dd77517a85731894bbea3d191a622bc:08dc3006352fdc01b331907fd3a68d4d68ed40329032598c1c0faa260421d66720965ace3ba29c6d6608ec1facdbf4624bca72df36c34afd4bdd753c4dfe049c] - [--path ./manifest.json] [--premine-validators 100] - ``` + ``` -5. Deploy and initialize rootchain contracts - this command deploys rootchain smart contracts and initializes them. It also updates manifest configuration with rootchain contract addresses and rootchain default sender address. +4. Start rootchain server - rootchain server is a Geth instance running in dev mode, which simulates Ethereum network. **This command is for testing purposes only.** ```bash - polygon-edge rootchain init-contracts - --data-dir | [--config ] - [--manifest ./manifest.json] - [--json-rpc http://127.0.0.1:8545] + $ polygon-edge rootchain server + ``` + +5. Deploy StakeManager - if not already deployed to rootchain. Command has a test flag used only in testing purposes which would deploy a mock ERC20 token which would be used for staking. If not used for testing, stake-token flag should be provided: + + ```bash + $ polygon-edge polybft stake-manager-deploy \ + --deployer-key \ + [--genesis ./genesis.json] \ + [--json-rpc http://127.0.0.1:8545] \ + [--stake-token 0xaddressOfStakeToken] \ [--test] ``` -6. Create chain configuration - this command creates chain configuration, which is needed to run a blockchain +6. Deploy and initialize rootchain contracts - this command deploys rootchain smart contracts and initializes them. It also updates genesis configuration with rootchain contract addresses and rootchain default sender address. ```bash - polygon-edge genesis --block-gas-limit 10000000 --epoch-size 10 - [--consensus polybft] [--bridge-json-rpc ] [--manifest ./manifest.json] + $ polygon-edge rootchain deploy \ + --deployer-key \ + --stake-manager \ + --stake-token 0xaddressOfStakeToken \ + [--genesis ./genesis.json] \ + [--json-rpc http://127.0.0.1:8545] \ + [--test] ``` 7. Fund validators on rootchain - in order for validators to be able to send transactions to Ethereum, they need to be funded in order to be able to cover gas cost. **This command is for testing purposes only.** ```bash - polygon-edge rootchain fund --data-dir test-chain- --num 4 + $ polygon-edge rootchain fund \ + --addresses 0x1234567890123456789012345678901234567890 \ + --amounts 200000000000000000000 + ``` + +8. Whitelist validators on rootchain - in order for validators to be able to be registered on the SupernetManager contract on rootchain. Note that only deployer of SupernetManager contract (the one who run the deploy command) can whitelist validators on rootchain. He can use either its hex encoded private key, or data-dir flag if he has secerets initialized: + + ```bash + $ polygon-edge polybft whitelist-validators --private-key \ + --addresses --supernet-manager + ``` + +9. Register validators on rootchain - each validator registers itself on SupernetManager. **This command is for testing purposes only.** + + ```bash + $ polygon-edge polybft register-validator --data-dir ./test-chain-1 \ + --supernet-manager + ``` + +10. Initial staking on rootchain - each validator needs to do initial staking on rootchain (StakeManager) contract. **This command is for testing purposes only.** + + ```bash + $ polygon-edge polybft stake --data-dir ./test-chain-1 --supernet-id \ + --amount \ + --stake-manager --stake-token + ``` + +11. Finalize genesis validator set on rootchain (SupernetManager) contract. This is done after all validators from genesis do initial staking on rootchain, and it's a final step that is required before starting the child chain. This needs to be done by the deployer of SupernetManager contract (the user that run the deploy command). He can use either its hex encoded private key, or data-dir flag if he has secerets initialized. If enable-staking flag is provided, validators will be able to continue staking on rootchain. If not, genesis validators will not be able update its stake or unstake, nor will newly registered validators after genesis will be able to stake tokens on the rootchain. Enabling of staking can be done through this command, or later after the child chain starts. + + ```bash + $ polygon-edge polybft supernet --private-key \ + --genesis \ + --supernet-manager \ + --stake-manager \ + --finalize-genesis --enable-staking ``` -8. Run (child chain) cluster, consisting of 4 Edge clients in this particular example +12. Run (child chain) cluster, consisting of 4 Edge clients in this particular example ```bash - polygon-edge server --data-dir ./test-chain-1 --chain genesis.json --grpc-address :5001 --libp2p :30301 --jsonrpc :9545 --seal --log-level DEBUG + $ polygon-edge server --data-dir ./test-chain-1 --chain genesis.json --grpc-address :5001 --libp2p :30301 --jsonrpc :9545 \ + --seal --log-level DEBUG - polygon-edge server --data-dir ./test-chain-2 --chain genesis.json --grpc-address :5002 --libp2p :30302 --jsonrpc :10002 --seal --log-level DEBUG + $ polygon-edge server --data-dir ./test-chain-2 --chain genesis.json --grpc-address :5002 --libp2p :30302 --jsonrpc :10002 \ + --seal --log-level DEBUG - polygon-edge server --data-dir ./test-chain-3 --chain genesis.json --grpc-address :5003 --libp2p :30303 --jsonrpc :10003 --seal --log-level DEBUG + $ polygon-edge server --data-dir ./test-chain-3 --chain genesis.json --grpc-address :5003 --libp2p :30303 --jsonrpc :10003 \ + --seal --log-level DEBUG - polygon-edge server --data-dir ./test-chain-4 --chain genesis.json --grpc-address :5004 --libp2p :30304 --jsonrpc :10004 --seal --log-level DEBUG + $ polygon-edge server --data-dir ./test-chain-4 --chain genesis.json --grpc-address :5004 --libp2p :30304 --jsonrpc :10004 \ + --seal --log-level DEBUG ``` It is possible to run child chain nodes in "relayer" mode. It allows automatic execution of deposit events on behalf of users. In order to start node in relayer mode, it is necessary to supply `--relayer` flag: ```bash - polygon-edge server --data-dir ./test-chain-1 --chain genesis.json --grpc-address :5001 --libp2p :30301 --jsonrpc :9545 --seal --log-level DEBUG --relayer + $ polygon-edge server --data-dir ./test-chain-1 --chain genesis.json --grpc-address :5001 --libp2p :30301 --jsonrpc :9545 \ + --seal --log-level DEBUG --relayer ``` diff --git a/consensus/polybft/block_builder.go b/consensus/polybft/block_builder.go index c141c8c5e1..3ba2f9f251 100644 --- a/consensus/polybft/block_builder.go +++ b/consensus/polybft/block_builder.go @@ -1,6 +1,7 @@ package polybft import ( + "fmt" "time" "github.com/0xPolygon/polygon-edge/consensus" @@ -35,6 +36,9 @@ type BlockBuilderParams struct { // txPoolInterface implementation TxPool txPoolInterface + + // BaseFee is the base fee + BaseFee uint64 } func NewBlockBuilder(params *BlockBuilderParams) *BlockBuilder { @@ -82,6 +86,7 @@ func (b *BlockBuilder) Reset() error { ReceiptsRoot: types.EmptyRootHash, // this avoids needing state for now Sha3Uncles: types.EmptyUncleHash, GasLimit: b.params.GasLimit, + BaseFee: b.params.BaseFee, Timestamp: uint64(headerTime.Unix()), } @@ -108,8 +113,15 @@ func (b *BlockBuilder) Build(handler func(h *types.Header)) (*types.FullBlock, e handler(b.header) } - _, b.header.StateRoot = b.state.Commit() + _, trace, stateRoot, err := b.state.Commit() + if err != nil { + return nil, fmt.Errorf("failed to commit the state changes: %w", err) + } + + trace.ParentStateRoot = b.params.Parent.StateRoot + b.header.StateRoot = stateRoot b.header.GasUsed = b.state.TotalGas() + b.header.LogsBloom = types.CreateBloom(b.Receipts()) // build the block b.block = consensus.BuildBlock(consensus.BuildBlockParams{ @@ -123,15 +135,15 @@ func (b *BlockBuilder) Build(handler func(h *types.Header)) (*types.FullBlock, e return &types.FullBlock{ Block: b.block, Receipts: b.state.Receipts(), + Trace: trace, }, nil } // WriteTx applies given transaction to the state. If transaction apply fails, it reverts the saved snapshot. func (b *BlockBuilder) WriteTx(tx *types.Transaction) error { - if tx.ExceedsBlockGasLimit(b.params.GasLimit) { - if err := b.state.WriteFailedReceipt(tx); err != nil { - return err - } + if tx.Gas > b.params.GasLimit { + b.params.Logger.Info("Transaction gas limit exceedes block gas limit", "hash", tx.Hash, + "tx gas limit", tx.Gas, "block gas limt", b.params.GasLimit) return txpool.ErrBlockLimitExceeded } @@ -149,7 +161,7 @@ func (b *BlockBuilder) WriteTx(tx *types.Transaction) error { func (b *BlockBuilder) Fill() { blockTimer := time.NewTimer(b.params.BlockTime) - b.params.TxPool.Prepare() + b.params.TxPool.Prepare(b.params.BaseFee) write: for { select { @@ -184,8 +196,7 @@ func (b *BlockBuilder) writeTxPoolTransaction(tx *types.Transaction) (bool, erro return true, nil } - err := b.WriteTx(tx) - if err != nil { + if err := b.WriteTx(tx); err != nil { if _, ok := err.(*state.GasLimitReachedTransitionApplicationError); ok { //nolint:errorlint // stop processing return true, err diff --git a/consensus/polybft/block_builder_test.go b/consensus/polybft/block_builder_test.go new file mode 100644 index 0000000000..aa4857dbf2 --- /dev/null +++ b/consensus/polybft/block_builder_test.go @@ -0,0 +1,160 @@ +package polybft + +import ( + "math/big" + "testing" + "time" + + "github.com/0xPolygon/polygon-edge/chain" + "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" + "github.com/0xPolygon/polygon-edge/crypto" + "github.com/0xPolygon/polygon-edge/helper/common" + "github.com/0xPolygon/polygon-edge/state" + itrie "github.com/0xPolygon/polygon-edge/state/immutable-trie" + "github.com/0xPolygon/polygon-edge/types" + "github.com/hashicorp/go-hclog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/umbracle/ethgo" +) + +func TestBlockBuilder_BuildBlockTxOneFailedTxAndOneTakesTooMuchGas(t *testing.T) { + t.Parallel() + + const ( + amount = 1_000 + gasPrice = 1_000 + gasLimit = 21000 + blockGasLimit = 21000 * 3 + chainID = 100 + ) + + accounts := [6]*wallet.Account{} + + for i := range accounts { + accounts[i] = generateTestAccount(t) + } + + forks := &chain.Forks{} + logger := hclog.NewNullLogger() + signer := crypto.NewSigner(forks.At(0), chainID) + + mchain := &chain.Chain{ + Params: &chain.Params{ + ChainID: chainID, + Forks: forks, + }, + } + + mstate := itrie.NewState(itrie.NewMemoryStorage()) + executor := state.NewExecutor(mchain.Params, mstate, logger) + + executor.GetHash = func(header *types.Header) func(i uint64) types.Hash { + return func(i uint64) (res types.Hash) { + return types.BytesToHash(common.EncodeUint64ToBytes(i)) + } + } + + balanceMap := map[types.Address]*chain.GenesisAccount{} + + for i, acc := range accounts { + // the third tx will fail because of insufficient balance + if i != 2 { + balanceMap[types.Address(acc.Ecdsa.Address())] = &chain.GenesisAccount{ + Balance: ethgo.Ether(1), + } + } + } + + hash, err := executor.WriteGenesis(balanceMap, types.ZeroHash) + + require.NoError(t, err) + require.NotEqual(t, types.ZeroHash, hash) + + // Gas Limit is important to be high for tx pool + parentHeader := &types.Header{StateRoot: hash, GasLimit: 1_000_000_000_000_000} + + txPool := &txPoolMock{} + txPool.On("Prepare", uint64(0)).Once() + + for i, acc := range accounts { + receiver := types.Address(acc.Ecdsa.Address()) + privateKey, err := acc.GetEcdsaPrivateKey() + + require.NoError(t, err) + + tx := &types.Transaction{ + Value: big.NewInt(amount), + GasPrice: big.NewInt(gasPrice), + Gas: gasLimit, + Nonce: 0, + To: &receiver, + } + + // fifth tx will cause filling to stop + if i == 4 { + tx.Gas = blockGasLimit - 1 + } + + tx, err = signer.SignTx(tx, privateKey) + require.NoError(t, err) + + // all tx until the fifth will be retrieved from the pool + if i <= 4 { + txPool.On("Peek").Return(tx).Once() + } + + // first two and fourth will be added to the block, third will be demoted + if i == 2 { + txPool.On("Demote", tx) + } else if i < 4 { + txPool.On("Pop", tx) + } + } + + bb := NewBlockBuilder(&BlockBuilderParams{ + BlockTime: time.Millisecond * 100, + Parent: parentHeader, + Coinbase: types.ZeroAddress, + Executor: executor, + GasLimit: blockGasLimit, + TxPool: txPool, + Logger: logger, + }) + + require.NoError(t, bb.Reset()) + + bb.Fill() + + fb, err := bb.Build(func(h *types.Header) { + // fake the logs for bloom + rs := bb.Receipts() + + if len(rs) == 3 { + rs[0].Logs = []*types.Log{ + {Address: types.StringToAddress("ff7783")}, + } + rs[1].Logs = []*types.Log{ + {Address: types.StringToAddress("03bbcc")}, + {Address: types.StringToAddress("112233")}, + } + } + }) + require.NoError(t, err) + + txPool.AssertExpectations(t) + require.Len(t, bb.txns, 3, "Should have 3 transactions but has %d", len(bb.txns)) + require.Len(t, bb.Receipts(), 3) + + // assert logs bloom + for _, r := range bb.Receipts() { + for _, l := range r.Logs { + assert.True(t, fb.Block.Header.LogsBloom.IsLogInBloom(l)) + } + } + + assert.False(t, fb.Block.Header.LogsBloom.IsLogInBloom( + &types.Log{Address: types.StringToAddress("999911117777")})) + assert.False(t, fb.Block.Header.LogsBloom.IsLogInBloom( + &types.Log{Address: types.StringToAddress("111177779999")})) +} diff --git a/consensus/polybft/blockchain_wrapper.go b/consensus/polybft/blockchain_wrapper.go index 3a8b642108..b7afd686b7 100644 --- a/consensus/polybft/blockchain_wrapper.go +++ b/consensus/polybft/blockchain_wrapper.go @@ -38,8 +38,7 @@ type blockchainBackend interface { txPool txPoolInterface, blockTime time.Duration, logger hclog.Logger) (blockBuilder, error) // ProcessBlock builds a final block from given 'block' on top of 'parent'. - ProcessBlock(parent *types.Header, block *types.Block, - callback func(*state.Transition) error) (*types.FullBlock, error) + ProcessBlock(parent *types.Header, block *types.Block) (*types.FullBlock, error) // GetStateProviderForBlock returns a reference to make queries to the state at 'block'. GetStateProviderForBlock(block *types.Header) (contract.Provider, error) @@ -60,6 +59,9 @@ type blockchainBackend interface { // GetChainID returns chain id of the current blockchain GetChainID() uint64 + + // GetReceiptsByHash retrieves receipts by hash + GetReceiptsByHash(hash types.Hash) ([]*types.Receipt, error) } var _ blockchainBackend = &blockchainWrapper{} @@ -76,17 +78,13 @@ func (p *blockchainWrapper) CurrentHeader() *types.Header { // CommitBlock commits a block to the chain func (p *blockchainWrapper) CommitBlock(block *types.FullBlock) error { - if err := p.blockchain.WriteFullBlock(block, consensusSource); err != nil { - return err - } - - return nil + return p.blockchain.WriteFullBlock(block, consensusSource) } // ProcessBlock builds a final block from given 'block' on top of 'parent' -func (p *blockchainWrapper) ProcessBlock(parent *types.Header, block *types.Block, - callback func(*state.Transition) error) (*types.FullBlock, error) { +func (p *blockchainWrapper) ProcessBlock(parent *types.Header, block *types.Block) (*types.FullBlock, error) { header := block.Header.Copy() + start := time.Now().UTC() transition, err := p.executor.BeginTxn(parent.StateRoot, header, types.BytesToAddress(header.Miner)) if err != nil { @@ -95,18 +93,19 @@ func (p *blockchainWrapper) ProcessBlock(parent *types.Header, block *types.Bloc // apply transactions from block for _, tx := range block.Transactions { - if err := transition.Write(tx); err != nil { + if err = transition.Write(tx); err != nil { return nil, fmt.Errorf("process block tx error, tx = %v, err = %w", tx.Hash, err) } } - if callback != nil { - if err := callback(transition); err != nil { - return nil, err - } + _, trace, root, err := transition.Commit() + if err != nil { + return nil, fmt.Errorf("failed to commit the state changes: %w", err) } - _, root := transition.Commit() + trace.ParentStateRoot = parent.StateRoot + + updateBlockExecutionMetric(start) if root != block.Header.StateRoot { return nil, fmt.Errorf("incorrect state root: (%s, %s)", root, block.Header.StateRoot) @@ -122,6 +121,7 @@ func (p *blockchainWrapper) ProcessBlock(parent *types.Header, block *types.Bloc return &types.FullBlock{ Block: builtBlock, Receipts: transition.Receipts(), + Trace: trace, }, nil } @@ -165,6 +165,7 @@ func (p *blockchainWrapper) NewBlockBuilder( Coinbase: coinbase, Executor: p.executor, GasLimit: gasLimit, + BaseFee: p.blockchain.CalculateBaseFee(parent), TxPool: txPool, Logger: logger, }), nil @@ -183,6 +184,10 @@ func (p *blockchainWrapper) GetChainID() uint64 { return uint64(p.blockchain.Config().ChainID) } +func (p *blockchainWrapper) GetReceiptsByHash(hash types.Hash) ([]*types.Receipt, error) { + return p.blockchain.GetReceiptsByHash(hash) +} + var _ contract.Provider = &stateProvider{} type stateProvider struct { diff --git a/consensus/polybft/checkpoint_manager.go b/consensus/polybft/checkpoint_manager.go index 4b058b83f7..3544e6d4ee 100644 --- a/consensus/polybft/checkpoint_manager.go +++ b/consensus/polybft/checkpoint_manager.go @@ -9,6 +9,7 @@ import ( "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/contracts" "github.com/0xPolygon/polygon-edge/helper/hex" "github.com/0xPolygon/polygon-edge/merkle-tree" @@ -196,7 +197,7 @@ func (c *checkpointManager) encodeAndSendCheckpoint(txn *ethgo.Transaction, header *types.Header, extra *Extra, isEndOfEpoch bool) error { c.logger.Debug("send checkpoint txn...", "block number", header.Number) - nextEpochValidators := AccountSet{} + nextEpochValidators := validator.AccountSet{} if isEndOfEpoch { var err error @@ -232,7 +233,7 @@ func (c *checkpointManager) encodeAndSendCheckpoint(txn *ethgo.Transaction, // abiEncodeCheckpointBlock encodes checkpoint data into ABI format for a given header func (c *checkpointManager) abiEncodeCheckpointBlock(blockNumber uint64, blockHash types.Hash, extra *Extra, - nextValidators AccountSet) ([]byte, error) { + nextValidators validator.AccountSet) ([]byte, error) { aggs, err := bls.UnmarshalSignature(extra.Committed.AggregatedSignature) if err != nil { return nil, err diff --git a/consensus/polybft/checkpoint_manager_test.go b/consensus/polybft/checkpoint_manager_test.go index 34595a8d71..7648eba1b0 100644 --- a/consensus/polybft/checkpoint_manager_test.go +++ b/consensus/polybft/checkpoint_manager_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/umbracle/ethgo/abi" + "github.com/umbracle/ethgo/jsonrpc" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" "github.com/0xPolygon/polygon-edge/contracts" @@ -18,9 +19,9 @@ import ( "github.com/stretchr/testify/require" "github.com/umbracle/ethgo" - "github.com/0xPolygon/polygon-edge/consensus/ibft/signer" "github.com/0xPolygon/polygon-edge/consensus/polybft/bitmap" bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" "github.com/0xPolygon/polygon-edge/txrelayer" "github.com/0xPolygon/polygon-edge/types" @@ -36,8 +37,8 @@ func TestCheckpointManager_SubmitCheckpoint(t *testing.T) { var aliases = []string{"A", "B", "C", "D", "E"} - validators := newTestValidatorsWithAliases(t, aliases) - validatorsMetadata := validators.getPublicIdentities() + validators := validator.NewTestValidatorsWithAliases(t, aliases) + validatorsMetadata := validators.GetPublicIdentities() txRelayerMock := newDummyTxRelayer(t) txRelayerMock.On("Call", mock.Anything, mock.Anything, mock.Anything). Return("2", error(nil)). @@ -59,9 +60,9 @@ func TestCheckpointManager_SubmitCheckpoint(t *testing.T) { signatures bls.Signatures ) - validators.iterAcct(aliases, func(t *testValidator) { + validators.IterAcct(aliases, func(t *validator.TestValidator) { bitmap.Set(idx) - signatures = append(signatures, t.mustSign(dummyMsg, bls.DomainCheckpointManager)) + signatures = append(signatures, t.MustSign(dummyMsg, bls.DomainCheckpointManager)) idx++ }) @@ -80,7 +81,7 @@ func TestCheckpointManager_SubmitCheckpoint(t *testing.T) { extra.Checkpoint = checkpoint extra.Committed = &Signature{Bitmap: bitmap, AggregatedSignature: signature} header = &types.Header{ - ExtraData: append(make([]byte, ExtraVanity), extra.MarshalRLPTo(nil)...), + ExtraData: extra.MarshalRLPTo(nil), } epochNumber++ } else { @@ -96,7 +97,7 @@ func TestCheckpointManager_SubmitCheckpoint(t *testing.T) { blockchainMock := new(blockchainMock) blockchainMock.On("GetHeaderByNumber", mock.Anything).Return(headersMap.getHeader) - validatorAcc := validators.getValidator("A") + validatorAcc := validators.GetValidator("A") c := &checkpointManager{ key: wallet.NewEcdsaSigner(validatorAcc.Key()), rootChainRelayer: txRelayerMock, @@ -122,8 +123,8 @@ func TestCheckpointManager_abiEncodeCheckpointBlock(t *testing.T) { const epochSize = uint64(10) - currentValidators := newTestValidatorsWithAliases(t, []string{"A", "B", "C", "D"}) - nextValidators := newTestValidatorsWithAliases(t, []string{"E", "F", "G", "H"}) + currentValidators := validator.NewTestValidatorsWithAliases(t, []string{"A", "B", "C", "D"}) + nextValidators := validator.NewTestValidatorsWithAliases(t, []string{"E", "F", "G", "H"}) header := &types.Header{Number: 50} checkpoint := &CheckpointData{ BlockRound: 1, @@ -138,8 +139,8 @@ func TestCheckpointManager_abiEncodeCheckpointBlock(t *testing.T) { var signatures bls.Signatures - currentValidators.iterAcct(nil, func(v *testValidator) { - signatures = append(signatures, v.mustSign(proposalHash, bls.DomainCheckpointManager)) + currentValidators.IterAcct(nil, func(v *validator.TestValidator) { + signatures = append(signatures, v.MustSign(proposalHash, bls.DomainCheckpointManager)) bmp.Set(i) i++ }) @@ -152,18 +153,18 @@ func TestCheckpointManager_abiEncodeCheckpointBlock(t *testing.T) { AggregatedSignature: aggSignature, Bitmap: bmp, } - header.ExtraData = append(make([]byte, signer.IstanbulExtraVanity), extra.MarshalRLPTo(nil)...) + header.ExtraData = extra.MarshalRLPTo(nil) header.ComputeHash() backendMock := new(polybftBackendMock) - backendMock.On("GetValidators", mock.Anything, mock.Anything).Return(currentValidators.getPublicIdentities()) + backendMock.On("GetValidators", mock.Anything, mock.Anything).Return(currentValidators.GetPublicIdentities()) c := &checkpointManager{ blockchain: &blockchainMock{}, consensusBackend: backendMock, logger: hclog.NewNullLogger(), } - checkpointDataEncoded, err := c.abiEncodeCheckpointBlock(header.Number, header.Hash, extra, nextValidators.getPublicIdentities()) + checkpointDataEncoded, err := c.abiEncodeCheckpointBlock(header.Number, header.Hash, extra, nextValidators.GetPublicIdentities()) require.NoError(t, err) submit := &contractsapi.SubmitCheckpointManagerFn{} @@ -486,7 +487,7 @@ func newDummyTxRelayer(t *testing.T) *dummyTxRelayer { return &dummyTxRelayer{test: t} } -func (d dummyTxRelayer) Call(from ethgo.Address, to ethgo.Address, input []byte) (string, error) { +func (d *dummyTxRelayer) Call(from ethgo.Address, to ethgo.Address, input []byte) (string, error) { args := d.Called(from, to, input) return args.String(0), args.Error(1) @@ -507,6 +508,10 @@ func (d *dummyTxRelayer) SendTransactionLocal(txn *ethgo.Transaction) (*ethgo.Re return args.Get(0).(*ethgo.Receipt), args.Error(1) //nolint:forcetypeassert } +func (d *dummyTxRelayer) Client() *jsonrpc.Client { + return nil +} + func getBlockNumberCheckpointSubmitInput(t *testing.T, input []byte) uint64 { t.Helper() diff --git a/consensus/polybft/consensus_metrics.go b/consensus/polybft/consensus_metrics.go index 29a916abca..6173af5d5e 100644 --- a/consensus/polybft/consensus_metrics.go +++ b/consensus/polybft/consensus_metrics.go @@ -34,6 +34,7 @@ func updateBlockMetrics(currentBlock *types.Block, parentHeader *types.Header) e metrics.SetGauge([]string{consensusMetricsPrefix, "rounds"}, float32(extra.Checkpoint.BlockRound)) metrics.SetGauge([]string{consensusMetricsPrefix, "chain_head"}, float32(currentBlock.Number())) metrics.IncrCounter([]string{consensusMetricsPrefix, "block_counter"}, float32(1)) + metrics.SetGauge([]string{consensusMetricsPrefix, "block_space_used"}, float32(currentBlock.Header.GasUsed)) return nil } @@ -46,3 +47,9 @@ func updateEpochMetrics(epoch epochMetadata) { // update number of validators metrics metrics.SetGauge([]string{consensusMetricsPrefix, "validators"}, float32(epoch.Validators.Len())) } + +// updateBlockExecutionMetric updates the block execution metric +func updateBlockExecutionMetric(start time.Time) { + metrics.SetGauge([]string{consensusMetricsPrefix, "block_execution_time"}, + float32(time.Now().UTC().Sub(start).Seconds())) +} diff --git a/consensus/polybft/consensus_runtime.go b/consensus/polybft/consensus_runtime.go index ad19d0d665..7f23b1b7fd 100644 --- a/consensus/polybft/consensus_runtime.go +++ b/consensus/polybft/consensus_runtime.go @@ -11,7 +11,9 @@ import ( "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" + "github.com/0xPolygon/polygon-edge/contracts" "github.com/0xPolygon/polygon-edge/txrelayer" "github.com/0xPolygon/polygon-edge/types" @@ -35,7 +37,7 @@ var ( // txPoolInterface is an abstraction of transaction pool type txPoolInterface interface { - Prepare() + Prepare(uint64) Length() uint64 Peek() *types.Transaction Pop(*types.Transaction) @@ -53,7 +55,7 @@ type epochMetadata struct { FirstBlockInEpoch uint64 // Validators is the set of validators for the epoch - Validators AccountSet + Validators validator.AccountSet } type guardedDataDTO struct { @@ -101,7 +103,7 @@ type consensusRuntime struct { lastBuiltBlock *types.Header // activeValidatorFlag indicates whether the given node is amongst currently active validator set - activeValidatorFlag uint32 + activeValidatorFlag atomic.Bool // checkpointManager represents abstraction for checkpoint submission checkpointManager CheckpointManager @@ -112,6 +114,9 @@ type consensusRuntime struct { // manager for state sync bridge transactions stateSyncManager StateSyncManager + // manager for handling validator stake change and updating validator set + stakeManager StakeManager + // logger instance logger hcf.Logger } @@ -139,6 +144,10 @@ func newConsensusRuntime(log hcf.Logger, config *runtimeConfig) (*consensusRunti return nil, err } + if err := runtime.initStakeManager(log); err != nil { + return nil, err + } + // we need to call restart epoch on runtime to initialize epoch state runtime.epoch, err = runtime.restartEpoch(runtime.lastBuiltBlock) if err != nil { @@ -157,8 +166,8 @@ func (c *consensusRuntime) close() { // if bridge is not enabled, then a dummy state sync manager will be used func (c *consensusRuntime) initStateSyncManager(logger hcf.Logger) error { if c.IsBridgeEnabled() { - stateSenderAddr := c.config.PolyBFTConfig.Bridge.BridgeAddr - stateSyncManager, err := newStateSyncManager( + stateSenderAddr := c.config.PolyBFTConfig.Bridge.StateSenderAddr + stateSyncManager := newStateSyncManager( logger.Named("state-sync-manager"), c.config.State, &stateSyncConfig{ @@ -173,10 +182,6 @@ func (c *consensusRuntime) initStateSyncManager(logger hcf.Logger) error { }, ) - if err != nil { - return err - } - c.stateSyncManager = stateSyncManager } else { c.stateSyncManager = &dummyStateSyncManager{} @@ -198,7 +203,7 @@ func (c *consensusRuntime) initCheckpointManager(logger hcf.Logger) error { c.checkpointManager = newCheckpointManager( wallet.NewEcdsaSigner(c.config.Key), defaultCheckpointsOffset, - c.config.PolyBFTConfig.Bridge.CheckpointAddr, + c.config.PolyBFTConfig.Bridge.CheckpointManagerAddr, txRelayer, c.config.blockchain, c.config.polybftBackend, @@ -211,6 +216,27 @@ func (c *consensusRuntime) initCheckpointManager(logger hcf.Logger) error { return nil } +// initStakeManager initializes stake manager +func (c *consensusRuntime) initStakeManager(logger hcf.Logger) error { + rootRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(c.config.PolyBFTConfig.Bridge.JSONRPCEndpoint)) + if err != nil { + return err + } + + c.stakeManager = newStakeManager( + logger.Named("stake-manager"), + c.state, + rootRelayer, + wallet.NewEcdsaSigner(c.config.Key), + contracts.ValidatorSetContract, + c.config.PolyBFTConfig.Bridge.CustomSupernetManagerAddr, + c.config.blockchain, + int(c.config.PolyBFTConfig.MaxValidatorSetSize), + ) + + return nil +} + // getGuardedData returns last build block, proposer snapshot and current epochMetadata in a thread-safe manner. func (c *consensusRuntime) getGuardedData() (guardedDataDTO, error) { c.lock.RLock() @@ -258,8 +284,8 @@ func (c *consensusRuntime) OnBlockInserted(fullBlock *types.FullBlock) { var ( epoch = c.epoch err error - //nolint:godox - // TODO - this will need to take inconsideration if slashing occurred (to be fixed in EVM-519) + // calculation of epoch and sprint end does not consider slashing currently + isEndOfEpoch = c.isFixedSizeOfEpochMet(fullBlock.Block.Header.Number, epoch) ) @@ -280,6 +306,11 @@ func (c *consensusRuntime) OnBlockInserted(fullBlock *types.FullBlock) { c.logger.Error("Could not update proposer calculator", "err", err) } + // handle transfer events that happened in block + if err := c.stakeManager.PostBlock(postBlock); err != nil { + c.logger.Error("failed to post block in stake manager", "err", err) + } + if isEndOfEpoch { if epoch, err = c.restartEpoch(fullBlock.Block.Header); err != nil { c.logger.Error("failed to restart epoch after block inserted", "error", err) @@ -310,7 +341,7 @@ func (c *consensusRuntime) FSM() error { parent, types.Address(c.config.Key.Address()), c.config.txPool, - c.config.PolyBFTConfig.BlockTime, + c.config.PolyBFTConfig.BlockTime.Duration, c.logger, ) @@ -318,15 +349,12 @@ func (c *consensusRuntime) FSM() error { return fmt.Errorf("cannot create block builder for fsm: %w", err) } - //nolint:godox - // TODO - recognize slashing occurred (to be fixed in EVM-519) - slash := false - pendingBlockNumber := parent.Number + 1 - isEndOfSprint := slash || c.isFixedSizeOfSprintMet(pendingBlockNumber, epoch) - isEndOfEpoch := slash || c.isFixedSizeOfEpochMet(pendingBlockNumber, epoch) + // calculation of epoch and sprint end does not consider slashing currently + isEndOfSprint := c.isFixedSizeOfSprintMet(pendingBlockNumber, epoch) + isEndOfEpoch := c.isFixedSizeOfEpochMet(pendingBlockNumber, epoch) - valSet := NewValidatorSet(epoch.Validators, c.logger) + valSet := validator.NewValidatorSet(epoch.Validators, c.logger) exitRootHash, err := c.checkpointManager.BuildEventRoot(epoch.Number) if err != nil { @@ -358,10 +386,15 @@ func (c *consensusRuntime) FSM() error { } if isEndOfEpoch { - ff.commitEpochInput, err = c.calculateCommitEpochInput(parent, epoch) + ff.commitEpochInput, ff.distributeRewardsInput, err = c.calculateCommitEpochInput(parent, epoch) if err != nil { return fmt.Errorf("cannot calculate commit epoch info: %w", err) } + + ff.newValidatorsDelta, err = c.stakeManager.UpdateValidatorSet(epoch.Number, epoch.Validators.Copy()) + if err != nil { + return fmt.Errorf("cannot update validator set on epoch ending: %w", err) + } } c.logger.Info( @@ -436,13 +469,17 @@ func (c *consensusRuntime) restartEpoch(header *types.Header) (*epochMetadata, e SystemState: systemState, NewEpochID: epochNumber, FirstBlockOfEpoch: firstBlockInEpoch, - ValidatorSet: NewValidatorSet(validatorSet, c.logger), + ValidatorSet: validator.NewValidatorSet(validatorSet, c.logger), } if err := c.stateSyncManager.PostEpoch(reqObj); err != nil { return nil, err } + if err := c.stakeManager.PostEpoch(reqObj); err != nil { + return nil, err + } + return &epochMetadata{ Number: epochNumber, Validators: validatorSet, @@ -454,13 +491,15 @@ func (c *consensusRuntime) restartEpoch(header *types.Header) (*epochMetadata, e // in the current epoch, and ending at the last block of previous epoch func (c *consensusRuntime) calculateCommitEpochInput( currentBlock *types.Header, - epoch *epochMetadata) (*contractsapi.CommitEpochChildValidatorSetFn, error) { + epoch *epochMetadata, +) (*contractsapi.CommitEpochValidatorSetFn, + *contractsapi.DistributeRewardForRewardPoolFn, error) { uptimeCounter := map[types.Address]int64{} blockHeader := currentBlock epochID := epoch.Number totalBlocks := int64(0) - getSealersForBlock := func(blockExtra *Extra, validators AccountSet) error { + getSealersForBlock := func(blockExtra *Extra, validators validator.AccountSet) error { signers, err := validators.GetFilteredValidators(blockExtra.Parent.Bitmap) if err != nil { return err @@ -477,18 +516,18 @@ func (c *consensusRuntime) calculateCommitEpochInput( blockExtra, err := GetIbftExtra(currentBlock.ExtraData) if err != nil { - return nil, err + return nil, nil, err } // calculate uptime for current epoch for blockHeader.Number > epoch.FirstBlockInEpoch { if err := getSealersForBlock(blockExtra, epoch.Validators); err != nil { - return nil, err + return nil, nil, err } blockHeader, blockExtra, err = getBlockData(blockHeader.Number-1, c.config.blockchain) if err != nil { - return nil, err + return nil, nil, err } } @@ -498,25 +537,20 @@ func (c *consensusRuntime) calculateCommitEpochInput( for i := 0; i < commitEpochLookbackSize; i++ { validators, err := c.config.polybftBackend.GetValidators(blockHeader.Number-2, nil) if err != nil { - return nil, err + return nil, nil, err } if err := getSealersForBlock(blockExtra, validators); err != nil { - return nil, err + return nil, nil, err } blockHeader, blockExtra, err = getBlockData(blockHeader.Number-1, c.config.blockchain) if err != nil { - return nil, err + return nil, nil, err } } } - uptime := &contractsapi.Uptime{ - EpochID: new(big.Int).SetUint64(epochID), - TotalBlocks: big.NewInt(totalBlocks), - } - // include the data in the uptime counter in a deterministic way addrSet := []types.Address{} @@ -524,25 +558,34 @@ func (c *consensusRuntime) calculateCommitEpochInput( addrSet = append(addrSet, addr) } + uptime := make([]*contractsapi.Uptime, len(addrSet)) + sort.Slice(addrSet, func(i, j int) bool { return bytes.Compare(addrSet[i][:], addrSet[j][:]) > 0 }) - for _, addr := range addrSet { - uptime.AddValidatorUptime(addr, uptimeCounter[addr]) + for i, addr := range addrSet { + uptime[i] = &contractsapi.Uptime{ + Validator: addr, + SignedBlocks: new(big.Int).SetInt64(uptimeCounter[addr]), + } } - commitEpoch := &contractsapi.CommitEpochChildValidatorSetFn{ + commitEpoch := &contractsapi.CommitEpochValidatorSetFn{ ID: new(big.Int).SetUint64(epochID), Epoch: &contractsapi.Epoch{ StartBlock: new(big.Int).SetUint64(epoch.FirstBlockInEpoch), EndBlock: new(big.Int).SetUint64(currentBlock.Number + 1), EpochRoot: types.Hash{}, }, - Uptime: uptime, } - return commitEpoch, nil + distributeRewards := &contractsapi.DistributeRewardForRewardPoolFn{ + EpochID: new(big.Int).SetUint64(epochID), + Uptime: uptime, + } + + return commitEpoch, distributeRewards, nil } // GenerateExitProof generates proof of exit and is a bridge endpoint store function @@ -557,16 +600,12 @@ func (c *consensusRuntime) GetStateSyncProof(stateSyncID uint64) (types.Proof, e // setIsActiveValidator updates the activeValidatorFlag field func (c *consensusRuntime) setIsActiveValidator(isActiveValidator bool) { - if isActiveValidator { - atomic.StoreUint32(&c.activeValidatorFlag, 1) - } else { - atomic.StoreUint32(&c.activeValidatorFlag, 0) - } + c.activeValidatorFlag.Store(isActiveValidator) } // isActiveValidator indicates if node is in validator set or not func (c *consensusRuntime) isActiveValidator() bool { - return atomic.LoadUint32(&c.activeValidatorFlag) == 1 + return c.activeValidatorFlag.Load() } // isFixedSizeOfEpochMet checks if epoch reached its end that was configured by its default size @@ -721,61 +760,19 @@ func (c *consensusRuntime) ID() []byte { return c.config.Key.Address().Bytes() } -// HasQuorum returns true if quorum is reached for the given blockNumber -func (c *consensusRuntime) HasQuorum( - height uint64, - messages []*proto.Message, - msgType proto.MessageType) bool { +// GetVotingPowers returns map of validators addresses and their voting powers for the specified height. +func (c *consensusRuntime) GetVotingPowers(height uint64) (map[string]*big.Int, error) { c.lock.RLock() defer c.lock.RUnlock() - // extract the addresses of all the signers of the messages - ppIncluded := false - signers := make(map[types.Address]struct{}, len(messages)) - - for _, message := range messages { - if message.Type == proto.MessageType_PREPREPARE { - ppIncluded = true - } - signers[types.BytesToAddress(message.From)] = struct{}{} + if c.fsm == nil { + return nil, errors.New("getting voting power failed - backend is not initialized") + } else if c.fsm.Height() != height { + return nil, fmt.Errorf("getting voting power failed - backend is not initialized for height %d, fsm height %d", + height, c.fsm.Height()) } - // check quorum - switch msgType { - case proto.MessageType_PREPREPARE: - return len(messages) >= 1 - case proto.MessageType_PREPARE: - if ppIncluded { - return c.fsm.validators.HasQuorum(signers) - } - - if len(messages) == 0 { - return false - } - - propAddress, err := c.fsm.proposerSnapshot.GetLatestProposer(messages[0].View.Round, height) - if err != nil { - // This can happen if e.g. node runs sequence on lower height and proposer calculator updated - // to a newer count as a consequence of inserting block from syncer - c.logger.Debug("HasQuorum has been called but proposer could not be retrieved", "error", err) - - return false - } - - if _, ok := signers[propAddress]; ok { - c.logger.Warn("HasQuorum failed - proposer is among signers but it is not expected to be") - - return false - } - - signers[propAddress] = struct{}{} // add proposer manually - - return c.fsm.validators.HasQuorum(signers) - case proto.MessageType_ROUND_CHANGE, proto.MessageType_COMMIT: - return c.fsm.validators.HasQuorum(signers) - default: - return false - } + return c.fsm.validators.GetVotingPowers(), nil } // BuildPrePrepareMessage builds a PREPREPARE message based on the passed in proposal @@ -958,7 +955,7 @@ func (c *consensusRuntime) getFirstBlockOfEpoch(epochNumber uint64, latestHeader // getSealersForBlock checks who sealed a given block and updates the counter func getSealersForBlock(sealersCounter map[types.Address]uint64, - blockExtra *Extra, validators AccountSet) error { + blockExtra *Extra, validators validator.AccountSet) error { signers, err := validators.GetFilteredValidators(blockExtra.Parent.Bitmap) if err != nil { return err diff --git a/consensus/polybft/consensus_runtime_test.go b/consensus/polybft/consensus_runtime_test.go index 6a231f538e..094c3a200f 100644 --- a/consensus/polybft/consensus_runtime_test.go +++ b/consensus/polybft/consensus_runtime_test.go @@ -13,8 +13,10 @@ import ( "github.com/0xPolygon/polygon-edge/consensus/polybft/bitmap" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" "github.com/0xPolygon/polygon-edge/contracts" + "github.com/0xPolygon/polygon-edge/helper/common" "github.com/0xPolygon/polygon-edge/types" "github.com/hashicorp/go-hclog" "github.com/stretchr/testify/assert" @@ -184,7 +186,7 @@ func TestConsensusRuntime_OnBlockInserted_EndOfEpoch(t *testing.T) { ) currentEpochNumber := getEpochNumber(t, epochSize, epochSize) - validatorSet := newTestValidators(t, validatorsCount).getPublicIdentities() + validatorSet := validator.NewTestValidators(t, validatorsCount).GetPublicIdentities() header, headerMap := createTestBlocks(t, epochSize, epochSize, validatorSet) builtBlock := consensus.BuildBlock(consensus.BuildBlockParams{ Header: header, @@ -227,6 +229,7 @@ func TestConsensusRuntime_OnBlockInserted_EndOfEpoch(t *testing.T) { lastBuiltBlock: &types.Header{Number: header.Number - 1}, stateSyncManager: &dummyStateSyncManager{}, checkpointManager: &dummyCheckpointManager{}, + stakeManager: &dummyStakeManager{}, } runtime.OnBlockInserted(&types.FullBlock{Block: builtBlock}) @@ -261,7 +264,7 @@ func TestConsensusRuntime_OnBlockInserted_MiddleOfEpoch(t *testing.T) { txPool := new(txPoolMock) txPool.On("ResetWithHeaders", mock.Anything).Once() - snapshot := NewProposerSnapshot(blockNumber, []*ValidatorMetadata{}) + snapshot := NewProposerSnapshot(blockNumber, []*validator.ValidatorMetadata{}) config := &runtimeConfig{ PolyBFTConfig: &PolyBFTConfig{EpochSize: epochSize}, blockchain: blockchainMock, @@ -290,7 +293,7 @@ func TestConsensusRuntime_OnBlockInserted_MiddleOfEpoch(t *testing.T) { func TestConsensusRuntime_FSM_NotInValidatorSet(t *testing.T) { t.Parallel() - validators := newTestValidatorsWithAliases(t, []string{"A", "B", "C", "D"}) + validators := validator.NewTestValidatorsWithAliases(t, []string{"A", "B", "C", "D"}) snapshot := NewProposerSnapshot(1, nil) config := &runtimeConfig{ @@ -300,15 +303,15 @@ func TestConsensusRuntime_FSM_NotInValidatorSet(t *testing.T) { Key: createTestKey(t), } runtime := &consensusRuntime{ - proposerCalculator: NewProposerCalculatorFromSnapshot(snapshot, config, hclog.NewNullLogger()), - activeValidatorFlag: 1, - config: config, + proposerCalculator: NewProposerCalculatorFromSnapshot(snapshot, config, hclog.NewNullLogger()), + config: config, epoch: &epochMetadata{ Number: 1, - Validators: validators.getPublicIdentities(), + Validators: validators.GetPublicIdentities(), }, lastBuiltBlock: &types.Header{}, } + runtime.setIsActiveValidator(true) err := runtime.FSM() assert.ErrorIs(t, err, errNotAValidator) @@ -322,10 +325,10 @@ func TestConsensusRuntime_FSM_NotEndOfEpoch_NotEndOfSprint(t *testing.T) { } lastBlock := &types.Header{ Number: 1, - ExtraData: append(make([]byte, ExtraVanity), extra.MarshalRLPTo(nil)...), + ExtraData: extra.MarshalRLPTo(nil), } - validators := newTestValidators(t, 3) + validators := validator.NewTestValidators(t, 3) blockchainMock := new(blockchainMock) blockchainMock.On("NewBlockBuilder", mock.Anything).Return(&BlockBuilder{}, nil).Once() @@ -335,17 +338,16 @@ func TestConsensusRuntime_FSM_NotEndOfEpoch_NotEndOfSprint(t *testing.T) { EpochSize: 10, SprintSize: 5, }, - Key: wallet.NewKey(validators.getPrivateIdentities()[0]), + Key: wallet.NewKey(validators.GetPrivateIdentities()[0]), blockchain: blockchainMock, } runtime := &consensusRuntime{ - proposerCalculator: NewProposerCalculatorFromSnapshot(snapshot, config, hclog.NewNullLogger()), - logger: hclog.NewNullLogger(), - activeValidatorFlag: 1, - config: config, + proposerCalculator: NewProposerCalculatorFromSnapshot(snapshot, config, hclog.NewNullLogger()), + logger: hclog.NewNullLogger(), + config: config, epoch: &epochMetadata{ Number: 1, - Validators: validators.getPublicIdentities(), + Validators: validators.GetPublicIdentities(), FirstBlockInEpoch: 1, }, lastBuiltBlock: lastBlock, @@ -353,6 +355,7 @@ func TestConsensusRuntime_FSM_NotEndOfEpoch_NotEndOfSprint(t *testing.T) { stateSyncManager: &dummyStateSyncManager{}, checkpointManager: &dummyCheckpointManager{}, } + runtime.setIsActiveValidator(true) err := runtime.FSM() require.NoError(t, err) @@ -383,8 +386,8 @@ func TestConsensusRuntime_FSM_EndOfEpoch_BuildCommitEpoch(t *testing.T) { toIndex = uint64(9) ) - validatorAccounts := newTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) - validators := validatorAccounts.getPublicIdentities() + validatorAccounts := validator.NewTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) + validators := validatorAccounts.GetPublicIdentities() lastBuiltBlock, headerMap := createTestBlocks(t, 9, epochSize, validators) @@ -406,7 +409,7 @@ func TestConsensusRuntime_FSM_EndOfEpoch_BuildCommitEpoch(t *testing.T) { EpochSize: epochSize, SprintSize: sprintSize, }, - Key: validatorAccounts.getValidator("A").Key(), + Key: validatorAccounts.GetValidator("A").Key(), blockchain: blockchainMock, } @@ -420,6 +423,7 @@ func TestConsensusRuntime_FSM_EndOfEpoch_BuildCommitEpoch(t *testing.T) { lastBuiltBlock: lastBuiltBlock, stateSyncManager: &dummyStateSyncManager{}, checkpointManager: &dummyCheckpointManager{}, + stakeManager: &dummyStakeManager{}, } err := runtime.FSM() @@ -441,16 +445,16 @@ func Test_NewConsensusRuntime(t *testing.T) { polyBftConfig := &PolyBFTConfig{ Bridge: &BridgeConfig{ - BridgeAddr: types.Address{0x13}, - CheckpointAddr: types.Address{0x10}, - JSONRPCEndpoint: "testEndpoint", + StateSenderAddr: types.Address{0x13}, + CheckpointManagerAddr: types.Address{0x10}, + JSONRPCEndpoint: "testEndpoint", }, EpochSize: 10, SprintSize: 10, - BlockTime: 2 * time.Second, + BlockTime: common.Duration{Duration: 2 * time.Second}, } - validators := newTestValidators(t, 3).getPublicIdentities() + validators := validator.NewTestValidators(t, 3).GetPublicIdentities() systemStateMock := new(systemStateMock) systemStateMock.On("GetEpoch").Return(uint64(1)).Once() @@ -483,8 +487,8 @@ func Test_NewConsensusRuntime(t *testing.T) { assert.Equal(t, uint64(10), runtime.config.PolyBFTConfig.SprintSize) assert.Equal(t, uint64(10), runtime.config.PolyBFTConfig.EpochSize) assert.Equal(t, "0x0000000000000000000000000000000000000101", contracts.ValidatorSetContract.String()) - assert.Equal(t, "0x1300000000000000000000000000000000000000", runtime.config.PolyBFTConfig.Bridge.BridgeAddr.String()) - assert.Equal(t, "0x1000000000000000000000000000000000000000", runtime.config.PolyBFTConfig.Bridge.CheckpointAddr.String()) + assert.Equal(t, "0x1300000000000000000000000000000000000000", runtime.config.PolyBFTConfig.Bridge.StateSenderAddr.String()) + assert.Equal(t, "0x1000000000000000000000000000000000000000", runtime.config.PolyBFTConfig.Bridge.CheckpointManagerAddr.String()) assert.True(t, runtime.IsBridgeEnabled()) systemStateMock.AssertExpectations(t) blockchainMock.AssertExpectations(t) @@ -497,7 +501,7 @@ func TestConsensusRuntime_restartEpoch_SameEpochNumberAsTheLastOne(t *testing.T) const originalBlockNumber = uint64(5) newCurrentHeader := &types.Header{Number: originalBlockNumber + 1} - validatorSet := newTestValidators(t, 3).getPublicIdentities() + validatorSet := validator.NewTestValidators(t, 3).GetPublicIdentities() systemStateMock := new(systemStateMock) systemStateMock.On("GetEpoch").Return(uint64(1), nil).Once() @@ -511,9 +515,8 @@ func TestConsensusRuntime_restartEpoch_SameEpochNumberAsTheLastOne(t *testing.T) blockchain: blockchainMock, } runtime := &consensusRuntime{ - proposerCalculator: NewProposerCalculatorFromSnapshot(snapshot, config, hclog.NewNullLogger()), - activeValidatorFlag: 1, - config: config, + proposerCalculator: NewProposerCalculatorFromSnapshot(snapshot, config, hclog.NewNullLogger()), + config: config, epoch: &epochMetadata{ Number: 1, Validators: validatorSet, @@ -523,6 +526,7 @@ func TestConsensusRuntime_restartEpoch_SameEpochNumberAsTheLastOne(t *testing.T) Number: originalBlockNumber, }, } + runtime.setIsActiveValidator(true) epoch, err := runtime.restartEpoch(newCurrentHeader) @@ -547,43 +551,45 @@ func TestConsensusRuntime_calculateCommitEpochInput_SecondEpoch(t *testing.T) { sprintSize = 5 ) - validators := newTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E"}) + validators := validator.NewTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E"}) polybftConfig := &PolyBFTConfig{ EpochSize: epochSize, SprintSize: sprintSize, } - lastBuiltBlock, headerMap := createTestBlocks(t, 19, epochSize, validators.getPublicIdentities()) + lastBuiltBlock, headerMap := createTestBlocks(t, 19, epochSize, validators.GetPublicIdentities()) blockchainMock := new(blockchainMock) blockchainMock.On("GetHeaderByNumber", mock.Anything).Return(headerMap.getHeader) polybftBackendMock := new(polybftBackendMock) - polybftBackendMock.On("GetValidators", mock.Anything, mock.Anything).Return(validators.getPublicIdentities()).Twice() + polybftBackendMock.On("GetValidators", mock.Anything, mock.Anything).Return(validators.GetPublicIdentities()).Twice() config := &runtimeConfig{ PolyBFTConfig: polybftConfig, blockchain: blockchainMock, polybftBackend: polybftBackendMock, - Key: validators.getValidator("A").Key(), + Key: validators.GetValidator("A").Key(), } consensusRuntime := &consensusRuntime{ config: config, epoch: &epochMetadata{ Number: epoch, - Validators: validators.getPublicIdentities(), + Validators: validators.GetPublicIdentities(), FirstBlockInEpoch: epochStartBlock, }, lastBuiltBlock: lastBuiltBlock, } - commitEpochInput, err := consensusRuntime.calculateCommitEpochInput(lastBuiltBlock, consensusRuntime.epoch) + commitEpochInput, distributeRewardsInput, err := consensusRuntime.calculateCommitEpochInput(lastBuiltBlock, + consensusRuntime.epoch) assert.NoError(t, err) assert.NotEmpty(t, commitEpochInput) assert.Equal(t, uint64(epoch), commitEpochInput.ID.Uint64()) assert.Equal(t, uint64(epochStartBlock), commitEpochInput.Epoch.StartBlock.Uint64()) assert.Equal(t, uint64(epochEndBlock), commitEpochInput.Epoch.EndBlock.Uint64()) + assert.Equal(t, uint64(epoch), distributeRewardsInput.EpochID.Uint64()) blockchainMock.AssertExpectations(t) polybftBackendMock.AssertExpectations(t) @@ -592,17 +598,17 @@ func TestConsensusRuntime_calculateCommitEpochInput_SecondEpoch(t *testing.T) { func TestConsensusRuntime_IsValidValidator_BasicCases(t *testing.T) { t.Parallel() - setupFn := func(t *testing.T) (*consensusRuntime, *testValidators) { + setupFn := func(t *testing.T) (*consensusRuntime, *validator.TestValidators) { t.Helper() - validatorAccounts := newTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) + validatorAccounts := validator.NewTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) epoch := &epochMetadata{ - Validators: validatorAccounts.getPublicIdentities("A", "B", "C", "D"), + Validators: validatorAccounts.GetPublicIdentities("A", "B", "C", "D"), } runtime := &consensusRuntime{ epoch: epoch, logger: hclog.NewNullLogger(), - fsm: &fsm{validators: NewValidatorSet(epoch.Validators, hclog.NewNullLogger())}, + fsm: &fsm{validators: validator.NewValidatorSet(epoch.Validators, hclog.NewNullLogger())}, } return runtime, validatorAccounts @@ -640,8 +646,8 @@ func TestConsensusRuntime_IsValidValidator_BasicCases(t *testing.T) { t.Parallel() runtime, validatorAccounts := setupFn(t) - signer := validatorAccounts.getValidator(c.signerAlias) - sender := validatorAccounts.getValidator(c.senderAlias) + signer := validatorAccounts.GetValidator(c.signerAlias) + sender := validatorAccounts.GetValidator(c.senderAlias) msg, err := signer.Key().SignIBFTMessage(&proto.Message{From: sender.Address().Bytes()}) require.NoError(t, err) @@ -653,18 +659,18 @@ func TestConsensusRuntime_IsValidValidator_BasicCases(t *testing.T) { func TestConsensusRuntime_IsValidValidator_TamperSignature(t *testing.T) { t.Parallel() - validatorAccounts := newTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) + validatorAccounts := validator.NewTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) epoch := &epochMetadata{ - Validators: validatorAccounts.getPublicIdentities("A", "B", "C", "D"), + Validators: validatorAccounts.GetPublicIdentities("A", "B", "C", "D"), } runtime := &consensusRuntime{ epoch: epoch, logger: hclog.NewNullLogger(), - fsm: &fsm{validators: NewValidatorSet(epoch.Validators, hclog.NewNullLogger())}, + fsm: &fsm{validators: validator.NewValidatorSet(epoch.Validators, hclog.NewNullLogger())}, } // provide invalid signature - sender := validatorAccounts.getValidator("A") + sender := validatorAccounts.GetValidator("A") msg := &proto.Message{ From: sender.Address().Bytes(), Signature: []byte{1, 2, 3, 4, 5}, @@ -675,16 +681,16 @@ func TestConsensusRuntime_IsValidValidator_TamperSignature(t *testing.T) { func TestConsensusRuntime_TamperMessageContent(t *testing.T) { t.Parallel() - validatorAccounts := newTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) + validatorAccounts := validator.NewTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) epoch := &epochMetadata{ - Validators: validatorAccounts.getPublicIdentities("A", "B", "C", "D"), + Validators: validatorAccounts.GetPublicIdentities("A", "B", "C", "D"), } runtime := &consensusRuntime{ epoch: epoch, logger: hclog.NewNullLogger(), - fsm: &fsm{validators: NewValidatorSet(epoch.Validators, hclog.NewNullLogger())}, + fsm: &fsm{validators: validator.NewValidatorSet(epoch.Validators, hclog.NewNullLogger())}, } - sender := validatorAccounts.getValidator("A") + sender := validatorAccounts.GetValidator("A") proposalHash := []byte{2, 4, 6, 8, 10} proposalSignature, err := sender.Key().SignWithDomain(proposalHash, bls.DomainCheckpointManager) require.NoError(t, err) @@ -729,7 +735,7 @@ func TestConsensusRuntime_IsValidProposalHash(t *testing.T) { block := &types.Block{ Header: &types.Header{ Number: 10, - ExtraData: append(make([]byte, ExtraVanity), extra.MarshalRLPTo(nil)...), + ExtraData: extra.MarshalRLPTo(nil), }, } block.Header.ComputeHash() @@ -758,7 +764,7 @@ func TestConsensusRuntime_IsValidProposalHash_InvalidProposalHash(t *testing.T) block := &types.Block{ Header: &types.Header{ Number: 10, - ExtraData: append(make([]byte, ExtraVanity), extra.MarshalRLPTo(nil)...), + ExtraData: extra.MarshalRLPTo(nil), }, } @@ -766,7 +772,7 @@ func TestConsensusRuntime_IsValidProposalHash_InvalidProposalHash(t *testing.T) require.NoError(t, err) extra.Checkpoint.BlockRound = 2 // change it so it is not the same as in proposal hash - block.Header.ExtraData = append(make([]byte, ExtraVanity), extra.MarshalRLPTo(nil)...) + block.Header.ExtraData = extra.MarshalRLPTo(nil) block.Header.ComputeHash() runtime := &consensusRuntime{ @@ -832,126 +838,35 @@ func TestConsensusRuntime_ID(t *testing.T) { require.NotEqual(t, runtime.ID(), key2.Address().Bytes()) } -func TestConsensusRuntime_HasQuorum(t *testing.T) { +func TestConsensusRuntime_GetVotingPowers(t *testing.T) { t.Parallel() - const round = 5 + const height = 100 - validatorAccounts := newTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) + validatorAccounts := validator.NewTestValidatorsWithAliases(t, []string{"A", "B", "C"}, []uint64{1, 3, 2}) + runtime := &consensusRuntime{} - extra := &Extra{ - Checkpoint: &CheckpointData{}, - } + _, err := runtime.GetVotingPowers(height) + require.Error(t, err) - lastBuildBlock := &types.Header{ - Number: 1, - ExtraData: append(make([]byte, ExtraVanity), extra.MarshalRLPTo(nil)...), + runtime.fsm = &fsm{ + validators: validatorAccounts.ToValidatorSet(), + parent: &types.Header{Number: height}, } - blockchainMock := new(blockchainMock) - blockchainMock.On("NewBlockBuilder", mock.Anything).Return(&BlockBuilder{}, nil).Once() - blockchainMock.On("GetHeaderByNumber", mock.Anything).Return(&types.Header{ - Number: 0, - }, true).Once() - - state := newTestState(t) - snapshot := NewProposerSnapshot(lastBuildBlock.Number+1, validatorAccounts.getPublicIdentities()) - config := &runtimeConfig{ - Key: validatorAccounts.getValidator("B").Key(), - blockchain: blockchainMock, - PolyBFTConfig: &PolyBFTConfig{EpochSize: 10, SprintSize: 5}, - } - runtime := &consensusRuntime{ - state: state, - config: config, - lastBuiltBlock: lastBuildBlock, - epoch: &epochMetadata{ - Number: 1, - Validators: validatorAccounts.getPublicIdentities()[:len(validatorAccounts.validators)-1], - }, - logger: hclog.NewNullLogger(), - proposerCalculator: NewProposerCalculatorFromSnapshot(snapshot, config, hclog.NewNullLogger()), - stateSyncManager: &dummyStateSyncManager{}, - checkpointManager: &dummyCheckpointManager{}, - } + _, err = runtime.GetVotingPowers(height) + require.Error(t, err) - require.NoError(t, runtime.FSM()) + runtime.fsm.parent.Number = height - 1 - proposer, err := snapshot.CalcProposer(round, lastBuildBlock.Number+1) + val, err := runtime.GetVotingPowers(height) require.NoError(t, err) - runtime.fsm.proposerSnapshot = snapshot - - messages := make([]*proto.Message, 0, len(validatorAccounts.validators)) - - // Unknown message type - assert.False(t, runtime.HasQuorum(lastBuildBlock.Number+1, messages, -1)) - - // invalid block number - for _, msgType := range []proto.MessageType{proto.MessageType_PREPREPARE, proto.MessageType_PREPARE, - proto.MessageType_ROUND_CHANGE, proto.MessageType_COMMIT} { - assert.False(t, runtime.HasQuorum(lastBuildBlock.Number, nil, msgType)) - } - - // MessageType_PREPREPARE - only one message is enough - messages = append(messages, &proto.Message{ - From: proposer.Bytes(), - Type: proto.MessageType_PREPREPARE, - View: &proto.View{Height: 1, Round: round}, - }) - - assert.False(t, runtime.HasQuorum(lastBuildBlock.Number+1, nil, proto.MessageType_PREPREPARE)) - assert.True(t, runtime.HasQuorum(lastBuildBlock.Number+1, messages, proto.MessageType_PREPREPARE)) - - // MessageType_PREPARE - messages = make([]*proto.Message, 0, len(validatorAccounts.validators)) - - for _, x := range validatorAccounts.validators { - address := x.Address() + addresses := validatorAccounts.GetPublicIdentities([]string{"A", "B", "C"}...).GetAddresses() - // proposer must not be included in prepare messages - if address != proposer { - messages = append(messages, &proto.Message{ - From: address[:], - Type: proto.MessageType_PREPARE, - View: &proto.View{Height: lastBuildBlock.Number + 1, Round: round}, - }) - } - } - - // enough quorum - assert.True(t, runtime.HasQuorum(lastBuildBlock.Number+1, messages, proto.MessageType_PREPARE)) - - // not enough quorum - assert.False(t, runtime.HasQuorum(lastBuildBlock.Number+1, messages[:1], proto.MessageType_PREPARE)) - - // include proposer which is not allowed - messages = append(messages, &proto.Message{ - From: proposer[:], - Type: proto.MessageType_PREPARE, - View: &proto.View{Height: lastBuildBlock.Number + 1, Round: round}, - }) - assert.False(t, runtime.HasQuorum(lastBuildBlock.Number+1, messages, proto.MessageType_PREPARE)) - - // last message is MessageType_PREPREPARE - this should be allowed - messages[len(messages)-1].Type = proto.MessageType_PREPREPARE - assert.True(t, runtime.HasQuorum(lastBuildBlock.Number+1, messages, proto.MessageType_PREPARE)) - - //proto.MessageType_ROUND_CHANGE, proto.MessageType_COMMIT - for _, msgType := range []proto.MessageType{proto.MessageType_ROUND_CHANGE, proto.MessageType_COMMIT} { - messages = make([]*proto.Message, 0, len(validatorAccounts.validators)) - - for _, x := range validatorAccounts.validators { - messages = append(messages, &proto.Message{ - From: x.Address().Bytes(), - Type: msgType, - View: &proto.View{Height: lastBuildBlock.Number + 1, Round: round}, - }) - } - - assert.True(t, runtime.HasQuorum(lastBuildBlock.Number+1, messages, msgType)) - assert.False(t, runtime.HasQuorum(lastBuildBlock.Number+1, messages[:1], msgType)) - } + assert.Equal(t, uint64(1), val[types.AddressToString(addresses[0])].Uint64()) + assert.Equal(t, uint64(3), val[types.AddressToString(addresses[1])].Uint64()) + assert.Equal(t, uint64(2), val[types.AddressToString(addresses[2])].Uint64()) } func TestConsensusRuntime_BuildRoundChangeMessage(t *testing.T) { @@ -1066,7 +981,7 @@ func TestConsensusRuntime_BuildPrepareMessage(t *testing.T) { } func createTestBlocks(t *testing.T, numberOfBlocks, defaultEpochSize uint64, - validatorSet AccountSet) (*types.Header, *testHeadersMap) { + validatorSet validator.AccountSet) (*types.Header, *testHeadersMap) { t.Helper() headerMap := &testHeadersMap{} @@ -1078,7 +993,7 @@ func createTestBlocks(t *testing.T, numberOfBlocks, defaultEpochSize uint64, genesisBlock := &types.Header{ Number: 0, - ExtraData: append(make([]byte, ExtraVanity), extra.MarshalRLPTo(nil)...), + ExtraData: extra.MarshalRLPTo(nil), } parentHash := types.BytesToHash(big.NewInt(0).Bytes()) @@ -1108,7 +1023,7 @@ func createTestBlocks(t *testing.T, numberOfBlocks, defaultEpochSize uint64, return blockHeader, headerMap } -func createTestBitmaps(t *testing.T, validators AccountSet, numberOfBlocks uint64) map[uint64]bitmap.Bitmap { +func createTestBitmaps(t *testing.T, validators validator.AccountSet, numberOfBlocks uint64) map[uint64]bitmap.Bitmap { t.Helper() bitmaps := make(map[uint64]bitmap.Bitmap, numberOfBlocks) @@ -1135,12 +1050,12 @@ func createTestBitmaps(t *testing.T, validators AccountSet, numberOfBlocks uint6 return bitmaps } -func createTestExtraForAccounts(t *testing.T, epoch uint64, validators AccountSet, b bitmap.Bitmap) []byte { +func createTestExtraForAccounts(t *testing.T, epoch uint64, validators validator.AccountSet, b bitmap.Bitmap) []byte { t.Helper() dummySignature := [64]byte{} extraData := Extra{ - Validators: &ValidatorSetDelta{ + Validators: &validator.ValidatorSetDelta{ Added: validators, Removed: bitmap.Bitmap{}, }, @@ -1149,12 +1064,7 @@ func createTestExtraForAccounts(t *testing.T, epoch uint64, validators AccountSe Checkpoint: &CheckpointData{EpochNumber: epoch}, } - marshaled := extraData.MarshalRLPTo(nil) - result := make([]byte, ExtraVanity+len(marshaled)) - - copy(result[ExtraVanity:], marshaled) - - return result + return extraData.MarshalRLPTo(nil) } func encodeExitEvents(t *testing.T, exitEvents []*ExitEvent) [][]byte { diff --git a/consensus/polybft/contracts_initializer.go b/consensus/polybft/contracts_initializer.go index 52633865fc..16239b8f6c 100644 --- a/consensus/polybft/contracts_initializer.go +++ b/consensus/polybft/contracts_initializer.go @@ -12,83 +12,267 @@ import ( ) const ( - // safe numbers for the test - minStake = 1 - minDelegation = 1 + contractCallGasLimit = 100_000_000 ) -var ( - nativeTokenName = "Polygon" - nativeTokenSymbol = "MATIC" - nativeTokenDecimals = uint8(18) -) +// initValidatorSet initializes ValidatorSet SC +func initValidatorSet(polyBFTConfig PolyBFTConfig, transition *state.Transition) error { + initialValidators := make([]*contractsapi.ValidatorInit, len(polyBFTConfig.InitialValidatorSet)) + for i, validator := range polyBFTConfig.InitialValidatorSet { + initialValidators[i] = &contractsapi.ValidatorInit{ + Addr: validator.Address, + Stake: validator.Stake, + } + } -// getInitChildValidatorSetInput builds input parameters for ChildValidatorSet SC initialization -func getInitChildValidatorSetInput(polyBFTConfig PolyBFTConfig) ([]byte, error) { - apiValidators := make([]*contractsapi.ValidatorInit, len(polyBFTConfig.InitialValidatorSet)) + initFn := &contractsapi.InitializeValidatorSetFn{ + NewStateSender: contracts.L2StateSenderContract, + NewStateReceiver: contracts.StateReceiverContract, + NewRootChainManager: polyBFTConfig.Bridge.CustomSupernetManagerAddr, + NewEpochSize: new(big.Int).SetUint64(polyBFTConfig.EpochSize), + InitialValidators: initialValidators, + } - for i, validator := range polyBFTConfig.InitialValidatorSet { - validatorData, err := validator.ToValidatorInitAPIBinding() - if err != nil { - return nil, err + input, err := initFn.EncodeAbi() + if err != nil { + return fmt.Errorf("ValidatorSet.initialize params encoding failed: %w", err) + } + + return callContract(contracts.SystemCaller, + contracts.ValidatorSetContract, input, "ValidatorSet.initialize", transition) +} + +// initRewardPool initializes RewardPool SC +func initRewardPool(polybftConfig PolyBFTConfig, transition *state.Transition) error { + initFn := &contractsapi.InitializeRewardPoolFn{ + NewRewardToken: polybftConfig.RewardConfig.TokenAddress, + NewRewardWallet: polybftConfig.RewardConfig.WalletAddress, + NewValidatorSet: contracts.ValidatorSetContract, + NewBaseReward: new(big.Int).SetUint64(polybftConfig.EpochReward), + } + + input, err := initFn.EncodeAbi() + if err != nil { + return fmt.Errorf("RewardPool.initialize params encoding failed: %w", err) + } + + return callContract(contracts.SystemCaller, + contracts.RewardPoolContract, input, "RewardPool.initialize", transition) +} + +// getInitERC20PredicateInput builds initialization input parameters for child chain ERC20Predicate SC +func getInitERC20PredicateInput(config *BridgeConfig, childChainMintable bool) ([]byte, error) { + var params contractsapi.StateTransactionInput + if childChainMintable { + params = &contractsapi.InitializeRootMintableERC20PredicateFn{ + NewL2StateSender: contracts.L2StateSenderContract, + NewStateReceiver: contracts.StateReceiverContract, + NewChildERC20Predicate: config.ChildMintableERC20PredicateAddr, + NewChildTokenTemplate: config.ChildERC20Addr, } + } else { + params = &contractsapi.InitializeChildERC20PredicateFn{ + NewL2StateSender: contracts.L2StateSenderContract, + NewStateReceiver: contracts.StateReceiverContract, + NewRootERC20Predicate: config.RootERC20PredicateAddr, + NewChildTokenTemplate: contracts.ChildERC20Contract, + NewNativeTokenRootAddress: config.RootNativeERC20Addr, + } + } + + return params.EncodeAbi() +} - apiValidators[i] = validatorData +// getInitERC20PredicateACLInput builds initialization input parameters for child chain ERC20PredicateAccessList SC +func getInitERC20PredicateACLInput(config *BridgeConfig, owner types.Address, + childChainMintable bool) ([]byte, error) { + var params contractsapi.StateTransactionInput + if childChainMintable { + params = &contractsapi.InitializeRootMintableERC20PredicateACLFn{ + NewL2StateSender: contracts.L2StateSenderContract, + NewStateReceiver: contracts.StateReceiverContract, + NewChildERC20Predicate: config.ChildMintableERC20PredicateAddr, + NewChildTokenTemplate: config.ChildERC20Addr, + NewUseAllowList: owner != contracts.SystemCaller, + NewUseBlockList: owner != contracts.SystemCaller, + NewOwner: owner, + } + } else { + params = &contractsapi.InitializeChildERC20PredicateACLFn{ + NewL2StateSender: contracts.L2StateSenderContract, + NewStateReceiver: contracts.StateReceiverContract, + NewRootERC20Predicate: config.RootERC20PredicateAddr, + NewChildTokenTemplate: contracts.ChildERC20Contract, + NewNativeTokenRootAddress: config.RootNativeERC20Addr, + NewUseAllowList: owner != contracts.SystemCaller, + NewUseBlockList: owner != contracts.SystemCaller, + NewOwner: owner, + } } - params := &contractsapi.InitializeChildValidatorSetFn{ - Init: &contractsapi.InitStruct{ - EpochReward: new(big.Int).SetUint64(polyBFTConfig.EpochReward), - MinStake: big.NewInt(minStake), - MinDelegation: big.NewInt(minDelegation), - EpochSize: new(big.Int).SetUint64(polyBFTConfig.EpochSize), - }, - NewBls: contracts.BLSContract, - Governance: polyBFTConfig.Governance, - Validators: apiValidators, + return params.EncodeAbi() +} + +// getInitERC721PredicateInput builds initialization input parameters for child chain ERC721Predicate SC +func getInitERC721PredicateInput(config *BridgeConfig, childOriginatedTokens bool) ([]byte, error) { + var params contractsapi.StateTransactionInput + if childOriginatedTokens { + params = &contractsapi.InitializeRootMintableERC721PredicateFn{ + NewL2StateSender: contracts.L2StateSenderContract, + NewStateReceiver: contracts.StateReceiverContract, + NewChildERC721Predicate: config.ChildMintableERC721PredicateAddr, + NewChildTokenTemplate: config.ChildERC721Addr, + } + } else { + params = &contractsapi.InitializeChildERC721PredicateFn{ + NewL2StateSender: contracts.L2StateSenderContract, + NewStateReceiver: contracts.StateReceiverContract, + NewRootERC721Predicate: config.RootERC721PredicateAddr, + NewChildTokenTemplate: contracts.ChildERC721Contract, + } } return params.EncodeAbi() } -// getInitChildERC20PredicateInput builds input parameters for ERC20Predicate SC initialization -func getInitChildERC20PredicateInput(config *BridgeConfig) ([]byte, error) { - //nolint:godox - // to be fixed with EVM-541 - // TODO: @Stefan-Ethernal Temporary workaround just to be able to run cluster in non-bridge mode, until SC is fixed - rootERC20PredicateAddr := types.StringToAddress("0xDEAD") - rootERC20Addr := types.ZeroAddress +// getInitERC721PredicateACLInput builds initialization input parameters +// for child chain ERC721PredicateAccessList SC +func getInitERC721PredicateACLInput(config *BridgeConfig, owner types.Address, + childChainMintable bool) ([]byte, error) { + var params contractsapi.StateTransactionInput + if childChainMintable { + params = &contractsapi.InitializeRootMintableERC721PredicateACLFn{ + NewL2StateSender: contracts.L2StateSenderContract, + NewStateReceiver: contracts.StateReceiverContract, + NewChildERC721Predicate: config.ChildMintableERC721PredicateAddr, + NewChildTokenTemplate: config.ChildERC721Addr, + NewUseAllowList: owner != contracts.SystemCaller, + NewUseBlockList: owner != contracts.SystemCaller, + NewOwner: owner, + } + } else { + params = &contractsapi.InitializeChildERC721PredicateACLFn{ + NewL2StateSender: contracts.L2StateSenderContract, + NewStateReceiver: contracts.StateReceiverContract, + NewRootERC721Predicate: config.RootERC721PredicateAddr, + NewChildTokenTemplate: contracts.ChildERC721Contract, + NewUseAllowList: owner != contracts.SystemCaller, + NewUseBlockList: owner != contracts.SystemCaller, + NewOwner: owner, + } + } - if config != nil { - rootERC20PredicateAddr = config.RootERC20PredicateAddr - rootERC20Addr = config.RootNativeERC20Addr + return params.EncodeAbi() +} + +// getInitERC1155PredicateInput builds initialization input parameters for child chain ERC1155Predicate SC +func getInitERC1155PredicateInput(config *BridgeConfig, childChainMintable bool) ([]byte, error) { + var params contractsapi.StateTransactionInput + if childChainMintable { + params = &contractsapi.InitializeRootMintableERC1155PredicateFn{ + NewL2StateSender: contracts.L2StateSenderContract, + NewStateReceiver: contracts.StateReceiverContract, + NewChildERC1155Predicate: config.ChildMintableERC1155PredicateAddr, + NewChildTokenTemplate: config.ChildERC1155Addr, + } + } else { + params = &contractsapi.InitializeChildERC1155PredicateFn{ + NewL2StateSender: contracts.L2StateSenderContract, + NewStateReceiver: contracts.StateReceiverContract, + NewRootERC1155Predicate: config.RootERC1155PredicateAddr, + NewChildTokenTemplate: contracts.ChildERC1155Contract, + } } - params := &contractsapi.InitializeChildERC20PredicateFn{ - NewL2StateSender: contracts.L2StateSenderContract, - NewStateReceiver: contracts.StateReceiverContract, - NewRootERC20Predicate: rootERC20PredicateAddr, - NewChildTokenTemplate: contracts.ChildERC20Contract, - NewNativeTokenRootAddress: rootERC20Addr, + return params.EncodeAbi() +} + +// getInitERC1155PredicateACLInput builds initialization input parameters +// for child chain ERC1155PredicateAccessList SC +func getInitERC1155PredicateACLInput(config *BridgeConfig, owner types.Address, + childChainMintable bool) ([]byte, error) { + var params contractsapi.StateTransactionInput + if childChainMintable { + params = &contractsapi.InitializeRootMintableERC1155PredicateACLFn{ + NewL2StateSender: contracts.L2StateSenderContract, + NewStateReceiver: contracts.StateReceiverContract, + NewChildERC1155Predicate: config.ChildMintableERC1155PredicateAddr, + NewChildTokenTemplate: config.ChildERC1155Addr, + NewUseAllowList: owner != contracts.SystemCaller, + NewUseBlockList: owner != contracts.SystemCaller, + NewOwner: owner, + } + } else { + params = &contractsapi.InitializeChildERC1155PredicateACLFn{ + NewL2StateSender: contracts.L2StateSenderContract, + NewStateReceiver: contracts.StateReceiverContract, + NewRootERC1155Predicate: config.RootERC1155PredicateAddr, + NewChildTokenTemplate: contracts.ChildERC1155Contract, + NewUseAllowList: owner != contracts.SystemCaller, + NewUseBlockList: owner != contracts.SystemCaller, + NewOwner: owner, + } } return params.EncodeAbi() } -func initContract(to types.Address, input []byte, contractName string, transition *state.Transition) error { - result := transition.Call2(contracts.SystemCaller, to, input, - big.NewInt(0), 100_000_000) +// mintRewardTokensToWallet mints configured amount of reward tokens to reward wallet address +func mintRewardTokensToWallet(polyBFTConfig PolyBFTConfig, transition *state.Transition) error { + if isNativeRewardToken(polyBFTConfig) { + // if reward token is a native erc20 token, we don't need to mint an amount of tokens + // for given wallet address to it since this is done in premine + return nil + } + + mintFn := contractsapi.MintRootERC20Fn{ + To: polyBFTConfig.RewardConfig.WalletAddress, + Amount: polyBFTConfig.RewardConfig.WalletAmount, + } + + input, err := mintFn.EncodeAbi() + if err != nil { + return fmt.Errorf("RewardToken.mint params encoding failed: %w", err) + } + + return callContract(contracts.SystemCaller, polyBFTConfig.RewardConfig.TokenAddress, input, + "RewardToken.mint", transition) +} + +// approveRewardPoolAsSpender approves reward pool contract as reward token spender +// since reward pool distributes rewards. +func approveRewardPoolAsSpender(polyBFTConfig PolyBFTConfig, transition *state.Transition) error { + approveFn := &contractsapi.ApproveRootERC20Fn{ + Spender: contracts.RewardPoolContract, + Amount: polyBFTConfig.RewardConfig.WalletAmount, + } + + input, err := approveFn.EncodeAbi() + if err != nil { + return fmt.Errorf("RewardToken.approve params encoding failed: %w", err) + } + return callContract(polyBFTConfig.RewardConfig.WalletAddress, + polyBFTConfig.RewardConfig.TokenAddress, input, "RewardToken.approve", transition) +} + +// callContract calls given smart contract function, encoded in input parameter +func callContract(from, to types.Address, input []byte, contractName string, transition *state.Transition) error { + result := transition.Call2(from, to, input, big.NewInt(0), contractCallGasLimit) if result.Failed() { if result.Reverted() { - unpackedRevert, err := abi.UnpackRevertError(result.ReturnValue) - if err == nil { - fmt.Printf("%v.initialize %v\n", contractName, unpackedRevert) + if revertReason, err := abi.UnpackRevertError(result.ReturnValue); err == nil { + return fmt.Errorf("%s contract call was reverted: %s", contractName, revertReason) } } - return fmt.Errorf("failed to initialize %s contract. Reason: %w", contractName, result.Err) + return fmt.Errorf("%s contract call failed: %w", contractName, result.Err) } return nil } + +// isNativeRewardToken returns true in case a native token is used as a reward token as well +func isNativeRewardToken(cfg PolyBFTConfig) bool { + return cfg.RewardConfig.TokenAddress == contracts.NativeERC20TokenContract +} diff --git a/consensus/polybft/contractsapi/artifacts-gen/main.go b/consensus/polybft/contractsapi/artifacts-gen/main.go index cedd7164b4..0f6b6ad12b 100644 --- a/consensus/polybft/contractsapi/artifacts-gen/main.go +++ b/consensus/polybft/contractsapi/artifacts-gen/main.go @@ -6,9 +6,15 @@ import ( "os" "path" "runtime" + "strings" - "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi/artifact" "github.com/dave/jennifer/jen" + + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi/artifact" +) + +const ( + extension = ".sol" ) func main() { @@ -23,10 +29,6 @@ func main() { Path string Name string }{ - { - "child/ChildValidatorSet.sol", - "ChildValidatorSet", - }, { "child/L2StateSender.sol", "L2StateSender", @@ -51,6 +53,58 @@ func main() { "child/ChildERC20Predicate.sol", "ChildERC20Predicate", }, + { + "child/ChildERC20PredicateAccessList.sol", + "ChildERC20PredicateACL", + }, + { + "child/RootMintableERC20Predicate.sol", + "RootMintableERC20Predicate", + }, + { + "child/RootMintableERC20PredicateAccessList.sol", + "RootMintableERC20PredicateACL", + }, + { + "child/ChildERC721.sol", + "ChildERC721", + }, + { + "child/ChildERC721Predicate.sol", + "ChildERC721Predicate", + }, + { + "child/ChildERC721PredicateAccessList.sol", + "ChildERC721PredicateACL", + }, + { + "child/RootMintableERC721Predicate.sol", + "RootMintableERC721Predicate", + }, + { + "child/RootMintableERC721PredicateAccessList.sol", + "RootMintableERC721PredicateACL", + }, + { + "child/ChildERC1155.sol", + "ChildERC1155", + }, + { + "child/ChildERC1155Predicate.sol", + "ChildERC1155Predicate", + }, + { + "child/ChildERC1155PredicateAccessList.sol", + "ChildERC1155PredicateACL", + }, + { + "child/RootMintableERC1155Predicate.sol", + "RootMintableERC1155Predicate", + }, + { + "child/RootMintableERC1155PredicateAccessList.sol", + "RootMintableERC1155PredicateACL", + }, { "child/System.sol", "System", @@ -79,18 +133,66 @@ func main() { "root/StateSender.sol", "StateSender", }, + { + "mocks/MockERC20.sol", + "MockERC20", + }, { "root/RootERC20Predicate.sol", "RootERC20Predicate", }, { - "mocks/MockERC20.sol", - "MockERC20", + "root/ChildMintableERC20Predicate.sol", + "ChildMintableERC20Predicate", + }, + { + "mocks/MockERC721.sol", + "MockERC721", + }, + { + "root/RootERC721Predicate.sol", + "RootERC721Predicate", + }, + { + "root/ChildMintableERC721Predicate.sol", + "ChildMintableERC721Predicate", + }, + { + "mocks/MockERC1155.sol", + "MockERC1155", + }, + { + "root/RootERC1155Predicate.sol", + "RootERC1155Predicate", + }, + { + "root/ChildMintableERC1155Predicate.sol", + "ChildMintableERC1155Predicate", + }, + { + "root/staking/CustomSupernetManager.sol", + "CustomSupernetManager", + }, + { + "root/staking/StakeManager.sol", + "StakeManager", + }, + { + "child/validator/RewardPool.sol", + "RewardPool", + }, + { + "child/validator/ValidatorSet.sol", + "ValidatorSet", + }, + { + "child/EIP1559Burn.sol", + "EIP1559Burn", }, } for _, v := range readContracts { - artifactBytes, err := artifact.ReadArtifactData(scpath, v.Path, v.Name) + artifactBytes, err := artifact.ReadArtifactData(scpath, v.Path, getContractName(v.Path)) if err != nil { log.Fatal(err) } @@ -108,3 +210,11 @@ func main() { log.Fatal(err) } } + +// getContractName extracts smart contract name from provided path +func getContractName(path string) string { + pathSegments := strings.Split(path, string([]rune{os.PathSeparator})) + nameSegment := pathSegments[len(pathSegments)-1] + + return strings.Split(nameSegment, extension)[0] +} diff --git a/consensus/polybft/contractsapi/bindings-gen/main.go b/consensus/polybft/contractsapi/bindings-gen/main.go index dbcdb51719..a30981d991 100644 --- a/consensus/polybft/contractsapi/bindings-gen/main.go +++ b/consensus/polybft/contractsapi/bindings-gen/main.go @@ -29,14 +29,16 @@ type generatedData struct { func main() { cases := []struct { - contractName string - artifact *artifact.Artifact - functions []string - events []string + contractName string + artifact *artifact.Artifact + generateConstructor bool + functions []string + events []string }{ { "StateReceiver", gensc.StateReceiver, + false, []string{ "commit", "execute", @@ -46,28 +48,10 @@ func main() { "NewCommitment", }, }, - { - "ChildValidatorSet", - gensc.ChildValidatorSet, - []string{ - "commitEpoch", - "initialize", - "addToWhitelist", - "register", - }, - []string{ - "NewValidator", - "Staked", - "Delegated", - "Unstaked", - "Undelegated", - "AddedToWhitelist", - "Withdrawal", - }, - }, { "StateSender", gensc.StateSender, + false, []string{ "syncState", }, @@ -78,6 +62,7 @@ func main() { { "L2StateSender", gensc.L2StateSender, + false, []string{}, []string{ "L2StateSynced", @@ -86,6 +71,7 @@ func main() { { "CheckpointManager", gensc.CheckpointManager, + false, []string{ "submit", "initialize", @@ -96,7 +82,9 @@ func main() { { "ExitHelper", gensc.ExitHelper, + false, []string{ + "initialize", "exit", }, []string{}, @@ -104,15 +92,45 @@ func main() { { "ChildERC20Predicate", gensc.ChildERC20Predicate, + false, []string{ "initialize", "withdrawTo", }, []string{}, }, + { + "ChildERC20PredicateACL", + gensc.ChildERC20PredicateACL, + false, + []string{ + "initialize", + "withdrawTo", + }, + []string{}, + }, + { + "RootMintableERC20Predicate", + gensc.RootMintableERC20Predicate, + false, + []string{ + "initialize", + }, + []string{}, + }, + { + "RootMintableERC20PredicateACL", + gensc.RootMintableERC20PredicateACL, + false, + []string{ + "initialize", + }, + []string{}, + }, { "NativeERC20", gensc.NativeERC20, + false, []string{ "initialize", }, @@ -121,6 +139,7 @@ func main() { { "NativeERC20Mintable", gensc.NativeERC20Mintable, + false, []string{ "initialize", }, @@ -129,26 +148,272 @@ func main() { { "RootERC20Predicate", gensc.RootERC20Predicate, + false, []string{ "initialize", "depositTo", }, - []string{}, + []string{ + "TokenMapped", + }, + }, + { + "ChildMintableERC20Predicate", + gensc.ChildMintableERC20Predicate, + false, + []string{ + "initialize", + }, + []string{ + "MintableTokenMapped", + }, }, { "RootERC20", gensc.RootERC20, + false, []string{ + "balanceOf", "approve", "mint", }, []string{}, }, + { + "RootERC1155Predicate", + gensc.RootERC1155Predicate, + false, + []string{ + "initialize", + "depositBatch", + }, + []string{}, + }, + { + "ChildMintableERC1155Predicate", + gensc.ChildMintableERC1155Predicate, + false, + []string{ + "initialize", + }, + []string{}, + }, + { + "RootERC1155", + gensc.RootERC1155, + false, + []string{ + "setApprovalForAll", + "mintBatch", + "balanceOf", + }, + []string{}, + }, + { + "ChildERC1155Predicate", + gensc.ChildERC1155Predicate, + false, + []string{ + "initialize", + "withdrawBatch", + }, + []string{}, + }, + { + "ChildERC1155PredicateACL", + gensc.ChildERC1155PredicateACL, + false, + []string{ + "initialize", + "withdrawBatch", + }, + []string{}, + }, + { + "RootMintableERC1155Predicate", + gensc.RootMintableERC1155Predicate, + false, + []string{ + "initialize", + }, + []string{}, + }, + { + "RootMintableERC1155PredicateACL", + gensc.RootMintableERC1155PredicateACL, + false, + []string{ + "initialize", + }, + []string{ + "L2MintableTokenMapped", + }, + }, + { + "ChildERC1155", + gensc.ChildERC1155, + false, + []string{ + "initialize", + "balanceOf", + }, + []string{}, + }, + { + "RootERC721Predicate", + gensc.RootERC721Predicate, + false, + []string{ + "initialize", + "depositBatch", + }, + []string{}, + }, + { + "ChildMintableERC721Predicate", + gensc.ChildMintableERC721Predicate, + false, + []string{ + "initialize", + }, + []string{}, + }, + { + "RootERC721", + gensc.RootERC721, + false, + []string{ + "setApprovalForAll", + "mint", + }, + []string{}, + }, + { + "ChildERC721Predicate", + gensc.ChildERC721Predicate, + false, + []string{ + "initialize", + "withdrawBatch", + }, + []string{}, + }, + { + "ChildERC721PredicateACL", + gensc.ChildERC721PredicateACL, + false, + []string{ + "initialize", + "withdrawBatch", + }, + []string{}, + }, + { + "RootMintableERC721Predicate", + gensc.RootMintableERC721Predicate, + false, + []string{ + "initialize", + }, + []string{}, + }, + { + "RootMintableERC721PredicateACL", + gensc.RootMintableERC721PredicateACL, + false, + []string{ + "initialize", + }, + []string{}, + }, + { + "ChildERC721", + gensc.ChildERC721, + false, + []string{ + "initialize", + "ownerOf", + }, + []string{}, + }, + { + "CustomSupernetManager", + gensc.CustomSupernetManager, + false, + []string{ + "initialize", + "whitelistValidators", + "register", + "getValidator", + }, + []string{ + "ValidatorRegistered", + "AddedToWhitelist", + }, + }, + { + "StakeManager", + gensc.StakeManager, + false, + []string{ + "initialize", + "registerChildChain", + "stakeFor", + "releaseStakeOf", + "withdrawStake", + "stakeOf", + }, + []string{ + "ChildManagerRegistered", + "StakeAdded", + "StakeWithdrawn", + }, + }, + { + "ValidatorSet", + gensc.ValidatorSet, + false, + []string{ + "commitEpoch", + "unstake", + "initialize", + }, + []string{ + "Transfer", + "WithdrawalRegistered", + "Withdrawal", + }, + }, + { + "RewardPool", + gensc.RewardPool, + false, + []string{ + "initialize", + "distributeRewardFor", + }, + []string{}, + }, + { + "EIP1559Burn", + gensc.EIP1559Burn, + false, + []string{ + "initialize", + }, + []string{}, + }, } generatedData := &generatedData{} for _, c := range cases { + if c.generateConstructor { + if err := generateConstructor(generatedData, c.contractName, c.artifact.Abi.Constructor); err != nil { + log.Fatal(err) + } + } + for _, method := range c.functions { if err := generateFunction(generatedData, c.contractName, c.artifact.Abi.Methods[method]); err != nil { log.Fatal(err) @@ -376,6 +641,52 @@ func ({{.Sig}} *{{.TName}}) ParseLog(log *ethgo.Log) (bool, error) { return nil } +// generateConstruct generates stubs for a smart contract constructor +func generateConstructor(generatedData *generatedData, + contractName string, constructor *abi.Method) error { + methodName := fmt.Sprintf(functionNameFormat, strings.Title(contractName+"Constructor")) + res := []string{} + + _, err := generateType(generatedData, methodName, constructor.Inputs, &res) + if err != nil { + return err + } + + // write encode/decode functions + tmplStr := ` +{{range .Structs}} + {{.}} +{{ end }} + +func ({{.Sig}} *{{.TName}}) Sig() []byte { + return {{.ContractName}}.Abi.Constructor.ID() +} + +func ({{.Sig}} *{{.TName}}) EncodeAbi() ([]byte, error) { + return {{.ContractName}}.Abi.Constructor.Inputs.Encode({{.Sig}}) +} + +func ({{.Sig}} *{{.TName}}) DecodeAbi(buf []byte) error { + return decodeMethod({{.ContractName}}.Abi.Constructor, buf, {{.Sig}}) +}` + + inputs := map[string]interface{}{ + "Structs": res, + "Sig": strings.ToLower(string(methodName[0])), + "ContractName": contractName, + "TName": strings.Title(methodName), + } + + renderedString, err := renderTmpl(tmplStr, inputs) + if err != nil { + return err + } + + generatedData.resultString = append(generatedData.resultString, renderedString) + + return nil +} + // generateFunction generates code for smart contract function and its parameters func generateFunction(generatedData *generatedData, contractName string, method *abi.Method) error { methodName := fmt.Sprintf(functionNameFormat, strings.Title(method.Name+contractName)) diff --git a/consensus/polybft/contractsapi/contractsapi.go b/consensus/polybft/contractsapi/contractsapi.go index dea0cf7a84..3b8dddfdf8 100644 --- a/consensus/polybft/contractsapi/contractsapi.go +++ b/consensus/polybft/contractsapi/contractsapi.go @@ -121,306 +121,6 @@ func (n *NewCommitmentEvent) ParseLog(log *ethgo.Log) (bool, error) { return true, decodeEvent(StateReceiver.Abi.Events["NewCommitment"], log, n) } -type Epoch struct { - StartBlock *big.Int `abi:"startBlock"` - EndBlock *big.Int `abi:"endBlock"` - EpochRoot types.Hash `abi:"epochRoot"` -} - -var EpochABIType = abi.MustNewType("tuple(uint256 startBlock,uint256 endBlock,bytes32 epochRoot)") - -func (e *Epoch) EncodeAbi() ([]byte, error) { - return EpochABIType.Encode(e) -} - -func (e *Epoch) DecodeAbi(buf []byte) error { - return decodeStruct(EpochABIType, buf, &e) -} - -type UptimeData struct { - Validator types.Address `abi:"validator"` - SignedBlocks *big.Int `abi:"signedBlocks"` -} - -var UptimeDataABIType = abi.MustNewType("tuple(address validator,uint256 signedBlocks)") - -func (u *UptimeData) EncodeAbi() ([]byte, error) { - return UptimeDataABIType.Encode(u) -} - -func (u *UptimeData) DecodeAbi(buf []byte) error { - return decodeStruct(UptimeDataABIType, buf, &u) -} - -type Uptime struct { - EpochID *big.Int `abi:"epochId"` - UptimeData []*UptimeData `abi:"uptimeData"` - TotalBlocks *big.Int `abi:"totalBlocks"` -} - -var UptimeABIType = abi.MustNewType("tuple(uint256 epochId,tuple(address validator,uint256 signedBlocks)[] uptimeData,uint256 totalBlocks)") - -func (u *Uptime) EncodeAbi() ([]byte, error) { - return UptimeABIType.Encode(u) -} - -func (u *Uptime) DecodeAbi(buf []byte) error { - return decodeStruct(UptimeABIType, buf, &u) -} - -type CommitEpochChildValidatorSetFn struct { - ID *big.Int `abi:"id"` - Epoch *Epoch `abi:"epoch"` - Uptime *Uptime `abi:"uptime"` -} - -func (c *CommitEpochChildValidatorSetFn) Sig() []byte { - return ChildValidatorSet.Abi.Methods["commitEpoch"].ID() -} - -func (c *CommitEpochChildValidatorSetFn) EncodeAbi() ([]byte, error) { - return ChildValidatorSet.Abi.Methods["commitEpoch"].Encode(c) -} - -func (c *CommitEpochChildValidatorSetFn) DecodeAbi(buf []byte) error { - return decodeMethod(ChildValidatorSet.Abi.Methods["commitEpoch"], buf, c) -} - -type InitStruct struct { - EpochReward *big.Int `abi:"epochReward"` - MinStake *big.Int `abi:"minStake"` - MinDelegation *big.Int `abi:"minDelegation"` - EpochSize *big.Int `abi:"epochSize"` -} - -var InitStructABIType = abi.MustNewType("tuple(uint256 epochReward,uint256 minStake,uint256 minDelegation,uint256 epochSize)") - -func (i *InitStruct) EncodeAbi() ([]byte, error) { - return InitStructABIType.Encode(i) -} - -func (i *InitStruct) DecodeAbi(buf []byte) error { - return decodeStruct(InitStructABIType, buf, &i) -} - -type ValidatorInit struct { - Addr types.Address `abi:"addr"` - Pubkey [4]*big.Int `abi:"pubkey"` - Signature [2]*big.Int `abi:"signature"` - Stake *big.Int `abi:"stake"` -} - -var ValidatorInitABIType = abi.MustNewType("tuple(address addr,uint256[4] pubkey,uint256[2] signature,uint256 stake)") - -func (v *ValidatorInit) EncodeAbi() ([]byte, error) { - return ValidatorInitABIType.Encode(v) -} - -func (v *ValidatorInit) DecodeAbi(buf []byte) error { - return decodeStruct(ValidatorInitABIType, buf, &v) -} - -type InitializeChildValidatorSetFn struct { - Init *InitStruct `abi:"init"` - Validators []*ValidatorInit `abi:"validators"` - NewBls types.Address `abi:"newBls"` - Governance types.Address `abi:"governance"` -} - -func (i *InitializeChildValidatorSetFn) Sig() []byte { - return ChildValidatorSet.Abi.Methods["initialize"].ID() -} - -func (i *InitializeChildValidatorSetFn) EncodeAbi() ([]byte, error) { - return ChildValidatorSet.Abi.Methods["initialize"].Encode(i) -} - -func (i *InitializeChildValidatorSetFn) DecodeAbi(buf []byte) error { - return decodeMethod(ChildValidatorSet.Abi.Methods["initialize"], buf, i) -} - -type AddToWhitelistChildValidatorSetFn struct { - WhitelistAddreses []ethgo.Address `abi:"whitelistAddreses"` -} - -func (a *AddToWhitelistChildValidatorSetFn) Sig() []byte { - return ChildValidatorSet.Abi.Methods["addToWhitelist"].ID() -} - -func (a *AddToWhitelistChildValidatorSetFn) EncodeAbi() ([]byte, error) { - return ChildValidatorSet.Abi.Methods["addToWhitelist"].Encode(a) -} - -func (a *AddToWhitelistChildValidatorSetFn) DecodeAbi(buf []byte) error { - return decodeMethod(ChildValidatorSet.Abi.Methods["addToWhitelist"], buf, a) -} - -type RegisterChildValidatorSetFn struct { - Signature [2]*big.Int `abi:"signature"` - Pubkey [4]*big.Int `abi:"pubkey"` -} - -func (r *RegisterChildValidatorSetFn) Sig() []byte { - return ChildValidatorSet.Abi.Methods["register"].ID() -} - -func (r *RegisterChildValidatorSetFn) EncodeAbi() ([]byte, error) { - return ChildValidatorSet.Abi.Methods["register"].Encode(r) -} - -func (r *RegisterChildValidatorSetFn) DecodeAbi(buf []byte) error { - return decodeMethod(ChildValidatorSet.Abi.Methods["register"], buf, r) -} - -type NewValidatorEvent struct { - Validator types.Address `abi:"validator"` - BlsKey [4]*big.Int `abi:"blsKey"` -} - -func (*NewValidatorEvent) Sig() ethgo.Hash { - return ChildValidatorSet.Abi.Events["NewValidator"].ID() -} - -func (*NewValidatorEvent) Encode(inputs interface{}) ([]byte, error) { - return ChildValidatorSet.Abi.Events["NewValidator"].Inputs.Encode(inputs) -} - -func (n *NewValidatorEvent) ParseLog(log *ethgo.Log) (bool, error) { - if !ChildValidatorSet.Abi.Events["NewValidator"].Match(log) { - return false, nil - } - - return true, decodeEvent(ChildValidatorSet.Abi.Events["NewValidator"], log, n) -} - -type StakedEvent struct { - Validator types.Address `abi:"validator"` - Amount *big.Int `abi:"amount"` -} - -func (*StakedEvent) Sig() ethgo.Hash { - return ChildValidatorSet.Abi.Events["Staked"].ID() -} - -func (*StakedEvent) Encode(inputs interface{}) ([]byte, error) { - return ChildValidatorSet.Abi.Events["Staked"].Inputs.Encode(inputs) -} - -func (s *StakedEvent) ParseLog(log *ethgo.Log) (bool, error) { - if !ChildValidatorSet.Abi.Events["Staked"].Match(log) { - return false, nil - } - - return true, decodeEvent(ChildValidatorSet.Abi.Events["Staked"], log, s) -} - -type DelegatedEvent struct { - Delegator types.Address `abi:"delegator"` - Validator types.Address `abi:"validator"` - Amount *big.Int `abi:"amount"` -} - -func (*DelegatedEvent) Sig() ethgo.Hash { - return ChildValidatorSet.Abi.Events["Delegated"].ID() -} - -func (*DelegatedEvent) Encode(inputs interface{}) ([]byte, error) { - return ChildValidatorSet.Abi.Events["Delegated"].Inputs.Encode(inputs) -} - -func (d *DelegatedEvent) ParseLog(log *ethgo.Log) (bool, error) { - if !ChildValidatorSet.Abi.Events["Delegated"].Match(log) { - return false, nil - } - - return true, decodeEvent(ChildValidatorSet.Abi.Events["Delegated"], log, d) -} - -type UnstakedEvent struct { - Validator types.Address `abi:"validator"` - Amount *big.Int `abi:"amount"` -} - -func (*UnstakedEvent) Sig() ethgo.Hash { - return ChildValidatorSet.Abi.Events["Unstaked"].ID() -} - -func (*UnstakedEvent) Encode(inputs interface{}) ([]byte, error) { - return ChildValidatorSet.Abi.Events["Unstaked"].Inputs.Encode(inputs) -} - -func (u *UnstakedEvent) ParseLog(log *ethgo.Log) (bool, error) { - if !ChildValidatorSet.Abi.Events["Unstaked"].Match(log) { - return false, nil - } - - return true, decodeEvent(ChildValidatorSet.Abi.Events["Unstaked"], log, u) -} - -type UndelegatedEvent struct { - Delegator types.Address `abi:"delegator"` - Validator types.Address `abi:"validator"` - Amount *big.Int `abi:"amount"` -} - -func (*UndelegatedEvent) Sig() ethgo.Hash { - return ChildValidatorSet.Abi.Events["Undelegated"].ID() -} - -func (*UndelegatedEvent) Encode(inputs interface{}) ([]byte, error) { - return ChildValidatorSet.Abi.Events["Undelegated"].Inputs.Encode(inputs) -} - -func (u *UndelegatedEvent) ParseLog(log *ethgo.Log) (bool, error) { - if !ChildValidatorSet.Abi.Events["Undelegated"].Match(log) { - return false, nil - } - - return true, decodeEvent(ChildValidatorSet.Abi.Events["Undelegated"], log, u) -} - -type AddedToWhitelistEvent struct { - Validator types.Address `abi:"validator"` -} - -func (*AddedToWhitelistEvent) Sig() ethgo.Hash { - return ChildValidatorSet.Abi.Events["AddedToWhitelist"].ID() -} - -func (*AddedToWhitelistEvent) Encode(inputs interface{}) ([]byte, error) { - return ChildValidatorSet.Abi.Events["AddedToWhitelist"].Inputs.Encode(inputs) -} - -func (a *AddedToWhitelistEvent) ParseLog(log *ethgo.Log) (bool, error) { - if !ChildValidatorSet.Abi.Events["AddedToWhitelist"].Match(log) { - return false, nil - } - - return true, decodeEvent(ChildValidatorSet.Abi.Events["AddedToWhitelist"], log, a) -} - -type WithdrawalEvent struct { - Account types.Address `abi:"account"` - To types.Address `abi:"to"` - Amount *big.Int `abi:"amount"` -} - -func (*WithdrawalEvent) Sig() ethgo.Hash { - return ChildValidatorSet.Abi.Events["Withdrawal"].ID() -} - -func (*WithdrawalEvent) Encode(inputs interface{}) ([]byte, error) { - return ChildValidatorSet.Abi.Events["Withdrawal"].Inputs.Encode(inputs) -} - -func (w *WithdrawalEvent) ParseLog(log *ethgo.Log) (bool, error) { - if !ChildValidatorSet.Abi.Events["Withdrawal"].Match(log) { - return false, nil - } - - return true, decodeEvent(ChildValidatorSet.Abi.Events["Withdrawal"], log, w) -} - type SyncStateStateSenderFn struct { Receiver types.Address `abi:"receiver"` Data []byte `abi:"data"` @@ -587,6 +287,22 @@ func (g *GetCheckpointBlockCheckpointManagerFn) DecodeAbi(buf []byte) error { return decodeMethod(CheckpointManager.Abi.Methods["getCheckpointBlock"], buf, g) } +type InitializeExitHelperFn struct { + NewCheckpointManager types.Address `abi:"newCheckpointManager"` +} + +func (i *InitializeExitHelperFn) Sig() []byte { + return ExitHelper.Abi.Methods["initialize"].ID() +} + +func (i *InitializeExitHelperFn) EncodeAbi() ([]byte, error) { + return ExitHelper.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeExitHelperFn) DecodeAbi(buf []byte) error { + return decodeMethod(ExitHelper.Abi.Methods["initialize"], buf, i) +} + type ExitExitHelperFn struct { BlockNumber *big.Int `abi:"blockNumber"` LeafIndex *big.Int `abi:"leafIndex"` @@ -644,12 +360,95 @@ func (w *WithdrawToChildERC20PredicateFn) DecodeAbi(buf []byte) error { return decodeMethod(ChildERC20Predicate.Abi.Methods["withdrawTo"], buf, w) } +type InitializeChildERC20PredicateACLFn struct { + NewL2StateSender types.Address `abi:"newL2StateSender"` + NewStateReceiver types.Address `abi:"newStateReceiver"` + NewRootERC20Predicate types.Address `abi:"newRootERC20Predicate"` + NewChildTokenTemplate types.Address `abi:"newChildTokenTemplate"` + NewNativeTokenRootAddress types.Address `abi:"newNativeTokenRootAddress"` + NewUseAllowList bool `abi:"newUseAllowList"` + NewUseBlockList bool `abi:"newUseBlockList"` + NewOwner types.Address `abi:"newOwner"` +} + +func (i *InitializeChildERC20PredicateACLFn) Sig() []byte { + return ChildERC20PredicateACL.Abi.Methods["initialize"].ID() +} + +func (i *InitializeChildERC20PredicateACLFn) EncodeAbi() ([]byte, error) { + return ChildERC20PredicateACL.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeChildERC20PredicateACLFn) DecodeAbi(buf []byte) error { + return decodeMethod(ChildERC20PredicateACL.Abi.Methods["initialize"], buf, i) +} + +type WithdrawToChildERC20PredicateACLFn struct { + ChildToken types.Address `abi:"childToken"` + Receiver types.Address `abi:"receiver"` + Amount *big.Int `abi:"amount"` +} + +func (w *WithdrawToChildERC20PredicateACLFn) Sig() []byte { + return ChildERC20PredicateACL.Abi.Methods["withdrawTo"].ID() +} + +func (w *WithdrawToChildERC20PredicateACLFn) EncodeAbi() ([]byte, error) { + return ChildERC20PredicateACL.Abi.Methods["withdrawTo"].Encode(w) +} + +func (w *WithdrawToChildERC20PredicateACLFn) DecodeAbi(buf []byte) error { + return decodeMethod(ChildERC20PredicateACL.Abi.Methods["withdrawTo"], buf, w) +} + +type InitializeRootMintableERC20PredicateFn struct { + NewL2StateSender types.Address `abi:"newL2StateSender"` + NewStateReceiver types.Address `abi:"newStateReceiver"` + NewChildERC20Predicate types.Address `abi:"newChildERC20Predicate"` + NewChildTokenTemplate types.Address `abi:"newChildTokenTemplate"` +} + +func (i *InitializeRootMintableERC20PredicateFn) Sig() []byte { + return RootMintableERC20Predicate.Abi.Methods["initialize"].ID() +} + +func (i *InitializeRootMintableERC20PredicateFn) EncodeAbi() ([]byte, error) { + return RootMintableERC20Predicate.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeRootMintableERC20PredicateFn) DecodeAbi(buf []byte) error { + return decodeMethod(RootMintableERC20Predicate.Abi.Methods["initialize"], buf, i) +} + +type InitializeRootMintableERC20PredicateACLFn struct { + NewL2StateSender types.Address `abi:"newL2StateSender"` + NewStateReceiver types.Address `abi:"newStateReceiver"` + NewChildERC20Predicate types.Address `abi:"newChildERC20Predicate"` + NewChildTokenTemplate types.Address `abi:"newChildTokenTemplate"` + NewUseAllowList bool `abi:"newUseAllowList"` + NewUseBlockList bool `abi:"newUseBlockList"` + NewOwner types.Address `abi:"newOwner"` +} + +func (i *InitializeRootMintableERC20PredicateACLFn) Sig() []byte { + return RootMintableERC20PredicateACL.Abi.Methods["initialize"].ID() +} + +func (i *InitializeRootMintableERC20PredicateACLFn) EncodeAbi() ([]byte, error) { + return RootMintableERC20PredicateACL.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeRootMintableERC20PredicateACLFn) DecodeAbi(buf []byte) error { + return decodeMethod(RootMintableERC20PredicateACL.Abi.Methods["initialize"], buf, i) +} + type InitializeNativeERC20Fn struct { - Predicate_ types.Address `abi:"predicate_"` - RootToken_ types.Address `abi:"rootToken_"` - Name_ string `abi:"name_"` - Symbol_ string `abi:"symbol_"` - Decimals_ uint8 `abi:"decimals_"` + Predicate_ types.Address `abi:"predicate_"` + RootToken_ types.Address `abi:"rootToken_"` + Name_ string `abi:"name_"` + Symbol_ string `abi:"symbol_"` + Decimals_ uint8 `abi:"decimals_"` + TokenSupply_ *big.Int `abi:"tokenSupply_"` } func (i *InitializeNativeERC20Fn) Sig() []byte { @@ -665,12 +464,13 @@ func (i *InitializeNativeERC20Fn) DecodeAbi(buf []byte) error { } type InitializeNativeERC20MintableFn struct { - Predicate_ types.Address `abi:"predicate_"` - Owner_ types.Address `abi:"owner_"` - RootToken_ types.Address `abi:"rootToken_"` - Name_ string `abi:"name_"` - Symbol_ string `abi:"symbol_"` - Decimals_ uint8 `abi:"decimals_"` + Predicate_ types.Address `abi:"predicate_"` + Owner_ types.Address `abi:"owner_"` + RootToken_ types.Address `abi:"rootToken_"` + Name_ string `abi:"name_"` + Symbol_ string `abi:"symbol_"` + Decimals_ uint8 `abi:"decimals_"` + TokenSupply_ *big.Int `abi:"tokenSupply_"` } func (i *InitializeNativeERC20MintableFn) Sig() []byte { @@ -723,17 +523,94 @@ func (d *DepositToRootERC20PredicateFn) DecodeAbi(buf []byte) error { return decodeMethod(RootERC20Predicate.Abi.Methods["depositTo"], buf, d) } -type ApproveRootERC20Fn struct { - Spender types.Address `abi:"spender"` - Amount *big.Int `abi:"amount"` +type TokenMappedEvent struct { + RootToken types.Address `abi:"rootToken"` + ChildToken types.Address `abi:"childToken"` } -func (a *ApproveRootERC20Fn) Sig() []byte { - return RootERC20.Abi.Methods["approve"].ID() +func (*TokenMappedEvent) Sig() ethgo.Hash { + return RootERC20Predicate.Abi.Events["TokenMapped"].ID() } -func (a *ApproveRootERC20Fn) EncodeAbi() ([]byte, error) { - return RootERC20.Abi.Methods["approve"].Encode(a) +func (*TokenMappedEvent) Encode(inputs interface{}) ([]byte, error) { + return RootERC20Predicate.Abi.Events["TokenMapped"].Inputs.Encode(inputs) +} + +func (t *TokenMappedEvent) ParseLog(log *ethgo.Log) (bool, error) { + if !RootERC20Predicate.Abi.Events["TokenMapped"].Match(log) { + return false, nil + } + + return true, decodeEvent(RootERC20Predicate.Abi.Events["TokenMapped"], log, t) +} + +type InitializeChildMintableERC20PredicateFn struct { + NewStateSender types.Address `abi:"newStateSender"` + NewExitHelper types.Address `abi:"newExitHelper"` + NewRootERC20Predicate types.Address `abi:"newRootERC20Predicate"` + NewChildTokenTemplate types.Address `abi:"newChildTokenTemplate"` +} + +func (i *InitializeChildMintableERC20PredicateFn) Sig() []byte { + return ChildMintableERC20Predicate.Abi.Methods["initialize"].ID() +} + +func (i *InitializeChildMintableERC20PredicateFn) EncodeAbi() ([]byte, error) { + return ChildMintableERC20Predicate.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeChildMintableERC20PredicateFn) DecodeAbi(buf []byte) error { + return decodeMethod(ChildMintableERC20Predicate.Abi.Methods["initialize"], buf, i) +} + +type MintableTokenMappedEvent struct { + RootToken types.Address `abi:"rootToken"` + ChildToken types.Address `abi:"childToken"` +} + +func (*MintableTokenMappedEvent) Sig() ethgo.Hash { + return ChildMintableERC20Predicate.Abi.Events["MintableTokenMapped"].ID() +} + +func (*MintableTokenMappedEvent) Encode(inputs interface{}) ([]byte, error) { + return ChildMintableERC20Predicate.Abi.Events["MintableTokenMapped"].Inputs.Encode(inputs) +} + +func (m *MintableTokenMappedEvent) ParseLog(log *ethgo.Log) (bool, error) { + if !ChildMintableERC20Predicate.Abi.Events["MintableTokenMapped"].Match(log) { + return false, nil + } + + return true, decodeEvent(ChildMintableERC20Predicate.Abi.Events["MintableTokenMapped"], log, m) +} + +type BalanceOfRootERC20Fn struct { + Account types.Address `abi:"account"` +} + +func (b *BalanceOfRootERC20Fn) Sig() []byte { + return RootERC20.Abi.Methods["balanceOf"].ID() +} + +func (b *BalanceOfRootERC20Fn) EncodeAbi() ([]byte, error) { + return RootERC20.Abi.Methods["balanceOf"].Encode(b) +} + +func (b *BalanceOfRootERC20Fn) DecodeAbi(buf []byte) error { + return decodeMethod(RootERC20.Abi.Methods["balanceOf"], buf, b) +} + +type ApproveRootERC20Fn struct { + Spender types.Address `abi:"spender"` + Amount *big.Int `abi:"amount"` +} + +func (a *ApproveRootERC20Fn) Sig() []byte { + return RootERC20.Abi.Methods["approve"].ID() +} + +func (a *ApproveRootERC20Fn) EncodeAbi() ([]byte, error) { + return RootERC20.Abi.Methods["approve"].Encode(a) } func (a *ApproveRootERC20Fn) DecodeAbi(buf []byte) error { @@ -756,3 +633,1022 @@ func (m *MintRootERC20Fn) EncodeAbi() ([]byte, error) { func (m *MintRootERC20Fn) DecodeAbi(buf []byte) error { return decodeMethod(RootERC20.Abi.Methods["mint"], buf, m) } + +type InitializeRootERC1155PredicateFn struct { + NewStateSender types.Address `abi:"newStateSender"` + NewExitHelper types.Address `abi:"newExitHelper"` + NewChildERC1155Predicate types.Address `abi:"newChildERC1155Predicate"` + NewChildTokenTemplate types.Address `abi:"newChildTokenTemplate"` +} + +func (i *InitializeRootERC1155PredicateFn) Sig() []byte { + return RootERC1155Predicate.Abi.Methods["initialize"].ID() +} + +func (i *InitializeRootERC1155PredicateFn) EncodeAbi() ([]byte, error) { + return RootERC1155Predicate.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeRootERC1155PredicateFn) DecodeAbi(buf []byte) error { + return decodeMethod(RootERC1155Predicate.Abi.Methods["initialize"], buf, i) +} + +type DepositBatchRootERC1155PredicateFn struct { + RootToken types.Address `abi:"rootToken"` + Receivers []ethgo.Address `abi:"receivers"` + TokenIDs []*big.Int `abi:"tokenIds"` + Amounts []*big.Int `abi:"amounts"` +} + +func (d *DepositBatchRootERC1155PredicateFn) Sig() []byte { + return RootERC1155Predicate.Abi.Methods["depositBatch"].ID() +} + +func (d *DepositBatchRootERC1155PredicateFn) EncodeAbi() ([]byte, error) { + return RootERC1155Predicate.Abi.Methods["depositBatch"].Encode(d) +} + +func (d *DepositBatchRootERC1155PredicateFn) DecodeAbi(buf []byte) error { + return decodeMethod(RootERC1155Predicate.Abi.Methods["depositBatch"], buf, d) +} + +type InitializeChildMintableERC1155PredicateFn struct { + NewStateSender types.Address `abi:"newStateSender"` + NewExitHelper types.Address `abi:"newExitHelper"` + NewRootERC1155Predicate types.Address `abi:"newRootERC1155Predicate"` + NewChildTokenTemplate types.Address `abi:"newChildTokenTemplate"` +} + +func (i *InitializeChildMintableERC1155PredicateFn) Sig() []byte { + return ChildMintableERC1155Predicate.Abi.Methods["initialize"].ID() +} + +func (i *InitializeChildMintableERC1155PredicateFn) EncodeAbi() ([]byte, error) { + return ChildMintableERC1155Predicate.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeChildMintableERC1155PredicateFn) DecodeAbi(buf []byte) error { + return decodeMethod(ChildMintableERC1155Predicate.Abi.Methods["initialize"], buf, i) +} + +type SetApprovalForAllRootERC1155Fn struct { + Operator types.Address `abi:"operator"` + Approved bool `abi:"approved"` +} + +func (s *SetApprovalForAllRootERC1155Fn) Sig() []byte { + return RootERC1155.Abi.Methods["setApprovalForAll"].ID() +} + +func (s *SetApprovalForAllRootERC1155Fn) EncodeAbi() ([]byte, error) { + return RootERC1155.Abi.Methods["setApprovalForAll"].Encode(s) +} + +func (s *SetApprovalForAllRootERC1155Fn) DecodeAbi(buf []byte) error { + return decodeMethod(RootERC1155.Abi.Methods["setApprovalForAll"], buf, s) +} + +type MintBatchRootERC1155Fn struct { + To types.Address `abi:"to"` + IDs []*big.Int `abi:"ids"` + Amounts []*big.Int `abi:"amounts"` + Data []byte `abi:"data"` +} + +func (m *MintBatchRootERC1155Fn) Sig() []byte { + return RootERC1155.Abi.Methods["mintBatch"].ID() +} + +func (m *MintBatchRootERC1155Fn) EncodeAbi() ([]byte, error) { + return RootERC1155.Abi.Methods["mintBatch"].Encode(m) +} + +func (m *MintBatchRootERC1155Fn) DecodeAbi(buf []byte) error { + return decodeMethod(RootERC1155.Abi.Methods["mintBatch"], buf, m) +} + +type BalanceOfRootERC1155Fn struct { + Account types.Address `abi:"account"` + ID *big.Int `abi:"id"` +} + +func (b *BalanceOfRootERC1155Fn) Sig() []byte { + return RootERC1155.Abi.Methods["balanceOf"].ID() +} + +func (b *BalanceOfRootERC1155Fn) EncodeAbi() ([]byte, error) { + return RootERC1155.Abi.Methods["balanceOf"].Encode(b) +} + +func (b *BalanceOfRootERC1155Fn) DecodeAbi(buf []byte) error { + return decodeMethod(RootERC1155.Abi.Methods["balanceOf"], buf, b) +} + +type InitializeChildERC1155PredicateFn struct { + NewL2StateSender types.Address `abi:"newL2StateSender"` + NewStateReceiver types.Address `abi:"newStateReceiver"` + NewRootERC1155Predicate types.Address `abi:"newRootERC1155Predicate"` + NewChildTokenTemplate types.Address `abi:"newChildTokenTemplate"` +} + +func (i *InitializeChildERC1155PredicateFn) Sig() []byte { + return ChildERC1155Predicate.Abi.Methods["initialize"].ID() +} + +func (i *InitializeChildERC1155PredicateFn) EncodeAbi() ([]byte, error) { + return ChildERC1155Predicate.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeChildERC1155PredicateFn) DecodeAbi(buf []byte) error { + return decodeMethod(ChildERC1155Predicate.Abi.Methods["initialize"], buf, i) +} + +type WithdrawBatchChildERC1155PredicateFn struct { + ChildToken types.Address `abi:"childToken"` + Receivers []ethgo.Address `abi:"receivers"` + TokenIDs []*big.Int `abi:"tokenIds"` + Amounts []*big.Int `abi:"amounts"` +} + +func (w *WithdrawBatchChildERC1155PredicateFn) Sig() []byte { + return ChildERC1155Predicate.Abi.Methods["withdrawBatch"].ID() +} + +func (w *WithdrawBatchChildERC1155PredicateFn) EncodeAbi() ([]byte, error) { + return ChildERC1155Predicate.Abi.Methods["withdrawBatch"].Encode(w) +} + +func (w *WithdrawBatchChildERC1155PredicateFn) DecodeAbi(buf []byte) error { + return decodeMethod(ChildERC1155Predicate.Abi.Methods["withdrawBatch"], buf, w) +} + +type InitializeChildERC1155PredicateACLFn struct { + NewL2StateSender types.Address `abi:"newL2StateSender"` + NewStateReceiver types.Address `abi:"newStateReceiver"` + NewRootERC1155Predicate types.Address `abi:"newRootERC1155Predicate"` + NewChildTokenTemplate types.Address `abi:"newChildTokenTemplate"` + NewUseAllowList bool `abi:"newUseAllowList"` + NewUseBlockList bool `abi:"newUseBlockList"` + NewOwner types.Address `abi:"newOwner"` +} + +func (i *InitializeChildERC1155PredicateACLFn) Sig() []byte { + return ChildERC1155PredicateACL.Abi.Methods["initialize"].ID() +} + +func (i *InitializeChildERC1155PredicateACLFn) EncodeAbi() ([]byte, error) { + return ChildERC1155PredicateACL.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeChildERC1155PredicateACLFn) DecodeAbi(buf []byte) error { + return decodeMethod(ChildERC1155PredicateACL.Abi.Methods["initialize"], buf, i) +} + +type WithdrawBatchChildERC1155PredicateACLFn struct { + ChildToken types.Address `abi:"childToken"` + Receivers []ethgo.Address `abi:"receivers"` + TokenIDs []*big.Int `abi:"tokenIds"` + Amounts []*big.Int `abi:"amounts"` +} + +func (w *WithdrawBatchChildERC1155PredicateACLFn) Sig() []byte { + return ChildERC1155PredicateACL.Abi.Methods["withdrawBatch"].ID() +} + +func (w *WithdrawBatchChildERC1155PredicateACLFn) EncodeAbi() ([]byte, error) { + return ChildERC1155PredicateACL.Abi.Methods["withdrawBatch"].Encode(w) +} + +func (w *WithdrawBatchChildERC1155PredicateACLFn) DecodeAbi(buf []byte) error { + return decodeMethod(ChildERC1155PredicateACL.Abi.Methods["withdrawBatch"], buf, w) +} + +type InitializeRootMintableERC1155PredicateFn struct { + NewL2StateSender types.Address `abi:"newL2StateSender"` + NewStateReceiver types.Address `abi:"newStateReceiver"` + NewChildERC1155Predicate types.Address `abi:"newChildERC1155Predicate"` + NewChildTokenTemplate types.Address `abi:"newChildTokenTemplate"` +} + +func (i *InitializeRootMintableERC1155PredicateFn) Sig() []byte { + return RootMintableERC1155Predicate.Abi.Methods["initialize"].ID() +} + +func (i *InitializeRootMintableERC1155PredicateFn) EncodeAbi() ([]byte, error) { + return RootMintableERC1155Predicate.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeRootMintableERC1155PredicateFn) DecodeAbi(buf []byte) error { + return decodeMethod(RootMintableERC1155Predicate.Abi.Methods["initialize"], buf, i) +} + +type InitializeRootMintableERC1155PredicateACLFn struct { + NewL2StateSender types.Address `abi:"newL2StateSender"` + NewStateReceiver types.Address `abi:"newStateReceiver"` + NewChildERC1155Predicate types.Address `abi:"newChildERC1155Predicate"` + NewChildTokenTemplate types.Address `abi:"newChildTokenTemplate"` + NewUseAllowList bool `abi:"newUseAllowList"` + NewUseBlockList bool `abi:"newUseBlockList"` + NewOwner types.Address `abi:"newOwner"` +} + +func (i *InitializeRootMintableERC1155PredicateACLFn) Sig() []byte { + return RootMintableERC1155PredicateACL.Abi.Methods["initialize"].ID() +} + +func (i *InitializeRootMintableERC1155PredicateACLFn) EncodeAbi() ([]byte, error) { + return RootMintableERC1155PredicateACL.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeRootMintableERC1155PredicateACLFn) DecodeAbi(buf []byte) error { + return decodeMethod(RootMintableERC1155PredicateACL.Abi.Methods["initialize"], buf, i) +} + +type L2MintableTokenMappedEvent struct { + RootToken types.Address `abi:"rootToken"` + ChildToken types.Address `abi:"childToken"` +} + +func (*L2MintableTokenMappedEvent) Sig() ethgo.Hash { + return RootMintableERC1155PredicateACL.Abi.Events["L2MintableTokenMapped"].ID() +} + +func (*L2MintableTokenMappedEvent) Encode(inputs interface{}) ([]byte, error) { + return RootMintableERC1155PredicateACL.Abi.Events["L2MintableTokenMapped"].Inputs.Encode(inputs) +} + +func (l *L2MintableTokenMappedEvent) ParseLog(log *ethgo.Log) (bool, error) { + if !RootMintableERC1155PredicateACL.Abi.Events["L2MintableTokenMapped"].Match(log) { + return false, nil + } + + return true, decodeEvent(RootMintableERC1155PredicateACL.Abi.Events["L2MintableTokenMapped"], log, l) +} + +type InitializeChildERC1155Fn struct { + RootToken_ types.Address `abi:"rootToken_"` + Uri_ string `abi:"uri_"` +} + +func (i *InitializeChildERC1155Fn) Sig() []byte { + return ChildERC1155.Abi.Methods["initialize"].ID() +} + +func (i *InitializeChildERC1155Fn) EncodeAbi() ([]byte, error) { + return ChildERC1155.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeChildERC1155Fn) DecodeAbi(buf []byte) error { + return decodeMethod(ChildERC1155.Abi.Methods["initialize"], buf, i) +} + +type BalanceOfChildERC1155Fn struct { + Account types.Address `abi:"account"` + ID *big.Int `abi:"id"` +} + +func (b *BalanceOfChildERC1155Fn) Sig() []byte { + return ChildERC1155.Abi.Methods["balanceOf"].ID() +} + +func (b *BalanceOfChildERC1155Fn) EncodeAbi() ([]byte, error) { + return ChildERC1155.Abi.Methods["balanceOf"].Encode(b) +} + +func (b *BalanceOfChildERC1155Fn) DecodeAbi(buf []byte) error { + return decodeMethod(ChildERC1155.Abi.Methods["balanceOf"], buf, b) +} + +type InitializeRootERC721PredicateFn struct { + NewStateSender types.Address `abi:"newStateSender"` + NewExitHelper types.Address `abi:"newExitHelper"` + NewChildERC721Predicate types.Address `abi:"newChildERC721Predicate"` + NewChildTokenTemplate types.Address `abi:"newChildTokenTemplate"` +} + +func (i *InitializeRootERC721PredicateFn) Sig() []byte { + return RootERC721Predicate.Abi.Methods["initialize"].ID() +} + +func (i *InitializeRootERC721PredicateFn) EncodeAbi() ([]byte, error) { + return RootERC721Predicate.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeRootERC721PredicateFn) DecodeAbi(buf []byte) error { + return decodeMethod(RootERC721Predicate.Abi.Methods["initialize"], buf, i) +} + +type DepositBatchRootERC721PredicateFn struct { + RootToken types.Address `abi:"rootToken"` + Receivers []ethgo.Address `abi:"receivers"` + TokenIDs []*big.Int `abi:"tokenIds"` +} + +func (d *DepositBatchRootERC721PredicateFn) Sig() []byte { + return RootERC721Predicate.Abi.Methods["depositBatch"].ID() +} + +func (d *DepositBatchRootERC721PredicateFn) EncodeAbi() ([]byte, error) { + return RootERC721Predicate.Abi.Methods["depositBatch"].Encode(d) +} + +func (d *DepositBatchRootERC721PredicateFn) DecodeAbi(buf []byte) error { + return decodeMethod(RootERC721Predicate.Abi.Methods["depositBatch"], buf, d) +} + +type InitializeChildMintableERC721PredicateFn struct { + NewStateSender types.Address `abi:"newStateSender"` + NewExitHelper types.Address `abi:"newExitHelper"` + NewRootERC721Predicate types.Address `abi:"newRootERC721Predicate"` + NewChildTokenTemplate types.Address `abi:"newChildTokenTemplate"` +} + +func (i *InitializeChildMintableERC721PredicateFn) Sig() []byte { + return ChildMintableERC721Predicate.Abi.Methods["initialize"].ID() +} + +func (i *InitializeChildMintableERC721PredicateFn) EncodeAbi() ([]byte, error) { + return ChildMintableERC721Predicate.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeChildMintableERC721PredicateFn) DecodeAbi(buf []byte) error { + return decodeMethod(ChildMintableERC721Predicate.Abi.Methods["initialize"], buf, i) +} + +type SetApprovalForAllRootERC721Fn struct { + Operator types.Address `abi:"operator"` + Approved bool `abi:"approved"` +} + +func (s *SetApprovalForAllRootERC721Fn) Sig() []byte { + return RootERC721.Abi.Methods["setApprovalForAll"].ID() +} + +func (s *SetApprovalForAllRootERC721Fn) EncodeAbi() ([]byte, error) { + return RootERC721.Abi.Methods["setApprovalForAll"].Encode(s) +} + +func (s *SetApprovalForAllRootERC721Fn) DecodeAbi(buf []byte) error { + return decodeMethod(RootERC721.Abi.Methods["setApprovalForAll"], buf, s) +} + +type MintRootERC721Fn struct { + To types.Address `abi:"to"` +} + +func (m *MintRootERC721Fn) Sig() []byte { + return RootERC721.Abi.Methods["mint"].ID() +} + +func (m *MintRootERC721Fn) EncodeAbi() ([]byte, error) { + return RootERC721.Abi.Methods["mint"].Encode(m) +} + +func (m *MintRootERC721Fn) DecodeAbi(buf []byte) error { + return decodeMethod(RootERC721.Abi.Methods["mint"], buf, m) +} + +type InitializeChildERC721PredicateFn struct { + NewL2StateSender types.Address `abi:"newL2StateSender"` + NewStateReceiver types.Address `abi:"newStateReceiver"` + NewRootERC721Predicate types.Address `abi:"newRootERC721Predicate"` + NewChildTokenTemplate types.Address `abi:"newChildTokenTemplate"` +} + +func (i *InitializeChildERC721PredicateFn) Sig() []byte { + return ChildERC721Predicate.Abi.Methods["initialize"].ID() +} + +func (i *InitializeChildERC721PredicateFn) EncodeAbi() ([]byte, error) { + return ChildERC721Predicate.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeChildERC721PredicateFn) DecodeAbi(buf []byte) error { + return decodeMethod(ChildERC721Predicate.Abi.Methods["initialize"], buf, i) +} + +type WithdrawBatchChildERC721PredicateFn struct { + ChildToken types.Address `abi:"childToken"` + Receivers []ethgo.Address `abi:"receivers"` + TokenIDs []*big.Int `abi:"tokenIds"` +} + +func (w *WithdrawBatchChildERC721PredicateFn) Sig() []byte { + return ChildERC721Predicate.Abi.Methods["withdrawBatch"].ID() +} + +func (w *WithdrawBatchChildERC721PredicateFn) EncodeAbi() ([]byte, error) { + return ChildERC721Predicate.Abi.Methods["withdrawBatch"].Encode(w) +} + +func (w *WithdrawBatchChildERC721PredicateFn) DecodeAbi(buf []byte) error { + return decodeMethod(ChildERC721Predicate.Abi.Methods["withdrawBatch"], buf, w) +} + +type InitializeChildERC721PredicateACLFn struct { + NewL2StateSender types.Address `abi:"newL2StateSender"` + NewStateReceiver types.Address `abi:"newStateReceiver"` + NewRootERC721Predicate types.Address `abi:"newRootERC721Predicate"` + NewChildTokenTemplate types.Address `abi:"newChildTokenTemplate"` + NewUseAllowList bool `abi:"newUseAllowList"` + NewUseBlockList bool `abi:"newUseBlockList"` + NewOwner types.Address `abi:"newOwner"` +} + +func (i *InitializeChildERC721PredicateACLFn) Sig() []byte { + return ChildERC721PredicateACL.Abi.Methods["initialize"].ID() +} + +func (i *InitializeChildERC721PredicateACLFn) EncodeAbi() ([]byte, error) { + return ChildERC721PredicateACL.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeChildERC721PredicateACLFn) DecodeAbi(buf []byte) error { + return decodeMethod(ChildERC721PredicateACL.Abi.Methods["initialize"], buf, i) +} + +type WithdrawBatchChildERC721PredicateACLFn struct { + ChildToken types.Address `abi:"childToken"` + Receivers []ethgo.Address `abi:"receivers"` + TokenIDs []*big.Int `abi:"tokenIds"` +} + +func (w *WithdrawBatchChildERC721PredicateACLFn) Sig() []byte { + return ChildERC721PredicateACL.Abi.Methods["withdrawBatch"].ID() +} + +func (w *WithdrawBatchChildERC721PredicateACLFn) EncodeAbi() ([]byte, error) { + return ChildERC721PredicateACL.Abi.Methods["withdrawBatch"].Encode(w) +} + +func (w *WithdrawBatchChildERC721PredicateACLFn) DecodeAbi(buf []byte) error { + return decodeMethod(ChildERC721PredicateACL.Abi.Methods["withdrawBatch"], buf, w) +} + +type InitializeRootMintableERC721PredicateFn struct { + NewL2StateSender types.Address `abi:"newL2StateSender"` + NewStateReceiver types.Address `abi:"newStateReceiver"` + NewChildERC721Predicate types.Address `abi:"newChildERC721Predicate"` + NewChildTokenTemplate types.Address `abi:"newChildTokenTemplate"` +} + +func (i *InitializeRootMintableERC721PredicateFn) Sig() []byte { + return RootMintableERC721Predicate.Abi.Methods["initialize"].ID() +} + +func (i *InitializeRootMintableERC721PredicateFn) EncodeAbi() ([]byte, error) { + return RootMintableERC721Predicate.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeRootMintableERC721PredicateFn) DecodeAbi(buf []byte) error { + return decodeMethod(RootMintableERC721Predicate.Abi.Methods["initialize"], buf, i) +} + +type InitializeRootMintableERC721PredicateACLFn struct { + NewL2StateSender types.Address `abi:"newL2StateSender"` + NewStateReceiver types.Address `abi:"newStateReceiver"` + NewChildERC721Predicate types.Address `abi:"newChildERC721Predicate"` + NewChildTokenTemplate types.Address `abi:"newChildTokenTemplate"` + NewUseAllowList bool `abi:"newUseAllowList"` + NewUseBlockList bool `abi:"newUseBlockList"` + NewOwner types.Address `abi:"newOwner"` +} + +func (i *InitializeRootMintableERC721PredicateACLFn) Sig() []byte { + return RootMintableERC721PredicateACL.Abi.Methods["initialize"].ID() +} + +func (i *InitializeRootMintableERC721PredicateACLFn) EncodeAbi() ([]byte, error) { + return RootMintableERC721PredicateACL.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeRootMintableERC721PredicateACLFn) DecodeAbi(buf []byte) error { + return decodeMethod(RootMintableERC721PredicateACL.Abi.Methods["initialize"], buf, i) +} + +type InitializeChildERC721Fn struct { + RootToken_ types.Address `abi:"rootToken_"` + Name_ string `abi:"name_"` + Symbol_ string `abi:"symbol_"` +} + +func (i *InitializeChildERC721Fn) Sig() []byte { + return ChildERC721.Abi.Methods["initialize"].ID() +} + +func (i *InitializeChildERC721Fn) EncodeAbi() ([]byte, error) { + return ChildERC721.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeChildERC721Fn) DecodeAbi(buf []byte) error { + return decodeMethod(ChildERC721.Abi.Methods["initialize"], buf, i) +} + +type OwnerOfChildERC721Fn struct { + TokenID *big.Int `abi:"tokenId"` +} + +func (o *OwnerOfChildERC721Fn) Sig() []byte { + return ChildERC721.Abi.Methods["ownerOf"].ID() +} + +func (o *OwnerOfChildERC721Fn) EncodeAbi() ([]byte, error) { + return ChildERC721.Abi.Methods["ownerOf"].Encode(o) +} + +func (o *OwnerOfChildERC721Fn) DecodeAbi(buf []byte) error { + return decodeMethod(ChildERC721.Abi.Methods["ownerOf"], buf, o) +} + +type InitializeCustomSupernetManagerFn struct { + NewStakeManager types.Address `abi:"newStakeManager"` + NewBls types.Address `abi:"newBls"` + NewStateSender types.Address `abi:"newStateSender"` + NewMatic types.Address `abi:"newMatic"` + NewChildValidatorSet types.Address `abi:"newChildValidatorSet"` + NewExitHelper types.Address `abi:"newExitHelper"` + NewDomain string `abi:"newDomain"` +} + +func (i *InitializeCustomSupernetManagerFn) Sig() []byte { + return CustomSupernetManager.Abi.Methods["initialize"].ID() +} + +func (i *InitializeCustomSupernetManagerFn) EncodeAbi() ([]byte, error) { + return CustomSupernetManager.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeCustomSupernetManagerFn) DecodeAbi(buf []byte) error { + return decodeMethod(CustomSupernetManager.Abi.Methods["initialize"], buf, i) +} + +type WhitelistValidatorsCustomSupernetManagerFn struct { + Validators_ []ethgo.Address `abi:"validators_"` +} + +func (w *WhitelistValidatorsCustomSupernetManagerFn) Sig() []byte { + return CustomSupernetManager.Abi.Methods["whitelistValidators"].ID() +} + +func (w *WhitelistValidatorsCustomSupernetManagerFn) EncodeAbi() ([]byte, error) { + return CustomSupernetManager.Abi.Methods["whitelistValidators"].Encode(w) +} + +func (w *WhitelistValidatorsCustomSupernetManagerFn) DecodeAbi(buf []byte) error { + return decodeMethod(CustomSupernetManager.Abi.Methods["whitelistValidators"], buf, w) +} + +type RegisterCustomSupernetManagerFn struct { + Signature [2]*big.Int `abi:"signature"` + Pubkey [4]*big.Int `abi:"pubkey"` +} + +func (r *RegisterCustomSupernetManagerFn) Sig() []byte { + return CustomSupernetManager.Abi.Methods["register"].ID() +} + +func (r *RegisterCustomSupernetManagerFn) EncodeAbi() ([]byte, error) { + return CustomSupernetManager.Abi.Methods["register"].Encode(r) +} + +func (r *RegisterCustomSupernetManagerFn) DecodeAbi(buf []byte) error { + return decodeMethod(CustomSupernetManager.Abi.Methods["register"], buf, r) +} + +type GetValidatorCustomSupernetManagerFn struct { + Validator_ types.Address `abi:"validator_"` +} + +func (g *GetValidatorCustomSupernetManagerFn) Sig() []byte { + return CustomSupernetManager.Abi.Methods["getValidator"].ID() +} + +func (g *GetValidatorCustomSupernetManagerFn) EncodeAbi() ([]byte, error) { + return CustomSupernetManager.Abi.Methods["getValidator"].Encode(g) +} + +func (g *GetValidatorCustomSupernetManagerFn) DecodeAbi(buf []byte) error { + return decodeMethod(CustomSupernetManager.Abi.Methods["getValidator"], buf, g) +} + +type ValidatorRegisteredEvent struct { + Validator types.Address `abi:"validator"` + BlsKey [4]*big.Int `abi:"blsKey"` +} + +func (*ValidatorRegisteredEvent) Sig() ethgo.Hash { + return CustomSupernetManager.Abi.Events["ValidatorRegistered"].ID() +} + +func (*ValidatorRegisteredEvent) Encode(inputs interface{}) ([]byte, error) { + return CustomSupernetManager.Abi.Events["ValidatorRegistered"].Inputs.Encode(inputs) +} + +func (v *ValidatorRegisteredEvent) ParseLog(log *ethgo.Log) (bool, error) { + if !CustomSupernetManager.Abi.Events["ValidatorRegistered"].Match(log) { + return false, nil + } + + return true, decodeEvent(CustomSupernetManager.Abi.Events["ValidatorRegistered"], log, v) +} + +type AddedToWhitelistEvent struct { + Validator types.Address `abi:"validator"` +} + +func (*AddedToWhitelistEvent) Sig() ethgo.Hash { + return CustomSupernetManager.Abi.Events["AddedToWhitelist"].ID() +} + +func (*AddedToWhitelistEvent) Encode(inputs interface{}) ([]byte, error) { + return CustomSupernetManager.Abi.Events["AddedToWhitelist"].Inputs.Encode(inputs) +} + +func (a *AddedToWhitelistEvent) ParseLog(log *ethgo.Log) (bool, error) { + if !CustomSupernetManager.Abi.Events["AddedToWhitelist"].Match(log) { + return false, nil + } + + return true, decodeEvent(CustomSupernetManager.Abi.Events["AddedToWhitelist"], log, a) +} + +type InitializeStakeManagerFn struct { + NewMatic types.Address `abi:"newMatic"` +} + +func (i *InitializeStakeManagerFn) Sig() []byte { + return StakeManager.Abi.Methods["initialize"].ID() +} + +func (i *InitializeStakeManagerFn) EncodeAbi() ([]byte, error) { + return StakeManager.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeStakeManagerFn) DecodeAbi(buf []byte) error { + return decodeMethod(StakeManager.Abi.Methods["initialize"], buf, i) +} + +type RegisterChildChainStakeManagerFn struct { + Manager types.Address `abi:"manager"` +} + +func (r *RegisterChildChainStakeManagerFn) Sig() []byte { + return StakeManager.Abi.Methods["registerChildChain"].ID() +} + +func (r *RegisterChildChainStakeManagerFn) EncodeAbi() ([]byte, error) { + return StakeManager.Abi.Methods["registerChildChain"].Encode(r) +} + +func (r *RegisterChildChainStakeManagerFn) DecodeAbi(buf []byte) error { + return decodeMethod(StakeManager.Abi.Methods["registerChildChain"], buf, r) +} + +type StakeForStakeManagerFn struct { + ID *big.Int `abi:"id"` + Amount *big.Int `abi:"amount"` +} + +func (s *StakeForStakeManagerFn) Sig() []byte { + return StakeManager.Abi.Methods["stakeFor"].ID() +} + +func (s *StakeForStakeManagerFn) EncodeAbi() ([]byte, error) { + return StakeManager.Abi.Methods["stakeFor"].Encode(s) +} + +func (s *StakeForStakeManagerFn) DecodeAbi(buf []byte) error { + return decodeMethod(StakeManager.Abi.Methods["stakeFor"], buf, s) +} + +type ReleaseStakeOfStakeManagerFn struct { + Validator types.Address `abi:"validator"` + Amount *big.Int `abi:"amount"` +} + +func (r *ReleaseStakeOfStakeManagerFn) Sig() []byte { + return StakeManager.Abi.Methods["releaseStakeOf"].ID() +} + +func (r *ReleaseStakeOfStakeManagerFn) EncodeAbi() ([]byte, error) { + return StakeManager.Abi.Methods["releaseStakeOf"].Encode(r) +} + +func (r *ReleaseStakeOfStakeManagerFn) DecodeAbi(buf []byte) error { + return decodeMethod(StakeManager.Abi.Methods["releaseStakeOf"], buf, r) +} + +type WithdrawStakeStakeManagerFn struct { + To types.Address `abi:"to"` + Amount *big.Int `abi:"amount"` +} + +func (w *WithdrawStakeStakeManagerFn) Sig() []byte { + return StakeManager.Abi.Methods["withdrawStake"].ID() +} + +func (w *WithdrawStakeStakeManagerFn) EncodeAbi() ([]byte, error) { + return StakeManager.Abi.Methods["withdrawStake"].Encode(w) +} + +func (w *WithdrawStakeStakeManagerFn) DecodeAbi(buf []byte) error { + return decodeMethod(StakeManager.Abi.Methods["withdrawStake"], buf, w) +} + +type StakeOfStakeManagerFn struct { + Validator types.Address `abi:"validator"` + ID *big.Int `abi:"id"` +} + +func (s *StakeOfStakeManagerFn) Sig() []byte { + return StakeManager.Abi.Methods["stakeOf"].ID() +} + +func (s *StakeOfStakeManagerFn) EncodeAbi() ([]byte, error) { + return StakeManager.Abi.Methods["stakeOf"].Encode(s) +} + +func (s *StakeOfStakeManagerFn) DecodeAbi(buf []byte) error { + return decodeMethod(StakeManager.Abi.Methods["stakeOf"], buf, s) +} + +type ChildManagerRegisteredEvent struct { + ID *big.Int `abi:"id"` + Manager types.Address `abi:"manager"` +} + +func (*ChildManagerRegisteredEvent) Sig() ethgo.Hash { + return StakeManager.Abi.Events["ChildManagerRegistered"].ID() +} + +func (*ChildManagerRegisteredEvent) Encode(inputs interface{}) ([]byte, error) { + return StakeManager.Abi.Events["ChildManagerRegistered"].Inputs.Encode(inputs) +} + +func (c *ChildManagerRegisteredEvent) ParseLog(log *ethgo.Log) (bool, error) { + if !StakeManager.Abi.Events["ChildManagerRegistered"].Match(log) { + return false, nil + } + + return true, decodeEvent(StakeManager.Abi.Events["ChildManagerRegistered"], log, c) +} + +type StakeAddedEvent struct { + ID *big.Int `abi:"id"` + Validator types.Address `abi:"validator"` + Amount *big.Int `abi:"amount"` +} + +func (*StakeAddedEvent) Sig() ethgo.Hash { + return StakeManager.Abi.Events["StakeAdded"].ID() +} + +func (*StakeAddedEvent) Encode(inputs interface{}) ([]byte, error) { + return StakeManager.Abi.Events["StakeAdded"].Inputs.Encode(inputs) +} + +func (s *StakeAddedEvent) ParseLog(log *ethgo.Log) (bool, error) { + if !StakeManager.Abi.Events["StakeAdded"].Match(log) { + return false, nil + } + + return true, decodeEvent(StakeManager.Abi.Events["StakeAdded"], log, s) +} + +type StakeWithdrawnEvent struct { + Validator types.Address `abi:"validator"` + Recipient types.Address `abi:"recipient"` + Amount *big.Int `abi:"amount"` +} + +func (*StakeWithdrawnEvent) Sig() ethgo.Hash { + return StakeManager.Abi.Events["StakeWithdrawn"].ID() +} + +func (*StakeWithdrawnEvent) Encode(inputs interface{}) ([]byte, error) { + return StakeManager.Abi.Events["StakeWithdrawn"].Inputs.Encode(inputs) +} + +func (s *StakeWithdrawnEvent) ParseLog(log *ethgo.Log) (bool, error) { + if !StakeManager.Abi.Events["StakeWithdrawn"].Match(log) { + return false, nil + } + + return true, decodeEvent(StakeManager.Abi.Events["StakeWithdrawn"], log, s) +} + +type Epoch struct { + StartBlock *big.Int `abi:"startBlock"` + EndBlock *big.Int `abi:"endBlock"` + EpochRoot types.Hash `abi:"epochRoot"` +} + +var EpochABIType = abi.MustNewType("tuple(uint256 startBlock,uint256 endBlock,bytes32 epochRoot)") + +func (e *Epoch) EncodeAbi() ([]byte, error) { + return EpochABIType.Encode(e) +} + +func (e *Epoch) DecodeAbi(buf []byte) error { + return decodeStruct(EpochABIType, buf, &e) +} + +type CommitEpochValidatorSetFn struct { + ID *big.Int `abi:"id"` + Epoch *Epoch `abi:"epoch"` +} + +func (c *CommitEpochValidatorSetFn) Sig() []byte { + return ValidatorSet.Abi.Methods["commitEpoch"].ID() +} + +func (c *CommitEpochValidatorSetFn) EncodeAbi() ([]byte, error) { + return ValidatorSet.Abi.Methods["commitEpoch"].Encode(c) +} + +func (c *CommitEpochValidatorSetFn) DecodeAbi(buf []byte) error { + return decodeMethod(ValidatorSet.Abi.Methods["commitEpoch"], buf, c) +} + +type UnstakeValidatorSetFn struct { + Amount *big.Int `abi:"amount"` +} + +func (u *UnstakeValidatorSetFn) Sig() []byte { + return ValidatorSet.Abi.Methods["unstake"].ID() +} + +func (u *UnstakeValidatorSetFn) EncodeAbi() ([]byte, error) { + return ValidatorSet.Abi.Methods["unstake"].Encode(u) +} + +func (u *UnstakeValidatorSetFn) DecodeAbi(buf []byte) error { + return decodeMethod(ValidatorSet.Abi.Methods["unstake"], buf, u) +} + +type ValidatorInit struct { + Addr types.Address `abi:"addr"` + Stake *big.Int `abi:"stake"` +} + +var ValidatorInitABIType = abi.MustNewType("tuple(address addr,uint256 stake)") + +func (v *ValidatorInit) EncodeAbi() ([]byte, error) { + return ValidatorInitABIType.Encode(v) +} + +func (v *ValidatorInit) DecodeAbi(buf []byte) error { + return decodeStruct(ValidatorInitABIType, buf, &v) +} + +type InitializeValidatorSetFn struct { + NewStateSender types.Address `abi:"newStateSender"` + NewStateReceiver types.Address `abi:"newStateReceiver"` + NewRootChainManager types.Address `abi:"newRootChainManager"` + NewEpochSize *big.Int `abi:"newEpochSize"` + InitialValidators []*ValidatorInit `abi:"initialValidators"` +} + +func (i *InitializeValidatorSetFn) Sig() []byte { + return ValidatorSet.Abi.Methods["initialize"].ID() +} + +func (i *InitializeValidatorSetFn) EncodeAbi() ([]byte, error) { + return ValidatorSet.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeValidatorSetFn) DecodeAbi(buf []byte) error { + return decodeMethod(ValidatorSet.Abi.Methods["initialize"], buf, i) +} + +type TransferEvent struct { + From types.Address `abi:"from"` + To types.Address `abi:"to"` + Value *big.Int `abi:"value"` +} + +func (*TransferEvent) Sig() ethgo.Hash { + return ValidatorSet.Abi.Events["Transfer"].ID() +} + +func (*TransferEvent) Encode(inputs interface{}) ([]byte, error) { + return ValidatorSet.Abi.Events["Transfer"].Inputs.Encode(inputs) +} + +func (t *TransferEvent) ParseLog(log *ethgo.Log) (bool, error) { + if !ValidatorSet.Abi.Events["Transfer"].Match(log) { + return false, nil + } + + return true, decodeEvent(ValidatorSet.Abi.Events["Transfer"], log, t) +} + +type WithdrawalRegisteredEvent struct { + Account types.Address `abi:"account"` + Amount *big.Int `abi:"amount"` +} + +func (*WithdrawalRegisteredEvent) Sig() ethgo.Hash { + return ValidatorSet.Abi.Events["WithdrawalRegistered"].ID() +} + +func (*WithdrawalRegisteredEvent) Encode(inputs interface{}) ([]byte, error) { + return ValidatorSet.Abi.Events["WithdrawalRegistered"].Inputs.Encode(inputs) +} + +func (w *WithdrawalRegisteredEvent) ParseLog(log *ethgo.Log) (bool, error) { + if !ValidatorSet.Abi.Events["WithdrawalRegistered"].Match(log) { + return false, nil + } + + return true, decodeEvent(ValidatorSet.Abi.Events["WithdrawalRegistered"], log, w) +} + +type WithdrawalEvent struct { + Account types.Address `abi:"account"` + Amount *big.Int `abi:"amount"` +} + +func (*WithdrawalEvent) Sig() ethgo.Hash { + return ValidatorSet.Abi.Events["Withdrawal"].ID() +} + +func (*WithdrawalEvent) Encode(inputs interface{}) ([]byte, error) { + return ValidatorSet.Abi.Events["Withdrawal"].Inputs.Encode(inputs) +} + +func (w *WithdrawalEvent) ParseLog(log *ethgo.Log) (bool, error) { + if !ValidatorSet.Abi.Events["Withdrawal"].Match(log) { + return false, nil + } + + return true, decodeEvent(ValidatorSet.Abi.Events["Withdrawal"], log, w) +} + +type InitializeRewardPoolFn struct { + NewRewardToken types.Address `abi:"newRewardToken"` + NewRewardWallet types.Address `abi:"newRewardWallet"` + NewValidatorSet types.Address `abi:"newValidatorSet"` + NewBaseReward *big.Int `abi:"newBaseReward"` +} + +func (i *InitializeRewardPoolFn) Sig() []byte { + return RewardPool.Abi.Methods["initialize"].ID() +} + +func (i *InitializeRewardPoolFn) EncodeAbi() ([]byte, error) { + return RewardPool.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeRewardPoolFn) DecodeAbi(buf []byte) error { + return decodeMethod(RewardPool.Abi.Methods["initialize"], buf, i) +} + +type Uptime struct { + Validator types.Address `abi:"validator"` + SignedBlocks *big.Int `abi:"signedBlocks"` +} + +var UptimeABIType = abi.MustNewType("tuple(address validator,uint256 signedBlocks)") + +func (u *Uptime) EncodeAbi() ([]byte, error) { + return UptimeABIType.Encode(u) +} + +func (u *Uptime) DecodeAbi(buf []byte) error { + return decodeStruct(UptimeABIType, buf, &u) +} + +type DistributeRewardForRewardPoolFn struct { + EpochID *big.Int `abi:"epochId"` + Uptime []*Uptime `abi:"uptime"` +} + +func (d *DistributeRewardForRewardPoolFn) Sig() []byte { + return RewardPool.Abi.Methods["distributeRewardFor"].ID() +} + +func (d *DistributeRewardForRewardPoolFn) EncodeAbi() ([]byte, error) { + return RewardPool.Abi.Methods["distributeRewardFor"].Encode(d) +} + +func (d *DistributeRewardForRewardPoolFn) DecodeAbi(buf []byte) error { + return decodeMethod(RewardPool.Abi.Methods["distributeRewardFor"], buf, d) +} + +type InitializeEIP1559BurnFn struct { + NewChildERC20Predicate types.Address `abi:"newChildERC20Predicate"` + NewBurnDestination types.Address `abi:"newBurnDestination"` +} + +func (i *InitializeEIP1559BurnFn) Sig() []byte { + return EIP1559Burn.Abi.Methods["initialize"].ID() +} + +func (i *InitializeEIP1559BurnFn) EncodeAbi() ([]byte, error) { + return EIP1559Burn.Abi.Methods["initialize"].Encode(i) +} + +func (i *InitializeEIP1559BurnFn) DecodeAbi(buf []byte) error { + return decodeMethod(EIP1559Burn.Abi.Methods["initialize"], buf, i) +} diff --git a/consensus/polybft/contractsapi/contractsapi_test.go b/consensus/polybft/contractsapi/contractsapi_test.go index ad10cd0881..153631d73e 100644 --- a/consensus/polybft/contractsapi/contractsapi_test.go +++ b/consensus/polybft/contractsapi/contractsapi_test.go @@ -33,22 +33,12 @@ func TestEncoding_Method(t *testing.T) { Bitmap: []byte{}, }, // empty commit epoch - &CommitEpochChildValidatorSetFn{ + &CommitEpochValidatorSetFn{ ID: big.NewInt(1), Epoch: &Epoch{ StartBlock: big.NewInt(1), EndBlock: big.NewInt(1), }, - Uptime: &Uptime{ - EpochID: big.NewInt(1), - UptimeData: []*UptimeData{ - { - Validator: types.Address{0x1}, - SignedBlocks: big.NewInt(1), - }, - }, - TotalBlocks: big.NewInt(1), - }, }, } @@ -114,27 +104,27 @@ func TestEncodingAndParsingEvent(t *testing.T) { // log matches event doesMatch, err := exitEvent.ParseLog(log) - require.True(t, doesMatch) require.NoError(t, err) + require.True(t, doesMatch) require.Equal(t, uint64(11), exitEvent.ID.Uint64()) // change exit event id log.Topics[1] = ethgo.BytesToHash(common.EncodeUint64ToBytes(22)) doesMatch, err = exitEvent.ParseLog(log) - require.True(t, doesMatch) require.NoError(t, err) + require.True(t, doesMatch) require.Equal(t, uint64(22), exitEvent.ID.Uint64()) // log does not match event log.Topics[0] = stateSyncEventAPI.Sig() doesMatch, err = exitEvent.ParseLog(log) - require.False(t, doesMatch) require.NoError(t, err) + require.False(t, doesMatch) // error on parsing log log.Topics[0] = exitEventAPI.Sig() log.Topics = log.Topics[:3] doesMatch, err = exitEvent.ParseLog(log) - require.True(t, doesMatch) require.Error(t, err) + require.True(t, doesMatch) } diff --git a/consensus/polybft/contractsapi/gen_sc_data.go b/consensus/polybft/contractsapi/gen_sc_data.go index 0815f7b848..e60b2ed2aa 100644 --- a/consensus/polybft/contractsapi/gen_sc_data.go +++ b/consensus/polybft/contractsapi/gen_sc_data.go @@ -1,19 +1,43 @@ package contractsapi // This is auto-generated file. DO NOT EDIT. -var ChildValidatorSetArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"ChildValidatorSet\",\n \"sourceName\": \"contracts/child/ChildValidatorSet.sol\",\n \"abi\": [\n {\n \"inputs\": [],\n \"name\": \"AmountZero\",\n \"type\": \"error\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"Exists\",\n \"type\": \"error\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"signer\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"InvalidSignature\",\n \"type\": \"error\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"NoTokensDelegated\",\n \"type\": \"error\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"NotFound\",\n \"type\": \"error\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"src\",\n \"type\": \"string\"\n },\n {\n \"internalType\": \"string\",\n \"name\": \"msg\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"StakeRequirement\",\n \"type\": \"error\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"only\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"Unauthorized\",\n \"type\": \"error\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"AddedToWhitelist\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"oldCommission\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"newCommission\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"CommissionUpdated\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"delegator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Delegated\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"delegator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bool\",\n \"name\": \"restake\",\n \"type\": \"bool\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"DelegatorRewardClaimed\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"DelegatorRewardDistributed\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"key\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"epoch\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"pbftRound\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"DoubleSignerSlashed\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"startBlock\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"endBlock\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bytes32\",\n \"name\": \"epochRoot\",\n \"type\": \"bytes32\"\n }\n ],\n \"name\": \"NewEpoch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[4]\",\n \"name\": \"blsKey\",\n \"type\": \"uint256[4]\"\n }\n ],\n \"name\": \"NewValidator\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"previousOwner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"OwnershipTransferStarted\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"previousOwner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"OwnershipTransferred\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"RemovedFromWhitelist\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Staked\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"delegator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Undelegated\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Unstaked\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"ValidatorRewardClaimed\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"ValidatorRewardDistributed\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Withdrawal\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"WithdrawalRegistered\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"ACTIVE_VALIDATOR_SET_SIZE\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DOMAIN\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DOUBLE_SIGNING_SLASHING_PERCENT\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAX_COMMISSION\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TOKEN_CONTRACT\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"SYSTEM\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAWAL_WAIT_PERIOD\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"acceptOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address[]\",\n \"name\": \"whitelistAddreses\",\n \"type\": \"address[]\"\n }\n ],\n \"name\": \"addToWhitelist\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"bls\",\n \"outputs\": [\n {\n \"internalType\": \"contract IBLS\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"restake\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"claimDelegatorReward\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"claimValidatorReward\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"startBlock\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"endBlock\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"epochRoot\",\n \"type\": \"bytes32\"\n }\n ],\n \"internalType\": \"struct Epoch\",\n \"name\": \"epoch\",\n \"type\": \"tuple\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"epochId\",\n \"type\": \"uint256\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"signedBlocks\",\n \"type\": \"uint256\"\n }\n ],\n \"internalType\": \"struct UptimeData[]\",\n \"name\": \"uptimeData\",\n \"type\": \"tuple[]\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"totalBlocks\",\n \"type\": \"uint256\"\n }\n ],\n \"internalType\": \"struct Uptime\",\n \"name\": \"uptime\",\n \"type\": \"tuple\"\n }\n ],\n \"name\": \"commitEpoch\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"curEpochId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockNumber\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"pbftRound\",\n \"type\": \"uint256\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"startBlock\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"endBlock\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"epochRoot\",\n \"type\": \"bytes32\"\n }\n ],\n \"internalType\": \"struct Epoch\",\n \"name\": \"epoch\",\n \"type\": \"tuple\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"epochId\",\n \"type\": \"uint256\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"signedBlocks\",\n \"type\": \"uint256\"\n }\n ],\n \"internalType\": \"struct UptimeData[]\",\n \"name\": \"uptimeData\",\n \"type\": \"tuple[]\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"totalBlocks\",\n \"type\": \"uint256\"\n }\n ],\n \"internalType\": \"struct Uptime\",\n \"name\": \"uptime\",\n \"type\": \"tuple\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"epochId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"eventRoot\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"currentValidatorSetHash\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"nextValidatorSetHash\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"blockHash\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"bitmap\",\n \"type\": \"bytes\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"signature\",\n \"type\": \"bytes\"\n }\n ],\n \"internalType\": \"struct IChildValidatorSetBase.DoubleSignerSlashingInput[]\",\n \"name\": \"inputs\",\n \"type\": \"tuple[]\"\n }\n ],\n \"name\": \"commitEpochWithDoubleSignerSlashing\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"currentEpochId\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"restake\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"delegate\",\n \"outputs\": [],\n \"stateMutability\": \"payable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"delegator\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"delegationOf\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"doubleSignerSlashes\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"epochEndBlocks\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"epochReward\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"epochSize\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"epochs\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"startBlock\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"endBlock\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"epochRoot\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"getCurrentValidatorSet\",\n \"outputs\": [\n {\n \"internalType\": \"address[]\",\n \"name\": \"\",\n \"type\": \"address[]\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"delegator\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"getDelegatorReward\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockNumber\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"getEpochByBlock\",\n \"outputs\": [\n {\n \"components\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"startBlock\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"endBlock\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"epochRoot\",\n \"type\": \"bytes32\"\n }\n ],\n \"internalType\": \"struct Epoch\",\n \"name\": \"\",\n \"type\": \"tuple\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"getValidator\",\n \"outputs\": [\n {\n \"internalType\": \"uint256[4]\",\n \"name\": \"blsKey\",\n \"type\": \"uint256[4]\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"stake\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"totalStake\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"commission\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"withdrawableRewards\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"active\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"getValidatorReward\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"components\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"epochReward\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"minStake\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"minDelegation\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"epochSize\",\n \"type\": \"uint256\"\n }\n ],\n \"internalType\": \"struct IChildValidatorSetBase.InitStruct\",\n \"name\": \"init\",\n \"type\": \"tuple\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"address\",\n \"name\": \"addr\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256[4]\",\n \"name\": \"pubkey\",\n \"type\": \"uint256[4]\"\n },\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"signature\",\n \"type\": \"uint256[2]\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"stake\",\n \"type\": \"uint256\"\n }\n ],\n \"internalType\": \"struct IChildValidatorSetBase.ValidatorInit[]\",\n \"name\": \"validators\",\n \"type\": \"tuple[]\"\n },\n {\n \"internalType\": \"contract IBLS\",\n \"name\": \"newBls\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"governance\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"minDelegation\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"minStake\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"owner\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"pendingOwner\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"pendingWithdrawals\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"signature\",\n \"type\": \"uint256[2]\"\n },\n {\n \"internalType\": \"uint256[4]\",\n \"name\": \"pubkey\",\n \"type\": \"uint256[4]\"\n }\n ],\n \"name\": \"register\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address[]\",\n \"name\": \"whitelistAddreses\",\n \"type\": \"address[]\"\n }\n ],\n \"name\": \"removeFromWhitelist\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"renounceOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"newCommission\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"setCommission\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"n\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"sortedValidators\",\n \"outputs\": [\n {\n \"internalType\": \"address[]\",\n \"name\": \"\",\n \"type\": \"address[]\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"stake\",\n \"outputs\": [],\n \"stateMutability\": \"payable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"totalActiveStake\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"activeStake\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"totalDelegationOf\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"totalStake\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"totalStakeOf\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"transferOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"undelegate\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"unstake\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"whitelist\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"withdraw\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"withdrawable\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50615f5b80620000216000396000f3fe6080604052600436106102ca5760003560e01c8063715018a61161017b578063a2562ddd116100d7578063e0563ab111610085578063e0563ab114610890578063e30c3978146108a6578063e3f56eaa146108c4578063ea0fee4f146108e4578063eacdc5ff146108f9578063f2fde38b1461090f578063f3f437031461092f57600080fd5b8063a2562ddd146107a4578063a2b915e2146107c4578063a77af229146107e4578063a90049d0146107f9578063ae97dde814610366578063c6b61e4c14610819578063ce513b6f1461087057600080fd5b8063947287cf11610134578063947287cf146106df57806395b0b027146106f557806397e5230d14610715578063982ef0a71461072c5780639a91e6d71461073f5780639b19251a14610754578063a15808791461078457600080fd5b8063715018a61461061057806378f619321461062557806379ba5097146106775780637f6497831461068c5780638b0e9f3f146106ac5780638da5cb5b146106c157600080fd5b80633a4b66f11161022a57806351351d53116101e357806351351d531461052b57806351cff8d91461054657806352a9674b14610566578063548db1741461059a5780635689762f146105ba578063572d356e146105da578063628da527146105f057600080fd5b80633a4b66f11461046b5780633b878c22146104735780633fd5000114610489578063410899c9146104a957806346df33d2146104c95780634d99dd161461050b57600080fd5b80632153f7fa116102875780632153f7fa1461039d578063284017f5146103bd57806328f73148146103e05780632e17de78146103f557806333378ada14610415578063355e6b4314610435578063375b3c0a1461045557600080fd5b80630209fdd0146102cf57806302985992146102fa5780631604e4161461031e5780631904bb2e146103345780631bce714d146103665780631f6590b81461037b575b600080fd5b3480156102db57600080fd5b506102e461094f565b6040516102f191906153b4565b60405180910390f35b34801561030657600080fd5b5061031060055481565b6040519081526020016102f1565b34801561032a57600080fd5b5061031060035481565b34801561034057600080fd5b5061035461034f366004615421565b610960565b6040516102f19695949392919061543e565b34801561037257600080fd5b50610310606481565b34801561038757600080fd5b5061039b610396366004615495565b610a33565b005b3480156103a957600080fd5b506102e46103b83660046154d7565b610b30565b3480156103c957600080fd5b506103d361202081565b6040516102f191906154f0565b3480156103ec57600080fd5b50610310610c3b565b34801561040157600080fd5b5061039b6104103660046154d7565b610d09565b34801561042157600080fd5b50610310610430366004615421565b610e2f565b34801561044157600080fd5b5061039b6104503660046154d7565b610e46565b34801561046157600080fd5b5061031060045481565b61039b610f11565b34801561047f57600080fd5b506103d361101081565b34801561049557600080fd5b506103106104a43660046154d7565b610ff0565b3480156104b557600080fd5b5061039b6104c4366004615516565b611011565b3480156104d557600080fd5b506104e96104e43660046154d7565b61121f565b60408051825181526020808401519082015291810151908201526060016102f1565b34801561051757600080fd5b5061039b61052636600461556d565b611297565b34801561053757600080fd5b506103d36002600160a01b0381565b34801561055257600080fd5b5061039b610561366004615421565b6113a2565b34801561057257600080fd5b506103107ffd10bf199d0185af9cce2005e6acc8d19924428058ac3374e16f18c97569b4ee81565b3480156105a657600080fd5b5061039b6105b53660046155dd565b6114d2565b3480156105c657600080fd5b506103106105d536600461561e565b61152b565b3480156105e657600080fd5b5061031060005481565b3480156105fc57600080fd5b5061031061060b36600461561e565b61154b565b34801561061c57600080fd5b5061039b611562565b34801561063157600080fd5b5061066761064036600461564c565b61013e60209081526000938452604080852082529284528284209052825290205460ff1681565b60405190151581526020016102f1565b34801561068357600080fd5b5061039b611576565b34801561069857600080fd5b5061039b6106a73660046155dd565b6115ed565b3480156106b857600080fd5b50600954610310565b3480156106cd57600080fd5b506076546001600160a01b03166103d3565b3480156106eb57600080fd5b5061031061520881565b34801561070157600080fd5b506006546103d3906001600160a01b031681565b34801561072157600080fd5b50610310620249f081565b61039b61073a366004615693565b611641565b34801561074b57600080fd5b5061039b61169d565b34801561076057600080fd5b5061066761076f366004615421565b60106020526000908152604090205460ff1681565b34801561079057600080fd5b5061039b61079f3660046156c1565b611702565b3480156107b057600080fd5b5061039b6107bf366004615770565b6119d0565b3480156107d057600080fd5b506103106107df366004615421565b611d5e565b3480156107f057600080fd5b50610310600a81565b34801561080557600080fd5b5061039b610814366004615693565b611d72565b34801561082557600080fd5b506108556108343660046154d7565b600f6020526000908152604090208054600182015460029092015490919083565b604080519384526020840192909252908201526060016102f1565b34801561087c57600080fd5b5061031061088b366004615421565b611e13565b34801561089c57600080fd5b506103d361203081565b3480156108b257600080fd5b5060a8546001600160a01b03166103d3565b3480156108d057600080fd5b506103106108df366004615421565b611e41565b3480156108f057600080fd5b50610310600181565b34801561090557600080fd5b5061031060015481565b34801561091b57600080fd5b5061039b61092a366004615421565b611e4e565b34801561093b57600080fd5b5061031061094a366004615421565b611ebf565b606061095b6064610b30565b905090565b610968615329565b6000808080808061097a600789611ee6565b604080516101208101909152908160a081018260048282826020028201915b8154815260200190600101908083116109995750505091835250506004820154602080830191909152600583015460408301526006830154606083015260079283015460ff1615156080909201919091528251908301519099509750909150610a029089611f04565b546020820151610a12919061581f565b94508060400151935080606001519250806080015191505091939550919395565b3360009081526010602052604090205460ff16610a845760405163973d02cb60e01b815260206004820152600960248201526815d2125511531254d560ba1b60448201526064015b60405180910390fd5b610a8f338383611f22565b604080516101208101909152610ae29033908060a0810185600482826080808284376000920182905250928452505060208201819052604082018190526060820152600160809091015260079190611fd7565b610aeb33612380565b336001600160a01b03167fcab5c47e498c5b85fd42d656842253cfe070f7648c3a198275347b47dec5d27b82604051610b249190615832565b60405180910390a25050565b60606000600760010154831115610b4957600854610b4b565b825b90506000816001600160401b03811115610b6757610b67615841565b604051908082528060200260200182016040528015610b90578160200160208202803683370190505b50905081600003610ba2579392505050565b6000610bae60076123c9565b90508082600081518110610bc457610bc4615857565b6001600160a01b039092166020928302919091019091015260015b83811015610c3157610bf260078361242a565b915081838281518110610c0757610c07615857565b6001600160a01b039092166020928302919091019091015280610c298161586d565b915050610bdf565b5090949350505050565b60008060076001015460641115610c5457600854610c57565b60645b905080600003610c6957600091505090565b6000610c7560076123c9565b9050610c82600782611f04565b54610c8e600783611ee6565b60040154610c9c919061581f565b610ca6908461581f565b925060015b82811015610d0357610cbe60078361242a565b9150610ccb600783611f04565b54610cd7600784611ee6565b60040154610ce5919061581f565b610cef908561581f565b935080610cfb8161586d565b915050610cab565b50505090565b6000610d16600c3361252c565b336000908152600a6020526040902060070154610d339190615886565b90506000610d4083612588565b905081811315610d63576040516396906e6360e01b8152600401610a7b906158c0565b6000610d6f8284615905565b905060045481128015610d8157508015155b15610d9f576040516396906e6360e01b8152600401610a7b90615945565b610da761169d565b610dc233610db784600019615968565b600c9190600061259b565b80600003610dea576000610dd7600733611ee6565b600701805460ff19169115159190911790555b610df433856126a2565b60405184815233907f0f5bb82176feb1b5e747e28471aa92156a04d9f3ab9f45f28e2d704232b93f759060200160405180910390a250505050565b6000610e3c600783611ee6565b6006015492915050565b610e51600733611ee6565b6007015460ff16610e755760405163973d02cb60e01b8152600401610a7b90615998565b6064811115610ebb5760405162461bcd60e51b815260206004820152601260248201527124a72b20a624a22fa1a7a6a6a4a9a9a4a7a760711b6044820152606401610a7b565b6000610ec8600733611ee6565b6005810154604080519182526020820185905291925033917f6e500db30ce535d38852e318f333e9be41a3fec6c65d234ebb06203c896db9a5910160405180910390a260050155565b610f1c600733611ee6565b6007015460ff16610f405760405163973d02cb60e01b8152600401610a7b90615998565b6000610f4d600c3361252c565b336000908152600a6020526040902060070154610f6a9190615886565b905060045481610f7934612588565b610f839190615886565b1215610fa2576040516396906e6360e01b8152600401610a7b906159bb565b610faa61169d565b610fb8600c3334600061259b565b60405134815233907f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d9060200160405180910390a250565b6002818154811061100057600080fd5b600091825260209091200154905081565b336002600160a01b03146110385760405163973d02cb60e01b8152600401610a7b906159e9565b60018054600091826110498361586d565b91905055905080841461106e5760405162461bcd60e51b8152600401610a7b90615a0d565b82356020840135116110925760405162461bcd60e51b8152600401610a7b90615a3a565b6000546110a484356020860135615a67565b6110af90600161581f565b6110b99190615a90565b156111145760405162461bcd60e51b815260206004820152602560248201527f45504f43485f4d5553545f42455f444956495349424c455f42595f45504f43486044820152645f53495a4560d81b6064820152608401610a7b565b8235600f6000611125600185615a67565b8152602001908152602001600020600101546001611143919061581f565b146111605760405162461bcd60e51b8152600401610a7b90615aa4565b6000818152600f602090815260408083209186013560018084018290558735845591870135600280850191909155805492830181559093527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace01919091556111c8848461270e565b6111d06128df565b83602001358460000135867f0ce8712c4dee4bd5a691f0bc1c39594671591e77395f8ebf6a3fb5f63fbea66a876040013560405161121091815260200190565b60405180910390a45050505050565b6040805160608101825260008082526020820181905291810182905290611247600284612c12565b9050600f600061125883600161581f565b81526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050915050919050565b60006112a4600784611f04565b905060006112b28233612cc7565b9050808311156112d5576040516396906e6360e01b8152600401610a7b90615aee565b6112e0823385612d13565b60006112ec8483615a67565b9050600554811080156112fe57508015155b1561131c576040516396906e6360e01b8152600401610a7b90615b25565b611327856000611d72565b600061133285612588565b905061135086600061134684600019615968565b600c92919061259b565b61135a33866126a2565b6040518581526001600160a01b0387169033907f4d10bd049775c77bd7f255195afba5088028ecb3c7c277d393ccff7934f2f92c9060200160405180910390a3505050505050565b6113aa612de8565b6001600160a01b0381166113c0576113c0615b48565b336000908152600e6020526040812060015490919081906113e2908490612e41565b80855560405182815291935091506001600160a01b0385169033907f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b63989060200160405180910390a36000846001600160a01b03168360405160006040518083038185875af1925050503d8060008114611477576040519150601f19603f3d011682016040523d82523d6000602084013e61147c565b606091505b50509050806114c15760405162461bcd60e51b815260206004820152601160248201527015d2551211149055d05317d19052531151607a1b6044820152606401610a7b565b505050506114cf600160da55565b50565b6114da612eba565b60005b81811015611526576115148383838181106114fa576114fa615857565b905060200201602081019061150f9190615421565b612380565b8061151e8161586d565b9150506114dd565b505050565b60006115428261153c600786611f04565b90612f14565b90505b92915050565b60006115428261155c600786611f04565b90612cc7565b61156a612eba565b6115746000612f43565b565b60a85433906001600160a01b031681146115e45760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610a7b565b6114cf81612f43565b6115f5612eba565b60005b818110156115265761162f83838381811061161557611615615857565b905060200201602081019061162a9190615421565b612f5c565b806116398161586d565b9150506115f8565b600061164e600784611f04565b6005549091503461165f8333612cc7565b611669919061581f565b1015611688576040516396906e6360e01b8152600401610a7b90615b5e565b6116928383611d72565b611526338434612fa8565b60006116aa600733611ee6565b600681015490915060008190036116bf575050565b600060068301556116d033826126a2565b60405181815233907f378c825c0ac073cbae19612eb73cde31c0972f0c8ba2dedb659840f32550df2b90602001610b24565b604354610100900460ff16158080156117225750604354600160ff909116105b8061173c5750303b15801561173c575060435460ff166001145b61179f5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610a7b565b6043805460ff1916600117905580156117c2576043805461ff0019166101001790555b336002600160a01b03146117e95760405163973d02cb60e01b8152600401610a7b906159e9565b6001805560608601356000556117fe82612f43565b611806613073565b853560035560208601356004556040860135600555600680546001600160a01b0319166001600160a01b03851617905560005b848110156119815760006040518060a0016040528088888581811061186057611860615857565b905061010002016020016004806020026040519081016040528092919082600460200280828437600092019190915250505081526020018888858181106118a9576118a9615857565b9050610100020160e00135815260200160008152602001600081526020016001151581525090506119058787848181106118e5576118e5615857565b6118fc926020610100909202019081019150615421565b60079083611fd7565b61196e87878481811061191a5761191a615857565b611931926020610100909202019081019150615421565b88888581811061194357611943615857565b9050610100020160a00189898681811061195f5761195f615857565b90506101000201602001611f22565b50806119798161586d565b915050611839565b5080156119c8576043805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b8060028110156119f25760405162461bcd60e51b8152600401610a7b90615b8f565b6119fc83836130a2565b611a3f5760405162461bcd60e51b8152602060048201526014602482015273424c4f434b484153485f4e4f545f554e4951554560601b6044820152606401610a7b565b60005b81811015611bd957611bd14689868685818110611a6157611a61615857565b9050602002810190611a739190615bb7565b608001358a888887818110611a8a57611a8a615857565b9050602002810190611a9c9190615bb7565b35898988818110611aaf57611aaf615857565b9050602002810190611ac19190615bb7565b602001358a8a89818110611ad757611ad7615857565b9050602002810190611ae99190615bb7565b604001358b8b8a818110611aff57611aff615857565b9050602002810190611b119190615bb7565b604080516020810199909952880196909652606087810195909552608087019390935260a086019190915260c085015260e084015201356101008201526101200160405160208183030381529060405280519060200120858584818110611b7a57611b7a615857565b9050602002810190611b8c9190615bb7565b611b9a9060c0810190615bd7565b878786818110611bac57611bac615857565b9050602002810190611bbe9190615bb7565b611bcc9060a0810190615bd7565b613158565b600101611a42565b506000606460076001015410611bf0576064611bf4565b6008545b90506000611c0182610b30565b90506000826001600160401b03811115611c1d57611c1d615841565b604051908082528060200260200182016040528015611c46578160200160208202803683370190505b50905060005b83811015611d44576000805b86811015611d3a57611c9b898983818110611c7557611c75615857565b9050602002810190611c879190615bb7565b611c959060a0810190615bd7565b8561325c565b15611cae5781611caa8161586d565b9250505b6001821115611d2857611cff858481518110611ccc57611ccc615857565b60200260200101518a8a84818110611ce657611ce6615857565b9050602002810190611cf89190615bb7565b358e6132c6565b6001848481518110611d1357611d13615857565b91151560209283029190910190910152611d3a565b80611d328161586d565b915050611c58565b5050600101611c4c565b50611d518b89898461349d565b5050505050505050505050565b6000611d6b600783611f04565b5492915050565b6000611d7f600784611f04565b90506000611d8d823361383a565b905080600003611d9d5750505050565b8215611db357611dae338583612fa8565b611dbd565b611dbd33826126a2565b821515846001600160a01b0316336001600160a01b03167f6b2cd13395c5d2d1f95934a6a8f884d2cb71e846eb99d6759f7e6a39c060b2d084604051611e0591815260200190565b60405180910390a450505050565b6001546001600160a01b0382166000908152600e602052604081209091611e3a9190612e41565b5092915050565b6000611545600783613881565b611e56612eba565b60a880546001600160a01b0383166001600160a01b03199091168117909155611e876076546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6001546001600160a01b0382166000908152600e60205260408120909161154591906138b6565b6001600160a01b031660009081526003918201602052604090200190565b6001600160a01b031660009081526004919091016020526040902090565b60065460009081906001600160a01b031663ebbdac918585611f438961394c565b6040518463ffffffff1660e01b8152600401611f6193929190615c1d565b6040805180830381865afa158015611f7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa19190615c61565b91509150801580611fb0575081155b15611fd05784604051633615713d60e21b8152600401610a7b91906154f0565b5050505050565b6001600160a01b038216611fed57611fed615b48565b611ff78383613a1c565b15612017578160405163cda981d560e01b8152600401610a7b91906154f0565b6001600160a01b0382166000908152600380850160205260409091208251839291909101906120499082906004615347565b50602082810151600483015560408301516005830155606083015160068301556080909201516007909101805460ff191691151591909117905581015160000361209257505050565b82546000906001600160a01b0316816120ab8686613881565b90505b6001600160a01b03821615612121578192506120ca8683613881565b8110156120f9576001600160a01b039182166000908152600387016020526040902060010154909116906120ae565b6001600160a01b039182166000908152600387016020526040902060020154909116906120ae565b6040518060a00160405280846001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160011515815260200185815250866003016000876001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060608201518160020160146101000a81548160ff021916908315150217905550608082015181600301600082015181600001906004612256929190615347565b506020820151600482015560408201516005820155606082015160068201556080909101516007909101805460ff191691151591909117905550506001600160a01b0383166122bd5785546001600160a01b0319166001600160a01b03861617865561233a565b6122c78684613881565b811015612306576001600160a01b038381166000908152600388016020526040902060010180546001600160a01b03191691871691909117905561233a565b6001600160a01b038381166000908152600388016020526040902060020180546001600160a01b0319169187169190911790555b6123448686613a6d565b6001860180549060006123568361586d565b91905055508360200151866002016000828254612373919061581f565b9091555050505050505050565b6001600160a01b038116600081815260106020526040808220805460ff19169055517fcdd2e9b91a56913d370075169cefa1602ba36be5301664f752192bb1709df7579190a250565b80546001600160a01b03168015612425575b6001600160a01b0381811660009081526003840160205260409020600201541615612425576001600160a01b039081166000908152600383016020526040902060020154166123db565b919050565b60006001600160a01b038216612453576040516365e52d5160e11b815260040160405180910390fd5b6001600160a01b03828116600090815260038501602052604090206001015416156124aa576001600160a01b0380831660009081526003850160205260409020600101546124a391859116613dba565b9050611545565b506001600160a01b038082166000908152600384016020526040902054165b6001600160a01b0381161580159061250257506001600160a01b0380821660009081526003850160205260409020600101548382169116145b15611545576001600160a01b038082166000908152600385016020526040902054919250166124c9565b6001600160a01b038116600090815260018301602052604081205461255357506000611545565b8261255e8184613e10565b8154811061256e5761256e615857565b906000526020600020906003020160010154905092915050565b6000818181121561154557611545615b48565b6001600160a01b0383166000908152600185016020526040812054908190036126465784546125cb90600161581f565b6001600160a01b03858116600081815260018981016020908152604080842087905580516060810182529485528482018a81529085018981528c548085018e558d8652929094209451600390920290940180546001600160a01b03191691909516178455915191830191909155516002909101559050611fd0565b6000856126538187613e10565b8154811061266357612663615857565b90600052602060002090600302019050838160010160008282546126879190615886565b92505081905550828160020160008282546123739190615886565b6126d381600180546126b4919061581f565b6001600160a01b0385166000908152600e602052604090209190613e46565b816001600160a01b03167f655c1cd0236fb6dc4916f34c8ff10e3b18fcaea5b344dfc16c36fbb1bdfc5df282604051610b2491815260200190565b6001805461271c9190615a67565b8135146127615760405162461bcd60e51b8152602060048201526013602482015272115413d0d217d393d517d0d3d3535255151151606a1b6044820152606401610a7b565b60006127706020830183615c90565b9150506064811180159061278657506008548111155b6127a25760405162461bcd60e51b8152600401610a7b90615b8f565b60006127ac610c3b565b90506000805460646127be9190615cd9565b6127cd86356020880135615a67565b6003546127da9190615cd9565b6127e5906064615cd9565b6127ef9190615cf0565b905060005b838110156119c857600061280b6020870187615c90565b8381811061281b5761281b615857565b9050604002018036038101906128319190615d3a565b805190915060009061284590600790611ee6565b90506000612857604089013587615cd9565b6020840151845161286a90600790611f04565b54600485015461287a919061581f565b6128849088615cd9565b61288e9190615cd9565b6128989190615cf0565b90506000806128ab856000015184613f64565b915091506128bd85600001518361409d565b84516128c99082614108565b5050505050806128d89061586d565b90506127f4565b600c60005b8154811015612aae57600082828154811061290157612901615857565b600091825260209182902060408051606081018252600390930290910180546001600160a01b03168084526001820154948401949094526002015490820152915061294d600782613a1c565b15612a9b57600061295f600783611ee6565b905061297d836020015182600401546129789190615886565b614152565b600482015560208301516009546129979161297891615886565b60095560006129a7600784613881565b905060006129b6600785614168565b90506001600160a01b038116158015906129d95750816129d7600783613881565b105b806129f85750816129f66129ee60078761242a565b600790613881565b115b15612a7e57612a08600785614263565b604080516101208101909152612a7e908590858160a081018260048282826020028201915b815481526020019060010190808311612a2d57505050918352505060048201546020820152600582015460408201526006820154606082015260079182015460ff1615156080909101529190611fd7565b6001600160a01b0384166000908152600d60205260408120555050505b505080612aa79061586d565b90506128e4565b5060005b8154811015612c09576000828281548110612acf57612acf615857565b600091825260209182902060408051606081018252600390930290910180546001600160a01b031680845260018201549484019490945260020154908201529150612b1b600782613a1c565b158015612b3f57506001600160a01b0381166000908152600d602052604090205415155b15612bf6576000612b51600783611ee6565b9050612b608360200151614152565b60048281019190915560408051610120810191829052835460a08201908152612bdb9386938692849290918491906001830160c08601808311612a2d57505050918352505060048201546020820152600582015460408201526006820154606082015260079182015460ff1615156080909101529190611fd7565b6001600160a01b0382166000908152600d6020526040812055505b505080612c029061586d565b9050612ab2565b506000600c5550565b81546000908103612c2557506000611545565b82546000905b80821015612c72576000612c3f8383614644565b60008781526020902090915085908201541115612c5e57809150612c6c565b612c6981600161581f565b92505b50612c2b565b600082118015612c9e575083612c9b86612c8d600186615a67565b600091825260209091200190565b54145b15612cb757612cae600183615a67565b92505050611545565b509050611545565b505092915050565b60008260010154600003612cdd57506000611545565b600183015483546001600160a01b0384166000908152600686016020526040902054612d099190615cd9565b6115429190615cf0565b8254600184015460009190612d289084615cd9565b612d329190615cf0565b6001600160a01b0384166000908152600686016020526040812080549293508392909190612d61908490615a67565b9250508190555080846001016000828254612d7c9190615a67565b90915550506002840154612d9a90612d95908390615cd9565b612588565b6001600160a01b038416600090815260048601602052604081208054909190612dc4908490615886565b9091555050835482908590600090612ddd908490615a67565b909155505050505050565b600260da5403612e3a5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a7b565b600260da55565b81546000905b8360010154811015612eac57600081815260028501602090815260409182902082518084019093528054835260010154908201819052841015612e8a5750612eac565b8051612e96908461581f565b9250508080612ea49061586d565b915050612e47565b9250929050565b600160da55565b6076546001600160a01b031633146115745760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a7b565b6001600160a01b0381166000908152600583016020526040812054612f39848461465f565b6115429190615a67565b60a880546001600160a01b03191690556114cf816146d9565b6001600160a01b038116600081815260106020526040808220805460ff19166001179055517fa850ae9193f515cbae8d35e8925bd2be26627fc91bce650b8652ed254e9cab039190a250565b612fb3600783611ee6565b6007015460ff16612ffb5760405163973d02cb60e01b815260206004820152601160248201527024a72b20a624a22fab20a624a220aa27a960791b6044820152606401610a7b565b61300a82600061134684612588565b613021838261301a600786611f04565b919061472b565b816001600160a01b0316836001600160a01b03167fe5541a6b6103d4fa7e021ed54fad39c66f27a76bd13d374cf6240ae6bd0bb72b8360405161306691815260200190565b60405180910390a3505050565b604354610100900460ff1661309a5760405162461bcd60e51b8152600401610a7b90615d74565b61157461480b565b600081815b8181101561314d5760006130bc82600161581f565b90505b8281101561313a578585828181106130d9576130d9615857565b90506020028101906130eb9190615bb7565b6080013586868481811061310157613101615857565b90506020028101906131139190615bb7565b60800135036131285760009350505050611545565b806131328161586d565b9150506130bf565b50806131458161586d565b9150506130a7565b506001949350505050565b6000806120306001600160a01b0316620249f08888888888604051602001613184959493929190615de8565b60408051601f198184030181529082905261319e91615e45565b6000604051808303818686fa925050503d80600081146131da576040519150601f19603f3d011682016040523d82523d6000602084013e6131df565b606091505b50915091506000818060200190518101906131fa9190615e57565b90508280156132065750805b6132525760405162461bcd60e51b815260206004820152601d60248201527f5349474e41545552455f564552494649434154494f4e5f4641494c45440000006044820152606401610a7b565b5050505050505050565b60008061326a600884615cf0565b90506000613279600885615a90565b905084821061328d576000925050506132bf565b6000600160ff83161b8787858181106132a8576132a8615857565b9050013560f81c60f81b60f81c60ff161611925050505b9392505050565b600082815261013e6020908152604080832084845282528083206001600160a01b038716845290915290205460ff16156132ff57505050565b600082815261013e6020908152604080832084845282528083206001600160a01b03871684529091528120805460ff19166001179055613340600785611ee6565b6001600160a01b0385166000908152600b602052604090205490915060649061336b90600a90615cd9565b6133759190615cf0565b6001600160a01b0385166000908152600b60205260408120805490919061339d908490615a67565b9250508190555060006064600a83600401546133b99190615cd9565b6133c39190615cf0565b90506133d0600786614263565b808260040160008282546133e49190615a67565b909155505060408051610120810190915261345e908690848160a08101826004828282602002820191815481526020019060010190808311612a2d57505050918352505060048201546020820152600582015460408201526006820154606082015260079182015460ff1615156080909101529190611fd7565b8284866001600160a01b03167f2d7432ca38933aadba9547f33f0568008e240e52e66f1a16c6182e742bce3b1360405160405180910390a45050505050565b60018054600091826134ae8361586d565b9190505590508085146134d35760405162461bcd60e51b8152600401610a7b90615a0d565b83356020850135116134f75760405162461bcd60e51b8152600401610a7b90615a3a565b8335600f6000613508600185615a67565b8152602001908152602001600020600101546001613526919061581f565b146135435760405162461bcd60e51b8152600401610a7b90615aa4565b6000818152600f6020908152604080832087830135600180830182905589358355928901356002808401919091558054938401815585527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace9092019190915591906135b090860186615c90565b915050606481118015906135c657506008548111155b6135e25760405162461bcd60e51b8152600401610a7b90615b8f565b60006135ec610c3b565b90506000805460646135fe9190615cd9565b61360d893560208b0135615a67565b60035461361a9190615cd9565b613625906064615cd9565b61362f9190615cf0565b905060005b838110156137de5786818151811061364e5761364e615857565b60200260200101516137ce57600061366960208a018a615c90565b8381811061367957613679615857565b90506040020180360381019061368f9190615d3a565b80519091506000906136a390600790611ee6565b905060006136b560408c013587615cd9565b602084015184516136c890600790611f04565b5460048501546136d8919061581f565b6136e29088615cd9565b6136ec9190615cd9565b6136f69190615cf0565b9050600080613709856000015184613f64565b9150915081846006016000828254613721919061581f565b909155505084516040518481526001600160a01b03909116907f65da9d8bbc1fc112cfb499f15f17b3bfe4c5070dfca6a3e30f7f5f7f17bd86849060200160405180910390a2845161378190829061377b90600790611f04565b90614832565b84600001516001600160a01b03167f520e62b73478b262ede881cd483440f8e7b8a4651b0ff9154aeb3510089ddbac826040516137c091815260200190565b60405180910390a250505050505b6137d78161586d565b9050613634565b506137e76128df565b876020013588600001358a7f0ce8712c4dee4bd5a691f0bc1c39594671591e77395f8ebf6a3fb5f63fbea66a8b6040013560405161382791815260200190565b60405180910390a4505050505050505050565b60006138468383612f14565b6001600160a01b038316600090815260058501602052604081208054929350839290919061387590849061581f565b90915550909392505050565b6001600160a01b038116600090815260048301602090815260408083205460038601909252822060070154611542919061581f565b60018201546000908082036138cf576000915050611545565b60006138dc600183615a67565b90505b84548110612cbf57600081815260028601602090815260409182902082518084019093528054835260010154908201819052851061391d5750612cbf565b8051613929908561581f565b9350816000036139395750612cbf565b508061394481615e74565b9150506138df565b613954615381565b6006546040516bffffffffffffffffffffffff19606085901b1660208201524660348201526001600160a01b039091169063a850a909907ffd10bf199d0185af9cce2005e6acc8d19924428058ac3374e16f18c97569b4ee906054016040516020818303038152906040526040518363ffffffff1660e01b81526004016139dc929190615e8b565b6040805180830381865afa1580156139f8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115459190615ec5565b60006001600160a01b03821615801590611542575082546001600160a01b03838116911614806115425750506001600160a01b03908116600090815260039290920160205260409091205416151590565b60005b82546001600160a01b03838116911614801590613aba57506001600160a01b0382811660009081526003850160205260408082205490921681522060020154600160a01b900460ff165b15613d8c576001600160a01b03808316600090815260038501602052604080822054831680835281832054841683529120600101549091168103613c42576001600160a01b0381811660009081526003860160205260408082205483168252808220600290810154909316808352912090910154909250600160a01b900460ff1615613ba3576001600160a01b0380821660008181526003870160205260408082206002808201805460ff60a01b1990811690915588871685528385208201805482169055825487168552928420018054909216600160a01b1790915591905254169250613d86565b6001600160a01b038082166000908152600386016020526040902060020154811690841603613bd957809250613bd984846148af565b506001600160a01b0380831660009081526003850160205260408082205483168083528183206002808201805460ff60a01b19908116909155825487168652938520018054909316600160a01b1790925591829052549091613c3d91869116614a62565b613d86565b6001600160a01b03818116600090815260038601602052604080822054831682528082206001015490921680825291902060020154909250600160a01b900460ff1615613cec576001600160a01b0380821660008181526003870160205260408082206002808201805460ff60a01b1990811690915588871685528385208201805482169055825487168552928420018054909216600160a01b1790915591905254169250613d86565b6001600160a01b038082166000908152600386016020526040902060010154811690841603613d2257809250613d228484614a62565b506001600160a01b0380831660009081526003850160205260408082205483168083528183206002808201805460ff60a01b19908116909155825487168652938520018054909316600160a01b1790925591829052549091613d86918691166148af565b50613a70565b505080546001600160a01b03166000908152600390910160205260409020600201805460ff60a01b19169055565b60005b6001600160a01b0382811660009081526003850160205260409020600201541615613e0a576001600160a01b03918216600090815260038401602052604090206002015490911690613dbd565b50919050565b6001600160a01b038116600090815260018301602052604081205490819003613e3b57613e3b615b48565b611542600182615a67565b81600003613e5657613e56615b48565b82546001840154818103613ead576040805180820182528581526020808201868152600085815260028a019092529281209151825591516001918201558601805491613ea18361586d565b91905055505050505050565b60006002860181613ebf600185615a67565b815260200190815260200160002060010154905080841015613ee357613ee3615b48565b83811015613f32576040805180820182528681526020808201878152600086815260028b019092529281209151825591516001918201558701805491613f288361586d565b91905055506119c8565b84600287016000613f44600186615a67565b81526020019081526020016000206000016000828254612373919061581f565b60008080613f73600786611ee6565b604080516101208101909152908160a081018260048282826020028201915b815481526020019060010190808311613f925750505091835250506004820154602080830191909152600583015460408301526006830154606083015260079283015460ff161515608090920191909152820151919250600090613ff69088611f04565b54905060008290036140115760008094509450505050612eac565b806000036140285785600094509450505050612eac565b6000614034828461581f565b61403e8489615cd9565b6140489190615cf0565b905060006140568289615a67565b90506000606482876040015161406c9190615cd9565b6140769190615cf0565b9050614082818461581f565b61408c8284615a67565b975097505050505050509250929050565b60006140aa600784611ee6565b9050818160060160008282546140c0919061581f565b90915550506040518281526001600160a01b038416907f65da9d8bbc1fc112cfb499f15f17b3bfe4c5070dfca6a3e30f7f5f7f17bd86849060200160405180910390a2505050565b6141178161377b600785611f04565b816001600160a01b03167f520e62b73478b262ede881cd483440f8e7b8a4651b0ff9154aeb3510089ddbac82604051610b2491815260200190565b60008082121561416457614164615b48565b5090565b60006001600160a01b038216614191576040516365e52d5160e11b815260040160405180910390fd5b6001600160a01b03828116600090815260038501602052604090206002015416156141e1576001600160a01b0380831660009081526003850160205260409020600201546124a391859116614c15565b506001600160a01b038082166000908152600384016020526040902054165b6001600160a01b0381161580159061423957506001600160a01b0380821660009081526003850160205260409020600201548382169116145b15611545576001600160a01b03808216600090815260038501602052604090205491925016614200565b6001600160a01b03811661427957614279615b48565b6142838282613a1c565b6142a25780604051634b2990ed60e11b8152600401610a7b91906154f0565b6001600160a01b038181166000908152600384016020526040812060010154909182911615806142ef57506001600160a01b03838116600090815260038601602052604090206002015416155b156142fb575081614367565b506001600160a01b038083166000908152600385016020526040902060020154165b6001600160a01b0381811660009081526003860160205260409020600101541615614367576001600160a01b0390811660009081526003850160205260409020600101541661431d565b6001600160a01b03818116600090815260038601602052604090206001015416156143b3576001600160a01b0380821660009081526003860160205260409020600101541691506143d6565b6001600160a01b0380821660009081526003860160205260409020600201541691505b6001600160a01b038082166000908152600386016020526040808220548584168352912080546001600160a01b0319169190921690811790915580156144af576001600160a01b038082166000908152600387016020526040902060010154811690831603614477576001600160a01b038181166000908152600387016020526040902060010180546001600160a01b0319169185169190911790556144c9565b6001600160a01b038181166000908152600387016020526040902060020180546001600160a01b0319169185169190911790556144c9565b84546001600160a01b0319166001600160a01b0384161785555b6001600160a01b038281166000818152600388016020526040902060020154600160a01b900460ff1615918616146145a457614506868487614c65565b6001600160a01b03858116600090815260038801602052604080822060018082015488861680865284862092830180549288166001600160a01b03199384168117909155865284862080548316821790556002938401805494909301805494909716938216841787559285529284208054909316821790925590549152815460ff60a01b1916600160a01b9182900460ff1615159091021790559193915b80156145b4576145b48685614d5d565b6001600160a01b0383166000908152600387016020526040812080546001600160a01b0319908116825560018083018054909216909155600290910180546001600160a81b0319169055870180549161460c83615e74565b90915550506001600160a01b038316600090815260038701602052604081206007015460028801805491929091612373908490615a67565b60006146536002848418615cf0565b6115429084841661581f565b6001600160a01b03811660009081526006830160205260408120546002840154829161468f91612d959190615cd9565b6001600160a01b0384166000908152600486016020526040812054919250906146bc906129789084615886565b90506146d0670de0b6b3a764000082615cf0565b95945050505050565b607680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600083600101546000148061473f57508354155b61476357835460018501546147549084615cd9565b61475e9190615cf0565b614765565b815b6001600160a01b038416600090815260068601602052604081208054929350839290919061479490849061581f565b92505081905550808460010160008282546147af919061581f565b90915550508354829085906000906147c890849061581f565b909155505060028401546147e190612d95908390615cd9565b6001600160a01b038416600090815260048601602052604081208054909190612ddd908490615905565b604354610100900460ff16612eb35760405162461bcd60e51b8152600401610a7b90615d74565b8060000361483e575050565b8160010154600003614872576003820154604051636130835f60e01b8152610a7b916001600160a01b0316906004016154f0565b6001820154614889670de0b6b3a764000083615cd9565b6148939190615cf0565b8260020160008282546148a6919061581f565b90915550505050565b6001600160a01b038082166000818152600385016020526040808220600281018054915482871680865293852060010154959094526001600160a01b031990911693851693841790559216908015614932576001600160a01b038181166000908152600387016020526040902080546001600160a01b0319169186169190911790555b6001600160a01b038381166000908152600387016020526040902080546001600160a01b03191691841691821790556149835784546001600160a01b0319166001600160a01b038416178555614a18565b6001600160a01b0380831660009081526003870160205260409020600101548116908516036149e4576001600160a01b038281166000908152600387016020526040902060010180546001600160a01b031916918516919091179055614a18565b6001600160a01b038281166000908152600387016020526040902060020180546001600160a01b0319169185169190911790555b50506001600160a01b039081166000818152600390940160205260408085206001018054939094166001600160a01b03199384168117909455928452919092208054909216179055565b6001600160a01b038082166000818152600385016020526040808220600181018054915482871680865293852060020154959094526001600160a01b031990911693851693841790559216908015614ae5576001600160a01b038181166000908152600387016020526040902080546001600160a01b0319169186169190911790555b6001600160a01b038381166000908152600387016020526040902080546001600160a01b0319169184169182179055614b365784546001600160a01b0319166001600160a01b038416178555614bcb565b6001600160a01b038083166000908152600387016020526040902060020154811690851603614b97576001600160a01b038281166000908152600387016020526040902060020180546001600160a01b031916918516919091179055614bcb565b6001600160a01b038281166000908152600387016020526040902060010180546001600160a01b0319169185169190911790555b50506001600160a01b039081166000818152600390940160205260408085206002018054939094166001600160a01b03199384168117909455928452919092208054909216179055565b60005b6001600160a01b0382811660009081526003850160205260409020600101541615613e0a576001600160a01b03918216600090815260038401602052604090206001015490911690614c18565b6001600160a01b038082166000908152600385016020526040808220548584168352912080546001600160a01b0319169190921690811790915580614cc25783546001600160a01b0319166001600160a01b038416178455614d57565b6001600160a01b038082166000908152600386016020526040902060010154811690831603614d23576001600160a01b038181166000908152600386016020526040902060010180546001600160a01b031916918516919091179055614d57565b6001600160a01b038181166000908152600386016020526040902060020180546001600160a01b0319169185169190911790555b50505050565b60005b82546001600160a01b03838116911614801590614da257506001600160a01b0382166000908152600384016020526040902060020154600160a01b900460ff16155b156152fe576001600160a01b038083166000818152600386016020526040808220548416808352912060010154909216900361506c576001600160a01b038181166000908152600386016020526040808220600290810154909316808352912090910154909250600160a01b900460ff1615614e89576001600160a01b0380831660009081526003860160205260408082206002908101805460ff60a01b1990811690915593851683529120018054909116600160a01b179055614e6684826148af565b6001600160a01b0380821660009081526003860160205260409020600201541691505b6001600160a01b0382811660009081526003860160205260408082206001015490921681522060020154600160a01b900460ff16158015614efc57506001600160a01b038281166000908152600386016020526040808220600290810154909316825290200154600160a01b900460ff16155b15614f37576001600160a01b03821660009081526003850160205260409020600201805460ff60a01b1916600160a01b1790559150816152f8565b6001600160a01b038281166000908152600386016020526040808220600290810154909316825290200154600160a01b900460ff16614fec576001600160a01b0380831660008181526003870160205260408082206001810154909416825281206002908101805460ff60a01b19908116909155929091529091018054909116600160a01b179055614fc98483614a62565b6001600160a01b0380821660009081526003860160205260409020600201541691505b6001600160a01b0380821660009081526003860160205260408082206002908101805487861685528385208301805460ff600160a01b9384900416151590920260ff60a01b1992831617815582548216909255905490941683529120018054909116905561505a84826148af565b83546001600160a01b031692506152f8565b6001600160a01b0381811660009081526003860160205260408082206001015490921680825291902060020154909250600160a01b900460ff161561511c576001600160a01b0380831660009081526003860160205260408082206002908101805460ff60a01b1990811690915593851683529120018054909116600160a01b1790556150f98482614a62565b6001600160a01b0380821660009081526003860160205260409020600101541691505b6001600160a01b038281166000908152600386016020526040808220600290810154909316825290200154600160a01b900460ff1615801561518f57506001600160a01b0382811660009081526003860160205260408082206001015490921681522060020154600160a01b900460ff16155b156151ca576001600160a01b03821660009081526003850160205260409020600201805460ff60a01b1916600160a01b1790559150816152f8565b6001600160a01b0382811660009081526003860160205260408082206001015490921681522060020154600160a01b900460ff16615277576001600160a01b03808316600081815260038701602052604080822060029081018054909516835290822001805460ff60a01b19908116909155919052815416600160a01b17905561525484836148af565b6001600160a01b0380821660009081526003860160205260409020600101541691505b6001600160a01b038082166000908152600386016020526040808220600290810180548786168552838520808401805460ff600160a01b9485900416151590930260ff60a01b19938416179055825482169092556001909101549094168352912001805490911690556152ea8482614a62565b83546001600160a01b031692505b50614d60565b506001600160a01b03166000908152600390910160205260409020600201805460ff60a01b19169055565b60405180608001604052806004906020820280368337509192915050565b8260048101928215615375579160200282015b8281111561537557825182559160200191906001019061535a565b5061416492915061539f565b60405180604001604052806002906020820280368337509192915050565b5b8082111561416457600081556001016153a0565b6020808252825182820181905260009190848201906040850190845b818110156153f55783516001600160a01b0316835292840192918401916001016153d0565b50909695505050505050565b6001600160a01b03811681146114cf57600080fd5b803561242581615401565b60006020828403121561543357600080fd5b81356132bf81615401565b6101208101818860005b6004811015615467578151835260209283019290910190600101615448565b505050608082019690965260a081019490945260c084019290925260e0830152151561010090910152919050565b60008060c083850312156154a857600080fd5b60408301848111156154b957600080fd5b8392508460c0850111156154cc57600080fd5b809150509250929050565b6000602082840312156154e957600080fd5b5035919050565b6001600160a01b0391909116815260200190565b600060608284031215613e0a57600080fd5b600080600060a0848603121561552b57600080fd5b8335925061553c8560208601615504565b915060808401356001600160401b0381111561555757600080fd5b61556386828701615504565b9150509250925092565b6000806040838503121561558057600080fd5b823561558b81615401565b946020939093013593505050565b60008083601f8401126155ab57600080fd5b5081356001600160401b038111156155c257600080fd5b6020830191508360208260051b8501011115612eac57600080fd5b600080602083850312156155f057600080fd5b82356001600160401b0381111561560657600080fd5b61561285828601615599565b90969095509350505050565b6000806040838503121561563157600080fd5b823561563c81615401565b915060208301356154cc81615401565b60008060006060848603121561566157600080fd5b8335925060208401359150604084013561567a81615401565b809150509250925092565b80151581146114cf57600080fd5b600080604083850312156156a657600080fd5b82356156b181615401565b915060208301356154cc81615685565b600080600080600085870360e08112156156da57600080fd5b60808112156156e857600080fd5b5085945060808601356001600160401b038082111561570657600080fd5b818801915088601f83011261571a57600080fd5b81358181111561572957600080fd5b8960208260081b850101111561573e57600080fd5b60208301965080955050505061575660a08701615416565b915061576460c08701615416565b90509295509295909350565b6000806000806000806000610100888a03121561578c57600080fd5b8735965060208801359550604088013594506157ab8960608a01615504565b935060c08801356001600160401b03808211156157c757600080fd5b6157d38b838c01615504565b945060e08a01359150808211156157e957600080fd5b506157f68a828b01615599565b989b979a50959850939692959293505050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561154557611545615809565b60808181019083833792915050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60006001820161587f5761587f615809565b5060010190565b8082018281126000831280158216821582161715612cbf57612cbf615809565b6007815266756e7374616b6560c81b602082015260400190565b6040815260006158d2604083016158a6565b82810360208401526132bf816014815273494e53554646494349454e545f42414c414e434560601b602082015260400190565b8181036000831280158383131683831282161715611e3a57611e3a615809565b600d81526c5354414b455f544f4f5f4c4f5760981b602082015260400190565b604081526000615957604083016158a6565b82810360208401526132bf81615925565b80820260008212600160ff1b8414161561598457615984615809565b818105831482151761154557611545615809565b6020808252600990820152682b20a624a220aa27a960b91b604082015260600190565b6040815260056040820152647374616b6560d81b606082015260806020820152600061154560808301615925565b6020808252600a908201526914d654d5115350d0531360b21b604082015260600190565b60208082526013908201527215539156141150d5115117d15413d0d217d251606a1b604082015260600190565b6020808252601390820152721393d7d09313d0d2d4d7d0d3d3535255151151606a1b604082015260600190565b8181038181111561154557611545615809565b634e487b7160e01b600052601260045260246000fd5b600082615a9f57615a9f615a7a565b500690565b602080825260139082015272494e56414c49445f53544152545f424c4f434b60681b604082015260600190565b600a815269756e64656c656761746560b01b602082015260400190565b6040815260006158d260408301615ad1565b601281527144454c45474154494f4e5f544f4f5f4c4f5760701b602082015260400190565b604081526000615b3760408301615ad1565b82810360208401526132bf81615b00565b634e487b7160e01b600052600160045260246000fd5b60408152600860408201526764656c656761746560c01b606082015260806020820152600061154560808301615b00565b6020808252600e908201526d0929cac82989288be988a9c8ea8960931b604082015260600190565b6000823560de19833603018112615bcd57600080fd5b9190910192915050565b6000808335601e19843603018112615bee57600080fd5b8301803591506001600160401b03821115615c0857600080fd5b602001915036819003821315612eac57600080fd5b61010081016040858337608084604084013760c082018360005b6002811015615c56578151835260209283019290910190600101615c37565b505050949350505050565b60008060408385031215615c7457600080fd5b8251615c7f81615685565b60208401519092506154cc81615685565b6000808335601e19843603018112615ca757600080fd5b8301803591506001600160401b03821115615cc157600080fd5b6020019150600681901b3603821315612eac57600080fd5b808202811582820484141761154557611545615809565b600082615cff57615cff615a7a565b500490565b604080519081016001600160401b0381118282101715615d3457634e487b7160e01b600052604160045260246000fd5b60405290565b600060408284031215615d4c57600080fd5b615d54615d04565b8235615d5f81615401565b81526020928301359281019290925250919050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b858152606060208201526000615e02606083018688615dbf565b8281036040840152615e15818587615dbf565b98975050505050505050565b60005b83811015615e3c578181015183820152602001615e24565b50506000910152565b60008251615bcd818460208701615e21565b600060208284031215615e6957600080fd5b81516132bf81615685565b600081615e8357615e83615809565b506000190190565b8281526040602082015260008251806040840152615eb0816060850160208701615e21565b601f01601f1916919091016060019392505050565b600060408284031215615ed757600080fd5b82601f830112615ee657600080fd5b615eee615d04565b806040840185811115615f0057600080fd5b845b81811015615f1a578051845260209384019301615f02565b50909594505050505056fea2646970667358221220a626fbc30de48fae03e0787e09215ca109af7c4393b840809136a8d3e07d3add64736f6c63430008110033\",\n \"deployedBytecode\": \"0x6080604052600436106102ca5760003560e01c8063715018a61161017b578063a2562ddd116100d7578063e0563ab111610085578063e0563ab114610890578063e30c3978146108a6578063e3f56eaa146108c4578063ea0fee4f146108e4578063eacdc5ff146108f9578063f2fde38b1461090f578063f3f437031461092f57600080fd5b8063a2562ddd146107a4578063a2b915e2146107c4578063a77af229146107e4578063a90049d0146107f9578063ae97dde814610366578063c6b61e4c14610819578063ce513b6f1461087057600080fd5b8063947287cf11610134578063947287cf146106df57806395b0b027146106f557806397e5230d14610715578063982ef0a71461072c5780639a91e6d71461073f5780639b19251a14610754578063a15808791461078457600080fd5b8063715018a61461061057806378f619321461062557806379ba5097146106775780637f6497831461068c5780638b0e9f3f146106ac5780638da5cb5b146106c157600080fd5b80633a4b66f11161022a57806351351d53116101e357806351351d531461052b57806351cff8d91461054657806352a9674b14610566578063548db1741461059a5780635689762f146105ba578063572d356e146105da578063628da527146105f057600080fd5b80633a4b66f11461046b5780633b878c22146104735780633fd5000114610489578063410899c9146104a957806346df33d2146104c95780634d99dd161461050b57600080fd5b80632153f7fa116102875780632153f7fa1461039d578063284017f5146103bd57806328f73148146103e05780632e17de78146103f557806333378ada14610415578063355e6b4314610435578063375b3c0a1461045557600080fd5b80630209fdd0146102cf57806302985992146102fa5780631604e4161461031e5780631904bb2e146103345780631bce714d146103665780631f6590b81461037b575b600080fd5b3480156102db57600080fd5b506102e461094f565b6040516102f191906153b4565b60405180910390f35b34801561030657600080fd5b5061031060055481565b6040519081526020016102f1565b34801561032a57600080fd5b5061031060035481565b34801561034057600080fd5b5061035461034f366004615421565b610960565b6040516102f19695949392919061543e565b34801561037257600080fd5b50610310606481565b34801561038757600080fd5b5061039b610396366004615495565b610a33565b005b3480156103a957600080fd5b506102e46103b83660046154d7565b610b30565b3480156103c957600080fd5b506103d361202081565b6040516102f191906154f0565b3480156103ec57600080fd5b50610310610c3b565b34801561040157600080fd5b5061039b6104103660046154d7565b610d09565b34801561042157600080fd5b50610310610430366004615421565b610e2f565b34801561044157600080fd5b5061039b6104503660046154d7565b610e46565b34801561046157600080fd5b5061031060045481565b61039b610f11565b34801561047f57600080fd5b506103d361101081565b34801561049557600080fd5b506103106104a43660046154d7565b610ff0565b3480156104b557600080fd5b5061039b6104c4366004615516565b611011565b3480156104d557600080fd5b506104e96104e43660046154d7565b61121f565b60408051825181526020808401519082015291810151908201526060016102f1565b34801561051757600080fd5b5061039b61052636600461556d565b611297565b34801561053757600080fd5b506103d36002600160a01b0381565b34801561055257600080fd5b5061039b610561366004615421565b6113a2565b34801561057257600080fd5b506103107ffd10bf199d0185af9cce2005e6acc8d19924428058ac3374e16f18c97569b4ee81565b3480156105a657600080fd5b5061039b6105b53660046155dd565b6114d2565b3480156105c657600080fd5b506103106105d536600461561e565b61152b565b3480156105e657600080fd5b5061031060005481565b3480156105fc57600080fd5b5061031061060b36600461561e565b61154b565b34801561061c57600080fd5b5061039b611562565b34801561063157600080fd5b5061066761064036600461564c565b61013e60209081526000938452604080852082529284528284209052825290205460ff1681565b60405190151581526020016102f1565b34801561068357600080fd5b5061039b611576565b34801561069857600080fd5b5061039b6106a73660046155dd565b6115ed565b3480156106b857600080fd5b50600954610310565b3480156106cd57600080fd5b506076546001600160a01b03166103d3565b3480156106eb57600080fd5b5061031061520881565b34801561070157600080fd5b506006546103d3906001600160a01b031681565b34801561072157600080fd5b50610310620249f081565b61039b61073a366004615693565b611641565b34801561074b57600080fd5b5061039b61169d565b34801561076057600080fd5b5061066761076f366004615421565b60106020526000908152604090205460ff1681565b34801561079057600080fd5b5061039b61079f3660046156c1565b611702565b3480156107b057600080fd5b5061039b6107bf366004615770565b6119d0565b3480156107d057600080fd5b506103106107df366004615421565b611d5e565b3480156107f057600080fd5b50610310600a81565b34801561080557600080fd5b5061039b610814366004615693565b611d72565b34801561082557600080fd5b506108556108343660046154d7565b600f6020526000908152604090208054600182015460029092015490919083565b604080519384526020840192909252908201526060016102f1565b34801561087c57600080fd5b5061031061088b366004615421565b611e13565b34801561089c57600080fd5b506103d361203081565b3480156108b257600080fd5b5060a8546001600160a01b03166103d3565b3480156108d057600080fd5b506103106108df366004615421565b611e41565b3480156108f057600080fd5b50610310600181565b34801561090557600080fd5b5061031060015481565b34801561091b57600080fd5b5061039b61092a366004615421565b611e4e565b34801561093b57600080fd5b5061031061094a366004615421565b611ebf565b606061095b6064610b30565b905090565b610968615329565b6000808080808061097a600789611ee6565b604080516101208101909152908160a081018260048282826020028201915b8154815260200190600101908083116109995750505091835250506004820154602080830191909152600583015460408301526006830154606083015260079283015460ff1615156080909201919091528251908301519099509750909150610a029089611f04565b546020820151610a12919061581f565b94508060400151935080606001519250806080015191505091939550919395565b3360009081526010602052604090205460ff16610a845760405163973d02cb60e01b815260206004820152600960248201526815d2125511531254d560ba1b60448201526064015b60405180910390fd5b610a8f338383611f22565b604080516101208101909152610ae29033908060a0810185600482826080808284376000920182905250928452505060208201819052604082018190526060820152600160809091015260079190611fd7565b610aeb33612380565b336001600160a01b03167fcab5c47e498c5b85fd42d656842253cfe070f7648c3a198275347b47dec5d27b82604051610b249190615832565b60405180910390a25050565b60606000600760010154831115610b4957600854610b4b565b825b90506000816001600160401b03811115610b6757610b67615841565b604051908082528060200260200182016040528015610b90578160200160208202803683370190505b50905081600003610ba2579392505050565b6000610bae60076123c9565b90508082600081518110610bc457610bc4615857565b6001600160a01b039092166020928302919091019091015260015b83811015610c3157610bf260078361242a565b915081838281518110610c0757610c07615857565b6001600160a01b039092166020928302919091019091015280610c298161586d565b915050610bdf565b5090949350505050565b60008060076001015460641115610c5457600854610c57565b60645b905080600003610c6957600091505090565b6000610c7560076123c9565b9050610c82600782611f04565b54610c8e600783611ee6565b60040154610c9c919061581f565b610ca6908461581f565b925060015b82811015610d0357610cbe60078361242a565b9150610ccb600783611f04565b54610cd7600784611ee6565b60040154610ce5919061581f565b610cef908561581f565b935080610cfb8161586d565b915050610cab565b50505090565b6000610d16600c3361252c565b336000908152600a6020526040902060070154610d339190615886565b90506000610d4083612588565b905081811315610d63576040516396906e6360e01b8152600401610a7b906158c0565b6000610d6f8284615905565b905060045481128015610d8157508015155b15610d9f576040516396906e6360e01b8152600401610a7b90615945565b610da761169d565b610dc233610db784600019615968565b600c9190600061259b565b80600003610dea576000610dd7600733611ee6565b600701805460ff19169115159190911790555b610df433856126a2565b60405184815233907f0f5bb82176feb1b5e747e28471aa92156a04d9f3ab9f45f28e2d704232b93f759060200160405180910390a250505050565b6000610e3c600783611ee6565b6006015492915050565b610e51600733611ee6565b6007015460ff16610e755760405163973d02cb60e01b8152600401610a7b90615998565b6064811115610ebb5760405162461bcd60e51b815260206004820152601260248201527124a72b20a624a22fa1a7a6a6a4a9a9a4a7a760711b6044820152606401610a7b565b6000610ec8600733611ee6565b6005810154604080519182526020820185905291925033917f6e500db30ce535d38852e318f333e9be41a3fec6c65d234ebb06203c896db9a5910160405180910390a260050155565b610f1c600733611ee6565b6007015460ff16610f405760405163973d02cb60e01b8152600401610a7b90615998565b6000610f4d600c3361252c565b336000908152600a6020526040902060070154610f6a9190615886565b905060045481610f7934612588565b610f839190615886565b1215610fa2576040516396906e6360e01b8152600401610a7b906159bb565b610faa61169d565b610fb8600c3334600061259b565b60405134815233907f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d9060200160405180910390a250565b6002818154811061100057600080fd5b600091825260209091200154905081565b336002600160a01b03146110385760405163973d02cb60e01b8152600401610a7b906159e9565b60018054600091826110498361586d565b91905055905080841461106e5760405162461bcd60e51b8152600401610a7b90615a0d565b82356020840135116110925760405162461bcd60e51b8152600401610a7b90615a3a565b6000546110a484356020860135615a67565b6110af90600161581f565b6110b99190615a90565b156111145760405162461bcd60e51b815260206004820152602560248201527f45504f43485f4d5553545f42455f444956495349424c455f42595f45504f43486044820152645f53495a4560d81b6064820152608401610a7b565b8235600f6000611125600185615a67565b8152602001908152602001600020600101546001611143919061581f565b146111605760405162461bcd60e51b8152600401610a7b90615aa4565b6000818152600f602090815260408083209186013560018084018290558735845591870135600280850191909155805492830181559093527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace01919091556111c8848461270e565b6111d06128df565b83602001358460000135867f0ce8712c4dee4bd5a691f0bc1c39594671591e77395f8ebf6a3fb5f63fbea66a876040013560405161121091815260200190565b60405180910390a45050505050565b6040805160608101825260008082526020820181905291810182905290611247600284612c12565b9050600f600061125883600161581f565b81526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050915050919050565b60006112a4600784611f04565b905060006112b28233612cc7565b9050808311156112d5576040516396906e6360e01b8152600401610a7b90615aee565b6112e0823385612d13565b60006112ec8483615a67565b9050600554811080156112fe57508015155b1561131c576040516396906e6360e01b8152600401610a7b90615b25565b611327856000611d72565b600061133285612588565b905061135086600061134684600019615968565b600c92919061259b565b61135a33866126a2565b6040518581526001600160a01b0387169033907f4d10bd049775c77bd7f255195afba5088028ecb3c7c277d393ccff7934f2f92c9060200160405180910390a3505050505050565b6113aa612de8565b6001600160a01b0381166113c0576113c0615b48565b336000908152600e6020526040812060015490919081906113e2908490612e41565b80855560405182815291935091506001600160a01b0385169033907f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b63989060200160405180910390a36000846001600160a01b03168360405160006040518083038185875af1925050503d8060008114611477576040519150601f19603f3d011682016040523d82523d6000602084013e61147c565b606091505b50509050806114c15760405162461bcd60e51b815260206004820152601160248201527015d2551211149055d05317d19052531151607a1b6044820152606401610a7b565b505050506114cf600160da55565b50565b6114da612eba565b60005b81811015611526576115148383838181106114fa576114fa615857565b905060200201602081019061150f9190615421565b612380565b8061151e8161586d565b9150506114dd565b505050565b60006115428261153c600786611f04565b90612f14565b90505b92915050565b60006115428261155c600786611f04565b90612cc7565b61156a612eba565b6115746000612f43565b565b60a85433906001600160a01b031681146115e45760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610a7b565b6114cf81612f43565b6115f5612eba565b60005b818110156115265761162f83838381811061161557611615615857565b905060200201602081019061162a9190615421565b612f5c565b806116398161586d565b9150506115f8565b600061164e600784611f04565b6005549091503461165f8333612cc7565b611669919061581f565b1015611688576040516396906e6360e01b8152600401610a7b90615b5e565b6116928383611d72565b611526338434612fa8565b60006116aa600733611ee6565b600681015490915060008190036116bf575050565b600060068301556116d033826126a2565b60405181815233907f378c825c0ac073cbae19612eb73cde31c0972f0c8ba2dedb659840f32550df2b90602001610b24565b604354610100900460ff16158080156117225750604354600160ff909116105b8061173c5750303b15801561173c575060435460ff166001145b61179f5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610a7b565b6043805460ff1916600117905580156117c2576043805461ff0019166101001790555b336002600160a01b03146117e95760405163973d02cb60e01b8152600401610a7b906159e9565b6001805560608601356000556117fe82612f43565b611806613073565b853560035560208601356004556040860135600555600680546001600160a01b0319166001600160a01b03851617905560005b848110156119815760006040518060a0016040528088888581811061186057611860615857565b905061010002016020016004806020026040519081016040528092919082600460200280828437600092019190915250505081526020018888858181106118a9576118a9615857565b9050610100020160e00135815260200160008152602001600081526020016001151581525090506119058787848181106118e5576118e5615857565b6118fc926020610100909202019081019150615421565b60079083611fd7565b61196e87878481811061191a5761191a615857565b611931926020610100909202019081019150615421565b88888581811061194357611943615857565b9050610100020160a00189898681811061195f5761195f615857565b90506101000201602001611f22565b50806119798161586d565b915050611839565b5080156119c8576043805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b8060028110156119f25760405162461bcd60e51b8152600401610a7b90615b8f565b6119fc83836130a2565b611a3f5760405162461bcd60e51b8152602060048201526014602482015273424c4f434b484153485f4e4f545f554e4951554560601b6044820152606401610a7b565b60005b81811015611bd957611bd14689868685818110611a6157611a61615857565b9050602002810190611a739190615bb7565b608001358a888887818110611a8a57611a8a615857565b9050602002810190611a9c9190615bb7565b35898988818110611aaf57611aaf615857565b9050602002810190611ac19190615bb7565b602001358a8a89818110611ad757611ad7615857565b9050602002810190611ae99190615bb7565b604001358b8b8a818110611aff57611aff615857565b9050602002810190611b119190615bb7565b604080516020810199909952880196909652606087810195909552608087019390935260a086019190915260c085015260e084015201356101008201526101200160405160208183030381529060405280519060200120858584818110611b7a57611b7a615857565b9050602002810190611b8c9190615bb7565b611b9a9060c0810190615bd7565b878786818110611bac57611bac615857565b9050602002810190611bbe9190615bb7565b611bcc9060a0810190615bd7565b613158565b600101611a42565b506000606460076001015410611bf0576064611bf4565b6008545b90506000611c0182610b30565b90506000826001600160401b03811115611c1d57611c1d615841565b604051908082528060200260200182016040528015611c46578160200160208202803683370190505b50905060005b83811015611d44576000805b86811015611d3a57611c9b898983818110611c7557611c75615857565b9050602002810190611c879190615bb7565b611c959060a0810190615bd7565b8561325c565b15611cae5781611caa8161586d565b9250505b6001821115611d2857611cff858481518110611ccc57611ccc615857565b60200260200101518a8a84818110611ce657611ce6615857565b9050602002810190611cf89190615bb7565b358e6132c6565b6001848481518110611d1357611d13615857565b91151560209283029190910190910152611d3a565b80611d328161586d565b915050611c58565b5050600101611c4c565b50611d518b89898461349d565b5050505050505050505050565b6000611d6b600783611f04565b5492915050565b6000611d7f600784611f04565b90506000611d8d823361383a565b905080600003611d9d5750505050565b8215611db357611dae338583612fa8565b611dbd565b611dbd33826126a2565b821515846001600160a01b0316336001600160a01b03167f6b2cd13395c5d2d1f95934a6a8f884d2cb71e846eb99d6759f7e6a39c060b2d084604051611e0591815260200190565b60405180910390a450505050565b6001546001600160a01b0382166000908152600e602052604081209091611e3a9190612e41565b5092915050565b6000611545600783613881565b611e56612eba565b60a880546001600160a01b0383166001600160a01b03199091168117909155611e876076546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6001546001600160a01b0382166000908152600e60205260408120909161154591906138b6565b6001600160a01b031660009081526003918201602052604090200190565b6001600160a01b031660009081526004919091016020526040902090565b60065460009081906001600160a01b031663ebbdac918585611f438961394c565b6040518463ffffffff1660e01b8152600401611f6193929190615c1d565b6040805180830381865afa158015611f7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa19190615c61565b91509150801580611fb0575081155b15611fd05784604051633615713d60e21b8152600401610a7b91906154f0565b5050505050565b6001600160a01b038216611fed57611fed615b48565b611ff78383613a1c565b15612017578160405163cda981d560e01b8152600401610a7b91906154f0565b6001600160a01b0382166000908152600380850160205260409091208251839291909101906120499082906004615347565b50602082810151600483015560408301516005830155606083015160068301556080909201516007909101805460ff191691151591909117905581015160000361209257505050565b82546000906001600160a01b0316816120ab8686613881565b90505b6001600160a01b03821615612121578192506120ca8683613881565b8110156120f9576001600160a01b039182166000908152600387016020526040902060010154909116906120ae565b6001600160a01b039182166000908152600387016020526040902060020154909116906120ae565b6040518060a00160405280846001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160011515815260200185815250866003016000876001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060608201518160020160146101000a81548160ff021916908315150217905550608082015181600301600082015181600001906004612256929190615347565b506020820151600482015560408201516005820155606082015160068201556080909101516007909101805460ff191691151591909117905550506001600160a01b0383166122bd5785546001600160a01b0319166001600160a01b03861617865561233a565b6122c78684613881565b811015612306576001600160a01b038381166000908152600388016020526040902060010180546001600160a01b03191691871691909117905561233a565b6001600160a01b038381166000908152600388016020526040902060020180546001600160a01b0319169187169190911790555b6123448686613a6d565b6001860180549060006123568361586d565b91905055508360200151866002016000828254612373919061581f565b9091555050505050505050565b6001600160a01b038116600081815260106020526040808220805460ff19169055517fcdd2e9b91a56913d370075169cefa1602ba36be5301664f752192bb1709df7579190a250565b80546001600160a01b03168015612425575b6001600160a01b0381811660009081526003840160205260409020600201541615612425576001600160a01b039081166000908152600383016020526040902060020154166123db565b919050565b60006001600160a01b038216612453576040516365e52d5160e11b815260040160405180910390fd5b6001600160a01b03828116600090815260038501602052604090206001015416156124aa576001600160a01b0380831660009081526003850160205260409020600101546124a391859116613dba565b9050611545565b506001600160a01b038082166000908152600384016020526040902054165b6001600160a01b0381161580159061250257506001600160a01b0380821660009081526003850160205260409020600101548382169116145b15611545576001600160a01b038082166000908152600385016020526040902054919250166124c9565b6001600160a01b038116600090815260018301602052604081205461255357506000611545565b8261255e8184613e10565b8154811061256e5761256e615857565b906000526020600020906003020160010154905092915050565b6000818181121561154557611545615b48565b6001600160a01b0383166000908152600185016020526040812054908190036126465784546125cb90600161581f565b6001600160a01b03858116600081815260018981016020908152604080842087905580516060810182529485528482018a81529085018981528c548085018e558d8652929094209451600390920290940180546001600160a01b03191691909516178455915191830191909155516002909101559050611fd0565b6000856126538187613e10565b8154811061266357612663615857565b90600052602060002090600302019050838160010160008282546126879190615886565b92505081905550828160020160008282546123739190615886565b6126d381600180546126b4919061581f565b6001600160a01b0385166000908152600e602052604090209190613e46565b816001600160a01b03167f655c1cd0236fb6dc4916f34c8ff10e3b18fcaea5b344dfc16c36fbb1bdfc5df282604051610b2491815260200190565b6001805461271c9190615a67565b8135146127615760405162461bcd60e51b8152602060048201526013602482015272115413d0d217d393d517d0d3d3535255151151606a1b6044820152606401610a7b565b60006127706020830183615c90565b9150506064811180159061278657506008548111155b6127a25760405162461bcd60e51b8152600401610a7b90615b8f565b60006127ac610c3b565b90506000805460646127be9190615cd9565b6127cd86356020880135615a67565b6003546127da9190615cd9565b6127e5906064615cd9565b6127ef9190615cf0565b905060005b838110156119c857600061280b6020870187615c90565b8381811061281b5761281b615857565b9050604002018036038101906128319190615d3a565b805190915060009061284590600790611ee6565b90506000612857604089013587615cd9565b6020840151845161286a90600790611f04565b54600485015461287a919061581f565b6128849088615cd9565b61288e9190615cd9565b6128989190615cf0565b90506000806128ab856000015184613f64565b915091506128bd85600001518361409d565b84516128c99082614108565b5050505050806128d89061586d565b90506127f4565b600c60005b8154811015612aae57600082828154811061290157612901615857565b600091825260209182902060408051606081018252600390930290910180546001600160a01b03168084526001820154948401949094526002015490820152915061294d600782613a1c565b15612a9b57600061295f600783611ee6565b905061297d836020015182600401546129789190615886565b614152565b600482015560208301516009546129979161297891615886565b60095560006129a7600784613881565b905060006129b6600785614168565b90506001600160a01b038116158015906129d95750816129d7600783613881565b105b806129f85750816129f66129ee60078761242a565b600790613881565b115b15612a7e57612a08600785614263565b604080516101208101909152612a7e908590858160a081018260048282826020028201915b815481526020019060010190808311612a2d57505050918352505060048201546020820152600582015460408201526006820154606082015260079182015460ff1615156080909101529190611fd7565b6001600160a01b0384166000908152600d60205260408120555050505b505080612aa79061586d565b90506128e4565b5060005b8154811015612c09576000828281548110612acf57612acf615857565b600091825260209182902060408051606081018252600390930290910180546001600160a01b031680845260018201549484019490945260020154908201529150612b1b600782613a1c565b158015612b3f57506001600160a01b0381166000908152600d602052604090205415155b15612bf6576000612b51600783611ee6565b9050612b608360200151614152565b60048281019190915560408051610120810191829052835460a08201908152612bdb9386938692849290918491906001830160c08601808311612a2d57505050918352505060048201546020820152600582015460408201526006820154606082015260079182015460ff1615156080909101529190611fd7565b6001600160a01b0382166000908152600d6020526040812055505b505080612c029061586d565b9050612ab2565b506000600c5550565b81546000908103612c2557506000611545565b82546000905b80821015612c72576000612c3f8383614644565b60008781526020902090915085908201541115612c5e57809150612c6c565b612c6981600161581f565b92505b50612c2b565b600082118015612c9e575083612c9b86612c8d600186615a67565b600091825260209091200190565b54145b15612cb757612cae600183615a67565b92505050611545565b509050611545565b505092915050565b60008260010154600003612cdd57506000611545565b600183015483546001600160a01b0384166000908152600686016020526040902054612d099190615cd9565b6115429190615cf0565b8254600184015460009190612d289084615cd9565b612d329190615cf0565b6001600160a01b0384166000908152600686016020526040812080549293508392909190612d61908490615a67565b9250508190555080846001016000828254612d7c9190615a67565b90915550506002840154612d9a90612d95908390615cd9565b612588565b6001600160a01b038416600090815260048601602052604081208054909190612dc4908490615886565b9091555050835482908590600090612ddd908490615a67565b909155505050505050565b600260da5403612e3a5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a7b565b600260da55565b81546000905b8360010154811015612eac57600081815260028501602090815260409182902082518084019093528054835260010154908201819052841015612e8a5750612eac565b8051612e96908461581f565b9250508080612ea49061586d565b915050612e47565b9250929050565b600160da55565b6076546001600160a01b031633146115745760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a7b565b6001600160a01b0381166000908152600583016020526040812054612f39848461465f565b6115429190615a67565b60a880546001600160a01b03191690556114cf816146d9565b6001600160a01b038116600081815260106020526040808220805460ff19166001179055517fa850ae9193f515cbae8d35e8925bd2be26627fc91bce650b8652ed254e9cab039190a250565b612fb3600783611ee6565b6007015460ff16612ffb5760405163973d02cb60e01b815260206004820152601160248201527024a72b20a624a22fab20a624a220aa27a960791b6044820152606401610a7b565b61300a82600061134684612588565b613021838261301a600786611f04565b919061472b565b816001600160a01b0316836001600160a01b03167fe5541a6b6103d4fa7e021ed54fad39c66f27a76bd13d374cf6240ae6bd0bb72b8360405161306691815260200190565b60405180910390a3505050565b604354610100900460ff1661309a5760405162461bcd60e51b8152600401610a7b90615d74565b61157461480b565b600081815b8181101561314d5760006130bc82600161581f565b90505b8281101561313a578585828181106130d9576130d9615857565b90506020028101906130eb9190615bb7565b6080013586868481811061310157613101615857565b90506020028101906131139190615bb7565b60800135036131285760009350505050611545565b806131328161586d565b9150506130bf565b50806131458161586d565b9150506130a7565b506001949350505050565b6000806120306001600160a01b0316620249f08888888888604051602001613184959493929190615de8565b60408051601f198184030181529082905261319e91615e45565b6000604051808303818686fa925050503d80600081146131da576040519150601f19603f3d011682016040523d82523d6000602084013e6131df565b606091505b50915091506000818060200190518101906131fa9190615e57565b90508280156132065750805b6132525760405162461bcd60e51b815260206004820152601d60248201527f5349474e41545552455f564552494649434154494f4e5f4641494c45440000006044820152606401610a7b565b5050505050505050565b60008061326a600884615cf0565b90506000613279600885615a90565b905084821061328d576000925050506132bf565b6000600160ff83161b8787858181106132a8576132a8615857565b9050013560f81c60f81b60f81c60ff161611925050505b9392505050565b600082815261013e6020908152604080832084845282528083206001600160a01b038716845290915290205460ff16156132ff57505050565b600082815261013e6020908152604080832084845282528083206001600160a01b03871684529091528120805460ff19166001179055613340600785611ee6565b6001600160a01b0385166000908152600b602052604090205490915060649061336b90600a90615cd9565b6133759190615cf0565b6001600160a01b0385166000908152600b60205260408120805490919061339d908490615a67565b9250508190555060006064600a83600401546133b99190615cd9565b6133c39190615cf0565b90506133d0600786614263565b808260040160008282546133e49190615a67565b909155505060408051610120810190915261345e908690848160a08101826004828282602002820191815481526020019060010190808311612a2d57505050918352505060048201546020820152600582015460408201526006820154606082015260079182015460ff1615156080909101529190611fd7565b8284866001600160a01b03167f2d7432ca38933aadba9547f33f0568008e240e52e66f1a16c6182e742bce3b1360405160405180910390a45050505050565b60018054600091826134ae8361586d565b9190505590508085146134d35760405162461bcd60e51b8152600401610a7b90615a0d565b83356020850135116134f75760405162461bcd60e51b8152600401610a7b90615a3a565b8335600f6000613508600185615a67565b8152602001908152602001600020600101546001613526919061581f565b146135435760405162461bcd60e51b8152600401610a7b90615aa4565b6000818152600f6020908152604080832087830135600180830182905589358355928901356002808401919091558054938401815585527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace9092019190915591906135b090860186615c90565b915050606481118015906135c657506008548111155b6135e25760405162461bcd60e51b8152600401610a7b90615b8f565b60006135ec610c3b565b90506000805460646135fe9190615cd9565b61360d893560208b0135615a67565b60035461361a9190615cd9565b613625906064615cd9565b61362f9190615cf0565b905060005b838110156137de5786818151811061364e5761364e615857565b60200260200101516137ce57600061366960208a018a615c90565b8381811061367957613679615857565b90506040020180360381019061368f9190615d3a565b80519091506000906136a390600790611ee6565b905060006136b560408c013587615cd9565b602084015184516136c890600790611f04565b5460048501546136d8919061581f565b6136e29088615cd9565b6136ec9190615cd9565b6136f69190615cf0565b9050600080613709856000015184613f64565b9150915081846006016000828254613721919061581f565b909155505084516040518481526001600160a01b03909116907f65da9d8bbc1fc112cfb499f15f17b3bfe4c5070dfca6a3e30f7f5f7f17bd86849060200160405180910390a2845161378190829061377b90600790611f04565b90614832565b84600001516001600160a01b03167f520e62b73478b262ede881cd483440f8e7b8a4651b0ff9154aeb3510089ddbac826040516137c091815260200190565b60405180910390a250505050505b6137d78161586d565b9050613634565b506137e76128df565b876020013588600001358a7f0ce8712c4dee4bd5a691f0bc1c39594671591e77395f8ebf6a3fb5f63fbea66a8b6040013560405161382791815260200190565b60405180910390a4505050505050505050565b60006138468383612f14565b6001600160a01b038316600090815260058501602052604081208054929350839290919061387590849061581f565b90915550909392505050565b6001600160a01b038116600090815260048301602090815260408083205460038601909252822060070154611542919061581f565b60018201546000908082036138cf576000915050611545565b60006138dc600183615a67565b90505b84548110612cbf57600081815260028601602090815260409182902082518084019093528054835260010154908201819052851061391d5750612cbf565b8051613929908561581f565b9350816000036139395750612cbf565b508061394481615e74565b9150506138df565b613954615381565b6006546040516bffffffffffffffffffffffff19606085901b1660208201524660348201526001600160a01b039091169063a850a909907ffd10bf199d0185af9cce2005e6acc8d19924428058ac3374e16f18c97569b4ee906054016040516020818303038152906040526040518363ffffffff1660e01b81526004016139dc929190615e8b565b6040805180830381865afa1580156139f8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115459190615ec5565b60006001600160a01b03821615801590611542575082546001600160a01b03838116911614806115425750506001600160a01b03908116600090815260039290920160205260409091205416151590565b60005b82546001600160a01b03838116911614801590613aba57506001600160a01b0382811660009081526003850160205260408082205490921681522060020154600160a01b900460ff165b15613d8c576001600160a01b03808316600090815260038501602052604080822054831680835281832054841683529120600101549091168103613c42576001600160a01b0381811660009081526003860160205260408082205483168252808220600290810154909316808352912090910154909250600160a01b900460ff1615613ba3576001600160a01b0380821660008181526003870160205260408082206002808201805460ff60a01b1990811690915588871685528385208201805482169055825487168552928420018054909216600160a01b1790915591905254169250613d86565b6001600160a01b038082166000908152600386016020526040902060020154811690841603613bd957809250613bd984846148af565b506001600160a01b0380831660009081526003850160205260408082205483168083528183206002808201805460ff60a01b19908116909155825487168652938520018054909316600160a01b1790925591829052549091613c3d91869116614a62565b613d86565b6001600160a01b03818116600090815260038601602052604080822054831682528082206001015490921680825291902060020154909250600160a01b900460ff1615613cec576001600160a01b0380821660008181526003870160205260408082206002808201805460ff60a01b1990811690915588871685528385208201805482169055825487168552928420018054909216600160a01b1790915591905254169250613d86565b6001600160a01b038082166000908152600386016020526040902060010154811690841603613d2257809250613d228484614a62565b506001600160a01b0380831660009081526003850160205260408082205483168083528183206002808201805460ff60a01b19908116909155825487168652938520018054909316600160a01b1790925591829052549091613d86918691166148af565b50613a70565b505080546001600160a01b03166000908152600390910160205260409020600201805460ff60a01b19169055565b60005b6001600160a01b0382811660009081526003850160205260409020600201541615613e0a576001600160a01b03918216600090815260038401602052604090206002015490911690613dbd565b50919050565b6001600160a01b038116600090815260018301602052604081205490819003613e3b57613e3b615b48565b611542600182615a67565b81600003613e5657613e56615b48565b82546001840154818103613ead576040805180820182528581526020808201868152600085815260028a019092529281209151825591516001918201558601805491613ea18361586d565b91905055505050505050565b60006002860181613ebf600185615a67565b815260200190815260200160002060010154905080841015613ee357613ee3615b48565b83811015613f32576040805180820182528681526020808201878152600086815260028b019092529281209151825591516001918201558701805491613f288361586d565b91905055506119c8565b84600287016000613f44600186615a67565b81526020019081526020016000206000016000828254612373919061581f565b60008080613f73600786611ee6565b604080516101208101909152908160a081018260048282826020028201915b815481526020019060010190808311613f925750505091835250506004820154602080830191909152600583015460408301526006830154606083015260079283015460ff161515608090920191909152820151919250600090613ff69088611f04565b54905060008290036140115760008094509450505050612eac565b806000036140285785600094509450505050612eac565b6000614034828461581f565b61403e8489615cd9565b6140489190615cf0565b905060006140568289615a67565b90506000606482876040015161406c9190615cd9565b6140769190615cf0565b9050614082818461581f565b61408c8284615a67565b975097505050505050509250929050565b60006140aa600784611ee6565b9050818160060160008282546140c0919061581f565b90915550506040518281526001600160a01b038416907f65da9d8bbc1fc112cfb499f15f17b3bfe4c5070dfca6a3e30f7f5f7f17bd86849060200160405180910390a2505050565b6141178161377b600785611f04565b816001600160a01b03167f520e62b73478b262ede881cd483440f8e7b8a4651b0ff9154aeb3510089ddbac82604051610b2491815260200190565b60008082121561416457614164615b48565b5090565b60006001600160a01b038216614191576040516365e52d5160e11b815260040160405180910390fd5b6001600160a01b03828116600090815260038501602052604090206002015416156141e1576001600160a01b0380831660009081526003850160205260409020600201546124a391859116614c15565b506001600160a01b038082166000908152600384016020526040902054165b6001600160a01b0381161580159061423957506001600160a01b0380821660009081526003850160205260409020600201548382169116145b15611545576001600160a01b03808216600090815260038501602052604090205491925016614200565b6001600160a01b03811661427957614279615b48565b6142838282613a1c565b6142a25780604051634b2990ed60e11b8152600401610a7b91906154f0565b6001600160a01b038181166000908152600384016020526040812060010154909182911615806142ef57506001600160a01b03838116600090815260038601602052604090206002015416155b156142fb575081614367565b506001600160a01b038083166000908152600385016020526040902060020154165b6001600160a01b0381811660009081526003860160205260409020600101541615614367576001600160a01b0390811660009081526003850160205260409020600101541661431d565b6001600160a01b03818116600090815260038601602052604090206001015416156143b3576001600160a01b0380821660009081526003860160205260409020600101541691506143d6565b6001600160a01b0380821660009081526003860160205260409020600201541691505b6001600160a01b038082166000908152600386016020526040808220548584168352912080546001600160a01b0319169190921690811790915580156144af576001600160a01b038082166000908152600387016020526040902060010154811690831603614477576001600160a01b038181166000908152600387016020526040902060010180546001600160a01b0319169185169190911790556144c9565b6001600160a01b038181166000908152600387016020526040902060020180546001600160a01b0319169185169190911790556144c9565b84546001600160a01b0319166001600160a01b0384161785555b6001600160a01b038281166000818152600388016020526040902060020154600160a01b900460ff1615918616146145a457614506868487614c65565b6001600160a01b03858116600090815260038801602052604080822060018082015488861680865284862092830180549288166001600160a01b03199384168117909155865284862080548316821790556002938401805494909301805494909716938216841787559285529284208054909316821790925590549152815460ff60a01b1916600160a01b9182900460ff1615159091021790559193915b80156145b4576145b48685614d5d565b6001600160a01b0383166000908152600387016020526040812080546001600160a01b0319908116825560018083018054909216909155600290910180546001600160a81b0319169055870180549161460c83615e74565b90915550506001600160a01b038316600090815260038701602052604081206007015460028801805491929091612373908490615a67565b60006146536002848418615cf0565b6115429084841661581f565b6001600160a01b03811660009081526006830160205260408120546002840154829161468f91612d959190615cd9565b6001600160a01b0384166000908152600486016020526040812054919250906146bc906129789084615886565b90506146d0670de0b6b3a764000082615cf0565b95945050505050565b607680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600083600101546000148061473f57508354155b61476357835460018501546147549084615cd9565b61475e9190615cf0565b614765565b815b6001600160a01b038416600090815260068601602052604081208054929350839290919061479490849061581f565b92505081905550808460010160008282546147af919061581f565b90915550508354829085906000906147c890849061581f565b909155505060028401546147e190612d95908390615cd9565b6001600160a01b038416600090815260048601602052604081208054909190612ddd908490615905565b604354610100900460ff16612eb35760405162461bcd60e51b8152600401610a7b90615d74565b8060000361483e575050565b8160010154600003614872576003820154604051636130835f60e01b8152610a7b916001600160a01b0316906004016154f0565b6001820154614889670de0b6b3a764000083615cd9565b6148939190615cf0565b8260020160008282546148a6919061581f565b90915550505050565b6001600160a01b038082166000818152600385016020526040808220600281018054915482871680865293852060010154959094526001600160a01b031990911693851693841790559216908015614932576001600160a01b038181166000908152600387016020526040902080546001600160a01b0319169186169190911790555b6001600160a01b038381166000908152600387016020526040902080546001600160a01b03191691841691821790556149835784546001600160a01b0319166001600160a01b038416178555614a18565b6001600160a01b0380831660009081526003870160205260409020600101548116908516036149e4576001600160a01b038281166000908152600387016020526040902060010180546001600160a01b031916918516919091179055614a18565b6001600160a01b038281166000908152600387016020526040902060020180546001600160a01b0319169185169190911790555b50506001600160a01b039081166000818152600390940160205260408085206001018054939094166001600160a01b03199384168117909455928452919092208054909216179055565b6001600160a01b038082166000818152600385016020526040808220600181018054915482871680865293852060020154959094526001600160a01b031990911693851693841790559216908015614ae5576001600160a01b038181166000908152600387016020526040902080546001600160a01b0319169186169190911790555b6001600160a01b038381166000908152600387016020526040902080546001600160a01b0319169184169182179055614b365784546001600160a01b0319166001600160a01b038416178555614bcb565b6001600160a01b038083166000908152600387016020526040902060020154811690851603614b97576001600160a01b038281166000908152600387016020526040902060020180546001600160a01b031916918516919091179055614bcb565b6001600160a01b038281166000908152600387016020526040902060010180546001600160a01b0319169185169190911790555b50506001600160a01b039081166000818152600390940160205260408085206002018054939094166001600160a01b03199384168117909455928452919092208054909216179055565b60005b6001600160a01b0382811660009081526003850160205260409020600101541615613e0a576001600160a01b03918216600090815260038401602052604090206001015490911690614c18565b6001600160a01b038082166000908152600385016020526040808220548584168352912080546001600160a01b0319169190921690811790915580614cc25783546001600160a01b0319166001600160a01b038416178455614d57565b6001600160a01b038082166000908152600386016020526040902060010154811690831603614d23576001600160a01b038181166000908152600386016020526040902060010180546001600160a01b031916918516919091179055614d57565b6001600160a01b038181166000908152600386016020526040902060020180546001600160a01b0319169185169190911790555b50505050565b60005b82546001600160a01b03838116911614801590614da257506001600160a01b0382166000908152600384016020526040902060020154600160a01b900460ff16155b156152fe576001600160a01b038083166000818152600386016020526040808220548416808352912060010154909216900361506c576001600160a01b038181166000908152600386016020526040808220600290810154909316808352912090910154909250600160a01b900460ff1615614e89576001600160a01b0380831660009081526003860160205260408082206002908101805460ff60a01b1990811690915593851683529120018054909116600160a01b179055614e6684826148af565b6001600160a01b0380821660009081526003860160205260409020600201541691505b6001600160a01b0382811660009081526003860160205260408082206001015490921681522060020154600160a01b900460ff16158015614efc57506001600160a01b038281166000908152600386016020526040808220600290810154909316825290200154600160a01b900460ff16155b15614f37576001600160a01b03821660009081526003850160205260409020600201805460ff60a01b1916600160a01b1790559150816152f8565b6001600160a01b038281166000908152600386016020526040808220600290810154909316825290200154600160a01b900460ff16614fec576001600160a01b0380831660008181526003870160205260408082206001810154909416825281206002908101805460ff60a01b19908116909155929091529091018054909116600160a01b179055614fc98483614a62565b6001600160a01b0380821660009081526003860160205260409020600201541691505b6001600160a01b0380821660009081526003860160205260408082206002908101805487861685528385208301805460ff600160a01b9384900416151590920260ff60a01b1992831617815582548216909255905490941683529120018054909116905561505a84826148af565b83546001600160a01b031692506152f8565b6001600160a01b0381811660009081526003860160205260408082206001015490921680825291902060020154909250600160a01b900460ff161561511c576001600160a01b0380831660009081526003860160205260408082206002908101805460ff60a01b1990811690915593851683529120018054909116600160a01b1790556150f98482614a62565b6001600160a01b0380821660009081526003860160205260409020600101541691505b6001600160a01b038281166000908152600386016020526040808220600290810154909316825290200154600160a01b900460ff1615801561518f57506001600160a01b0382811660009081526003860160205260408082206001015490921681522060020154600160a01b900460ff16155b156151ca576001600160a01b03821660009081526003850160205260409020600201805460ff60a01b1916600160a01b1790559150816152f8565b6001600160a01b0382811660009081526003860160205260408082206001015490921681522060020154600160a01b900460ff16615277576001600160a01b03808316600081815260038701602052604080822060029081018054909516835290822001805460ff60a01b19908116909155919052815416600160a01b17905561525484836148af565b6001600160a01b0380821660009081526003860160205260409020600101541691505b6001600160a01b038082166000908152600386016020526040808220600290810180548786168552838520808401805460ff600160a01b9485900416151590930260ff60a01b19938416179055825482169092556001909101549094168352912001805490911690556152ea8482614a62565b83546001600160a01b031692505b50614d60565b506001600160a01b03166000908152600390910160205260409020600201805460ff60a01b19169055565b60405180608001604052806004906020820280368337509192915050565b8260048101928215615375579160200282015b8281111561537557825182559160200191906001019061535a565b5061416492915061539f565b60405180604001604052806002906020820280368337509192915050565b5b8082111561416457600081556001016153a0565b6020808252825182820181905260009190848201906040850190845b818110156153f55783516001600160a01b0316835292840192918401916001016153d0565b50909695505050505050565b6001600160a01b03811681146114cf57600080fd5b803561242581615401565b60006020828403121561543357600080fd5b81356132bf81615401565b6101208101818860005b6004811015615467578151835260209283019290910190600101615448565b505050608082019690965260a081019490945260c084019290925260e0830152151561010090910152919050565b60008060c083850312156154a857600080fd5b60408301848111156154b957600080fd5b8392508460c0850111156154cc57600080fd5b809150509250929050565b6000602082840312156154e957600080fd5b5035919050565b6001600160a01b0391909116815260200190565b600060608284031215613e0a57600080fd5b600080600060a0848603121561552b57600080fd5b8335925061553c8560208601615504565b915060808401356001600160401b0381111561555757600080fd5b61556386828701615504565b9150509250925092565b6000806040838503121561558057600080fd5b823561558b81615401565b946020939093013593505050565b60008083601f8401126155ab57600080fd5b5081356001600160401b038111156155c257600080fd5b6020830191508360208260051b8501011115612eac57600080fd5b600080602083850312156155f057600080fd5b82356001600160401b0381111561560657600080fd5b61561285828601615599565b90969095509350505050565b6000806040838503121561563157600080fd5b823561563c81615401565b915060208301356154cc81615401565b60008060006060848603121561566157600080fd5b8335925060208401359150604084013561567a81615401565b809150509250925092565b80151581146114cf57600080fd5b600080604083850312156156a657600080fd5b82356156b181615401565b915060208301356154cc81615685565b600080600080600085870360e08112156156da57600080fd5b60808112156156e857600080fd5b5085945060808601356001600160401b038082111561570657600080fd5b818801915088601f83011261571a57600080fd5b81358181111561572957600080fd5b8960208260081b850101111561573e57600080fd5b60208301965080955050505061575660a08701615416565b915061576460c08701615416565b90509295509295909350565b6000806000806000806000610100888a03121561578c57600080fd5b8735965060208801359550604088013594506157ab8960608a01615504565b935060c08801356001600160401b03808211156157c757600080fd5b6157d38b838c01615504565b945060e08a01359150808211156157e957600080fd5b506157f68a828b01615599565b989b979a50959850939692959293505050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561154557611545615809565b60808181019083833792915050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60006001820161587f5761587f615809565b5060010190565b8082018281126000831280158216821582161715612cbf57612cbf615809565b6007815266756e7374616b6560c81b602082015260400190565b6040815260006158d2604083016158a6565b82810360208401526132bf816014815273494e53554646494349454e545f42414c414e434560601b602082015260400190565b8181036000831280158383131683831282161715611e3a57611e3a615809565b600d81526c5354414b455f544f4f5f4c4f5760981b602082015260400190565b604081526000615957604083016158a6565b82810360208401526132bf81615925565b80820260008212600160ff1b8414161561598457615984615809565b818105831482151761154557611545615809565b6020808252600990820152682b20a624a220aa27a960b91b604082015260600190565b6040815260056040820152647374616b6560d81b606082015260806020820152600061154560808301615925565b6020808252600a908201526914d654d5115350d0531360b21b604082015260600190565b60208082526013908201527215539156141150d5115117d15413d0d217d251606a1b604082015260600190565b6020808252601390820152721393d7d09313d0d2d4d7d0d3d3535255151151606a1b604082015260600190565b8181038181111561154557611545615809565b634e487b7160e01b600052601260045260246000fd5b600082615a9f57615a9f615a7a565b500690565b602080825260139082015272494e56414c49445f53544152545f424c4f434b60681b604082015260600190565b600a815269756e64656c656761746560b01b602082015260400190565b6040815260006158d260408301615ad1565b601281527144454c45474154494f4e5f544f4f5f4c4f5760701b602082015260400190565b604081526000615b3760408301615ad1565b82810360208401526132bf81615b00565b634e487b7160e01b600052600160045260246000fd5b60408152600860408201526764656c656761746560c01b606082015260806020820152600061154560808301615b00565b6020808252600e908201526d0929cac82989288be988a9c8ea8960931b604082015260600190565b6000823560de19833603018112615bcd57600080fd5b9190910192915050565b6000808335601e19843603018112615bee57600080fd5b8301803591506001600160401b03821115615c0857600080fd5b602001915036819003821315612eac57600080fd5b61010081016040858337608084604084013760c082018360005b6002811015615c56578151835260209283019290910190600101615c37565b505050949350505050565b60008060408385031215615c7457600080fd5b8251615c7f81615685565b60208401519092506154cc81615685565b6000808335601e19843603018112615ca757600080fd5b8301803591506001600160401b03821115615cc157600080fd5b6020019150600681901b3603821315612eac57600080fd5b808202811582820484141761154557611545615809565b600082615cff57615cff615a7a565b500490565b604080519081016001600160401b0381118282101715615d3457634e487b7160e01b600052604160045260246000fd5b60405290565b600060408284031215615d4c57600080fd5b615d54615d04565b8235615d5f81615401565b81526020928301359281019290925250919050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b858152606060208201526000615e02606083018688615dbf565b8281036040840152615e15818587615dbf565b98975050505050505050565b60005b83811015615e3c578181015183820152602001615e24565b50506000910152565b60008251615bcd818460208701615e21565b600060208284031215615e6957600080fd5b81516132bf81615685565b600081615e8357615e83615809565b506000190190565b8281526040602082015260008251806040840152615eb0816060850160208701615e21565b601f01601f1916919091016060019392505050565b600060408284031215615ed757600080fd5b82601f830112615ee657600080fd5b615eee615d04565b806040840185811115615f0057600080fd5b845b81811015615f1a578051845260209384019301615f02565b50909594505050505056fea2646970667358221220a626fbc30de48fae03e0787e09215ca109af7c4393b840809136a8d3e07d3add64736f6c63430008110033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" -var L2StateSenderArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"L2StateSender\",\n \"sourceName\": \"contracts/child/L2StateSender.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"L2StateSynced\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAX_LENGTH\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"counter\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"syncState\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50610297806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806316f198311461004657806361bc221a1461005b578063a6f9885c14610076575b600080fd5b61005961005436600461017a565b61007f565b005b61006460005481565b60405190815260200160405180910390f35b61006461080081565b6001600160a01b0383166100cd5760405162461bcd60e51b815260206004820152601060248201526f24a72b20a624a22fa922a1a2a4ab22a960811b60448201526064015b60405180910390fd5b6108008111156101145760405162461bcd60e51b815260206004820152601260248201527108ab0868a8a88a6be9a82b0be988a9c8ea8960731b60448201526064016100c4565b826001600160a01b0316336001600160a01b031660008081546101369061020b565b9190508190557fedaf3c471ebd67d60c29efe34b639ede7d6a1d92eaeb3f503e784971e67118a5858560405161016d929190610232565b60405180910390a4505050565b60008060006040848603121561018f57600080fd5b83356001600160a01b03811681146101a657600080fd5b9250602084013567ffffffffffffffff808211156101c357600080fd5b818601915086601f8301126101d757600080fd5b8135818111156101e657600080fd5b8760208285010111156101f857600080fd5b6020830194508093505050509250925092565b60006001820161022b57634e487b7160e01b600052601160045260246000fd5b5060010190565b60208152816020820152818360408301376000818301604090810191909152601f909201601f1916010191905056fea2646970667358221220d2d546f135265c71683c4923890de2d8ae66f3be17185690036424019a5309ae64736f6c63430008110033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106100415760003560e01c806316f198311461004657806361bc221a1461005b578063a6f9885c14610076575b600080fd5b61005961005436600461017a565b61007f565b005b61006460005481565b60405190815260200160405180910390f35b61006461080081565b6001600160a01b0383166100cd5760405162461bcd60e51b815260206004820152601060248201526f24a72b20a624a22fa922a1a2a4ab22a960811b60448201526064015b60405180910390fd5b6108008111156101145760405162461bcd60e51b815260206004820152601260248201527108ab0868a8a88a6be9a82b0be988a9c8ea8960731b60448201526064016100c4565b826001600160a01b0316336001600160a01b031660008081546101369061020b565b9190508190557fedaf3c471ebd67d60c29efe34b639ede7d6a1d92eaeb3f503e784971e67118a5858560405161016d929190610232565b60405180910390a4505050565b60008060006040848603121561018f57600080fd5b83356001600160a01b03811681146101a657600080fd5b9250602084013567ffffffffffffffff808211156101c357600080fd5b818601915086601f8301126101d757600080fd5b8135818111156101e657600080fd5b8760208285010111156101f857600080fd5b6020830194508093505050509250925092565b60006001820161022b57634e487b7160e01b600052601160045260246000fd5b5060010190565b60208152816020820152818360408301376000818301604090810191909152601f909201601f1916010191905056fea2646970667358221220d2d546f135265c71683c4923890de2d8ae66f3be17185690036424019a5309ae64736f6c63430008110033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" -var StateReceiverArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"StateReceiver\",\n \"sourceName\": \"contracts/child/StateReceiver.sol\",\n \"abi\": [\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"only\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"Unauthorized\",\n \"type\": \"error\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"startId\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"endId\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bytes32\",\n \"name\": \"root\",\n \"type\": \"bytes32\"\n }\n ],\n \"name\": \"NewCommitment\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"counter\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bool\",\n \"name\": \"status\",\n \"type\": \"bool\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bytes\",\n \"name\": \"message\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"StateSyncResult\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TOKEN_CONTRACT\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"SYSTEM\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32[][]\",\n \"name\": \"proofs\",\n \"type\": \"bytes32[][]\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"internalType\": \"struct StateReceiver.StateSync[]\",\n \"name\": \"objs\",\n \"type\": \"tuple[]\"\n }\n ],\n \"name\": \"batchExecute\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"components\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"startId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"endId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"root\",\n \"type\": \"bytes32\"\n }\n ],\n \"internalType\": \"struct StateReceiver.StateSyncCommitment\",\n \"name\": \"commitment\",\n \"type\": \"tuple\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"signature\",\n \"type\": \"bytes\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"bitmap\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"commit\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"commitmentCounter\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"commitmentIds\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"commitments\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"startId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"endId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"root\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32[]\",\n \"name\": \"proof\",\n \"type\": \"bytes32[]\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"internalType\": \"struct StateReceiver.StateSync\",\n \"name\": \"obj\",\n \"type\": \"tuple\"\n }\n ],\n \"name\": \"execute\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"getCommitmentByStateSyncId\",\n \"outputs\": [\n {\n \"components\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"startId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"endId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"root\",\n \"type\": \"bytes32\"\n }\n ],\n \"internalType\": \"struct StateReceiver.StateSyncCommitment\",\n \"name\": \"\",\n \"type\": \"tuple\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"getRootByStateSyncId\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"lastCommittedId\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"processedStateSyncs\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50611428806100206000396000f3fe608060405234801561001057600080fd5b50600436106100e05760003560e01c80639017c127116100875780639017c127146101de578063947287cf146101f157806397e5230d146101fa578063ad240c2a14610204578063c59a18f71461020d578063c6df461714610220578063e0563ab114610233578063eb70ef441461023c57600080fd5b8063196f1b2d146100e557806323e281cf1461010b578063284017f5146101145780633b878c221461013557806349ce89971461013e57806350d5b95b1461018857806351351d531461019d578063544c5e0f146101ab575b600080fd5b6100f86100f3366004610e88565b610271565b6040519081526020015b60405180910390f35b6100f860325481565b61011d61202081565b6040516001600160a01b039091168152602001610102565b61011d61101081565b61016d61014c366004610e88565b60356020526000908152604090208054600182015460029092015490919083565b60408051938452602084019290925290820152606001610102565b61019b610196366004610eec565b6102f0565b005b61011d6002600160a01b0381565b6101ce6101b9366004610e88565b60346020526000908152604090205460ff1681565b6040519015158152602001610102565b61019b6101ec366004610f5b565b6103b7565b6100f861520881565b6100f8620249f081565b6100f860335481565b6100f861021b366004610e88565b610557565b61019b61022e366004611007565b610578565b61011d61203081565b61024f61024a366004610e88565b61075c565b6040805182518152602080840151908201529181015190820152606001610102565b60008060358161028260368661081f565b81526020810191909152604001600020600201549050806102ea5760405162461bcd60e51b815260206004820152601d60248201527f537461746552656365697665723a204e4f5f524f4f545f464f525f494400000060448201526064015b60405180910390fd5b92915050565b60006102fc823561075c565b805190915061036c906103109084356110a5565b8251602084015161032191906110a5565b61032c9060016110b8565b83604001518787876040516020016103449190611110565b604051602081830303815290604052805190602001206108cc9095949392919063ffffffff16565b6103a85760405162461bcd60e51b815260206004820152600d60248201526c24a72b20a624a22fa82927a7a360991b60448201526064016102e1565b6103b182610a68565b50505050565b8281811461041a5760405162461bcd60e51b815260206004820152602a60248201527f537461746552656365697665723a20554e4d4154434845445f4c454e4754485f604482015269504152414d455445525360b01b60648201526084016102e1565b60005b8181101561054f57600061045485858481811061043c5761043c6111ac565b905060200281019061044e91906111c2565b3561075c565b905060006105088260000151878786818110610472576104726111ac565b905060200281019061048491906111c2565b61048f9190356110a5565b835160208501516104a091906110a5565b6104ab9060016110b8565b84604001518b8b888181106104c2576104c26111ac565b90506020028101906104d491906111e2565b8b8b8a8181106104e6576104e66111ac565b90506020028101906104f891906111c2565b6040516020016103449190611110565b90508061051957505060010161041d565b61054586868581811061052e5761052e6111ac565b905060200281019061054091906111c2565b610a68565b505060010161041d565b505050505050565b6036818154811061056757600080fd5b600091825260209091200154905081565b336002600160a01b03146105bc5760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b60448201526064016102e1565b6033546105ca9060016110b8565b85351461060c5760405162461bcd60e51b815260206004820152601060248201526f1253959053125117d4d510549517d25160821b60448201526064016102e1565b8435602086013510156106525760405162461bcd60e51b815260206004820152600e60248201526d1253959053125117d1539117d25160921b60448201526064016102e1565b60408051863560208083019190915287013581830152908601356060820152610697906080016040516020818303038152906040528051906020012085858585610c83565b603280548691603591600091826106ad8361122b565b90915550815260208082019290925260409081016000208335815591830135600183015582013560028201555050603680546001810182556000919091526020868101357f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b89092018290556033829055604080519088013581528735917f11efd893530b26afc66d488ff54cb15df117cb6e0e4a08c6dcb166d766c3bf3b910160405180910390a35050505050565b604080516060810182526000808252602082018190529181018290529061078460368461081f565b60365490915081036107e45760405162461bcd60e51b815260206004820152602360248201527f537461746552656365697665723a204e4f5f434f4d4d49544d454e545f464f5260448201526217d25160ea1b60648201526084016102e1565b600090815260356020908152604091829020825160608101845281548152600182015492810192909252600201549181019190915292915050565b81546000908103610832575060006102ea565b82546000905b8082101561087f57600061084c8383610d87565b6000878152602090209091508590820154111561086b57809150610879565b6108768160016110b8565b92505b50610838565b6000821180156108ab5750836108a88661089a6001866110a5565b600091825260209091200190565b54145b156108c4576108bb6001836110a5565b925050506102ea565b509392505050565b6000816108da866001610da9565b811461091f5760405162461bcd60e51b81526020600482015260146024820152730929cac82989288bea0a49e9e8cbe988a9c8ea8960631b60448201526064016102e1565b8587106109635760405162461bcd60e51b81526020600482015260126024820152710929cac82989288be988a828cbe929c888ab60731b60448201526064016102e1565b8761099f5760405162461bcd60e51b815260206004820152600c60248201526b24a72b20a624a22fa622a0a360a11b60448201526064016102e1565b8760005b82811015610a595760008686838181106109bf576109bf6111ac565b90506020020135905060028a6109d5919061125a565b600003610a0d576040805160208101859052908101829052606001604051602081830303815290604052805190602001209250610a3a565b60408051602081018390529081018490526060016040516020818303038152906040528051906020012092505b610a4560028b61126e565b99505080610a529061122b565b90506109a3565b50909414979650505050505050565b803560009081526034602052604090205460ff1615610ad85760405162461bcd60e51b815260206004820152602660248201527f537461746552656365697665723a2053544154455f53594e435f49535f50524f60448201526510d154d4d15160d21b60648201526084016102e1565b610ae86060820160408301611282565b6001600160a01b03163b600003610b3c576040805160208082526000908201819052918335917f31c652130602f3ce96ceaf8a4c2b8b49f049166c6fcf2eb31943a75ec7c936ae910160405180910390a350565b8035600090815260346020526040808220805460ff191660011790558190610b6a9060608501908501611282565b6001600160a01b03168335610b856040860160208701611282565b610b92606087018761129d565b604051602401610ba594939291906112e3565b60408051601f198184030181529181526020820180516001600160e01b031663eeb4994560e01b17905251610bda919061133c565b6000604051808303816000865af19150503d8060008114610c17576040519150601f19603f3d011682016040523d82523d6000602084013e610c1c565b606091505b509150915081610c3f5782356000908152603460205260409020805460ff191690555b81151583600001357f31c652130602f3ce96ceaf8a4c2b8b49f049166c6fcf2eb31943a75ec7c936ae83604051610c76919061134e565b60405180910390a3505050565b6000806120306001600160a01b0316620249f08888888888604051602001610caf959493929190611381565b60408051601f1981840301815290829052610cc99161133c565b6000604051808303818686fa925050503d8060008114610d05576040519150601f19603f3d011682016040523d82523d6000602084013e610d0a565b606091505b5091509150600081806020019051810190610d2591906113ba565b9050828015610d315750805b610d7d5760405162461bcd60e51b815260206004820152601d60248201527f5349474e41545552455f564552494649434154494f4e5f4641494c454400000060448201526064016102e1565b5050505050505050565b6000610d96600284841861126e565b610da2908484166110b8565b9392505050565b600080610db584610df4565b90506001836002811115610dcb57610dcb6113dc565b148015610ddb575083816001901b105b610de6576000610de9565b60015b60ff16019392505050565b600080608083901c15610e0957608092831c92015b604083901c15610e1b57604092831c92015b602083901c15610e2d57602092831c92015b601083901c15610e3f57601092831c92015b600883901c15610e5157600892831c92015b600483901c15610e6357600492831c92015b600283901c15610e7557600292831c92015b600183901c156102ea5760010192915050565b600060208284031215610e9a57600080fd5b5035919050565b60008083601f840112610eb357600080fd5b5081356001600160401b03811115610eca57600080fd5b6020830191508360208260051b8501011115610ee557600080fd5b9250929050565b600080600060408486031215610f0157600080fd5b83356001600160401b0380821115610f1857600080fd5b610f2487838801610ea1565b90955093506020860135915080821115610f3d57600080fd5b50840160808187031215610f5057600080fd5b809150509250925092565b60008060008060408587031215610f7157600080fd5b84356001600160401b0380821115610f8857600080fd5b610f9488838901610ea1565b90965094506020870135915080821115610fad57600080fd5b50610fba87828801610ea1565b95989497509550505050565b60008083601f840112610fd857600080fd5b5081356001600160401b03811115610fef57600080fd5b602083019150836020828501011115610ee557600080fd5b600080600080600085870360a081121561102057600080fd5b606081121561102e57600080fd5b5085945060608601356001600160401b038082111561104c57600080fd5b61105889838a01610fc6565b9096509450608088013591508082111561107157600080fd5b5061107e88828901610fc6565b969995985093965092949392505050565b634e487b7160e01b600052601160045260246000fd5b818103818111156102ea576102ea61108f565b808201808211156102ea576102ea61108f565b80356001600160a01b03811681146110e257600080fd5b919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60208152813560208201526000611129602084016110cb565b60018060a01b03808216604085015280611145604087016110cb565b16606085015250506060830135601e1984360301811261116457600080fd5b83016020810190356001600160401b0381111561118057600080fd5b80360382131561118f57600080fd5b6080808501526111a360a0850182846110e7565b95945050505050565b634e487b7160e01b600052603260045260246000fd5b60008235607e198336030181126111d857600080fd5b9190910192915050565b6000808335601e198436030181126111f957600080fd5b8301803591506001600160401b0382111561121357600080fd5b6020019150600581901b3603821315610ee557600080fd5b60006001820161123d5761123d61108f565b5060010190565b634e487b7160e01b600052601260045260246000fd5b60008261126957611269611244565b500690565b60008261127d5761127d611244565b500490565b60006020828403121561129457600080fd5b610da2826110cb565b6000808335601e198436030181126112b457600080fd5b8301803591506001600160401b038211156112ce57600080fd5b602001915036819003821315610ee557600080fd5b8481526001600160a01b038416602082015260606040820181905260009061130e90830184866110e7565b9695505050505050565b60005b8381101561133357818101518382015260200161131b565b50506000910152565b600082516111d8818460208701611318565b602081526000825180602084015261136d816040850160208701611318565b601f01601f19169190910160400192915050565b85815260606020820152600061139b6060830186886110e7565b82810360408401526113ae8185876110e7565b98975050505050505050565b6000602082840312156113cc57600080fd5b81518015158114610da257600080fd5b634e487b7160e01b600052602160045260246000fdfea2646970667358221220f12de4c572934572c3dae6184bcfe87730e8a0938ba1504547710fd27554218264736f6c63430008110033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106100e05760003560e01c80639017c127116100875780639017c127146101de578063947287cf146101f157806397e5230d146101fa578063ad240c2a14610204578063c59a18f71461020d578063c6df461714610220578063e0563ab114610233578063eb70ef441461023c57600080fd5b8063196f1b2d146100e557806323e281cf1461010b578063284017f5146101145780633b878c221461013557806349ce89971461013e57806350d5b95b1461018857806351351d531461019d578063544c5e0f146101ab575b600080fd5b6100f86100f3366004610e88565b610271565b6040519081526020015b60405180910390f35b6100f860325481565b61011d61202081565b6040516001600160a01b039091168152602001610102565b61011d61101081565b61016d61014c366004610e88565b60356020526000908152604090208054600182015460029092015490919083565b60408051938452602084019290925290820152606001610102565b61019b610196366004610eec565b6102f0565b005b61011d6002600160a01b0381565b6101ce6101b9366004610e88565b60346020526000908152604090205460ff1681565b6040519015158152602001610102565b61019b6101ec366004610f5b565b6103b7565b6100f861520881565b6100f8620249f081565b6100f860335481565b6100f861021b366004610e88565b610557565b61019b61022e366004611007565b610578565b61011d61203081565b61024f61024a366004610e88565b61075c565b6040805182518152602080840151908201529181015190820152606001610102565b60008060358161028260368661081f565b81526020810191909152604001600020600201549050806102ea5760405162461bcd60e51b815260206004820152601d60248201527f537461746552656365697665723a204e4f5f524f4f545f464f525f494400000060448201526064015b60405180910390fd5b92915050565b60006102fc823561075c565b805190915061036c906103109084356110a5565b8251602084015161032191906110a5565b61032c9060016110b8565b83604001518787876040516020016103449190611110565b604051602081830303815290604052805190602001206108cc9095949392919063ffffffff16565b6103a85760405162461bcd60e51b815260206004820152600d60248201526c24a72b20a624a22fa82927a7a360991b60448201526064016102e1565b6103b182610a68565b50505050565b8281811461041a5760405162461bcd60e51b815260206004820152602a60248201527f537461746552656365697665723a20554e4d4154434845445f4c454e4754485f604482015269504152414d455445525360b01b60648201526084016102e1565b60005b8181101561054f57600061045485858481811061043c5761043c6111ac565b905060200281019061044e91906111c2565b3561075c565b905060006105088260000151878786818110610472576104726111ac565b905060200281019061048491906111c2565b61048f9190356110a5565b835160208501516104a091906110a5565b6104ab9060016110b8565b84604001518b8b888181106104c2576104c26111ac565b90506020028101906104d491906111e2565b8b8b8a8181106104e6576104e66111ac565b90506020028101906104f891906111c2565b6040516020016103449190611110565b90508061051957505060010161041d565b61054586868581811061052e5761052e6111ac565b905060200281019061054091906111c2565b610a68565b505060010161041d565b505050505050565b6036818154811061056757600080fd5b600091825260209091200154905081565b336002600160a01b03146105bc5760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b60448201526064016102e1565b6033546105ca9060016110b8565b85351461060c5760405162461bcd60e51b815260206004820152601060248201526f1253959053125117d4d510549517d25160821b60448201526064016102e1565b8435602086013510156106525760405162461bcd60e51b815260206004820152600e60248201526d1253959053125117d1539117d25160921b60448201526064016102e1565b60408051863560208083019190915287013581830152908601356060820152610697906080016040516020818303038152906040528051906020012085858585610c83565b603280548691603591600091826106ad8361122b565b90915550815260208082019290925260409081016000208335815591830135600183015582013560028201555050603680546001810182556000919091526020868101357f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b89092018290556033829055604080519088013581528735917f11efd893530b26afc66d488ff54cb15df117cb6e0e4a08c6dcb166d766c3bf3b910160405180910390a35050505050565b604080516060810182526000808252602082018190529181018290529061078460368461081f565b60365490915081036107e45760405162461bcd60e51b815260206004820152602360248201527f537461746552656365697665723a204e4f5f434f4d4d49544d454e545f464f5260448201526217d25160ea1b60648201526084016102e1565b600090815260356020908152604091829020825160608101845281548152600182015492810192909252600201549181019190915292915050565b81546000908103610832575060006102ea565b82546000905b8082101561087f57600061084c8383610d87565b6000878152602090209091508590820154111561086b57809150610879565b6108768160016110b8565b92505b50610838565b6000821180156108ab5750836108a88661089a6001866110a5565b600091825260209091200190565b54145b156108c4576108bb6001836110a5565b925050506102ea565b509392505050565b6000816108da866001610da9565b811461091f5760405162461bcd60e51b81526020600482015260146024820152730929cac82989288bea0a49e9e8cbe988a9c8ea8960631b60448201526064016102e1565b8587106109635760405162461bcd60e51b81526020600482015260126024820152710929cac82989288be988a828cbe929c888ab60731b60448201526064016102e1565b8761099f5760405162461bcd60e51b815260206004820152600c60248201526b24a72b20a624a22fa622a0a360a11b60448201526064016102e1565b8760005b82811015610a595760008686838181106109bf576109bf6111ac565b90506020020135905060028a6109d5919061125a565b600003610a0d576040805160208101859052908101829052606001604051602081830303815290604052805190602001209250610a3a565b60408051602081018390529081018490526060016040516020818303038152906040528051906020012092505b610a4560028b61126e565b99505080610a529061122b565b90506109a3565b50909414979650505050505050565b803560009081526034602052604090205460ff1615610ad85760405162461bcd60e51b815260206004820152602660248201527f537461746552656365697665723a2053544154455f53594e435f49535f50524f60448201526510d154d4d15160d21b60648201526084016102e1565b610ae86060820160408301611282565b6001600160a01b03163b600003610b3c576040805160208082526000908201819052918335917f31c652130602f3ce96ceaf8a4c2b8b49f049166c6fcf2eb31943a75ec7c936ae910160405180910390a350565b8035600090815260346020526040808220805460ff191660011790558190610b6a9060608501908501611282565b6001600160a01b03168335610b856040860160208701611282565b610b92606087018761129d565b604051602401610ba594939291906112e3565b60408051601f198184030181529181526020820180516001600160e01b031663eeb4994560e01b17905251610bda919061133c565b6000604051808303816000865af19150503d8060008114610c17576040519150601f19603f3d011682016040523d82523d6000602084013e610c1c565b606091505b509150915081610c3f5782356000908152603460205260409020805460ff191690555b81151583600001357f31c652130602f3ce96ceaf8a4c2b8b49f049166c6fcf2eb31943a75ec7c936ae83604051610c76919061134e565b60405180910390a3505050565b6000806120306001600160a01b0316620249f08888888888604051602001610caf959493929190611381565b60408051601f1981840301815290829052610cc99161133c565b6000604051808303818686fa925050503d8060008114610d05576040519150601f19603f3d011682016040523d82523d6000602084013e610d0a565b606091505b5091509150600081806020019051810190610d2591906113ba565b9050828015610d315750805b610d7d5760405162461bcd60e51b815260206004820152601d60248201527f5349474e41545552455f564552494649434154494f4e5f4641494c454400000060448201526064016102e1565b5050505050505050565b6000610d96600284841861126e565b610da2908484166110b8565b9392505050565b600080610db584610df4565b90506001836002811115610dcb57610dcb6113dc565b148015610ddb575083816001901b105b610de6576000610de9565b60015b60ff16019392505050565b600080608083901c15610e0957608092831c92015b604083901c15610e1b57604092831c92015b602083901c15610e2d57602092831c92015b601083901c15610e3f57601092831c92015b600883901c15610e5157600892831c92015b600483901c15610e6357600492831c92015b600283901c15610e7557600292831c92015b600183901c156102ea5760010192915050565b600060208284031215610e9a57600080fd5b5035919050565b60008083601f840112610eb357600080fd5b5081356001600160401b03811115610eca57600080fd5b6020830191508360208260051b8501011115610ee557600080fd5b9250929050565b600080600060408486031215610f0157600080fd5b83356001600160401b0380821115610f1857600080fd5b610f2487838801610ea1565b90955093506020860135915080821115610f3d57600080fd5b50840160808187031215610f5057600080fd5b809150509250925092565b60008060008060408587031215610f7157600080fd5b84356001600160401b0380821115610f8857600080fd5b610f9488838901610ea1565b90965094506020870135915080821115610fad57600080fd5b50610fba87828801610ea1565b95989497509550505050565b60008083601f840112610fd857600080fd5b5081356001600160401b03811115610fef57600080fd5b602083019150836020828501011115610ee557600080fd5b600080600080600085870360a081121561102057600080fd5b606081121561102e57600080fd5b5085945060608601356001600160401b038082111561104c57600080fd5b61105889838a01610fc6565b9096509450608088013591508082111561107157600080fd5b5061107e88828901610fc6565b969995985093965092949392505050565b634e487b7160e01b600052601160045260246000fd5b818103818111156102ea576102ea61108f565b808201808211156102ea576102ea61108f565b80356001600160a01b03811681146110e257600080fd5b919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60208152813560208201526000611129602084016110cb565b60018060a01b03808216604085015280611145604087016110cb565b16606085015250506060830135601e1984360301811261116457600080fd5b83016020810190356001600160401b0381111561118057600080fd5b80360382131561118f57600080fd5b6080808501526111a360a0850182846110e7565b95945050505050565b634e487b7160e01b600052603260045260246000fd5b60008235607e198336030181126111d857600080fd5b9190910192915050565b6000808335601e198436030181126111f957600080fd5b8301803591506001600160401b0382111561121357600080fd5b6020019150600581901b3603821315610ee557600080fd5b60006001820161123d5761123d61108f565b5060010190565b634e487b7160e01b600052601260045260246000fd5b60008261126957611269611244565b500690565b60008261127d5761127d611244565b500490565b60006020828403121561129457600080fd5b610da2826110cb565b6000808335601e198436030181126112b457600080fd5b8301803591506001600160401b038211156112ce57600080fd5b602001915036819003821315610ee557600080fd5b8481526001600160a01b038416602082015260606040820181905260009061130e90830184866110e7565b9695505050505050565b60005b8381101561133357818101518382015260200161131b565b50506000910152565b600082516111d8818460208701611318565b602081526000825180602084015261136d816040850160208701611318565b601f01601f19169190910160400192915050565b85815260606020820152600061139b6060830186886110e7565b82810360408401526113ae8185876110e7565b98975050505050505050565b6000602082840312156113cc57600080fd5b81518015158114610da257600080fd5b634e487b7160e01b600052602160045260246000fdfea2646970667358221220f12de4c572934572c3dae6184bcfe87730e8a0938ba1504547710fd27554218264736f6c63430008110033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" -var NativeERC20Artifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"NativeERC20\",\n \"sourceName\": \"contracts/child/NativeERC20.sol\",\n \"abi\": [\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"only\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"Unauthorized\",\n \"type\": \"error\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Approval\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Transfer\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TOKEN_CONTRACT\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"SYSTEM\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"allowance\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"approve\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"balanceOf\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"burn\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"decimals\",\n \"outputs\": [\n {\n \"internalType\": \"uint8\",\n \"name\": \"\",\n \"type\": \"uint8\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"subtractedValue\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"decreaseAllowance\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"addedValue\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"increaseAllowance\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"predicate_\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"rootToken_\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"string\",\n \"name\": \"name_\",\n \"type\": \"string\"\n },\n {\n \"internalType\": \"string\",\n \"name\": \"symbol_\",\n \"type\": \"string\"\n },\n {\n \"internalType\": \"uint8\",\n \"name\": \"decimals_\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"mint\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"name\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"rootToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"symbol\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"totalSupply\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transfer\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transferFrom\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b506111c3806100206000396000f3fe608060405234801561001057600080fd5b50600436106101425760003560e01c806370a08231116100b85780639dc29fac1161007c5780639dc29fac14610278578063a457c2d71461028b578063a9059cbb1461029e578063dd62ed3e146102b1578063e0563ab1146102c4578063e6198705146102cd57600080fd5b806370a082311461022d5780638420ce9914610248578063947287cf1461025d57806395d89b411461026657806397e5230d1461026e57600080fd5b8063284017f51161010a578063284017f5146101d2578063313ce567146101db57806339509351146101f05780633b878c221461020357806340c10f191461020c57806351351d531461021f57600080fd5b806306fdde0314610147578063095ea7b31461016557806318160ddd146101885780631f2d00651461019a57806323b872dd146101bf575b600080fd5b61014f6102de565b60405161015c9190610cfd565b60405180910390f35b610178610173366004610d4c565b610370565b604051901515815260200161015c565b6034545b60405190815260200161015c565b6036546001600160a01b03165b6040516001600160a01b03909116815260200161015c565b6101786101cd366004610d76565b61038a565b6101a761202081565b60395460405160ff909116815260200161015c565b6101786101fe366004610d4c565b6103ae565b6101a761101081565b61017861021a366004610d4c565b6103d0565b6101a76002600160a01b0381565b61018c61023b366004610db2565b6001600160a01b03163190565b61025b610256366004610e1d565b610419565b005b61018c61520881565b61014f6105c8565b61018c620249f081565b610178610286366004610d4c565b6105d7565b610178610299366004610d4c565b61060e565b6101786102ac366004610d4c565b610689565b61018c6102bf366004610ec8565b610697565b6101a761203081565b6035546001600160a01b03166101a7565b6060603780546102ed90610efb565b80601f016020809104026020016040519081016040528092919081815260200182805461031990610efb565b80156103665780601f1061033b57610100808354040283529160200191610366565b820191906000526020600020905b81548152906001019060200180831161034957829003601f168201915b5050505050905090565b60003361037e8185856106c2565b60019150505b92915050565b6000336103988582856107e6565b6103a3858585610860565b506001949350505050565b60003361037e8185856103c18383610697565b6103cb9190610f4b565b6106c2565b6035546000906001600160a01b031633146104065760405162461bcd60e51b81526004016103fd90610f5e565b60405180910390fd5b6104108383610a25565b50600192915050565b600054610100900460ff16158080156104395750600054600160ff909116105b806104535750303b158015610453575060005460ff166001145b6104b65760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016103fd565b6000805460ff1916600117905580156104d9576000805461ff0019166101001790555b336002600160a01b031461051d5760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b60448201526064016103fd565b603580546001600160a01b03808b166001600160a01b03199283161790925560368054928a1692909116919091179055603761055a868883611007565b506038610568848683611007565b506039805460ff191660ff841617905580156105be576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b6060603880546102ed90610efb565b6035546000906001600160a01b031633146106045760405162461bcd60e51b81526004016103fd90610f5e565b6104108383610b7f565b6000338161061c8286610697565b90508381101561067c5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016103fd565b6103a382868684036106c2565b60003361037e818585610860565b6001600160a01b03918216600090815260336020908152604080832093909416825291909152205490565b6001600160a01b0383166107245760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016103fd565b6001600160a01b0382166107855760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016103fd565b6001600160a01b0383811660008181526033602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60006107f28484610697565b9050600019811461085a578181101561084d5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016103fd565b61085a84848484036106c2565b50505050565b6001600160a01b0383166108c45760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016103fd565b6001600160a01b0382166109265760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016103fd565b6000806120206001600160a01b031685858560405160200161094a939291906110c8565b60408051601f1981840301815290829052610964916110ec565b6000604051808303816000865af19150503d80600081146109a1576040519150601f19603f3d011682016040523d82523d6000602084013e6109a6565b606091505b50915091508180156109c75750808060200190518101906109c79190611108565b6109e35760405162461bcd60e51b81526004016103fd9061112a565b836001600160a01b0316856001600160a01b031660008051602061116e83398151915285604051610a1691815260200190565b60405180910390a35050505050565b6001600160a01b038216610a7b5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016103fd565b8060346000828254610a8d9190610f4b565b9091555050604051600090819061202090610ab0908390879087906020016110c8565b60408051601f1981840301815290829052610aca916110ec565b6000604051808303816000865af19150503d8060008114610b07576040519150601f19603f3d011682016040523d82523d6000602084013e610b0c565b606091505b5091509150818015610b2d575080806020019051810190610b2d9190611108565b610b495760405162461bcd60e51b81526004016103fd9061112a565b6040518381526001600160a01b0385169060009060008051602061116e833981519152906020015b60405180910390a350505050565b6001600160a01b038216610bdf5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016103fd565b8060346000828254610bf1919061115a565b9091555050604051600090819061202090610c14908690849087906020016110c8565b60408051601f1981840301815290829052610c2e916110ec565b6000604051808303816000865af19150503d8060008114610c6b576040519150601f19603f3d011682016040523d82523d6000602084013e610c70565b606091505b5091509150818015610c91575080806020019051810190610c919190611108565b610cad5760405162461bcd60e51b81526004016103fd9061112a565b6040518381526000906001600160a01b0386169060008051602061116e83398151915290602001610b71565b60005b83811015610cf4578181015183820152602001610cdc565b50506000910152565b6020815260008251806020840152610d1c816040850160208701610cd9565b601f01601f19169190910160400192915050565b80356001600160a01b0381168114610d4757600080fd5b919050565b60008060408385031215610d5f57600080fd5b610d6883610d30565b946020939093013593505050565b600080600060608486031215610d8b57600080fd5b610d9484610d30565b9250610da260208501610d30565b9150604084013590509250925092565b600060208284031215610dc457600080fd5b610dcd82610d30565b9392505050565b60008083601f840112610de657600080fd5b50813567ffffffffffffffff811115610dfe57600080fd5b602083019150836020828501011115610e1657600080fd5b9250929050565b600080600080600080600060a0888a031215610e3857600080fd5b610e4188610d30565b9650610e4f60208901610d30565b9550604088013567ffffffffffffffff80821115610e6c57600080fd5b610e788b838c01610dd4565b909750955060608a0135915080821115610e9157600080fd5b50610e9e8a828b01610dd4565b909450925050608088013560ff81168114610eb857600080fd5b8091505092959891949750929550565b60008060408385031215610edb57600080fd5b610ee483610d30565b9150610ef260208401610d30565b90509250929050565b600181811c90821680610f0f57607f821691505b602082108103610f2f57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561038457610384610f35565b60208082526024908201527f4e617469766545524332303a204f6e6c79207072656469636174652063616e2060408201526318d85b1b60e21b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b601f82111561100257600081815260208120601f850160051c81016020861015610fdf5750805b601f850160051c820191505b81811015610ffe57828155600101610feb565b5050505b505050565b67ffffffffffffffff83111561101f5761101f610fa2565b6110338361102d8354610efb565b83610fb8565b6000601f841160018114611067576000851561104f5750838201355b600019600387901b1c1916600186901b1783556110c1565b600083815260209020601f19861690835b828110156110985786850135825560209485019460019092019101611078565b50868210156110b55760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b600082516110fe818460208701610cd9565b9190910192915050565b60006020828403121561111a57600080fd5b81518015158114610dcd57600080fd5b60208082526016908201527514149150d3d35412531157d0d0531317d1905253115160521b604082015260600190565b8181038181111561038457610384610f3556feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212201cc2b3ea246b46198f0ff59b53d69a9ac96c47a287d6ed78414118383506ad4264736f6c63430008110033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101425760003560e01c806370a08231116100b85780639dc29fac1161007c5780639dc29fac14610278578063a457c2d71461028b578063a9059cbb1461029e578063dd62ed3e146102b1578063e0563ab1146102c4578063e6198705146102cd57600080fd5b806370a082311461022d5780638420ce9914610248578063947287cf1461025d57806395d89b411461026657806397e5230d1461026e57600080fd5b8063284017f51161010a578063284017f5146101d2578063313ce567146101db57806339509351146101f05780633b878c221461020357806340c10f191461020c57806351351d531461021f57600080fd5b806306fdde0314610147578063095ea7b31461016557806318160ddd146101885780631f2d00651461019a57806323b872dd146101bf575b600080fd5b61014f6102de565b60405161015c9190610cfd565b60405180910390f35b610178610173366004610d4c565b610370565b604051901515815260200161015c565b6034545b60405190815260200161015c565b6036546001600160a01b03165b6040516001600160a01b03909116815260200161015c565b6101786101cd366004610d76565b61038a565b6101a761202081565b60395460405160ff909116815260200161015c565b6101786101fe366004610d4c565b6103ae565b6101a761101081565b61017861021a366004610d4c565b6103d0565b6101a76002600160a01b0381565b61018c61023b366004610db2565b6001600160a01b03163190565b61025b610256366004610e1d565b610419565b005b61018c61520881565b61014f6105c8565b61018c620249f081565b610178610286366004610d4c565b6105d7565b610178610299366004610d4c565b61060e565b6101786102ac366004610d4c565b610689565b61018c6102bf366004610ec8565b610697565b6101a761203081565b6035546001600160a01b03166101a7565b6060603780546102ed90610efb565b80601f016020809104026020016040519081016040528092919081815260200182805461031990610efb565b80156103665780601f1061033b57610100808354040283529160200191610366565b820191906000526020600020905b81548152906001019060200180831161034957829003601f168201915b5050505050905090565b60003361037e8185856106c2565b60019150505b92915050565b6000336103988582856107e6565b6103a3858585610860565b506001949350505050565b60003361037e8185856103c18383610697565b6103cb9190610f4b565b6106c2565b6035546000906001600160a01b031633146104065760405162461bcd60e51b81526004016103fd90610f5e565b60405180910390fd5b6104108383610a25565b50600192915050565b600054610100900460ff16158080156104395750600054600160ff909116105b806104535750303b158015610453575060005460ff166001145b6104b65760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016103fd565b6000805460ff1916600117905580156104d9576000805461ff0019166101001790555b336002600160a01b031461051d5760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b60448201526064016103fd565b603580546001600160a01b03808b166001600160a01b03199283161790925560368054928a1692909116919091179055603761055a868883611007565b506038610568848683611007565b506039805460ff191660ff841617905580156105be576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b6060603880546102ed90610efb565b6035546000906001600160a01b031633146106045760405162461bcd60e51b81526004016103fd90610f5e565b6104108383610b7f565b6000338161061c8286610697565b90508381101561067c5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016103fd565b6103a382868684036106c2565b60003361037e818585610860565b6001600160a01b03918216600090815260336020908152604080832093909416825291909152205490565b6001600160a01b0383166107245760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016103fd565b6001600160a01b0382166107855760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016103fd565b6001600160a01b0383811660008181526033602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60006107f28484610697565b9050600019811461085a578181101561084d5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016103fd565b61085a84848484036106c2565b50505050565b6001600160a01b0383166108c45760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016103fd565b6001600160a01b0382166109265760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016103fd565b6000806120206001600160a01b031685858560405160200161094a939291906110c8565b60408051601f1981840301815290829052610964916110ec565b6000604051808303816000865af19150503d80600081146109a1576040519150601f19603f3d011682016040523d82523d6000602084013e6109a6565b606091505b50915091508180156109c75750808060200190518101906109c79190611108565b6109e35760405162461bcd60e51b81526004016103fd9061112a565b836001600160a01b0316856001600160a01b031660008051602061116e83398151915285604051610a1691815260200190565b60405180910390a35050505050565b6001600160a01b038216610a7b5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016103fd565b8060346000828254610a8d9190610f4b565b9091555050604051600090819061202090610ab0908390879087906020016110c8565b60408051601f1981840301815290829052610aca916110ec565b6000604051808303816000865af19150503d8060008114610b07576040519150601f19603f3d011682016040523d82523d6000602084013e610b0c565b606091505b5091509150818015610b2d575080806020019051810190610b2d9190611108565b610b495760405162461bcd60e51b81526004016103fd9061112a565b6040518381526001600160a01b0385169060009060008051602061116e833981519152906020015b60405180910390a350505050565b6001600160a01b038216610bdf5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016103fd565b8060346000828254610bf1919061115a565b9091555050604051600090819061202090610c14908690849087906020016110c8565b60408051601f1981840301815290829052610c2e916110ec565b6000604051808303816000865af19150503d8060008114610c6b576040519150601f19603f3d011682016040523d82523d6000602084013e610c70565b606091505b5091509150818015610c91575080806020019051810190610c919190611108565b610cad5760405162461bcd60e51b81526004016103fd9061112a565b6040518381526000906001600160a01b0386169060008051602061116e83398151915290602001610b71565b60005b83811015610cf4578181015183820152602001610cdc565b50506000910152565b6020815260008251806020840152610d1c816040850160208701610cd9565b601f01601f19169190910160400192915050565b80356001600160a01b0381168114610d4757600080fd5b919050565b60008060408385031215610d5f57600080fd5b610d6883610d30565b946020939093013593505050565b600080600060608486031215610d8b57600080fd5b610d9484610d30565b9250610da260208501610d30565b9150604084013590509250925092565b600060208284031215610dc457600080fd5b610dcd82610d30565b9392505050565b60008083601f840112610de657600080fd5b50813567ffffffffffffffff811115610dfe57600080fd5b602083019150836020828501011115610e1657600080fd5b9250929050565b600080600080600080600060a0888a031215610e3857600080fd5b610e4188610d30565b9650610e4f60208901610d30565b9550604088013567ffffffffffffffff80821115610e6c57600080fd5b610e788b838c01610dd4565b909750955060608a0135915080821115610e9157600080fd5b50610e9e8a828b01610dd4565b909450925050608088013560ff81168114610eb857600080fd5b8091505092959891949750929550565b60008060408385031215610edb57600080fd5b610ee483610d30565b9150610ef260208401610d30565b90509250929050565b600181811c90821680610f0f57607f821691505b602082108103610f2f57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561038457610384610f35565b60208082526024908201527f4e617469766545524332303a204f6e6c79207072656469636174652063616e2060408201526318d85b1b60e21b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b601f82111561100257600081815260208120601f850160051c81016020861015610fdf5750805b601f850160051c820191505b81811015610ffe57828155600101610feb565b5050505b505050565b67ffffffffffffffff83111561101f5761101f610fa2565b6110338361102d8354610efb565b83610fb8565b6000601f841160018114611067576000851561104f5750838201355b600019600387901b1c1916600186901b1783556110c1565b600083815260209020601f19861690835b828110156110985786850135825560209485019460019092019101611078565b50868210156110b55760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b600082516110fe818460208701610cd9565b9190910192915050565b60006020828403121561111a57600080fd5b81518015158114610dcd57600080fd5b60208082526016908201527514149150d3d35412531157d0d0531317d1905253115160521b604082015260600190565b8181038181111561038457610384610f3556feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212201cc2b3ea246b46198f0ff59b53d69a9ac96c47a287d6ed78414118383506ad4264736f6c63430008110033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" -var NativeERC20MintableArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"NativeERC20Mintable\",\n \"sourceName\": \"contracts/child/NativeERC20Mintable.sol\",\n \"abi\": [\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"only\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"Unauthorized\",\n \"type\": \"error\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Approval\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"previousOwner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"OwnershipTransferStarted\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"previousOwner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"OwnershipTransferred\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Transfer\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TOKEN_CONTRACT\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"SYSTEM\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"acceptOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"allowance\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"approve\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"balanceOf\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"burn\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"decimals\",\n \"outputs\": [\n {\n \"internalType\": \"uint8\",\n \"name\": \"\",\n \"type\": \"uint8\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"subtractedValue\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"decreaseAllowance\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"addedValue\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"increaseAllowance\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"predicate_\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"owner_\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"rootToken_\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"string\",\n \"name\": \"name_\",\n \"type\": \"string\"\n },\n {\n \"internalType\": \"string\",\n \"name\": \"symbol_\",\n \"type\": \"string\"\n },\n {\n \"internalType\": \"uint8\",\n \"name\": \"decimals_\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"mint\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"name\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"owner\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"pendingOwner\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"renounceOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"rootToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"symbol\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"totalSupply\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transfer\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transferFrom\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"transferOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b5061001a3361001f565b610098565b603480546001600160a01b031916905561004381610046602090811b6108ce17901c565b50565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6114ad806100a76000396000f3fe608060405234801561001057600080fd5b50600436106101795760003560e01c8063715018a6116100d9578063a457c2d711610087578063a457c2d7146102e3578063a9059cbb146102f6578063dd62ed3e14610309578063e0563ab11461031c578063e30c397814610325578063e619870514610336578063f2fde38b1461034757600080fd5b8063715018a61461029457806379ba50971461029c5780638da5cb5b146102a4578063947287cf146102b557806395d89b41146102be57806397e5230d146102c65780639dc29fac146102d057600080fd5b8063284017f511610136578063284017f51461021e578063313ce56714610227578063395093511461023c5780633b878c221461024f57806340c10f191461025857806351351d531461026b57806370a082311461027957600080fd5b806306fdde031461017e578063095ea7b31461019c57806318160ddd146101bf5780631f2d0065146101d1578063238b4bc5146101f657806323b872dd1461020b575b600080fd5b61018661035a565b6040516101939190610fce565b60405180910390f35b6101af6101aa36600461101d565b6103ec565b6040519015158152602001610193565b6036545b604051908152602001610193565b6038546001600160a01b03165b6040516001600160a01b039091168152602001610193565b610209610204366004611090565b610406565b005b6101af61021936600461114b565b610625565b6101de61202081565b603b5460405160ff9091168152602001610193565b6101af61024a36600461101d565b610649565b6101de61101081565b6101af61026636600461101d565b61066b565b6101de6002600160a01b0381565b6101c3610287366004611187565b6001600160a01b03163190565b6102096106c0565b6102096106d4565b6033546001600160a01b03166101de565b6101c361520881565b61018661074e565b6101c3620249f081565b6101af6102de36600461101d565b61075d565b6101af6102f136600461101d565b6107a9565b6101af61030436600461101d565b610824565b6101c36103173660046111a9565b610832565b6101de61203081565b6034546001600160a01b03166101de565b6037546001600160a01b03166101de565b610209610355366004611187565b61085d565b606060398054610369906111dc565b80601f0160208091040260200160405190810160405280929190818152602001828054610395906111dc565b80156103e25780601f106103b7576101008083540402835291602001916103e2565b820191906000526020600020905b8154815290600101906020018083116103c557829003601f168201915b5050505050905090565b6000336103fa818585610920565b60019150505b92915050565b600054610100900460ff16158080156104265750600054600160ff909116105b806104405750303b158015610440575060005460ff166001145b6104a85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff1916600117905580156104cb576000805461ff0019166101001790555b336002600160a01b031461050f5760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b604482015260640161049f565b6001600160a01b0388166105705760405162461bcd60e51b815260206004820152602260248201527f4e617469766545524332303a20496e76616c6964206f776e6572206164647265604482015261737360f01b606482015260840161049f565b603780546001600160a01b03808c166001600160a01b03199283161790925560388054928a169290911691909117905560396105ad86888361127b565b50603a6105bb84868361127b565b50603b805460ff191660ff84161790556105d488610a44565b801561061a576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050505050565b600033610633858285610a5d565b61063e858585610ad7565b506001949350505050565b6000336103fa81858561065c8383610832565b6106669190611352565b610920565b6037546000906001600160a01b031633148061069157506033546001600160a01b031633145b6106ad5760405162461bcd60e51b815260040161049f90611365565b6106b78383610c9c565b50600192915050565b6106c8610df6565b6106d26000610a44565b565b60345433906001600160a01b031681146107425760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b606482015260840161049f565b61074b81610a44565b50565b6060603a8054610369906111dc565b6037546000906001600160a01b031633148061078357506033546001600160a01b031633145b61079f5760405162461bcd60e51b815260040161049f90611365565b6106b78383610e50565b600033816107b78286610832565b9050838110156108175760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b606482015260840161049f565b61063e8286868403610920565b6000336103fa818585610ad7565b6001600160a01b03918216600090815260356020908152604080832093909416825291909152205490565b610865610df6565b603480546001600160a01b0383166001600160a01b031990911681179091556108966033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b0383166109825760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b606482015260840161049f565b6001600160a01b0382166109e35760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b606482015260840161049f565b6001600160a01b0383811660008181526035602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b603480546001600160a01b031916905561074b816108ce565b6000610a698484610832565b90506000198114610ad15781811015610ac45760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161049f565b610ad18484848403610920565b50505050565b6001600160a01b038316610b3b5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b606482015260840161049f565b6001600160a01b038216610b9d5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b606482015260840161049f565b6000806120206001600160a01b0316858585604051602001610bc1939291906113b2565b60408051601f1981840301815290829052610bdb916113d6565b6000604051808303816000865af19150503d8060008114610c18576040519150601f19603f3d011682016040523d82523d6000602084013e610c1d565b606091505b5091509150818015610c3e575080806020019051810190610c3e91906113f2565b610c5a5760405162461bcd60e51b815260040161049f90611414565b836001600160a01b0316856001600160a01b031660008051602061145883398151915285604051610c8d91815260200190565b60405180910390a35050505050565b6001600160a01b038216610cf25760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640161049f565b8060366000828254610d049190611352565b9091555050604051600090819061202090610d27908390879087906020016113b2565b60408051601f1981840301815290829052610d41916113d6565b6000604051808303816000865af19150503d8060008114610d7e576040519150601f19603f3d011682016040523d82523d6000602084013e610d83565b606091505b5091509150818015610da4575080806020019051810190610da491906113f2565b610dc05760405162461bcd60e51b815260040161049f90611414565b6040518381526001600160a01b03851690600090600080516020611458833981519152906020015b60405180910390a350505050565b6033546001600160a01b031633146106d25760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161049f565b6001600160a01b038216610eb05760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b606482015260840161049f565b8060366000828254610ec29190611444565b9091555050604051600090819061202090610ee5908690849087906020016113b2565b60408051601f1981840301815290829052610eff916113d6565b6000604051808303816000865af19150503d8060008114610f3c576040519150601f19603f3d011682016040523d82523d6000602084013e610f41565b606091505b5091509150818015610f62575080806020019051810190610f6291906113f2565b610f7e5760405162461bcd60e51b815260040161049f90611414565b6040518381526000906001600160a01b0386169060008051602061145883398151915290602001610de8565b60005b83811015610fc5578181015183820152602001610fad565b50506000910152565b6020815260008251806020840152610fed816040850160208701610faa565b601f01601f19169190910160400192915050565b80356001600160a01b038116811461101857600080fd5b919050565b6000806040838503121561103057600080fd5b61103983611001565b946020939093013593505050565b60008083601f84011261105957600080fd5b50813567ffffffffffffffff81111561107157600080fd5b60208301915083602082850101111561108957600080fd5b9250929050565b60008060008060008060008060c0898b0312156110ac57600080fd5b6110b589611001565b97506110c360208a01611001565b96506110d160408a01611001565b9550606089013567ffffffffffffffff808211156110ee57600080fd5b6110fa8c838d01611047565b909750955060808b013591508082111561111357600080fd5b506111208b828c01611047565b90945092505060a089013560ff8116811461113a57600080fd5b809150509295985092959890939650565b60008060006060848603121561116057600080fd5b61116984611001565b925061117760208501611001565b9150604084013590509250925092565b60006020828403121561119957600080fd5b6111a282611001565b9392505050565b600080604083850312156111bc57600080fd5b6111c583611001565b91506111d360208401611001565b90509250929050565b600181811c908216806111f057607f821691505b60208210810361121057634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052604160045260246000fd5b601f82111561127657600081815260208120601f850160051c810160208610156112535750805b601f850160051c820191505b818110156112725782815560010161125f565b5050505b505050565b67ffffffffffffffff83111561129357611293611216565b6112a7836112a183546111dc565b8361122c565b6000601f8411600181146112db57600085156112c35750838201355b600019600387901b1c1916600186901b178355611335565b600083815260209020601f19861690835b8281101561130c57868501358255602094850194600190920191016112ec565b50868210156113295760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b634e487b7160e01b600052601160045260246000fd5b808201808211156104005761040061133c565b6020808252602d908201527f4e617469766545524332303a204f6e6c7920707265646963617465206f72206f60408201526c1ddb995c8818d85b8818d85b1b609a1b606082015260800190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b600082516113e8818460208701610faa565b9190910192915050565b60006020828403121561140457600080fd5b815180151581146111a257600080fd5b60208082526016908201527514149150d3d35412531157d0d0531317d1905253115160521b604082015260600190565b818103818111156104005761040061133c56feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212209be318415f88ce7ef3eb3e9be7eed0fb2e93811e73c7b0d5b1fd4e46144f210d64736f6c63430008110033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101795760003560e01c8063715018a6116100d9578063a457c2d711610087578063a457c2d7146102e3578063a9059cbb146102f6578063dd62ed3e14610309578063e0563ab11461031c578063e30c397814610325578063e619870514610336578063f2fde38b1461034757600080fd5b8063715018a61461029457806379ba50971461029c5780638da5cb5b146102a4578063947287cf146102b557806395d89b41146102be57806397e5230d146102c65780639dc29fac146102d057600080fd5b8063284017f511610136578063284017f51461021e578063313ce56714610227578063395093511461023c5780633b878c221461024f57806340c10f191461025857806351351d531461026b57806370a082311461027957600080fd5b806306fdde031461017e578063095ea7b31461019c57806318160ddd146101bf5780631f2d0065146101d1578063238b4bc5146101f657806323b872dd1461020b575b600080fd5b61018661035a565b6040516101939190610fce565b60405180910390f35b6101af6101aa36600461101d565b6103ec565b6040519015158152602001610193565b6036545b604051908152602001610193565b6038546001600160a01b03165b6040516001600160a01b039091168152602001610193565b610209610204366004611090565b610406565b005b6101af61021936600461114b565b610625565b6101de61202081565b603b5460405160ff9091168152602001610193565b6101af61024a36600461101d565b610649565b6101de61101081565b6101af61026636600461101d565b61066b565b6101de6002600160a01b0381565b6101c3610287366004611187565b6001600160a01b03163190565b6102096106c0565b6102096106d4565b6033546001600160a01b03166101de565b6101c361520881565b61018661074e565b6101c3620249f081565b6101af6102de36600461101d565b61075d565b6101af6102f136600461101d565b6107a9565b6101af61030436600461101d565b610824565b6101c36103173660046111a9565b610832565b6101de61203081565b6034546001600160a01b03166101de565b6037546001600160a01b03166101de565b610209610355366004611187565b61085d565b606060398054610369906111dc565b80601f0160208091040260200160405190810160405280929190818152602001828054610395906111dc565b80156103e25780601f106103b7576101008083540402835291602001916103e2565b820191906000526020600020905b8154815290600101906020018083116103c557829003601f168201915b5050505050905090565b6000336103fa818585610920565b60019150505b92915050565b600054610100900460ff16158080156104265750600054600160ff909116105b806104405750303b158015610440575060005460ff166001145b6104a85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff1916600117905580156104cb576000805461ff0019166101001790555b336002600160a01b031461050f5760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b604482015260640161049f565b6001600160a01b0388166105705760405162461bcd60e51b815260206004820152602260248201527f4e617469766545524332303a20496e76616c6964206f776e6572206164647265604482015261737360f01b606482015260840161049f565b603780546001600160a01b03808c166001600160a01b03199283161790925560388054928a169290911691909117905560396105ad86888361127b565b50603a6105bb84868361127b565b50603b805460ff191660ff84161790556105d488610a44565b801561061a576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050505050565b600033610633858285610a5d565b61063e858585610ad7565b506001949350505050565b6000336103fa81858561065c8383610832565b6106669190611352565b610920565b6037546000906001600160a01b031633148061069157506033546001600160a01b031633145b6106ad5760405162461bcd60e51b815260040161049f90611365565b6106b78383610c9c565b50600192915050565b6106c8610df6565b6106d26000610a44565b565b60345433906001600160a01b031681146107425760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b606482015260840161049f565b61074b81610a44565b50565b6060603a8054610369906111dc565b6037546000906001600160a01b031633148061078357506033546001600160a01b031633145b61079f5760405162461bcd60e51b815260040161049f90611365565b6106b78383610e50565b600033816107b78286610832565b9050838110156108175760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b606482015260840161049f565b61063e8286868403610920565b6000336103fa818585610ad7565b6001600160a01b03918216600090815260356020908152604080832093909416825291909152205490565b610865610df6565b603480546001600160a01b0383166001600160a01b031990911681179091556108966033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b0383166109825760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b606482015260840161049f565b6001600160a01b0382166109e35760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b606482015260840161049f565b6001600160a01b0383811660008181526035602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b603480546001600160a01b031916905561074b816108ce565b6000610a698484610832565b90506000198114610ad15781811015610ac45760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161049f565b610ad18484848403610920565b50505050565b6001600160a01b038316610b3b5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b606482015260840161049f565b6001600160a01b038216610b9d5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b606482015260840161049f565b6000806120206001600160a01b0316858585604051602001610bc1939291906113b2565b60408051601f1981840301815290829052610bdb916113d6565b6000604051808303816000865af19150503d8060008114610c18576040519150601f19603f3d011682016040523d82523d6000602084013e610c1d565b606091505b5091509150818015610c3e575080806020019051810190610c3e91906113f2565b610c5a5760405162461bcd60e51b815260040161049f90611414565b836001600160a01b0316856001600160a01b031660008051602061145883398151915285604051610c8d91815260200190565b60405180910390a35050505050565b6001600160a01b038216610cf25760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640161049f565b8060366000828254610d049190611352565b9091555050604051600090819061202090610d27908390879087906020016113b2565b60408051601f1981840301815290829052610d41916113d6565b6000604051808303816000865af19150503d8060008114610d7e576040519150601f19603f3d011682016040523d82523d6000602084013e610d83565b606091505b5091509150818015610da4575080806020019051810190610da491906113f2565b610dc05760405162461bcd60e51b815260040161049f90611414565b6040518381526001600160a01b03851690600090600080516020611458833981519152906020015b60405180910390a350505050565b6033546001600160a01b031633146106d25760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161049f565b6001600160a01b038216610eb05760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b606482015260840161049f565b8060366000828254610ec29190611444565b9091555050604051600090819061202090610ee5908690849087906020016113b2565b60408051601f1981840301815290829052610eff916113d6565b6000604051808303816000865af19150503d8060008114610f3c576040519150601f19603f3d011682016040523d82523d6000602084013e610f41565b606091505b5091509150818015610f62575080806020019051810190610f6291906113f2565b610f7e5760405162461bcd60e51b815260040161049f90611414565b6040518381526000906001600160a01b0386169060008051602061145883398151915290602001610de8565b60005b83811015610fc5578181015183820152602001610fad565b50506000910152565b6020815260008251806020840152610fed816040850160208701610faa565b601f01601f19169190910160400192915050565b80356001600160a01b038116811461101857600080fd5b919050565b6000806040838503121561103057600080fd5b61103983611001565b946020939093013593505050565b60008083601f84011261105957600080fd5b50813567ffffffffffffffff81111561107157600080fd5b60208301915083602082850101111561108957600080fd5b9250929050565b60008060008060008060008060c0898b0312156110ac57600080fd5b6110b589611001565b97506110c360208a01611001565b96506110d160408a01611001565b9550606089013567ffffffffffffffff808211156110ee57600080fd5b6110fa8c838d01611047565b909750955060808b013591508082111561111357600080fd5b506111208b828c01611047565b90945092505060a089013560ff8116811461113a57600080fd5b809150509295985092959890939650565b60008060006060848603121561116057600080fd5b61116984611001565b925061117760208501611001565b9150604084013590509250925092565b60006020828403121561119957600080fd5b6111a282611001565b9392505050565b600080604083850312156111bc57600080fd5b6111c583611001565b91506111d360208401611001565b90509250929050565b600181811c908216806111f057607f821691505b60208210810361121057634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052604160045260246000fd5b601f82111561127657600081815260208120601f850160051c810160208610156112535750805b601f850160051c820191505b818110156112725782815560010161125f565b5050505b505050565b67ffffffffffffffff83111561129357611293611216565b6112a7836112a183546111dc565b8361122c565b6000601f8411600181146112db57600085156112c35750838201355b600019600387901b1c1916600186901b178355611335565b600083815260209020601f19861690835b8281101561130c57868501358255602094850194600190920191016112ec565b50868210156113295760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b634e487b7160e01b600052601160045260246000fd5b808201808211156104005761040061133c565b6020808252602d908201527f4e617469766545524332303a204f6e6c7920707265646963617465206f72206f60408201526c1ddb995c8818d85b8818d85b1b609a1b606082015260800190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b600082516113e8818460208701610faa565b9190910192915050565b60006020828403121561140457600080fd5b815180151581146111a257600080fd5b60208082526016908201527514149150d3d35412531157d0d0531317d1905253115160521b604082015260600190565b818103818111156104005761040061133c56feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212209be318415f88ce7ef3eb3e9be7eed0fb2e93811e73c7b0d5b1fd4e46144f210d64736f6c63430008110033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" -var ChildERC20Artifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"ChildERC20\",\n \"sourceName\": \"contracts/child/ChildERC20.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Approval\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"userAddress\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"relayerAddress\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bytes\",\n \"name\": \"functionSignature\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"MetaTransactionExecuted\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Transfer\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"allowance\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"approve\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"balanceOf\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"burn\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"decimals\",\n \"outputs\": [\n {\n \"internalType\": \"uint8\",\n \"name\": \"\",\n \"type\": \"uint8\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"subtractedValue\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"decreaseAllowance\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"userAddress\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"functionSignature\",\n \"type\": \"bytes\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"sigR\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"sigS\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint8\",\n \"name\": \"sigV\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"executeMetaTransaction\",\n \"outputs\": [\n {\n \"internalType\": \"bytes\",\n \"name\": \"\",\n \"type\": \"bytes\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"getNonce\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"nonce\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"addedValue\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"increaseAllowance\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"rootToken_\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"string\",\n \"name\": \"name_\",\n \"type\": \"string\"\n },\n {\n \"internalType\": \"string\",\n \"name\": \"symbol_\",\n \"type\": \"string\"\n },\n {\n \"internalType\": \"uint8\",\n \"name\": \"decimals_\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"mint\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"name\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"rootToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"symbol\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"totalSupply\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transfer\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transferFrom\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b506118e3806100206000396000f3fe608060405234801561001057600080fd5b50600436106101165760003560e01c806340c10f19116100a2578063a457c2d711610071578063a457c2d71461026b578063a9059cbb1461027e578063dd62ed3e14610291578063e6198705146102a4578063f6d2ee86146102b557600080fd5b806340c10f191461021457806370a082311461022757806395d89b41146102505780639dc29fac1461025857600080fd5b80631f2d0065116100e95780631f2d00651461018157806323b872dd146101a65780632d0335ab146101b9578063313ce567146101e2578063395093511461020157600080fd5b806306fdde031461011b578063095ea7b3146101395780630c53c51c1461015c57806318160ddd1461016f575b600080fd5b6101236102ca565b6040516101309190611371565b60405180910390f35b61014c6101473660046113a7565b61035c565b6040519015158152602001610130565b61012361016a36600461142b565b610380565b603c545b604051908152602001610130565b606d546001600160a01b03165b6040516001600160a01b039091168152602001610130565b61014c6101b43660046114a1565b610663565b6101736101c73660046114dd565b6001600160a01b031660009081526006602052604090205490565b606d54600160a01b900460ff1660405160ff9091168152602001610130565b61014c61020f3660046113a7565b610691565b61014c6102223660046113a7565b6106bd565b6101736102353660046114dd565b6001600160a01b03166000908152603a602052604090205490565b6101236106fd565b61014c6102663660046113a7565b61070c565b61014c6102793660046113a7565b610743565b61014c61028c3660046113a7565b6107c9565b61017361029f3660046114f8565b6107e1565b606c546001600160a01b031661018e565b6102c86102c336600461152b565b61080c565b005b6060603d80546102d9906115af565b80601f0160208091040260200160405190810160405280929190818152602001828054610305906115af565b80156103525780601f1061032757610100808354040283529160200191610352565b820191906000526020600020905b81548152906001019060200180831161033557829003601f168201915b5050505050905090565b600080610367610a8c565b9050610374818585610a9b565b60019150505b92915050565b606060006103c387878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610bc092505050565b90506001600160e01b031960003581169082160361044e5760405162461bcd60e51b815260206004820152603d60248201527f66756e6374696f6e5369676e61747572652063616e206e6f74206265206f662060448201527f657865637574654d6574615472616e73616374696f6e206d6574686f6400000060648201526084015b60405180910390fd5b604080516060810182526001600160a01b038a16600081815260066020908152848220548452808401929092528351601f8b0183900483028101830185528a815290938301918b908b9081908401838280828437600092019190915250505091525090506104bf8982888888610bdb565b6105155760405162461bcd60e51b815260206004820152602160248201527f5369676e657220616e64207369676e617475726520646f206e6f74206d6174636044820152600d60fb1b6064820152608401610445565b600660008a6001600160a01b03166001600160a01b031681526020019081526020016000206000815460010191905081905550600080306001600160a01b03168a8a8d60405160200161056a939291906115e9565b60408051601f19818403018152908290526105849161160f565b6000604051808303816000865af19150503d80600081146105c1576040519150601f19603f3d011682016040523d82523d6000602084013e6105c6565b606091505b5091509150816106185760405162461bcd60e51b815260206004820152601c60248201527f46756e6374696f6e2063616c6c206e6f74207375636365737366756c000000006044820152606401610445565b7f5845892132946850460bff5a0083f71031bc5bf9aadcd40f1de79423eac9b10b8b338c8c60405161064d949392919061162b565b60405180910390a19a9950505050505050505050565b60008061066e610a8c565b905061067b858285610cb7565b610686858585610d31565b506001949350505050565b60008061069c610a8c565b90506103748185856106ae85896107e1565b6106b89190611677565b610a9b565b606c546000906001600160a01b031633146106ea5760405162461bcd60e51b815260040161044590611698565b6106f48383610eca565b50600192915050565b6060603e80546102d9906115af565b606c546000906001600160a01b031633146107395760405162461bcd60e51b815260040161044590611698565b6106f48383610f7a565b60008061074e610a8c565b9050600061075c82866107e1565b9050838110156107bc5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610445565b6106868286868403610a9b565b6000806107d4610a8c565b9050610374818585610d31565b6001600160a01b039182166000908152603b6020908152604080832093909416825291909152205490565b600754610100900460ff161580801561082c5750600754600160ff909116105b806108465750303b158015610846575060075460ff166001145b6108a95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610445565b6007805460ff1916600117905580156108cc576007805461ff0019166101001790555b6001600160a01b038716158015906108e357508415155b80156108ee57508215155b61093a5760405162461bcd60e51b815260206004820152601e60248201527f4368696c6445524332303a204241445f494e495449414c495a4154494f4e00006044820152606401610445565b606d805460ff8416600160a01b026001600160a81b03199091166001600160a01b038a1617179055606c80546001600160a01b03191633179055604080516020601f88018190048102820181019092528681526109e591889088908190840183828082843760009201919091525050604080516020601f8a01819004810282018101909252888152925088915087908190840183828082843760009201919091525061109992505050565b610a3d86868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260018152603160f81b602082015291506110ca9050565b8015610a83576007805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6000610a96611136565b905090565b6001600160a01b038316610afd5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610445565b6001600160a01b038216610b5e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610445565b6001600160a01b038381166000818152603b602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b60008151600003610bd357506000919050565b506020015190565b6000806001610bf1610bec88611192565b61120f565b6040805160008152602081018083529290925260ff861690820152606081018790526080810186905260a0016020604051602081039080840390855afa158015610c3f573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610c965760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b6044820152606401610445565b866001600160a01b0316816001600160a01b03161491505095945050505050565b6000610cc384846107e1565b90506000198114610d2b5781811015610d1e5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610445565b610d2b8484848403610a9b565b50505050565b6001600160a01b038316610d955760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610445565b6001600160a01b038216610df75760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610445565b6001600160a01b0383166000908152603a602052604090205481811015610e6f5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610445565b6001600160a01b038085166000818152603a6020526040808220868603905592861680825290839020805486019055915160008051602061188e83398151915290610ebd9086815260200190565b60405180910390a3610d2b565b6001600160a01b038216610f205760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610445565b80603c6000828254610f329190611677565b90915550506001600160a01b0382166000818152603a602090815260408083208054860190555184815260008051602061188e833981519152910160405180910390a35b5050565b6001600160a01b038216610fda5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610445565b6001600160a01b0382166000908152603a60205260409020548181101561104e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610445565b6001600160a01b0383166000818152603a602090815260408083208686039055603c805487900390555185815291929160008051602061188e8339815191529101610bb3565b505050565b600754610100900460ff166110c05760405162461bcd60e51b8152600401610445906116db565b610f76828261125d565b815160208084019190912082519183019190912060038290556004819055466001557f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f61111881848461129d565b600055600280546001600160a01b0319163017905560055550505050565b600030330361118c57600080368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050503601516001600160a01b0316915061118f9050565b50335b90565b600060405180608001604052806043815260200161184b60439139805160209182012083518483015160408087015180519086012090516111f2950193845260208401929092526001600160a01b03166040830152606082015260800190565b604051602081830303815290604052805190602001209050919050565b600061037a61121c6112e6565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b600754610100900460ff166112845760405162461bcd60e51b8152600401610445906116db565b603d611290838261178a565b50603e611094828261178a565b6040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b6002546000906001600160a01b031630148015611304575060015446145b15611310575060005490565b610a9660055460035460045461129d565b60005b8381101561133c578181015183820152602001611324565b50506000910152565b6000815180845261135d816020860160208601611321565b601f01601f19169290920160200192915050565b6020815260006113846020830184611345565b9392505050565b80356001600160a01b03811681146113a257600080fd5b919050565b600080604083850312156113ba57600080fd5b6113c38361138b565b946020939093013593505050565b60008083601f8401126113e357600080fd5b50813567ffffffffffffffff8111156113fb57600080fd5b60208301915083602082850101111561141357600080fd5b9250929050565b803560ff811681146113a257600080fd5b60008060008060008060a0878903121561144457600080fd5b61144d8761138b565b9550602087013567ffffffffffffffff81111561146957600080fd5b61147589828a016113d1565b90965094505060408701359250606087013591506114956080880161141a565b90509295509295509295565b6000806000606084860312156114b657600080fd5b6114bf8461138b565b92506114cd6020850161138b565b9150604084013590509250925092565b6000602082840312156114ef57600080fd5b6113848261138b565b6000806040838503121561150b57600080fd5b6115148361138b565b91506115226020840161138b565b90509250929050565b6000806000806000806080878903121561154457600080fd5b61154d8761138b565b9550602087013567ffffffffffffffff8082111561156a57600080fd5b6115768a838b016113d1565b9097509550604089013591508082111561158f57600080fd5b5061159c89828a016113d1565b909450925061149590506060880161141a565b600181811c908216806115c357607f821691505b6020821081036115e357634e487b7160e01b600052602260045260246000fd5b50919050565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b60008251611621818460208701611321565b9190910192915050565b6001600160a01b0385811682528416602082015260606040820181905281018290526000828460808401376000608084840101526080601f19601f850116830101905095945050505050565b8082018082111561037a57634e487b7160e01b600052601160045260246000fd5b60208082526023908201527f4368696c6445524332303a204f6e6c79207072656469636174652063616e2063604082015262185b1b60ea1b606082015260800190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b601f82111561109457600081815260208120601f850160051c810160208610156117635750805b601f850160051c820191505b818110156117825782815560010161176f565b505050505050565b815167ffffffffffffffff8111156117a4576117a4611726565b6117b8816117b284546115af565b8461173c565b602080601f8311600181146117ed57600084156117d55750858301515b600019600386901b1c1916600185901b178555611782565b600085815260208120601f198616915b8281101561181c578886015182559484019460019091019084016117fd565b508582101561183a5787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fe4d6574615472616e73616374696f6e2875696e74323536206e6f6e63652c616464726573732066726f6d2c62797465732066756e6374696f6e5369676e617475726529ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122006e7874e62afcc37d931c31b2d4bea5f12ba721af845c8552d4733d66d6dcbb064736f6c63430008110033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101165760003560e01c806340c10f19116100a2578063a457c2d711610071578063a457c2d71461026b578063a9059cbb1461027e578063dd62ed3e14610291578063e6198705146102a4578063f6d2ee86146102b557600080fd5b806340c10f191461021457806370a082311461022757806395d89b41146102505780639dc29fac1461025857600080fd5b80631f2d0065116100e95780631f2d00651461018157806323b872dd146101a65780632d0335ab146101b9578063313ce567146101e2578063395093511461020157600080fd5b806306fdde031461011b578063095ea7b3146101395780630c53c51c1461015c57806318160ddd1461016f575b600080fd5b6101236102ca565b6040516101309190611371565b60405180910390f35b61014c6101473660046113a7565b61035c565b6040519015158152602001610130565b61012361016a36600461142b565b610380565b603c545b604051908152602001610130565b606d546001600160a01b03165b6040516001600160a01b039091168152602001610130565b61014c6101b43660046114a1565b610663565b6101736101c73660046114dd565b6001600160a01b031660009081526006602052604090205490565b606d54600160a01b900460ff1660405160ff9091168152602001610130565b61014c61020f3660046113a7565b610691565b61014c6102223660046113a7565b6106bd565b6101736102353660046114dd565b6001600160a01b03166000908152603a602052604090205490565b6101236106fd565b61014c6102663660046113a7565b61070c565b61014c6102793660046113a7565b610743565b61014c61028c3660046113a7565b6107c9565b61017361029f3660046114f8565b6107e1565b606c546001600160a01b031661018e565b6102c86102c336600461152b565b61080c565b005b6060603d80546102d9906115af565b80601f0160208091040260200160405190810160405280929190818152602001828054610305906115af565b80156103525780601f1061032757610100808354040283529160200191610352565b820191906000526020600020905b81548152906001019060200180831161033557829003601f168201915b5050505050905090565b600080610367610a8c565b9050610374818585610a9b565b60019150505b92915050565b606060006103c387878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610bc092505050565b90506001600160e01b031960003581169082160361044e5760405162461bcd60e51b815260206004820152603d60248201527f66756e6374696f6e5369676e61747572652063616e206e6f74206265206f662060448201527f657865637574654d6574615472616e73616374696f6e206d6574686f6400000060648201526084015b60405180910390fd5b604080516060810182526001600160a01b038a16600081815260066020908152848220548452808401929092528351601f8b0183900483028101830185528a815290938301918b908b9081908401838280828437600092019190915250505091525090506104bf8982888888610bdb565b6105155760405162461bcd60e51b815260206004820152602160248201527f5369676e657220616e64207369676e617475726520646f206e6f74206d6174636044820152600d60fb1b6064820152608401610445565b600660008a6001600160a01b03166001600160a01b031681526020019081526020016000206000815460010191905081905550600080306001600160a01b03168a8a8d60405160200161056a939291906115e9565b60408051601f19818403018152908290526105849161160f565b6000604051808303816000865af19150503d80600081146105c1576040519150601f19603f3d011682016040523d82523d6000602084013e6105c6565b606091505b5091509150816106185760405162461bcd60e51b815260206004820152601c60248201527f46756e6374696f6e2063616c6c206e6f74207375636365737366756c000000006044820152606401610445565b7f5845892132946850460bff5a0083f71031bc5bf9aadcd40f1de79423eac9b10b8b338c8c60405161064d949392919061162b565b60405180910390a19a9950505050505050505050565b60008061066e610a8c565b905061067b858285610cb7565b610686858585610d31565b506001949350505050565b60008061069c610a8c565b90506103748185856106ae85896107e1565b6106b89190611677565b610a9b565b606c546000906001600160a01b031633146106ea5760405162461bcd60e51b815260040161044590611698565b6106f48383610eca565b50600192915050565b6060603e80546102d9906115af565b606c546000906001600160a01b031633146107395760405162461bcd60e51b815260040161044590611698565b6106f48383610f7a565b60008061074e610a8c565b9050600061075c82866107e1565b9050838110156107bc5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610445565b6106868286868403610a9b565b6000806107d4610a8c565b9050610374818585610d31565b6001600160a01b039182166000908152603b6020908152604080832093909416825291909152205490565b600754610100900460ff161580801561082c5750600754600160ff909116105b806108465750303b158015610846575060075460ff166001145b6108a95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610445565b6007805460ff1916600117905580156108cc576007805461ff0019166101001790555b6001600160a01b038716158015906108e357508415155b80156108ee57508215155b61093a5760405162461bcd60e51b815260206004820152601e60248201527f4368696c6445524332303a204241445f494e495449414c495a4154494f4e00006044820152606401610445565b606d805460ff8416600160a01b026001600160a81b03199091166001600160a01b038a1617179055606c80546001600160a01b03191633179055604080516020601f88018190048102820181019092528681526109e591889088908190840183828082843760009201919091525050604080516020601f8a01819004810282018101909252888152925088915087908190840183828082843760009201919091525061109992505050565b610a3d86868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260018152603160f81b602082015291506110ca9050565b8015610a83576007805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6000610a96611136565b905090565b6001600160a01b038316610afd5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610445565b6001600160a01b038216610b5e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610445565b6001600160a01b038381166000818152603b602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b60008151600003610bd357506000919050565b506020015190565b6000806001610bf1610bec88611192565b61120f565b6040805160008152602081018083529290925260ff861690820152606081018790526080810186905260a0016020604051602081039080840390855afa158015610c3f573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610c965760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b6044820152606401610445565b866001600160a01b0316816001600160a01b03161491505095945050505050565b6000610cc384846107e1565b90506000198114610d2b5781811015610d1e5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610445565b610d2b8484848403610a9b565b50505050565b6001600160a01b038316610d955760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610445565b6001600160a01b038216610df75760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610445565b6001600160a01b0383166000908152603a602052604090205481811015610e6f5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610445565b6001600160a01b038085166000818152603a6020526040808220868603905592861680825290839020805486019055915160008051602061188e83398151915290610ebd9086815260200190565b60405180910390a3610d2b565b6001600160a01b038216610f205760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610445565b80603c6000828254610f329190611677565b90915550506001600160a01b0382166000818152603a602090815260408083208054860190555184815260008051602061188e833981519152910160405180910390a35b5050565b6001600160a01b038216610fda5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610445565b6001600160a01b0382166000908152603a60205260409020548181101561104e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610445565b6001600160a01b0383166000818152603a602090815260408083208686039055603c805487900390555185815291929160008051602061188e8339815191529101610bb3565b505050565b600754610100900460ff166110c05760405162461bcd60e51b8152600401610445906116db565b610f76828261125d565b815160208084019190912082519183019190912060038290556004819055466001557f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f61111881848461129d565b600055600280546001600160a01b0319163017905560055550505050565b600030330361118c57600080368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050503601516001600160a01b0316915061118f9050565b50335b90565b600060405180608001604052806043815260200161184b60439139805160209182012083518483015160408087015180519086012090516111f2950193845260208401929092526001600160a01b03166040830152606082015260800190565b604051602081830303815290604052805190602001209050919050565b600061037a61121c6112e6565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b600754610100900460ff166112845760405162461bcd60e51b8152600401610445906116db565b603d611290838261178a565b50603e611094828261178a565b6040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b6002546000906001600160a01b031630148015611304575060015446145b15611310575060005490565b610a9660055460035460045461129d565b60005b8381101561133c578181015183820152602001611324565b50506000910152565b6000815180845261135d816020860160208601611321565b601f01601f19169290920160200192915050565b6020815260006113846020830184611345565b9392505050565b80356001600160a01b03811681146113a257600080fd5b919050565b600080604083850312156113ba57600080fd5b6113c38361138b565b946020939093013593505050565b60008083601f8401126113e357600080fd5b50813567ffffffffffffffff8111156113fb57600080fd5b60208301915083602082850101111561141357600080fd5b9250929050565b803560ff811681146113a257600080fd5b60008060008060008060a0878903121561144457600080fd5b61144d8761138b565b9550602087013567ffffffffffffffff81111561146957600080fd5b61147589828a016113d1565b90965094505060408701359250606087013591506114956080880161141a565b90509295509295509295565b6000806000606084860312156114b657600080fd5b6114bf8461138b565b92506114cd6020850161138b565b9150604084013590509250925092565b6000602082840312156114ef57600080fd5b6113848261138b565b6000806040838503121561150b57600080fd5b6115148361138b565b91506115226020840161138b565b90509250929050565b6000806000806000806080878903121561154457600080fd5b61154d8761138b565b9550602087013567ffffffffffffffff8082111561156a57600080fd5b6115768a838b016113d1565b9097509550604089013591508082111561158f57600080fd5b5061159c89828a016113d1565b909450925061149590506060880161141a565b600181811c908216806115c357607f821691505b6020821081036115e357634e487b7160e01b600052602260045260246000fd5b50919050565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b60008251611621818460208701611321565b9190910192915050565b6001600160a01b0385811682528416602082015260606040820181905281018290526000828460808401376000608084840101526080601f19601f850116830101905095945050505050565b8082018082111561037a57634e487b7160e01b600052601160045260246000fd5b60208082526023908201527f4368696c6445524332303a204f6e6c79207072656469636174652063616e2063604082015262185b1b60ea1b606082015260800190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b601f82111561109457600081815260208120601f850160051c810160208610156117635750805b601f850160051c820191505b818110156117825782815560010161176f565b505050505050565b815167ffffffffffffffff8111156117a4576117a4611726565b6117b8816117b284546115af565b8461173c565b602080601f8311600181146117ed57600084156117d55750858301515b600019600386901b1c1916600185901b178555611782565b600085815260208120601f198616915b8281101561181c578886015182559484019460019091019084016117fd565b508582101561183a5787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fe4d6574615472616e73616374696f6e2875696e74323536206e6f6e63652c616464726573732066726f6d2c62797465732066756e6374696f6e5369676e617475726529ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122006e7874e62afcc37d931c31b2d4bea5f12ba721af845c8552d4733d66d6dcbb064736f6c63430008110033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" -var ChildERC20PredicateArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"ChildERC20Predicate\",\n \"sourceName\": \"contracts/child/ChildERC20Predicate.sol\",\n \"abi\": [\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"only\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"Unauthorized\",\n \"type\": \"error\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2ERC20Deposit\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2ERC20Withdraw\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"L2TokenMapped\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAP_TOKEN_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TOKEN_CONTRACT\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"SYSTEM\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childTokenTemplate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newL2StateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newStateReceiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newRootERC20Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newNativeTokenRootAddress\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"l2StateSender\",\n \"outputs\": [\n {\n \"internalType\": \"contract IStateSender\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onStateReceive\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"rootERC20Predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"rootTokenToChildToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"stateReceiver\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC20\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"withdraw\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC20\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"withdrawTo\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50611490806100206000396000f3fe608060405234801561001057600080fd5b50600436106101165760003560e01c806397e5230d116100a2578063d41f177111610071578063d41f17711461023d578063e0563ab114610264578063eeb499451461026d578063f3fef3a314610280578063f64512551461029357600080fd5b806397e5230d146101e6578063b1768065146101f0578063b68ad1e414610217578063c3b35a7e1461022a57600080fd5b80633b878c22116100e95780633b878c221461017c57806351351d531461018557806371cf93b7146101935780637efab4f5146101a6578063947287cf146101cf57600080fd5b806305dc2e8f1461011b5780631459457a1461014b5780631bc114ba14610160578063284017f514610173575b600080fd5b60345461012e906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b61015e610159366004610f98565b6102ba565b005b60335461012e906001600160a01b031681565b61012e61202081565b61012e61101081565b61012e6002600160a01b0381565b60355461012e906001600160a01b031681565b61012e6101b4366004611009565b6037602052600090815260409020546001600160a01b031681565b6101d861520881565b604051908152602001610142565b6101d8620249f081565b6101d87f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b60365461012e906001600160a01b031681565b61015e61023836600461102d565b61055a565b6101d87f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b61012e61203081565b61015e61027b36600461106e565b61056a565b61015e61028e3660046110f7565b61073e565b6101d87f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b336002600160a01b03146103035760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b60448201526064015b60405180910390fd5b600054610100900460ff16158080156103235750600054600160ff909116105b8061033d5750303b15801561033d575060005460ff166001145b6103a05760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016102fa565b6000805460ff1916600117905580156103c3576000805461ff0019166101001790555b6001600160a01b038616158015906103e357506001600160a01b03851615155b80156103f757506001600160a01b03841615155b801561040b57506001600160a01b03831615155b6104675760405162461bcd60e51b815260206004820152602760248201527f4368696c6445524332305072656469636174653a204241445f494e495449414c60448201526624ad20aa24a7a760c91b60648201526084016102fa565b603380546001600160a01b03199081166001600160a01b03898116919091179092556034805482168884161790556035805482168784161790556036805490911685831617905582161561050c576001600160a01b03821660008181526037602052604080822080546001600160a01b03191661101090811790915590519092917f46bd56f98e1b14fd35691959270a6e1edf7cb8fcd489e0f9dda89e46c0d1ff0d91a35b8015610552576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b61056583838361074d565b505050565b6034546001600160a01b031633146105d55760405162461bcd60e51b815260206004820152602860248201527f4368696c6445524332305072656469636174653a204f4e4c595f53544154455f6044820152672922a1a2a4ab22a960c11b60648201526084016102fa565b6035546001600160a01b038481169116146106435760405162461bcd60e51b815260206004820152602860248201527f4368696c6445524332305072656469636174653a204f4e4c595f524f4f545f50604482015267524544494341544560c01b60648201526084016102fa565b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f821610672602060008486611123565b61067b9161114d565b0361069a576106956106908260208186611123565b610ac3565b610738565b7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad6106c9602060008486611123565b6106d29161114d565b036106e1576106958282610d6e565b60405162461bcd60e51b815260206004820152602660248201527f4368696c6445524332305072656469636174653a20494e56414c49445f5349476044820152654e415455524560d01b60648201526084016102fa565b50505050565b61074982338361074d565b5050565b826001600160a01b03163b6000036107b15760405162461bcd60e51b815260206004820152602160248201527f4368696c6445524332305072656469636174653a204e4f545f434f4e545241436044820152601560fa1b60648201526084016102fa565b6000836001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107f1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610815919061116b565b6001600160a01b038181166000908152603760205260409020549192508581169116146108545760405162461bcd60e51b81526004016102fa90611188565b6001600160a01b03811661086a5761086a6111cb565b306001600160a01b0316846001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d6919061116b565b6001600160a01b0316146108ec576108ec6111cb565b604051632770a7eb60e21b81526001600160a01b03851690639dc29fac9061091a90339086906004016111e1565b6020604051808303816000875af1158015610939573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061095d91906111fa565b6109a95760405162461bcd60e51b815260206004820181905260248201527f4368696c6445524332305072656469636174653a204255524e5f4641494c454460448201526064016102fa565b603354603554604080517f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286960208201526001600160a01b0385811682840152336060830152878116608083015260a08083018890528351808403909101815260c08301938490526316f1983160e01b909352938416936316f1983193610a349391169160c401611262565b600060405180830381600087803b158015610a4e57600080fd5b505af1158015610a62573d6000803e3d6000fd5b50505050826001600160a01b0316846001600160a01b0316826001600160a01b03167fa0923f060a16fc784558d43de424ffde7b01643de5e5d335851b9df94c76bb273386604051610ab59291906111e1565b60405180910390a450505050565b6000808080610ad48587018761128e565b6001600160a01b0380851660009081526037602052604090205494985092965090945092501680610b175760405162461bcd60e51b81526004016102fa90611188565b806001600160a01b03163b600003610b3157610b316111cb565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b95919061116b565b9050856001600160a01b0316816001600160a01b031614610bb857610bb86111cb565b6001600160a01b038116610bce57610bce6111cb565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3a919061116b565b6001600160a01b031614610c5057610c506111cb565b6040516340c10f1960e01b81526001600160a01b038316906340c10f1990610c7e90879087906004016111e1565b6020604051808303816000875af1158015610c9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc191906111fa565b610d0d5760405162461bcd60e51b815260206004820181905260248201527f4368696c6445524332305072656469636174653a204d494e545f4641494c454460448201526064016102fa565b836001600160a01b0316826001600160a01b0316876001600160a01b03167fdf34f3a3ed8bedc14a4b284ebaee5374d55b64bac6a84c270dabe8fd6b4cdafd8887604051610d5c9291906111e1565b60405180910390a45050505050505050565b6000808080610d7f85870187611382565b92975090955093509150506001600160a01b038416610da057610da06111cb565b6001600160a01b038481166000908152603760205260409020541615610dc857610dc86111cb565b6036546040516bffffffffffffffffffffffff19606087901b166020820152600091610e18916001600160a01b039091169060340160405160208183030381529060405280519060200120610ee3565b6001600160a01b038681166000908152603760205260409081902080546001600160a01b031916928416928317905551637b69774360e11b81529192509063f6d2ee8690610e7090889088908890889060040161140f565b600060405180830381600087803b158015610e8a57600080fd5b505af1158015610e9e573d6000803e3d6000fd5b50506040516001600160a01b038085169350881691507f46bd56f98e1b14fd35691959270a6e1edf7cb8fcd489e0f9dda89e46c0d1ff0d90600090a350505050505050565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b038116610f7a5760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b60448201526064016102fa565b92915050565b6001600160a01b0381168114610f9557600080fd5b50565b600080600080600060a08688031215610fb057600080fd5b8535610fbb81610f80565b94506020860135610fcb81610f80565b93506040860135610fdb81610f80565b92506060860135610feb81610f80565b91506080860135610ffb81610f80565b809150509295509295909350565b60006020828403121561101b57600080fd5b813561102681610f80565b9392505050565b60008060006060848603121561104257600080fd5b833561104d81610f80565b9250602084013561105d81610f80565b929592945050506040919091013590565b6000806000806060858703121561108457600080fd5b84359350602085013561109681610f80565b9250604085013567ffffffffffffffff808211156110b357600080fd5b818701915087601f8301126110c757600080fd5b8135818111156110d657600080fd5b8860208285010111156110e857600080fd5b95989497505060200194505050565b6000806040838503121561110a57600080fd5b823561111581610f80565b946020939093013593505050565b6000808585111561113357600080fd5b8386111561114057600080fd5b5050820193919092039150565b80356020831015610f7a57600019602084900360031b1b1692915050565b60006020828403121561117d57600080fd5b815161102681610f80565b60208082526023908201527f4368696c6445524332305072656469636174653a20554e4d41505045445f544f60408201526225a2a760e91b606082015260800190565b634e487b7160e01b600052600160045260246000fd5b6001600160a01b03929092168252602082015260400190565b60006020828403121561120c57600080fd5b8151801515811461102657600080fd5b6000815180845260005b8181101561124257602081850181015186830182015201611226565b506000602082860101526020601f19601f83011685010191505092915050565b6001600160a01b03831681526040602082018190526000906112869083018461121c565b949350505050565b600080600080608085870312156112a457600080fd5b84356112af81610f80565b935060208501356112bf81610f80565b925060408501356112cf81610f80565b9396929550929360600135925050565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261130657600080fd5b813567ffffffffffffffff80821115611321576113216112df565b604051601f8301601f19908116603f01168101908282118183101715611349576113496112df565b8160405283815286602085880101111561136257600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060a0868803121561139a57600080fd5b8535945060208601356113ac81610f80565b9350604086013567ffffffffffffffff808211156113c957600080fd5b6113d589838a016112f5565b945060608801359150808211156113eb57600080fd5b506113f8888289016112f5565b925050608086013560ff81168114610ffb57600080fd5b6001600160a01b03851681526080602082018190526000906114339083018661121c565b8281036040840152611445818661121c565b91505060ff831660608301529594505050505056fea2646970667358221220826f58ea208b8a100d3343999582bb4813e24a5dd686101ad5da8213058bdfaf64736f6c63430008110033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101165760003560e01c806397e5230d116100a2578063d41f177111610071578063d41f17711461023d578063e0563ab114610264578063eeb499451461026d578063f3fef3a314610280578063f64512551461029357600080fd5b806397e5230d146101e6578063b1768065146101f0578063b68ad1e414610217578063c3b35a7e1461022a57600080fd5b80633b878c22116100e95780633b878c221461017c57806351351d531461018557806371cf93b7146101935780637efab4f5146101a6578063947287cf146101cf57600080fd5b806305dc2e8f1461011b5780631459457a1461014b5780631bc114ba14610160578063284017f514610173575b600080fd5b60345461012e906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b61015e610159366004610f98565b6102ba565b005b60335461012e906001600160a01b031681565b61012e61202081565b61012e61101081565b61012e6002600160a01b0381565b60355461012e906001600160a01b031681565b61012e6101b4366004611009565b6037602052600090815260409020546001600160a01b031681565b6101d861520881565b604051908152602001610142565b6101d8620249f081565b6101d87f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b60365461012e906001600160a01b031681565b61015e61023836600461102d565b61055a565b6101d87f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b61012e61203081565b61015e61027b36600461106e565b61056a565b61015e61028e3660046110f7565b61073e565b6101d87f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b336002600160a01b03146103035760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b60448201526064015b60405180910390fd5b600054610100900460ff16158080156103235750600054600160ff909116105b8061033d5750303b15801561033d575060005460ff166001145b6103a05760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016102fa565b6000805460ff1916600117905580156103c3576000805461ff0019166101001790555b6001600160a01b038616158015906103e357506001600160a01b03851615155b80156103f757506001600160a01b03841615155b801561040b57506001600160a01b03831615155b6104675760405162461bcd60e51b815260206004820152602760248201527f4368696c6445524332305072656469636174653a204241445f494e495449414c60448201526624ad20aa24a7a760c91b60648201526084016102fa565b603380546001600160a01b03199081166001600160a01b03898116919091179092556034805482168884161790556035805482168784161790556036805490911685831617905582161561050c576001600160a01b03821660008181526037602052604080822080546001600160a01b03191661101090811790915590519092917f46bd56f98e1b14fd35691959270a6e1edf7cb8fcd489e0f9dda89e46c0d1ff0d91a35b8015610552576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b61056583838361074d565b505050565b6034546001600160a01b031633146105d55760405162461bcd60e51b815260206004820152602860248201527f4368696c6445524332305072656469636174653a204f4e4c595f53544154455f6044820152672922a1a2a4ab22a960c11b60648201526084016102fa565b6035546001600160a01b038481169116146106435760405162461bcd60e51b815260206004820152602860248201527f4368696c6445524332305072656469636174653a204f4e4c595f524f4f545f50604482015267524544494341544560c01b60648201526084016102fa565b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f821610672602060008486611123565b61067b9161114d565b0361069a576106956106908260208186611123565b610ac3565b610738565b7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad6106c9602060008486611123565b6106d29161114d565b036106e1576106958282610d6e565b60405162461bcd60e51b815260206004820152602660248201527f4368696c6445524332305072656469636174653a20494e56414c49445f5349476044820152654e415455524560d01b60648201526084016102fa565b50505050565b61074982338361074d565b5050565b826001600160a01b03163b6000036107b15760405162461bcd60e51b815260206004820152602160248201527f4368696c6445524332305072656469636174653a204e4f545f434f4e545241436044820152601560fa1b60648201526084016102fa565b6000836001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107f1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610815919061116b565b6001600160a01b038181166000908152603760205260409020549192508581169116146108545760405162461bcd60e51b81526004016102fa90611188565b6001600160a01b03811661086a5761086a6111cb565b306001600160a01b0316846001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d6919061116b565b6001600160a01b0316146108ec576108ec6111cb565b604051632770a7eb60e21b81526001600160a01b03851690639dc29fac9061091a90339086906004016111e1565b6020604051808303816000875af1158015610939573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061095d91906111fa565b6109a95760405162461bcd60e51b815260206004820181905260248201527f4368696c6445524332305072656469636174653a204255524e5f4641494c454460448201526064016102fa565b603354603554604080517f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286960208201526001600160a01b0385811682840152336060830152878116608083015260a08083018890528351808403909101815260c08301938490526316f1983160e01b909352938416936316f1983193610a349391169160c401611262565b600060405180830381600087803b158015610a4e57600080fd5b505af1158015610a62573d6000803e3d6000fd5b50505050826001600160a01b0316846001600160a01b0316826001600160a01b03167fa0923f060a16fc784558d43de424ffde7b01643de5e5d335851b9df94c76bb273386604051610ab59291906111e1565b60405180910390a450505050565b6000808080610ad48587018761128e565b6001600160a01b0380851660009081526037602052604090205494985092965090945092501680610b175760405162461bcd60e51b81526004016102fa90611188565b806001600160a01b03163b600003610b3157610b316111cb565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b95919061116b565b9050856001600160a01b0316816001600160a01b031614610bb857610bb86111cb565b6001600160a01b038116610bce57610bce6111cb565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3a919061116b565b6001600160a01b031614610c5057610c506111cb565b6040516340c10f1960e01b81526001600160a01b038316906340c10f1990610c7e90879087906004016111e1565b6020604051808303816000875af1158015610c9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc191906111fa565b610d0d5760405162461bcd60e51b815260206004820181905260248201527f4368696c6445524332305072656469636174653a204d494e545f4641494c454460448201526064016102fa565b836001600160a01b0316826001600160a01b0316876001600160a01b03167fdf34f3a3ed8bedc14a4b284ebaee5374d55b64bac6a84c270dabe8fd6b4cdafd8887604051610d5c9291906111e1565b60405180910390a45050505050505050565b6000808080610d7f85870187611382565b92975090955093509150506001600160a01b038416610da057610da06111cb565b6001600160a01b038481166000908152603760205260409020541615610dc857610dc86111cb565b6036546040516bffffffffffffffffffffffff19606087901b166020820152600091610e18916001600160a01b039091169060340160405160208183030381529060405280519060200120610ee3565b6001600160a01b038681166000908152603760205260409081902080546001600160a01b031916928416928317905551637b69774360e11b81529192509063f6d2ee8690610e7090889088908890889060040161140f565b600060405180830381600087803b158015610e8a57600080fd5b505af1158015610e9e573d6000803e3d6000fd5b50506040516001600160a01b038085169350881691507f46bd56f98e1b14fd35691959270a6e1edf7cb8fcd489e0f9dda89e46c0d1ff0d90600090a350505050505050565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b038116610f7a5760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b60448201526064016102fa565b92915050565b6001600160a01b0381168114610f9557600080fd5b50565b600080600080600060a08688031215610fb057600080fd5b8535610fbb81610f80565b94506020860135610fcb81610f80565b93506040860135610fdb81610f80565b92506060860135610feb81610f80565b91506080860135610ffb81610f80565b809150509295509295909350565b60006020828403121561101b57600080fd5b813561102681610f80565b9392505050565b60008060006060848603121561104257600080fd5b833561104d81610f80565b9250602084013561105d81610f80565b929592945050506040919091013590565b6000806000806060858703121561108457600080fd5b84359350602085013561109681610f80565b9250604085013567ffffffffffffffff808211156110b357600080fd5b818701915087601f8301126110c757600080fd5b8135818111156110d657600080fd5b8860208285010111156110e857600080fd5b95989497505060200194505050565b6000806040838503121561110a57600080fd5b823561111581610f80565b946020939093013593505050565b6000808585111561113357600080fd5b8386111561114057600080fd5b5050820193919092039150565b80356020831015610f7a57600019602084900360031b1b1692915050565b60006020828403121561117d57600080fd5b815161102681610f80565b60208082526023908201527f4368696c6445524332305072656469636174653a20554e4d41505045445f544f60408201526225a2a760e91b606082015260800190565b634e487b7160e01b600052600160045260246000fd5b6001600160a01b03929092168252602082015260400190565b60006020828403121561120c57600080fd5b8151801515811461102657600080fd5b6000815180845260005b8181101561124257602081850181015186830182015201611226565b506000602082860101526020601f19601f83011685010191505092915050565b6001600160a01b03831681526040602082018190526000906112869083018461121c565b949350505050565b600080600080608085870312156112a457600080fd5b84356112af81610f80565b935060208501356112bf81610f80565b925060408501356112cf81610f80565b9396929550929360600135925050565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261130657600080fd5b813567ffffffffffffffff80821115611321576113216112df565b604051601f8301601f19908116603f01168101908282118183101715611349576113496112df565b8160405283815286602085880101111561136257600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060a0868803121561139a57600080fd5b8535945060208601356113ac81610f80565b9350604086013567ffffffffffffffff808211156113c957600080fd5b6113d589838a016112f5565b945060608801359150808211156113eb57600080fd5b506113f8888289016112f5565b925050608086013560ff81168114610ffb57600080fd5b6001600160a01b03851681526080602082018190526000906114339083018661121c565b8281036040840152611445818661121c565b91505060ff831660608301529594505050505056fea2646970667358221220826f58ea208b8a100d3343999582bb4813e24a5dd686101ad5da8213058bdfaf64736f6c63430008110033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" -var SystemArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"System\",\n \"sourceName\": \"contracts/child/System.sol\",\n \"abi\": [\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TOKEN_CONTRACT\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"SYSTEM\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b5060f58061001f6000396000f3fe6080604052348015600f57600080fd5b5060043610605a5760003560e01c8063284017f514605f5780633b878c2214608457806351351d5314608c578063947287cf14609957806397e5230d1460ae578063e0563ab11460b7575b600080fd5b606761202081565b6040516001600160a01b0390911681526020015b60405180910390f35b606761101081565b60676002600160a01b0381565b60a161520881565b604051908152602001607b565b60a1620249f081565b60676120308156fea264697066735822122064014c9d48fdaeeccbde77e32e0a3289adc5bd43847b6b471e83d76a9ba6fbab64736f6c63430008110033\",\n \"deployedBytecode\": \"0x6080604052348015600f57600080fd5b5060043610605a5760003560e01c8063284017f514605f5780633b878c2214608457806351351d5314608c578063947287cf14609957806397e5230d1460ae578063e0563ab11460b7575b600080fd5b606761202081565b6040516001600160a01b0390911681526020015b60405180910390f35b606761101081565b60676002600160a01b0381565b60a161520881565b604051908152602001607b565b60a1620249f081565b60676120308156fea264697066735822122064014c9d48fdaeeccbde77e32e0a3289adc5bd43847b6b471e83d76a9ba6fbab64736f6c63430008110033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" -var BLSArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"BLS\",\n \"sourceName\": \"contracts/common/BLS.sol\",\n \"abi\": [\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"domain\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"message\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"expandMsgTo96\",\n \"outputs\": [\n {\n \"internalType\": \"bytes\",\n \"name\": \"\",\n \"type\": \"bytes\"\n }\n ],\n \"stateMutability\": \"pure\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"domain\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"messages\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"hashToField\",\n \"outputs\": [\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"\",\n \"type\": \"uint256[2]\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"domain\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"message\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"hashToPoint\",\n \"outputs\": [\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"\",\n \"type\": \"uint256[2]\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"point\",\n \"type\": \"uint256[2]\"\n }\n ],\n \"name\": \"isOnCurveG1\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"_isOnCurve\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"pure\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256[4]\",\n \"name\": \"point\",\n \"type\": \"uint256[4]\"\n }\n ],\n \"name\": \"isOnCurveG2\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"_isOnCurve\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"pure\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"signature\",\n \"type\": \"uint256[2]\"\n }\n ],\n \"name\": \"isValidSignature\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"_x\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"mapToPoint\",\n \"outputs\": [\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"p\",\n \"type\": \"uint256[2]\"\n }\n ],\n \"stateMutability\": \"pure\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"signature\",\n \"type\": \"uint256[2]\"\n },\n {\n \"internalType\": \"uint256[4][]\",\n \"name\": \"pubkeys\",\n \"type\": \"uint256[4][]\"\n },\n {\n \"internalType\": \"uint256[2][]\",\n \"name\": \"messages\",\n \"type\": \"uint256[2][]\"\n }\n ],\n \"name\": \"verifyMultiple\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"checkResult\",\n \"type\": \"bool\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"callSuccess\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"signature\",\n \"type\": \"uint256[2]\"\n },\n {\n \"internalType\": \"uint256[4][]\",\n \"name\": \"pubkeys\",\n \"type\": \"uint256[4][]\"\n },\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"message\",\n \"type\": \"uint256[2]\"\n }\n ],\n \"name\": \"verifyMultipleSameMsg\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"checkResult\",\n \"type\": \"bool\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"callSuccess\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"signature\",\n \"type\": \"uint256[2]\"\n },\n {\n \"internalType\": \"uint256[4]\",\n \"name\": \"pubkey\",\n \"type\": \"uint256[4]\"\n },\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"message\",\n \"type\": \"uint256[2]\"\n }\n ],\n \"name\": \"verifySingle\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50612df8806100206000396000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c806391ec2d2b1161006657806391ec2d2b1461013b578063a850a9091461015b578063d58e77331461016e578063e242cce914610181578063ebbdac911461019457600080fd5b8063115000fe146100a3578063247dd9fb146100cb5780633e5476ce146100de5780638669026f146101085780639141376314610128575b600080fd5b6100b66100b1366004612708565b6101a7565b60405190151581526020015b60405180910390f35b6100b66100d9366004612785565b61030e565b6100f16100ec366004612841565b6103b8565b6040805192151583529015156020830152016100c2565b61011b6101163660046128ce565b61079f565b6040516100c29190612957565b6100f1610136366004612988565b6108bb565b61014e6101493660046128ce565b610d5c565b6040516100c29190612a86565b61011b6101693660046128ce565b610ff8565b61011b61017c366004612aa0565b6111d4565b6100b661018f366004612785565b6115aa565b6100f16101a2366004612ab9565b611609565b600081516020830151600080516020612d63833981519152828309600080516020612d638339815191528283098182830101600080516020612d638339815191528283840108600080516020612d638339815191528682600080516020612d6383398151915203860109935050600080516020612d638339815191528483600080516020612d63833981519152038301099150600080516020612d638339815191527f2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e584089450600080516020612d638339815191527e9713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d2830893506040870151925060608701519150600080516020612d638339815191528083600080516020612d63833981519152038508600080516020612d63833981519152848608099050600080516020612d63833981519152828460011b0994149290931491909116949350505050565b8051600090600080516020612d6383398151915211158061034157506020820151600080516020612d6383398151915211155b1561034e57506000919050565b60405163e242cce960e01b8152309063e242cce990610371908590600401612957565b602060405180830381865afa15801561038e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103b29190612b1c565b92915050565b60008083806103e25760405162461bcd60e51b81526004016103d990612b3e565b60405180910390fd5b60006103ef826001612b95565b6103fa906006612ba8565b90506000816001600160401b038111156104165761041661269a565b60405190808252806020026020018201604052801561043f578160200160208202803683370190505b50905088600060200201358160008151811061045d5761045d612b06565b602090810291909101015288600160200201358160018151811061048357610483612b06565b602002602001018181525050600080516020612d43833981519152816002815181106104b1576104b1612b06565b602002602001018181525050600080516020612d23833981519152816003815181106104df576104df612b06565b602002602001018181525050600080516020612d838339815191528160048151811061050d5761050d612b06565b602002602001018181525050600080516020612da38339815191528160058151811061053b5761053b612b06565b60200260200101818152505060005b8381101561075a57863582610560836006612ba8565b61056b906006612b95565b8151811061057b5761057b612b06565b602090810291909101015286600160200201358261059a836006612ba8565b6105a5906007612b95565b815181106105b5576105b5612b06565b6020026020010181815250508888828181106105d3576105d3612b06565b9050608002016001600481106105eb576105eb612b06565b6020020135826105fc836006612ba8565b610607906008612b95565b8151811061061757610617612b06565b60200260200101818152505088888281811061063557610635612b06565b90506080020160006004811061064d5761064d612b06565b60200201358261065e836006612ba8565b610669906009612b95565b8151811061067957610679612b06565b60200260200101818152505088888281811061069757610697612b06565b9050608002016003600481106106af576106af612b06565b6020020135826106c0836006612ba8565b6106cb90600a612b95565b815181106106db576106db612b06565b6020026020010181815250508888828181106106f9576106f9612b06565b90506080020160026004811061071157610711612b06565b602002013582610722836006612ba8565b61072d90600b612b95565b8151811061073d5761073d612b06565b60209081029190910101528061075281612bbf565b91505061054a565b50610763612640565b602081602085026020850160085afa945084610789576000809550955050505050610796565b5115159450600193505050505b94509492505050565b6107a761265e565b6040516391ec2d2b60e01b815260009030906391ec2d2b906107cf9087908790600401612bd8565b600060405180830381865afa1580156107ec573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108149190810190612bf9565b9050600080600080601885016001600160c01b0381511693506030860190506001600160c01b038151169450600080516020612d6383398151915285600080516020612d63833981519152600160c01b870908604887015160608801516001600160c01b0390811697501694509250600080516020612d6383398151915290508481600160c01b860908604080518082019091529283526020830152509695505050505050565b60008084806108dc5760405162461bcd60e51b81526004016103d990612b3e565b8084146109495760405162461bcd60e51b815260206004820152603560248201527f424c533a206e756d626572206f66207075626c6963206b65797320616e64206d604482015274195cdcd859d95cc81b5d5cdd08189948195c5d585b605a1b60648201526084016103d9565b6000610956826001612b95565b610961906006612ba8565b90506000816001600160401b0381111561097d5761097d61269a565b6040519080825280602002602001820160405280156109a6578160200160208202803683370190505b5090508960006020020135816000815181106109c4576109c4612b06565b60209081029190910101528960016020020135816001815181106109ea576109ea612b06565b602002602001018181525050600080516020612d4383398151915281600281518110610a1857610a18612b06565b602002602001018181525050600080516020612d2383398151915281600381518110610a4657610a46612b06565b602002602001018181525050600080516020612d8383398151915281600481518110610a7457610a74612b06565b602002602001018181525050600080516020612da383398151915281600581518110610aa257610aa2612b06565b60200260200101818152505060005b83811015610d1657878782818110610acb57610acb612b06565b905060400201600060028110610ae357610ae3612b06565b602002013582610af4836006612ba8565b610aff906006612b95565b81518110610b0f57610b0f612b06565b602002602001018181525050878782818110610b2d57610b2d612b06565b905060400201600160028110610b4557610b45612b06565b602002013582610b56836006612ba8565b610b61906007612b95565b81518110610b7157610b71612b06565b602002602001018181525050898982818110610b8f57610b8f612b06565b905060800201600160048110610ba757610ba7612b06565b602002013582610bb8836006612ba8565b610bc3906008612b95565b81518110610bd357610bd3612b06565b602002602001018181525050898982818110610bf157610bf1612b06565b905060800201600060048110610c0957610c09612b06565b602002013582610c1a836006612ba8565b610c25906009612b95565b81518110610c3557610c35612b06565b602002602001018181525050898982818110610c5357610c53612b06565b905060800201600360048110610c6b57610c6b612b06565b602002013582610c7c836006612ba8565b610c8790600a612b95565b81518110610c9757610c97612b06565b602002602001018181525050898982818110610cb557610cb5612b06565b905060800201600260048110610ccd57610ccd612b06565b602002013582610cde836006612ba8565b610ce990600b612b95565b81518110610cf957610cf9612b06565b602090810291909101015280610d0e81612bbf565b915050610ab1565b50610d1f612640565b602081602085026020850160085afa945084610d45576000809550955050505050610d52565b5115159450600193505050505b9550959350505050565b80516060906000610d6e826020612b95565b610d79906040612b95565b610d84906004612b95565b6001600160401b03811115610d9b57610d9b61269a565b6040519080825280601f01601f191660200182016040528015610dc5576020820181803683370190505b5060408051606080825260808201909252919250600091906020820181803683370190505090506060820160005b84811015610e0d5760208188018101518383015201610df3565b5083016000815360010160608153600101600081536001810187905260210160208153506000600283604051610e439190612c6f565b602060405180830381855afa158015610e60573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610e839190612c8b565b9050600060429450848452816020850152600160408501536041840188905260206061850153600284604051610eb99190612c6f565b602060405180830381855afa158015610ed6573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610ef99190612c8b565b905080602084015280821880602086015250600260408501536041840188905260206061850153600284604051610f309190612c6f565b602060405180830381855afa158015610f4d573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610f709190612c8b565b905080604084015280821880602086015250600360408501536041840188905260206061850153600284604051610fa79190612c6f565b602060405180830381855afa158015610fc4573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610fe79190612c8b565b606084015250909695505050505050565b61100061265e565b604051638669026f60e01b81526000903090638669026f906110289087908790600401612bd8565b6040805180830381865afa158015611044573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110689190612ca4565b805160405163d58e773360e01b81526004810191909152909150600090309063d58e7733906024016040805180830381865afa1580156110ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110d09190612ca4565b602083015160405163d58e773360e01b81526004810191909152909150600090309063d58e7733906024016040805180830381865afa158015611117573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113b9190612ca4565b905061114561267c565b825181526020808401518282015282516040808401919091529083015160608301526000908460808460066107d05a03fa9050808061118057fe5b50806111c85760405162461bcd60e51b8152602060048201526017602482015276109314ce88189b881859190818d85b1b0819985a5b1959604a1b60448201526064016103d9565b50919695505050505050565b6111dc61265e565b600080516020612d6383398151915282106112455760405162461bcd60e51b815260206004820152602360248201527f6d6170546f506f696e7446543a20696e76616c6964206669656c6420656c656d604482015262195b9d60ea1b60648201526084016103d9565b81600061125182611790565b9150506000600080516020612d638339815191528061127257611272612cf9565b8384099050600080516020612d638339815191526004820890506000600080516020612d6383398151915277b3c4d79d41a91759a9e4c7e359b6b89eaec68e62effffffd850990506000600080516020612d6383398151915283830990506112d9816117b9565b9050600080516020612d638339815191528283099150600080516020612d638339815191528183099150600080516020612d638339815191528286099150600080516020612d6383398151915261133e83600080516020612d63833981519152612d0f565b7759e26bcea0d48bacd4f263f1acdb5c4f5763473177fffffe089450600080516020612d638339815191528586099150600080516020612d638339815191528583099150600080516020612d6383398151915260038308915060006113a283611790565b909350905080156113ea57846113cd576113ca83600080516020612d63833981519152612d0f565b92505b505060408051808201909152938452602084015250909392505050565b600080516020612d638339815191526001870861141590600080516020612d63833981519152612d0f565b9550600080516020612d638339815191528687099250600080516020612d638339815191528684099250600080516020612d6383398151915260038408925061145d83611790565b9093509050801561148557846113cd576113ca83600080516020612d63833981519152612d0f565b600080516020612d638339815191528485099550600080516020612d638339815191528687099550600080516020612d638339815191528287099550600080516020612d638339815191528287099550600080516020612d63833981519152600187089550600080516020612d638339815191528687099250600080516020612d638339815191528684099250600080516020612d6383398151915260038408925061153083611790565b90935090508061158d5760405162461bcd60e51b815260206004820152602260248201527f424c533a20626164206674206d617070696e6720696d706c656d656e7461746960448201526137b760f11b60648201526084016103d9565b846113cd576113ca83600080516020612d63833981519152612d0f565b600081516020830151600080516020612d63833981519152828309600080516020612d638339815191528382099050600080516020612d63833981519152600382089050600080516020612d6383398151915282830914949350505050565b60008060006040518061018001604052808760006002811061162d5761162d612b06565b602002013581526020018760016002811061164a5761164a612b06565b60200201358152602001600080516020612d438339815191528152602001600080516020612d238339815191528152602001600080516020612d838339815191528152602001600080516020612da38339815191528152602001856000600281106116b7576116b7612b06565b60200201358152602001856001600281106116d4576116d4612b06565b60200201358152602001866001600481106116f1576116f1612b06565b602002013581526020018660006004811061170e5761170e612b06565b602002013581526020018660036004811061172b5761172b612b06565b602002013581526020018660026004811061174857611748612b06565b602002013590529050611759612640565b60006020826101808560085afa90508061177c5760008094509450505050611788565b50511515925060019150505b935093915050565b60008061179c836117c4565b915082600080516020612d63833981519152838409149050915091565b60006103b282611ef9565b6000600080516020612d638339815191528083840991508083830981838209828283098385830984848309858484098684850997508684840987858409945087898a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087838a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985050868889099750868889099750868889099750868889099750868889099750868889099750868489099750868889099750868889099750868889099750868889099750868889099750868989099750868889099750868889099750868889099750868889099750868889099750868889099750868989099750868889099750868889099750868889099750868889099750868889099750868689099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868189099750508587880996508587880996508587880996508585880996508587880996508587880996508587880996508585880996508587880996508587880996508587880996508587880996508587880996508587880996508587880996508587880996508583880996508587880996508587880996508587880996508587880996508581880996508587880996508587880996508587880996508587880996508583880996508587880996508587880996508587880996508584880996508587880996508587880996508587880996508587880996508587880996508581880996505050505050808283099392505050565b6000600080516020612d638339815191528083840991508083830981838209828283098385830984848309858484098684850997508684840987858409945087898a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087838a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985050868889099750868889099750868889099750868889099750868889099750868889099750868489099750868889099750868889099750868889099750868889099750868889099750868989099750868889099750868889099750868889099750868889099750868889099750868889099750868989099750868889099750868889099750868889099750868889099750868889099750868689099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868189099750508587880996508587880996508587880996508585880996508587880996508587880996508587880996508585880996508587880996508587880996508587880996508587880996508587880996508587880996508587880996508587880996508583880996508587880996508587880996508587880996508587880996508581880996505050838586099450838586099450838586099450838586099450838186099450508284850993508284850993508284850993508281850993508284850993508284850993508285850993508284850993508284850993508284850993508284850993508284850993508284850993508281850995945050505050565b60405180602001604052806001906020820280368337509192915050565b60405180604001604052806002906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b03811182821017156126d2576126d261269a565b60405290565b604051601f8201601f191681016001600160401b03811182821017156127005761270061269a565b604052919050565b60006080828403121561271a57600080fd5b82601f83011261272957600080fd5b604051608081018181106001600160401b038211171561274b5761274b61269a565b60405280608084018581111561276057600080fd5b845b8181101561277a578035835260209283019201612762565b509195945050505050565b60006040828403121561279757600080fd5b82601f8301126127a657600080fd5b6127ae6126b0565b8060408401858111156127c057600080fd5b845b818110156127da5780358452602093840193016127c2565b509095945050505050565b80604081018310156103b257600080fd5b60008083601f84011261280857600080fd5b5081356001600160401b0381111561281f57600080fd5b6020830191508360208260071b850101111561283a57600080fd5b9250929050565b60008060008060a0858703121561285757600080fd5b61286186866127e5565b935060408501356001600160401b0381111561287c57600080fd5b612888878288016127f6565b909450925061289c905086606087016127e5565b905092959194509250565b60006001600160401b038211156128c0576128c061269a565b50601f01601f191660200190565b600080604083850312156128e157600080fd5b8235915060208301356001600160401b038111156128fe57600080fd5b8301601f8101851361290f57600080fd5b803561292261291d826128a7565b6126d8565b81815286602083850101111561293757600080fd5b816020840160208301376000602083830101528093505050509250929050565b60408101818360005b600281101561297f578151835260209283019290910190600101612960565b50505092915050565b6000806000806000608086880312156129a057600080fd5b6129aa87876127e5565b945060408601356001600160401b03808211156129c657600080fd5b6129d289838a016127f6565b909650945060608801359150808211156129eb57600080fd5b818801915088601f8301126129ff57600080fd5b813581811115612a0e57600080fd5b8960208260061b8501011115612a2357600080fd5b9699959850939650602001949392505050565b60005b83811015612a51578181015183820152602001612a39565b50506000910152565b60008151808452612a72816020860160208601612a36565b601f01601f19169290920160200192915050565b602081526000612a996020830184612a5a565b9392505050565b600060208284031215612ab257600080fd5b5035919050565b60008060006101008486031215612acf57600080fd5b612ad985856127e5565b925060c0840185811115612aec57600080fd5b604085019250612afc86826127e5565b9150509250925092565b634e487b7160e01b600052603260045260246000fd5b600060208284031215612b2e57600080fd5b81518015158114612a9957600080fd5b60208082526021908201527f424c533a206e756d626572206f66207075626c6963206b6579206973207a65726040820152606f60f81b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b808201808211156103b2576103b2612b7f565b80820281158282048414176103b2576103b2612b7f565b600060018201612bd157612bd1612b7f565b5060010190565b828152604060208201526000612bf16040830184612a5a565b949350505050565b600060208284031215612c0b57600080fd5b81516001600160401b03811115612c2157600080fd5b8201601f81018413612c3257600080fd5b8051612c4061291d826128a7565b818152856020838501011115612c5557600080fd5b612c66826020830160208601612a36565b95945050505050565b60008251612c81818460208701612a36565b9190910192915050565b600060208284031215612c9d57600080fd5b5051919050565b600060408284031215612cb657600080fd5b82601f830112612cc557600080fd5b612ccd6126b0565b806040840185811115612cdf57600080fd5b845b818110156127da578051845260209384019301612ce1565b634e487b7160e01b600052601260045260246000fd5b818103818111156103b2576103b2612b7f56fe1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c230644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9da264697066735822122026307d7712f2d905c1e8d78be9a5b3a609a6d61f5bdebb114a32bfdb7fdfb8ce64736f6c63430008110033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b506004361061009e5760003560e01c806391ec2d2b1161006657806391ec2d2b1461013b578063a850a9091461015b578063d58e77331461016e578063e242cce914610181578063ebbdac911461019457600080fd5b8063115000fe146100a3578063247dd9fb146100cb5780633e5476ce146100de5780638669026f146101085780639141376314610128575b600080fd5b6100b66100b1366004612708565b6101a7565b60405190151581526020015b60405180910390f35b6100b66100d9366004612785565b61030e565b6100f16100ec366004612841565b6103b8565b6040805192151583529015156020830152016100c2565b61011b6101163660046128ce565b61079f565b6040516100c29190612957565b6100f1610136366004612988565b6108bb565b61014e6101493660046128ce565b610d5c565b6040516100c29190612a86565b61011b6101693660046128ce565b610ff8565b61011b61017c366004612aa0565b6111d4565b6100b661018f366004612785565b6115aa565b6100f16101a2366004612ab9565b611609565b600081516020830151600080516020612d63833981519152828309600080516020612d638339815191528283098182830101600080516020612d638339815191528283840108600080516020612d638339815191528682600080516020612d6383398151915203860109935050600080516020612d638339815191528483600080516020612d63833981519152038301099150600080516020612d638339815191527f2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e584089450600080516020612d638339815191527e9713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d2830893506040870151925060608701519150600080516020612d638339815191528083600080516020612d63833981519152038508600080516020612d63833981519152848608099050600080516020612d63833981519152828460011b0994149290931491909116949350505050565b8051600090600080516020612d6383398151915211158061034157506020820151600080516020612d6383398151915211155b1561034e57506000919050565b60405163e242cce960e01b8152309063e242cce990610371908590600401612957565b602060405180830381865afa15801561038e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103b29190612b1c565b92915050565b60008083806103e25760405162461bcd60e51b81526004016103d990612b3e565b60405180910390fd5b60006103ef826001612b95565b6103fa906006612ba8565b90506000816001600160401b038111156104165761041661269a565b60405190808252806020026020018201604052801561043f578160200160208202803683370190505b50905088600060200201358160008151811061045d5761045d612b06565b602090810291909101015288600160200201358160018151811061048357610483612b06565b602002602001018181525050600080516020612d43833981519152816002815181106104b1576104b1612b06565b602002602001018181525050600080516020612d23833981519152816003815181106104df576104df612b06565b602002602001018181525050600080516020612d838339815191528160048151811061050d5761050d612b06565b602002602001018181525050600080516020612da38339815191528160058151811061053b5761053b612b06565b60200260200101818152505060005b8381101561075a57863582610560836006612ba8565b61056b906006612b95565b8151811061057b5761057b612b06565b602090810291909101015286600160200201358261059a836006612ba8565b6105a5906007612b95565b815181106105b5576105b5612b06565b6020026020010181815250508888828181106105d3576105d3612b06565b9050608002016001600481106105eb576105eb612b06565b6020020135826105fc836006612ba8565b610607906008612b95565b8151811061061757610617612b06565b60200260200101818152505088888281811061063557610635612b06565b90506080020160006004811061064d5761064d612b06565b60200201358261065e836006612ba8565b610669906009612b95565b8151811061067957610679612b06565b60200260200101818152505088888281811061069757610697612b06565b9050608002016003600481106106af576106af612b06565b6020020135826106c0836006612ba8565b6106cb90600a612b95565b815181106106db576106db612b06565b6020026020010181815250508888828181106106f9576106f9612b06565b90506080020160026004811061071157610711612b06565b602002013582610722836006612ba8565b61072d90600b612b95565b8151811061073d5761073d612b06565b60209081029190910101528061075281612bbf565b91505061054a565b50610763612640565b602081602085026020850160085afa945084610789576000809550955050505050610796565b5115159450600193505050505b94509492505050565b6107a761265e565b6040516391ec2d2b60e01b815260009030906391ec2d2b906107cf9087908790600401612bd8565b600060405180830381865afa1580156107ec573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108149190810190612bf9565b9050600080600080601885016001600160c01b0381511693506030860190506001600160c01b038151169450600080516020612d6383398151915285600080516020612d63833981519152600160c01b870908604887015160608801516001600160c01b0390811697501694509250600080516020612d6383398151915290508481600160c01b860908604080518082019091529283526020830152509695505050505050565b60008084806108dc5760405162461bcd60e51b81526004016103d990612b3e565b8084146109495760405162461bcd60e51b815260206004820152603560248201527f424c533a206e756d626572206f66207075626c6963206b65797320616e64206d604482015274195cdcd859d95cc81b5d5cdd08189948195c5d585b605a1b60648201526084016103d9565b6000610956826001612b95565b610961906006612ba8565b90506000816001600160401b0381111561097d5761097d61269a565b6040519080825280602002602001820160405280156109a6578160200160208202803683370190505b5090508960006020020135816000815181106109c4576109c4612b06565b60209081029190910101528960016020020135816001815181106109ea576109ea612b06565b602002602001018181525050600080516020612d4383398151915281600281518110610a1857610a18612b06565b602002602001018181525050600080516020612d2383398151915281600381518110610a4657610a46612b06565b602002602001018181525050600080516020612d8383398151915281600481518110610a7457610a74612b06565b602002602001018181525050600080516020612da383398151915281600581518110610aa257610aa2612b06565b60200260200101818152505060005b83811015610d1657878782818110610acb57610acb612b06565b905060400201600060028110610ae357610ae3612b06565b602002013582610af4836006612ba8565b610aff906006612b95565b81518110610b0f57610b0f612b06565b602002602001018181525050878782818110610b2d57610b2d612b06565b905060400201600160028110610b4557610b45612b06565b602002013582610b56836006612ba8565b610b61906007612b95565b81518110610b7157610b71612b06565b602002602001018181525050898982818110610b8f57610b8f612b06565b905060800201600160048110610ba757610ba7612b06565b602002013582610bb8836006612ba8565b610bc3906008612b95565b81518110610bd357610bd3612b06565b602002602001018181525050898982818110610bf157610bf1612b06565b905060800201600060048110610c0957610c09612b06565b602002013582610c1a836006612ba8565b610c25906009612b95565b81518110610c3557610c35612b06565b602002602001018181525050898982818110610c5357610c53612b06565b905060800201600360048110610c6b57610c6b612b06565b602002013582610c7c836006612ba8565b610c8790600a612b95565b81518110610c9757610c97612b06565b602002602001018181525050898982818110610cb557610cb5612b06565b905060800201600260048110610ccd57610ccd612b06565b602002013582610cde836006612ba8565b610ce990600b612b95565b81518110610cf957610cf9612b06565b602090810291909101015280610d0e81612bbf565b915050610ab1565b50610d1f612640565b602081602085026020850160085afa945084610d45576000809550955050505050610d52565b5115159450600193505050505b9550959350505050565b80516060906000610d6e826020612b95565b610d79906040612b95565b610d84906004612b95565b6001600160401b03811115610d9b57610d9b61269a565b6040519080825280601f01601f191660200182016040528015610dc5576020820181803683370190505b5060408051606080825260808201909252919250600091906020820181803683370190505090506060820160005b84811015610e0d5760208188018101518383015201610df3565b5083016000815360010160608153600101600081536001810187905260210160208153506000600283604051610e439190612c6f565b602060405180830381855afa158015610e60573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610e839190612c8b565b9050600060429450848452816020850152600160408501536041840188905260206061850153600284604051610eb99190612c6f565b602060405180830381855afa158015610ed6573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610ef99190612c8b565b905080602084015280821880602086015250600260408501536041840188905260206061850153600284604051610f309190612c6f565b602060405180830381855afa158015610f4d573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610f709190612c8b565b905080604084015280821880602086015250600360408501536041840188905260206061850153600284604051610fa79190612c6f565b602060405180830381855afa158015610fc4573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610fe79190612c8b565b606084015250909695505050505050565b61100061265e565b604051638669026f60e01b81526000903090638669026f906110289087908790600401612bd8565b6040805180830381865afa158015611044573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110689190612ca4565b805160405163d58e773360e01b81526004810191909152909150600090309063d58e7733906024016040805180830381865afa1580156110ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110d09190612ca4565b602083015160405163d58e773360e01b81526004810191909152909150600090309063d58e7733906024016040805180830381865afa158015611117573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113b9190612ca4565b905061114561267c565b825181526020808401518282015282516040808401919091529083015160608301526000908460808460066107d05a03fa9050808061118057fe5b50806111c85760405162461bcd60e51b8152602060048201526017602482015276109314ce88189b881859190818d85b1b0819985a5b1959604a1b60448201526064016103d9565b50919695505050505050565b6111dc61265e565b600080516020612d6383398151915282106112455760405162461bcd60e51b815260206004820152602360248201527f6d6170546f506f696e7446543a20696e76616c6964206669656c6420656c656d604482015262195b9d60ea1b60648201526084016103d9565b81600061125182611790565b9150506000600080516020612d638339815191528061127257611272612cf9565b8384099050600080516020612d638339815191526004820890506000600080516020612d6383398151915277b3c4d79d41a91759a9e4c7e359b6b89eaec68e62effffffd850990506000600080516020612d6383398151915283830990506112d9816117b9565b9050600080516020612d638339815191528283099150600080516020612d638339815191528183099150600080516020612d638339815191528286099150600080516020612d6383398151915261133e83600080516020612d63833981519152612d0f565b7759e26bcea0d48bacd4f263f1acdb5c4f5763473177fffffe089450600080516020612d638339815191528586099150600080516020612d638339815191528583099150600080516020612d6383398151915260038308915060006113a283611790565b909350905080156113ea57846113cd576113ca83600080516020612d63833981519152612d0f565b92505b505060408051808201909152938452602084015250909392505050565b600080516020612d638339815191526001870861141590600080516020612d63833981519152612d0f565b9550600080516020612d638339815191528687099250600080516020612d638339815191528684099250600080516020612d6383398151915260038408925061145d83611790565b9093509050801561148557846113cd576113ca83600080516020612d63833981519152612d0f565b600080516020612d638339815191528485099550600080516020612d638339815191528687099550600080516020612d638339815191528287099550600080516020612d638339815191528287099550600080516020612d63833981519152600187089550600080516020612d638339815191528687099250600080516020612d638339815191528684099250600080516020612d6383398151915260038408925061153083611790565b90935090508061158d5760405162461bcd60e51b815260206004820152602260248201527f424c533a20626164206674206d617070696e6720696d706c656d656e7461746960448201526137b760f11b60648201526084016103d9565b846113cd576113ca83600080516020612d63833981519152612d0f565b600081516020830151600080516020612d63833981519152828309600080516020612d638339815191528382099050600080516020612d63833981519152600382089050600080516020612d6383398151915282830914949350505050565b60008060006040518061018001604052808760006002811061162d5761162d612b06565b602002013581526020018760016002811061164a5761164a612b06565b60200201358152602001600080516020612d438339815191528152602001600080516020612d238339815191528152602001600080516020612d838339815191528152602001600080516020612da38339815191528152602001856000600281106116b7576116b7612b06565b60200201358152602001856001600281106116d4576116d4612b06565b60200201358152602001866001600481106116f1576116f1612b06565b602002013581526020018660006004811061170e5761170e612b06565b602002013581526020018660036004811061172b5761172b612b06565b602002013581526020018660026004811061174857611748612b06565b602002013590529050611759612640565b60006020826101808560085afa90508061177c5760008094509450505050611788565b50511515925060019150505b935093915050565b60008061179c836117c4565b915082600080516020612d63833981519152838409149050915091565b60006103b282611ef9565b6000600080516020612d638339815191528083840991508083830981838209828283098385830984848309858484098684850997508684840987858409945087898a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087838a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985050868889099750868889099750868889099750868889099750868889099750868889099750868489099750868889099750868889099750868889099750868889099750868889099750868989099750868889099750868889099750868889099750868889099750868889099750868889099750868989099750868889099750868889099750868889099750868889099750868889099750868689099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868189099750508587880996508587880996508587880996508585880996508587880996508587880996508587880996508585880996508587880996508587880996508587880996508587880996508587880996508587880996508587880996508587880996508583880996508587880996508587880996508587880996508587880996508581880996508587880996508587880996508587880996508587880996508583880996508587880996508587880996508587880996508584880996508587880996508587880996508587880996508587880996508587880996508581880996505050505050808283099392505050565b6000600080516020612d638339815191528083840991508083830981838209828283098385830984848309858484098684850997508684840987858409945087898a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087838a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985050868889099750868889099750868889099750868889099750868889099750868889099750868489099750868889099750868889099750868889099750868889099750868889099750868989099750868889099750868889099750868889099750868889099750868889099750868889099750868989099750868889099750868889099750868889099750868889099750868889099750868689099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868189099750508587880996508587880996508587880996508585880996508587880996508587880996508587880996508585880996508587880996508587880996508587880996508587880996508587880996508587880996508587880996508587880996508583880996508587880996508587880996508587880996508587880996508581880996505050838586099450838586099450838586099450838586099450838186099450508284850993508284850993508284850993508281850993508284850993508284850993508285850993508284850993508284850993508284850993508284850993508284850993508284850993508281850995945050505050565b60405180602001604052806001906020820280368337509192915050565b60405180604001604052806002906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b03811182821017156126d2576126d261269a565b60405290565b604051601f8201601f191681016001600160401b03811182821017156127005761270061269a565b604052919050565b60006080828403121561271a57600080fd5b82601f83011261272957600080fd5b604051608081018181106001600160401b038211171561274b5761274b61269a565b60405280608084018581111561276057600080fd5b845b8181101561277a578035835260209283019201612762565b509195945050505050565b60006040828403121561279757600080fd5b82601f8301126127a657600080fd5b6127ae6126b0565b8060408401858111156127c057600080fd5b845b818110156127da5780358452602093840193016127c2565b509095945050505050565b80604081018310156103b257600080fd5b60008083601f84011261280857600080fd5b5081356001600160401b0381111561281f57600080fd5b6020830191508360208260071b850101111561283a57600080fd5b9250929050565b60008060008060a0858703121561285757600080fd5b61286186866127e5565b935060408501356001600160401b0381111561287c57600080fd5b612888878288016127f6565b909450925061289c905086606087016127e5565b905092959194509250565b60006001600160401b038211156128c0576128c061269a565b50601f01601f191660200190565b600080604083850312156128e157600080fd5b8235915060208301356001600160401b038111156128fe57600080fd5b8301601f8101851361290f57600080fd5b803561292261291d826128a7565b6126d8565b81815286602083850101111561293757600080fd5b816020840160208301376000602083830101528093505050509250929050565b60408101818360005b600281101561297f578151835260209283019290910190600101612960565b50505092915050565b6000806000806000608086880312156129a057600080fd5b6129aa87876127e5565b945060408601356001600160401b03808211156129c657600080fd5b6129d289838a016127f6565b909650945060608801359150808211156129eb57600080fd5b818801915088601f8301126129ff57600080fd5b813581811115612a0e57600080fd5b8960208260061b8501011115612a2357600080fd5b9699959850939650602001949392505050565b60005b83811015612a51578181015183820152602001612a39565b50506000910152565b60008151808452612a72816020860160208601612a36565b601f01601f19169290920160200192915050565b602081526000612a996020830184612a5a565b9392505050565b600060208284031215612ab257600080fd5b5035919050565b60008060006101008486031215612acf57600080fd5b612ad985856127e5565b925060c0840185811115612aec57600080fd5b604085019250612afc86826127e5565b9150509250925092565b634e487b7160e01b600052603260045260246000fd5b600060208284031215612b2e57600080fd5b81518015158114612a9957600080fd5b60208082526021908201527f424c533a206e756d626572206f66207075626c6963206b6579206973207a65726040820152606f60f81b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b808201808211156103b2576103b2612b7f565b80820281158282048414176103b2576103b2612b7f565b600060018201612bd157612bd1612b7f565b5060010190565b828152604060208201526000612bf16040830184612a5a565b949350505050565b600060208284031215612c0b57600080fd5b81516001600160401b03811115612c2157600080fd5b8201601f81018413612c3257600080fd5b8051612c4061291d826128a7565b818152856020838501011115612c5557600080fd5b612c66826020830160208601612a36565b95945050505050565b60008251612c81818460208701612a36565b9190910192915050565b600060208284031215612c9d57600080fd5b5051919050565b600060408284031215612cb657600080fd5b82601f830112612cc557600080fd5b612ccd6126b0565b806040840185811115612cdf57600080fd5b845b818110156127da578051845260209384019301612ce1565b634e487b7160e01b600052601260045260246000fd5b818103818111156103b2576103b2612b7f56fe1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c230644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9da264697066735822122026307d7712f2d905c1e8d78be9a5b3a609a6d61f5bdebb114a32bfdb7fdfb8ce64736f6c63430008110033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" -var BN256G2Artifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"BN256G2\",\n \"sourceName\": \"contracts/common/BN256G2.sol\",\n \"abi\": [\n {\n \"inputs\": [],\n \"name\": \"G2_NEG_X_IM\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"G2_NEG_X_RE\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"G2_NEG_Y_IM\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"G2_NEG_Y_RE\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt1xx\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt1xy\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt1yx\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt1yy\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt2xx\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt2xy\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt2yx\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt2yy\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"ecTwistAdd\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"s\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt1xx\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt1xy\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt1yx\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt1yy\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"ecTwistMul\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"getFieldModulus\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"pure\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50610dfd806100206000396000f3fe608060405234801561001057600080fd5b506004361061006d5760003560e01c80635120675214610072578063779d890d146100ac578063783bde80146100c05780639b0c399a146100e7578063ad50f9c11461010e578063cbe96a5014610135578063defbcdee14610168575b600080fd5b6100997f1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d81565b6040519081526020015b60405180910390f35b600080516020610da8833981519152610099565b6100997f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c281565b6100997f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed81565b6100997f275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec81565b610148610143366004610c8c565b61017b565b6040805194855260208501939093529183015260608201526080016100a3565b610148610176366004610ce1565b61031a565b60008080808b15801561018c57508a155b8015610196575089155b80156101a0575088155b1561020a57871580156101b1575086155b80156101bb575085155b80156101c5575084155b6101fa576101d5888888886103b1565b6101fa5760405162461bcd60e51b81526004016101f190610d1c565b60405180910390fd5b508692508591508490508361030b565b87158015610216575086155b8015610220575085155b801561022a575084155b156102675761023b8c8c8c8c6103b1565b6102575760405162461bcd60e51b81526004016101f190610d1c565b508a92508991508890508761030b565b6102738c8c8c8c6103b1565b61028f5760405162461bcd60e51b81526004016101f190610d1c565b61029b888888886103b1565b6102b75760405162461bcd60e51b81526004016101f190610d1c565b60006102d18d8d8d8d600160008f8f8f8f60016000610466565b90506103018160005b602090810291909101519083015160408401516060850151608086015160a08701516106f1565b9450945094509450505b98509850985098945050505050565b600080808060018815801561032d575087155b8015610337575086155b8015610341575085155b15610355575060019750879550600061037d565b610361898989896103b1565b61037d5760405162461bcd60e51b81526004016101f190610d1c565b600061038f8b8b8b8b8b87600061075c565b905061039c8160006102da565b929e919d509b50909950975050505050505050565b60008060008060006103c5878789896107df565b90945092506103d6898981816107df565b90925090506103e782828b8b6107df565b90925090506103f884848484610850565b909450925061044884847f2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e57e9713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d2610850565b909450925083158015610459575082155b9998505050505050505050565b61046e610c50565b8815801561047a575087155b156104bc578686868686868660005b60a089019290925260808801929092526060870192909252604086019290925260208581019390935290910201526106e1565b821580156104c8575081155b156104db578c8c8c8c8c8c866000610489565b6104e785858b8b6107df565b90955093506104f88b8b85856107df565b6060830152604082015261050e87878b8b6107df565b909750955061051f8d8d85856107df565b60a0830152608082018190528714801561053c575060a081015186145b15610581576040810151851480156105575750606081015184145b156105725761056a8d8d8d8d8d8d610892565b866000610489565b60016000818180808681610489565b61058d898985856107df565b90935091506105ad858583600260200201518460035b6020020151610850565b909d509b506105c887878360045b60200201518460056105a3565b909b5099506105d98b8b81816107df565b90995097506105fa89898360045b60200201518460055b60200201516107df565b909550935061060b89898d8d6107df565b909950975061061c898985856107df565b60a083015260808201526106328d8d81816107df565b9097509550610643878785856107df565b909750955061065487878b8b610850565b909750955061066585856002610ada565b909350915061067687878585610850565b90975095506106878b8b89896107df565b6020830152815261069a85858989610850565b909b5099506106ab8d8d8d8d6107df565b909b5099506106c5898983600260200201518460036105f0565b909d509b506106d68b8b8f8f610850565b606083015260408201525b9c9b505050505050505050505050565b600080600080600080610702610c6e565b61070c8989610b0d565b909350915061071d8d8d85856107df565b602083015281526107308b8b85856107df565b60608301819052604083018290528251602090930151929f929e50909c509a5098505050505050505050565b610764610c50565b87156107d45760018816156107a5578051602082015160408301516060840151608085015160a08601516107a29594939291908d8d8d8d8d8d610466565b90505b6107b3878787878787610892565b949b509299509097509550935091506107cd600289610d5e565b9750610764565b979650505050505050565b60008061081d600080516020610da8833981519152858809600080516020610da8833981519152858809600080516020610da8833981519152610b98565b600080516020610da883398151915280868809600080516020610da8833981519152868a09089150915094509492505050565b60008061086c8685600080516020610da8833981519152610b98565b6108858685600080516020610da8833981519152610b98565b9150915094509492505050565b6000806000806000806108a3610c50565b6108af8d8d6003610ada565b602083018190528183526108c591908f8f6107df565b602083015281526108d88b8b8b8b6107df565b90995097506108e98d8d8d8d6107df565b606083015260408201819052610909908260035b60200201518b8b6107df565b60608301526040820152805161092c908260015b602002015183518460016105f0565b6040830151919e509c5061094a908260035b60200201516008610ada565b60a083015260808201526109618d8d8360046105bb565b909d509b50610972898981816107df565b60a083015260808201526040810151606082015161099291906004610ada565b60608301819052604083018290526109ac91908f8f610850565b6060830152604082018190526109c49082600361091d565b606083015260408201526109da8b8b6008610ada565b602083018190528183526109f091908d8d6107df565b60208301819052818352610a0791908360046105e7565b602083015280825260408201516060830151610a25928460016105a3565b60608301526040820152610a3b8d8d6002610ada565b6020830152808252610a4f908260016108fd565b60208301528152610a6389898360046105e7565b60a083015260808201819052610a7b9082600561093e565b826004602002018360056020020191909152528060006020020151816001602002015182600260200201518360036020020151846004602002015185600560200201519650965096509650965096505096509650965096509650969050565b600080600080516020610da8833981519152838609600080516020610da883398151915284860991509150935093915050565b60008080610b4e600080516020610da883398151915280878809600080516020610da883398151915287880908600080516020610da8833981519152610bbc565b9050600080516020610da8833981519152818609600080516020610da8833981519152828609610b8c90600080516020610da8833981519152610d80565b92509250509250929050565b60008180610ba857610ba8610d48565b610bb28484610d80565b8508949350505050565b60008060405160208152602080820152602060408201528460608201526002840360808201528360a082015260208160c08360056107d05a03fa90519250905080610c495760405162461bcd60e51b815260206004820152601a60248201527f6572726f722077697468206d6f64756c617220696e766572736500000000000060448201526064016101f1565b5092915050565b6040518060c001604052806006906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b600080600080600080600080610100898b031215610ca957600080fd5b505086359860208801359850604088013597606081013597506080810135965060a0810135955060c0810135945060e0013592509050565b600080600080600060a08688031215610cf957600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b602080825260129082015271706f696e74206e6f7420696e20637572766560701b604082015260600190565b634e487b7160e01b600052601260045260246000fd5b600082610d7b57634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115610da157634e487b7160e01b600052601160045260246000fd5b9291505056fe30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47a2646970667358221220bef62bc28068690954bff720632bf34d282621c8a9da6cc064b8d7b5b6d91bb564736f6c63430008110033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b506004361061006d5760003560e01c80635120675214610072578063779d890d146100ac578063783bde80146100c05780639b0c399a146100e7578063ad50f9c11461010e578063cbe96a5014610135578063defbcdee14610168575b600080fd5b6100997f1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d81565b6040519081526020015b60405180910390f35b600080516020610da8833981519152610099565b6100997f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c281565b6100997f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed81565b6100997f275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec81565b610148610143366004610c8c565b61017b565b6040805194855260208501939093529183015260608201526080016100a3565b610148610176366004610ce1565b61031a565b60008080808b15801561018c57508a155b8015610196575089155b80156101a0575088155b1561020a57871580156101b1575086155b80156101bb575085155b80156101c5575084155b6101fa576101d5888888886103b1565b6101fa5760405162461bcd60e51b81526004016101f190610d1c565b60405180910390fd5b508692508591508490508361030b565b87158015610216575086155b8015610220575085155b801561022a575084155b156102675761023b8c8c8c8c6103b1565b6102575760405162461bcd60e51b81526004016101f190610d1c565b508a92508991508890508761030b565b6102738c8c8c8c6103b1565b61028f5760405162461bcd60e51b81526004016101f190610d1c565b61029b888888886103b1565b6102b75760405162461bcd60e51b81526004016101f190610d1c565b60006102d18d8d8d8d600160008f8f8f8f60016000610466565b90506103018160005b602090810291909101519083015160408401516060850151608086015160a08701516106f1565b9450945094509450505b98509850985098945050505050565b600080808060018815801561032d575087155b8015610337575086155b8015610341575085155b15610355575060019750879550600061037d565b610361898989896103b1565b61037d5760405162461bcd60e51b81526004016101f190610d1c565b600061038f8b8b8b8b8b87600061075c565b905061039c8160006102da565b929e919d509b50909950975050505050505050565b60008060008060006103c5878789896107df565b90945092506103d6898981816107df565b90925090506103e782828b8b6107df565b90925090506103f884848484610850565b909450925061044884847f2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e57e9713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d2610850565b909450925083158015610459575082155b9998505050505050505050565b61046e610c50565b8815801561047a575087155b156104bc578686868686868660005b60a089019290925260808801929092526060870192909252604086019290925260208581019390935290910201526106e1565b821580156104c8575081155b156104db578c8c8c8c8c8c866000610489565b6104e785858b8b6107df565b90955093506104f88b8b85856107df565b6060830152604082015261050e87878b8b6107df565b909750955061051f8d8d85856107df565b60a0830152608082018190528714801561053c575060a081015186145b15610581576040810151851480156105575750606081015184145b156105725761056a8d8d8d8d8d8d610892565b866000610489565b60016000818180808681610489565b61058d898985856107df565b90935091506105ad858583600260200201518460035b6020020151610850565b909d509b506105c887878360045b60200201518460056105a3565b909b5099506105d98b8b81816107df565b90995097506105fa89898360045b60200201518460055b60200201516107df565b909550935061060b89898d8d6107df565b909950975061061c898985856107df565b60a083015260808201526106328d8d81816107df565b9097509550610643878785856107df565b909750955061065487878b8b610850565b909750955061066585856002610ada565b909350915061067687878585610850565b90975095506106878b8b89896107df565b6020830152815261069a85858989610850565b909b5099506106ab8d8d8d8d6107df565b909b5099506106c5898983600260200201518460036105f0565b909d509b506106d68b8b8f8f610850565b606083015260408201525b9c9b505050505050505050505050565b600080600080600080610702610c6e565b61070c8989610b0d565b909350915061071d8d8d85856107df565b602083015281526107308b8b85856107df565b60608301819052604083018290528251602090930151929f929e50909c509a5098505050505050505050565b610764610c50565b87156107d45760018816156107a5578051602082015160408301516060840151608085015160a08601516107a29594939291908d8d8d8d8d8d610466565b90505b6107b3878787878787610892565b949b509299509097509550935091506107cd600289610d5e565b9750610764565b979650505050505050565b60008061081d600080516020610da8833981519152858809600080516020610da8833981519152858809600080516020610da8833981519152610b98565b600080516020610da883398151915280868809600080516020610da8833981519152868a09089150915094509492505050565b60008061086c8685600080516020610da8833981519152610b98565b6108858685600080516020610da8833981519152610b98565b9150915094509492505050565b6000806000806000806108a3610c50565b6108af8d8d6003610ada565b602083018190528183526108c591908f8f6107df565b602083015281526108d88b8b8b8b6107df565b90995097506108e98d8d8d8d6107df565b606083015260408201819052610909908260035b60200201518b8b6107df565b60608301526040820152805161092c908260015b602002015183518460016105f0565b6040830151919e509c5061094a908260035b60200201516008610ada565b60a083015260808201526109618d8d8360046105bb565b909d509b50610972898981816107df565b60a083015260808201526040810151606082015161099291906004610ada565b60608301819052604083018290526109ac91908f8f610850565b6060830152604082018190526109c49082600361091d565b606083015260408201526109da8b8b6008610ada565b602083018190528183526109f091908d8d6107df565b60208301819052818352610a0791908360046105e7565b602083015280825260408201516060830151610a25928460016105a3565b60608301526040820152610a3b8d8d6002610ada565b6020830152808252610a4f908260016108fd565b60208301528152610a6389898360046105e7565b60a083015260808201819052610a7b9082600561093e565b826004602002018360056020020191909152528060006020020151816001602002015182600260200201518360036020020151846004602002015185600560200201519650965096509650965096505096509650965096509650969050565b600080600080516020610da8833981519152838609600080516020610da883398151915284860991509150935093915050565b60008080610b4e600080516020610da883398151915280878809600080516020610da883398151915287880908600080516020610da8833981519152610bbc565b9050600080516020610da8833981519152818609600080516020610da8833981519152828609610b8c90600080516020610da8833981519152610d80565b92509250509250929050565b60008180610ba857610ba8610d48565b610bb28484610d80565b8508949350505050565b60008060405160208152602080820152602060408201528460608201526002840360808201528360a082015260208160c08360056107d05a03fa90519250905080610c495760405162461bcd60e51b815260206004820152601a60248201527f6572726f722077697468206d6f64756c617220696e766572736500000000000060448201526064016101f1565b5092915050565b6040518060c001604052806006906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b600080600080600080600080610100898b031215610ca957600080fd5b505086359860208801359850604088013597606081013597506080810135965060a0810135955060c0810135945060e0013592509050565b600080600080600060a08688031215610cf957600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b602080825260129082015271706f696e74206e6f7420696e20637572766560701b604082015260600190565b634e487b7160e01b600052601260045260246000fd5b600082610d7b57634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115610da157634e487b7160e01b600052601160045260246000fd5b9291505056fe30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47a2646970667358221220bef62bc28068690954bff720632bf34d282621c8a9da6cc064b8d7b5b6d91bb564736f6c63430008110033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" -var MerkleArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"Merkle\",\n \"sourceName\": \"contracts/common/Merkle.sol\",\n \"abi\": [],\n \"bytecode\": \"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220fb95e4956e03415a17fac86b59ad7d42d699865638cab948804a84759122547a64736f6c63430008110033\",\n \"deployedBytecode\": \"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220fb95e4956e03415a17fac86b59ad7d42d699865638cab948804a84759122547a64736f6c63430008110033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" -var CheckpointManagerArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"CheckpointManager\",\n \"sourceName\": \"contracts/root/CheckpointManager.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"DOMAIN\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"bls\",\n \"outputs\": [\n {\n \"internalType\": \"contract IBLS\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"bn256G2\",\n \"outputs\": [\n {\n \"internalType\": \"contract IBN256G2\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"chainId\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"checkpointBlockNumbers\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"checkpoints\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"epoch\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockNumber\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"eventRoot\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"currentCheckpointBlockNumber\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"currentEpoch\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"currentValidatorSet\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"_address\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"votingPower\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"currentValidatorSetHash\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"currentValidatorSetLength\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockNumber\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"getCheckpointBlock\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockNumber\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"leaf\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"leafIndex\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32[]\",\n \"name\": \"proof\",\n \"type\": \"bytes32[]\"\n }\n ],\n \"name\": \"getEventMembershipByBlockNumber\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"epoch\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"leaf\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"leafIndex\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32[]\",\n \"name\": \"proof\",\n \"type\": \"bytes32[]\"\n }\n ],\n \"name\": \"getEventMembershipByEpoch\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockNumber\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"getEventRootByBlock\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IBLS\",\n \"name\": \"newBls\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"contract IBN256G2\",\n \"name\": \"newBn256G2\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"chainId_\",\n \"type\": \"uint256\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"address\",\n \"name\": \"_address\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256[4]\",\n \"name\": \"blsKey\",\n \"type\": \"uint256[4]\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"votingPower\",\n \"type\": \"uint256\"\n }\n ],\n \"internalType\": \"struct ICheckpointManager.Validator[]\",\n \"name\": \"newValidatorSet\",\n \"type\": \"tuple[]\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"components\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"blockHash\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockRound\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"currentValidatorSetHash\",\n \"type\": \"bytes32\"\n }\n ],\n \"internalType\": \"struct ICheckpointManager.CheckpointMetadata\",\n \"name\": \"checkpointMetadata\",\n \"type\": \"tuple\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"epoch\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockNumber\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"eventRoot\",\n \"type\": \"bytes32\"\n }\n ],\n \"internalType\": \"struct ICheckpointManager.Checkpoint\",\n \"name\": \"checkpoint\",\n \"type\": \"tuple\"\n },\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"signature\",\n \"type\": \"uint256[2]\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"address\",\n \"name\": \"_address\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256[4]\",\n \"name\": \"blsKey\",\n \"type\": \"uint256[4]\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"votingPower\",\n \"type\": \"uint256\"\n }\n ],\n \"internalType\": \"struct ICheckpointManager.Validator[]\",\n \"name\": \"newValidatorSet\",\n \"type\": \"tuple[]\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"bitmap\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"submit\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"totalVotingPower\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b506116f2806100206000396000f3fe608060405234801561001057600080fd5b50600436106101165760003560e01c806376671808116100a2578063babd4ee411610071578063babd4ee4146102c8578063d4c8e3e8146102db578063e416d677146102ee578063e9193d2b146102f7578063f896f1a51461030a57600080fd5b8063766718081461024157806395b0b0271461024a5780639a8a059214610275578063b8a242521461027e57600080fd5b806361a02208116100e957806361a022081461019b578063671b3793146101be5780636969a25c146101c7578063729e7c6e1461021957806373cb1a111461022c57600080fd5b80631d1d4f261461011b57806322fd1818146101375780633569ed931461016157806352a9674b14610174575b600080fd5b61012460035481565b6040519081526020015b60405180910390f35b61014a610145366004610fdb565b610313565b60408051921515835260208301919091520161012e565b61012461016f366004610fdb565b610364565b6101247fbee7fa562a38908559e4a988e62d6c08b84ef05f2ebd5d2bb2b855dc19d19fe281565b6101ae6101a9366004610ff4565b610398565b604051901515815260200161012e565b61012460055481565b6101fa6101d5366004610fdb565b600960205260009081526040902080546005909101546001600160a01b039091169082565b604080516001600160a01b03909316835260208301919091520161012e565b6101ae610227366004610ff4565b610410565b61023f61023a3660046110e8565b610469565b005b61012460025481565b60065461025d906001600160a01b031681565b6040516001600160a01b03909116815260200161012e565b61012460015481565b6102ad61028c366004610fdb565b60086020526000908152604090208054600182015460029092015490919083565b6040805193845260208401929092529082015260600161012e565b61023f6102d6366004611173565b6105bb565b60075461025d906001600160a01b031681565b61012460045481565b610124610305366004610fdb565b610820565b610124600b5481565b60008080610322600a85610841565b600a54909150810361033a5750600093849350915050565b6001600a828154811061034f5761034f61124c565b90600052602060002001549250925050915091565b6000600881610374600a85610841565b61037f906001611278565b8152602001908152602001600020600201549050919050565b6000806103a487610364565b9050806103f85760405162461bcd60e51b815260206004820152601e60248201527f4e4f5f4556454e545f524f4f545f464f525f424c4f434b5f4e554d424552000060448201526064015b60405180910390fd5b61040586868387876108f0565b979650505050505050565b600085815260086020526040812060020154806103f85760405162461bcd60e51b815260206004820152601760248201527609c9ebe8aac8a9ca8bea49e9ea8be8c9ea4be8aa09e869604b1b60448201526064016103ef565b600054610100900460ff16158080156104895750600054600160ff909116105b806104a35750303b1580156104a3575060005460ff166001145b6105065760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016103ef565b6000805460ff191660011790558015610529576000805461ff0019166101001790555b6001849055600680546001600160a01b038089166001600160a01b0319928316179092556007805492881692909116919091179055600382905561056d8383610a45565b80156105b3576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b8660400135600b54146106105760405162461bcd60e51b815260206004820152601a60248201527f494e56414c49445f56414c494441544f525f5345545f4841534800000000000060448201526064016103ef565b6000600154876020013589600001358a602001358a600001358b604001358d604001358b8b60405160200161064692919061128b565b604051602081830303815290604052805190602001206040516020016106739897969594939291906112ee565b60408051601f198184030181528282528051602091820120908301520160408051601f198184030181529082905260065463a850a90960e01b835290925061073f916001600160a01b039091169063a850a909906106f7907fbee7fa562a38908559e4a988e62d6c08b84ef05f2ebd5d2bb2b855dc19d19fe2908690600401611324565b6040805180830381865afa158015610713573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610737919061137a565b878585610b4b565b60025461074c8189610e55565b8735600081815260086020908152604091829020838155908b01356001820155908a01356002909101558110156107cf57600a8054600181018255600091825260208a01357fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a890910155600280549091906107c690611408565b90915550610803565b600a805460208a013591906107e690600190611421565b815481106107f6576107f661124c565b6000918252602090912001555b60208801356004556108158686610a45565b505050505050505050565b600a818154811061083057600080fd5b600091825260209091200154905081565b81546000908103610854575060006108ea565b82546000905b808210156108a157600061086e8383610f32565b6000878152602090209091508590820154111561088d5780915061089b565b610898816001611278565b92505b5061085a565b6000821180156108cd5750836108ca866108bc600186611421565b600091825260209091200190565b54145b156108e6576108dd600183611421565b925050506108ea565b5090505b92915050565b6000816108fe816002611518565b86106109415760405162461bcd60e51b81526020600482015260126024820152710929cac82989288be988a828cbe929c888ab60731b60448201526064016103ef565b8661097d5760405162461bcd60e51b815260206004820152600c60248201526b24a72b20a624a22fa622a0a360a11b60448201526064016103ef565b8660005b82811015610a3757600086868381811061099d5761099d61124c565b9050602002013590506002896109b3919061153a565b6000036109eb576040805160208101859052908101829052606001604051602081830303815290604052805190602001209250610a18565b60408051602081018390529081018490526060016040516020818303038152906040528051906020012092505b610a2360028a61154e565b98505080610a3090611408565b9050610981565b509094149695505050505050565b60038190556040518190610a5f908490839060200161128b565b60408051601f198184030181529190528051602090910120600b556000805b82811015610b42576000858583818110610a9a57610a9a61124c565b905060c0020160a00135905060008111610aea5760405162461bcd60e51b8152602060048201526011602482015270564f54494e475f504f5745525f5a45524f60781b60448201526064016103ef565b610af48184611278565b9250858583818110610b0857610b0861124c565b905060c00201600960008481526020019081526020016000208181610b2d9190611579565b9050505080610b3b90611408565b9050610a7e565b50600555505050565b600354610b56610fbd565b6000805b83811015610cda57610b6d868683610f54565b15610cd25781600003610bc1576000818152600960205260409081902081516080810190925260010160048282826020028201915b815481526020019060010190808311610ba25750505050509250610cb3565b60008181526009602052604080822081516080810190925260010160048282826020028201915b815481526020019060010190808311610be857505060075488516020808b01516040808d01516060808f01518b51958c0151848d0151928d01519451630cbe96a560e41b81529c9d506001600160a01b039098169b63cbe96a509b50610c5f9a5096985093969195939493919290916004016112ee565b608060405180830381865afa158015610c7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca091906115d8565b6060880152604087015260208601528452505b600081815260096020526040902060050154610ccf9083611278565b91505b600101610b5a565b5080600003610d1d5760405162461bcd60e51b815260206004820152600f60248201526e4249544d41505f49535f454d50545960881b60448201526064016103ef565b60036005546002610d2e9190611562565b610d38919061154e565b8111610d825760405162461bcd60e51b815260206004820152601960248201527824a729aaa32324a1a4a2a72a2fab27aa24a723afa827aba2a960391b60448201526064016103ef565b60065460405163ebbdac9160e01b815260009182916001600160a01b039091169063ebbdac9190610dbb908b9088908e9060040161160e565b6040805180830381865afa158015610dd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dfb9190611689565b91509150818015610e095750805b6108155760405162461bcd60e51b815260206004820152601d60248201527f5349474e41545552455f564552494649434154494f4e5f4641494c454400000060448201526064016103ef565b600082815260086020908152604091829020825160608101845281548082526001830154938201939093526002909101549281019290925282351480610ea757508051610ea3906001611278565b8235145b610ee35760405162461bcd60e51b815260206004820152600d60248201526c0929cac82989288be8aa09e869609b1b60448201526064016103ef565b8060200151826020013511610f2d5760405162461bcd60e51b815260206004820152601060248201526f115354151657d0d21150d2d413d2539560821b60448201526064016103ef565b505050565b6000610f41600284841861154e565b610f4d90848416611278565b9392505050565b600080610f6260088461154e565b90506000610f7160088561153a565b9050848210610f8557600092505050610f4d565b6000600160ff83161b878785818110610fa057610fa061124c565b9050013560f81c60f81b60f81c60ff161611925050509392505050565b60405180608001604052806004906020820280368337509192915050565b600060208284031215610fed57600080fd5b5035919050565b60008060008060006080868803121561100c57600080fd5b853594506020860135935060408601359250606086013567ffffffffffffffff8082111561103957600080fd5b818801915088601f83011261104d57600080fd5b81358181111561105c57600080fd5b8960208260051b850101111561107157600080fd5b9699959850939650602001949392505050565b6001600160a01b038116811461109957600080fd5b50565b60008083601f8401126110ae57600080fd5b50813567ffffffffffffffff8111156110c657600080fd5b60208301915083602060c0830285010111156110e157600080fd5b9250929050565b60008060008060006080868803121561110057600080fd5b853561110b81611084565b9450602086013561111b81611084565b935060408601359250606086013567ffffffffffffffff81111561113e57600080fd5b61114a8882890161109c565b969995985093965092949392505050565b60006060828403121561116d57600080fd5b50919050565b6000806000806000806000610140888a03121561118f57600080fd5b611199898961115b565b96506111a88960608a0161115b565b95506101008801898111156111bc57600080fd5b60c0890195503567ffffffffffffffff808211156111d957600080fd5b6111e58b838c0161109c565b90965094506101208a01359150808211156111ff57600080fd5b818a0191508a601f83011261121357600080fd5b81358181111561122257600080fd5b8b602082850101111561123457600080fd5b60208301945080935050505092959891949750929550565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b808201808211156108ea576108ea611262565b60208082528181018390526000908460408401835b868110156112e35782356112b381611084565b6001600160a01b0316825260808385018584013760a0838101359083015260c092830192909101906001016112a0565b509695505050505050565b978852602088019690965260408701949094526060860192909252608085015260a084015260c083015260e08201526101000190565b82815260006020604081840152835180604085015260005b818110156113585785810183015185820160600152820161133c565b506000606082860101526060601f19601f830116850101925050509392505050565b60006040828403121561138c57600080fd5b82601f83011261139b57600080fd5b6040516040810181811067ffffffffffffffff821117156113cc57634e487b7160e01b600052604160045260246000fd5b80604052508060408401858111156113e357600080fd5b845b818110156113fd5780518352602092830192016113e5565b509195945050505050565b60006001820161141a5761141a611262565b5060010190565b818103818111156108ea576108ea611262565b600181815b8085111561146f57816000190482111561145557611455611262565b8085161561146257918102915b93841c9390800290611439565b509250929050565b600082611486575060016108ea565b81611493575060006108ea565b81600181146114a957600281146114b3576114cf565b60019150506108ea565b60ff8411156114c4576114c4611262565b50506001821b6108ea565b5060208310610133831016604e8410600b84101617156114f2575081810a6108ea565b6114fc8383611434565b806000190482111561151057611510611262565b029392505050565b6000610f4d8383611477565b634e487b7160e01b600052601260045260246000fd5b60008261154957611549611524565b500690565b60008261155d5761155d611524565b500490565b80820281158282048414176108ea576108ea611262565b813561158481611084565b81546001600160a01b0319166001600160a01b0391909116178155602082810160005b60048110156115c7578135600182860181019190915591830191016115a7565b50505060a082013560058201555050565b600080600080608085870312156115ee57600080fd5b505082516020840151604085015160609095015191969095509092509050565b61010081016040858337604082018460005b600481101561163f578151835260209283019290910190600101611620565b50505060c082018360005b600281101561166957815183526020928301929091019060010161164a565b505050949350505050565b8051801515811461168457600080fd5b919050565b6000806040838503121561169c57600080fd5b6116a583611674565b91506116b360208401611674565b9050925092905056fea2646970667358221220a7bbc925b936828d67df832f2932e0f475f5fa7058472853cfff77d2f8eded9464736f6c63430008110033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101165760003560e01c806376671808116100a2578063babd4ee411610071578063babd4ee4146102c8578063d4c8e3e8146102db578063e416d677146102ee578063e9193d2b146102f7578063f896f1a51461030a57600080fd5b8063766718081461024157806395b0b0271461024a5780639a8a059214610275578063b8a242521461027e57600080fd5b806361a02208116100e957806361a022081461019b578063671b3793146101be5780636969a25c146101c7578063729e7c6e1461021957806373cb1a111461022c57600080fd5b80631d1d4f261461011b57806322fd1818146101375780633569ed931461016157806352a9674b14610174575b600080fd5b61012460035481565b6040519081526020015b60405180910390f35b61014a610145366004610fdb565b610313565b60408051921515835260208301919091520161012e565b61012461016f366004610fdb565b610364565b6101247fbee7fa562a38908559e4a988e62d6c08b84ef05f2ebd5d2bb2b855dc19d19fe281565b6101ae6101a9366004610ff4565b610398565b604051901515815260200161012e565b61012460055481565b6101fa6101d5366004610fdb565b600960205260009081526040902080546005909101546001600160a01b039091169082565b604080516001600160a01b03909316835260208301919091520161012e565b6101ae610227366004610ff4565b610410565b61023f61023a3660046110e8565b610469565b005b61012460025481565b60065461025d906001600160a01b031681565b6040516001600160a01b03909116815260200161012e565b61012460015481565b6102ad61028c366004610fdb565b60086020526000908152604090208054600182015460029092015490919083565b6040805193845260208401929092529082015260600161012e565b61023f6102d6366004611173565b6105bb565b60075461025d906001600160a01b031681565b61012460045481565b610124610305366004610fdb565b610820565b610124600b5481565b60008080610322600a85610841565b600a54909150810361033a5750600093849350915050565b6001600a828154811061034f5761034f61124c565b90600052602060002001549250925050915091565b6000600881610374600a85610841565b61037f906001611278565b8152602001908152602001600020600201549050919050565b6000806103a487610364565b9050806103f85760405162461bcd60e51b815260206004820152601e60248201527f4e4f5f4556454e545f524f4f545f464f525f424c4f434b5f4e554d424552000060448201526064015b60405180910390fd5b61040586868387876108f0565b979650505050505050565b600085815260086020526040812060020154806103f85760405162461bcd60e51b815260206004820152601760248201527609c9ebe8aac8a9ca8bea49e9ea8be8c9ea4be8aa09e869604b1b60448201526064016103ef565b600054610100900460ff16158080156104895750600054600160ff909116105b806104a35750303b1580156104a3575060005460ff166001145b6105065760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016103ef565b6000805460ff191660011790558015610529576000805461ff0019166101001790555b6001849055600680546001600160a01b038089166001600160a01b0319928316179092556007805492881692909116919091179055600382905561056d8383610a45565b80156105b3576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b8660400135600b54146106105760405162461bcd60e51b815260206004820152601a60248201527f494e56414c49445f56414c494441544f525f5345545f4841534800000000000060448201526064016103ef565b6000600154876020013589600001358a602001358a600001358b604001358d604001358b8b60405160200161064692919061128b565b604051602081830303815290604052805190602001206040516020016106739897969594939291906112ee565b60408051601f198184030181528282528051602091820120908301520160408051601f198184030181529082905260065463a850a90960e01b835290925061073f916001600160a01b039091169063a850a909906106f7907fbee7fa562a38908559e4a988e62d6c08b84ef05f2ebd5d2bb2b855dc19d19fe2908690600401611324565b6040805180830381865afa158015610713573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610737919061137a565b878585610b4b565b60025461074c8189610e55565b8735600081815260086020908152604091829020838155908b01356001820155908a01356002909101558110156107cf57600a8054600181018255600091825260208a01357fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a890910155600280549091906107c690611408565b90915550610803565b600a805460208a013591906107e690600190611421565b815481106107f6576107f661124c565b6000918252602090912001555b60208801356004556108158686610a45565b505050505050505050565b600a818154811061083057600080fd5b600091825260209091200154905081565b81546000908103610854575060006108ea565b82546000905b808210156108a157600061086e8383610f32565b6000878152602090209091508590820154111561088d5780915061089b565b610898816001611278565b92505b5061085a565b6000821180156108cd5750836108ca866108bc600186611421565b600091825260209091200190565b54145b156108e6576108dd600183611421565b925050506108ea565b5090505b92915050565b6000816108fe816002611518565b86106109415760405162461bcd60e51b81526020600482015260126024820152710929cac82989288be988a828cbe929c888ab60731b60448201526064016103ef565b8661097d5760405162461bcd60e51b815260206004820152600c60248201526b24a72b20a624a22fa622a0a360a11b60448201526064016103ef565b8660005b82811015610a3757600086868381811061099d5761099d61124c565b9050602002013590506002896109b3919061153a565b6000036109eb576040805160208101859052908101829052606001604051602081830303815290604052805190602001209250610a18565b60408051602081018390529081018490526060016040516020818303038152906040528051906020012092505b610a2360028a61154e565b98505080610a3090611408565b9050610981565b509094149695505050505050565b60038190556040518190610a5f908490839060200161128b565b60408051601f198184030181529190528051602090910120600b556000805b82811015610b42576000858583818110610a9a57610a9a61124c565b905060c0020160a00135905060008111610aea5760405162461bcd60e51b8152602060048201526011602482015270564f54494e475f504f5745525f5a45524f60781b60448201526064016103ef565b610af48184611278565b9250858583818110610b0857610b0861124c565b905060c00201600960008481526020019081526020016000208181610b2d9190611579565b9050505080610b3b90611408565b9050610a7e565b50600555505050565b600354610b56610fbd565b6000805b83811015610cda57610b6d868683610f54565b15610cd25781600003610bc1576000818152600960205260409081902081516080810190925260010160048282826020028201915b815481526020019060010190808311610ba25750505050509250610cb3565b60008181526009602052604080822081516080810190925260010160048282826020028201915b815481526020019060010190808311610be857505060075488516020808b01516040808d01516060808f01518b51958c0151848d0151928d01519451630cbe96a560e41b81529c9d506001600160a01b039098169b63cbe96a509b50610c5f9a5096985093969195939493919290916004016112ee565b608060405180830381865afa158015610c7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca091906115d8565b6060880152604087015260208601528452505b600081815260096020526040902060050154610ccf9083611278565b91505b600101610b5a565b5080600003610d1d5760405162461bcd60e51b815260206004820152600f60248201526e4249544d41505f49535f454d50545960881b60448201526064016103ef565b60036005546002610d2e9190611562565b610d38919061154e565b8111610d825760405162461bcd60e51b815260206004820152601960248201527824a729aaa32324a1a4a2a72a2fab27aa24a723afa827aba2a960391b60448201526064016103ef565b60065460405163ebbdac9160e01b815260009182916001600160a01b039091169063ebbdac9190610dbb908b9088908e9060040161160e565b6040805180830381865afa158015610dd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dfb9190611689565b91509150818015610e095750805b6108155760405162461bcd60e51b815260206004820152601d60248201527f5349474e41545552455f564552494649434154494f4e5f4641494c454400000060448201526064016103ef565b600082815260086020908152604091829020825160608101845281548082526001830154938201939093526002909101549281019290925282351480610ea757508051610ea3906001611278565b8235145b610ee35760405162461bcd60e51b815260206004820152600d60248201526c0929cac82989288be8aa09e869609b1b60448201526064016103ef565b8060200151826020013511610f2d5760405162461bcd60e51b815260206004820152601060248201526f115354151657d0d21150d2d413d2539560821b60448201526064016103ef565b505050565b6000610f41600284841861154e565b610f4d90848416611278565b9392505050565b600080610f6260088461154e565b90506000610f7160088561153a565b9050848210610f8557600092505050610f4d565b6000600160ff83161b878785818110610fa057610fa061124c565b9050013560f81c60f81b60f81c60ff161611925050509392505050565b60405180608001604052806004906020820280368337509192915050565b600060208284031215610fed57600080fd5b5035919050565b60008060008060006080868803121561100c57600080fd5b853594506020860135935060408601359250606086013567ffffffffffffffff8082111561103957600080fd5b818801915088601f83011261104d57600080fd5b81358181111561105c57600080fd5b8960208260051b850101111561107157600080fd5b9699959850939650602001949392505050565b6001600160a01b038116811461109957600080fd5b50565b60008083601f8401126110ae57600080fd5b50813567ffffffffffffffff8111156110c657600080fd5b60208301915083602060c0830285010111156110e157600080fd5b9250929050565b60008060008060006080868803121561110057600080fd5b853561110b81611084565b9450602086013561111b81611084565b935060408601359250606086013567ffffffffffffffff81111561113e57600080fd5b61114a8882890161109c565b969995985093965092949392505050565b60006060828403121561116d57600080fd5b50919050565b6000806000806000806000610140888a03121561118f57600080fd5b611199898961115b565b96506111a88960608a0161115b565b95506101008801898111156111bc57600080fd5b60c0890195503567ffffffffffffffff808211156111d957600080fd5b6111e58b838c0161109c565b90965094506101208a01359150808211156111ff57600080fd5b818a0191508a601f83011261121357600080fd5b81358181111561122257600080fd5b8b602082850101111561123457600080fd5b60208301945080935050505092959891949750929550565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b808201808211156108ea576108ea611262565b60208082528181018390526000908460408401835b868110156112e35782356112b381611084565b6001600160a01b0316825260808385018584013760a0838101359083015260c092830192909101906001016112a0565b509695505050505050565b978852602088019690965260408701949094526060860192909252608085015260a084015260c083015260e08201526101000190565b82815260006020604081840152835180604085015260005b818110156113585785810183015185820160600152820161133c565b506000606082860101526060601f19601f830116850101925050509392505050565b60006040828403121561138c57600080fd5b82601f83011261139b57600080fd5b6040516040810181811067ffffffffffffffff821117156113cc57634e487b7160e01b600052604160045260246000fd5b80604052508060408401858111156113e357600080fd5b845b818110156113fd5780518352602092830192016113e5565b509195945050505050565b60006001820161141a5761141a611262565b5060010190565b818103818111156108ea576108ea611262565b600181815b8085111561146f57816000190482111561145557611455611262565b8085161561146257918102915b93841c9390800290611439565b509250929050565b600082611486575060016108ea565b81611493575060006108ea565b81600181146114a957600281146114b3576114cf565b60019150506108ea565b60ff8411156114c4576114c4611262565b50506001821b6108ea565b5060208310610133831016604e8410600b84101617156114f2575081810a6108ea565b6114fc8383611434565b806000190482111561151057611510611262565b029392505050565b6000610f4d8383611477565b634e487b7160e01b600052601260045260246000fd5b60008261154957611549611524565b500690565b60008261155d5761155d611524565b500490565b80820281158282048414176108ea576108ea611262565b813561158481611084565b81546001600160a01b0319166001600160a01b0391909116178155602082810160005b60048110156115c7578135600182860181019190915591830191016115a7565b50505060a082013560058201555050565b600080600080608085870312156115ee57600080fd5b505082516020840151604085015160609095015191969095509092509050565b61010081016040858337604082018460005b600481101561163f578151835260209283019290910190600101611620565b50505060c082018360005b600281101561166957815183526020928301929091019060010161164a565b505050949350505050565b8051801515811461168457600080fd5b919050565b6000806040838503121561169c57600080fd5b6116a583611674565b91506116b360208401611674565b9050925092905056fea2646970667358221220a7bbc925b936828d67df832f2932e0f475f5fa7058472853cfff77d2f8eded9464736f6c63430008110033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" -var ExitHelperArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"ExitHelper\",\n \"sourceName\": \"contracts/root/ExitHelper.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bool\",\n \"name\": \"success\",\n \"type\": \"bool\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bytes\",\n \"name\": \"returnData\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"ExitProcessed\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [\n {\n \"components\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockNumber\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"leafIndex\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"unhashedLeaf\",\n \"type\": \"bytes\"\n },\n {\n \"internalType\": \"bytes32[]\",\n \"name\": \"proof\",\n \"type\": \"bytes32[]\"\n }\n ],\n \"internalType\": \"struct IExitHelper.BatchExitInput[]\",\n \"name\": \"inputs\",\n \"type\": \"tuple[]\"\n }\n ],\n \"name\": \"batchExit\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"checkpointManager\",\n \"outputs\": [\n {\n \"internalType\": \"contract ICheckpointManager\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockNumber\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"leafIndex\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"unhashedLeaf\",\n \"type\": \"bytes\"\n },\n {\n \"internalType\": \"bytes32[]\",\n \"name\": \"proof\",\n \"type\": \"bytes32[]\"\n }\n ],\n \"name\": \"exit\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract ICheckpointManager\",\n \"name\": \"newCheckpointManager\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"processedExits\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50610b62806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c806350607b351461005c578063aa209cc314610071578063bd88ea7914610084578063c0857ba0146100bc578063c4d66de8146100e7575b600080fd5b61006f61006a3660046106c9565b6100fa565b005b61006f61007f36600461070b565b610200565b6100a76100923660046107bc565b60016020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6002546100cf906001600160a01b031681565b6040516001600160a01b0390911681526020016100b3565b61006f6100f53660046107ed565b610240565b6002546001600160a01b031661012b5760405162461bcd60e51b815260040161012290610811565b60405180910390fd5b8060005b818110156101fa576101f284848381811061014c5761014c610848565b905060200281019061015e919061085e565b3585858481811061017157610171610848565b9050602002810190610183919061085e565b6020013586868581811061019957610199610848565b90506020028101906101ab919061085e565b6101b990604081019061087e565b8888878181106101cb576101cb610848565b90506020028101906101dd919061085e565b6101eb9060608101906108c5565b60016103d2565b60010161012f565b50505050565b6002546001600160a01b03166102285760405162461bcd60e51b815260040161012290610811565b61023886868686868660006103d2565b505050505050565b600054610100900460ff16158080156102605750600054600160ff909116105b8061027a5750303b15801561027a575060005460ff166001145b6102dd5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610122565b6000805460ff191660011790558015610300576000805461ff0019166101001790555b6001600160a01b0382161580159061032157506001600160a01b0382163b15155b61036d5760405162461bcd60e51b815260206004820152601b60248201527f4578697448656c7065723a20494e56414c49445f4144445245535300000000006044820152606401610122565b600280546001600160a01b0319166001600160a01b03841617905580156103ce576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b60008080806103e3888a018a610925565b935093509350935084156104165760008481526001602052604090205460ff16156104115750505050610674565b610480565b60008481526001602052604090205460ff16156104805760405162461bcd60e51b815260206004820152602260248201527f4578697448656c7065723a20455849545f414c52454144595f50524f43455353604482015261115160f21b6064820152608401610122565b6002546040516001600160a01b03909116906361a02208908d906104a7908d908d90610a05565b6040519081900381206001600160e01b031960e085901b1682526104d492918f908d908d90600401610a15565b602060405180830381865afa1580156104f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105159190610a62565b61055d5760405162461bcd60e51b815260206004820152601960248201527822bc34ba2432b63832b91d1024a72b20a624a22fa82927a7a360391b6044820152606401610122565b6000848152600160208190526040808320805460ff19169092179091555181906001600160a01b0385169061059a90889088908790602401610ad4565b60408051601f198184030181529181526020820180516001600160e01b031663f43cda8b60e01b179052516105cf9190610b07565b6000604051808303816000865af19150503d806000811461060c576040519150601f19603f3d011682016040523d82523d6000602084013e610611565b606091505b509150915081610632576000868152600160205260409020805460ff191690555b811515867f8bbfa0c9bee3785c03700d2a909592286efb83fc7e7002be5764424b9842f7ec836040516106659190610b19565b60405180910390a35050505050505b50505050505050565b60008083601f84011261068f57600080fd5b50813567ffffffffffffffff8111156106a757600080fd5b6020830191508360208260051b85010111156106c257600080fd5b9250929050565b600080602083850312156106dc57600080fd5b823567ffffffffffffffff8111156106f357600080fd5b6106ff8582860161067d565b90969095509350505050565b6000806000806000806080878903121561072457600080fd5b8635955060208701359450604087013567ffffffffffffffff8082111561074a57600080fd5b818901915089601f83011261075e57600080fd5b81358181111561076d57600080fd5b8a602082850101111561077f57600080fd5b60208301965080955050606089013591508082111561079d57600080fd5b506107aa89828a0161067d565b979a9699509497509295939492505050565b6000602082840312156107ce57600080fd5b5035919050565b6001600160a01b03811681146107ea57600080fd5b50565b6000602082840312156107ff57600080fd5b813561080a816107d5565b9392505050565b6020808252601b908201527f4578697448656c7065723a204e4f545f494e495449414c495a45440000000000604082015260600190565b634e487b7160e01b600052603260045260246000fd5b60008235607e1983360301811261087457600080fd5b9190910192915050565b6000808335601e1984360301811261089557600080fd5b83018035915067ffffffffffffffff8211156108b057600080fd5b6020019150368190038213156106c257600080fd5b6000808335601e198436030181126108dc57600080fd5b83018035915067ffffffffffffffff8211156108f757600080fd5b6020019150600581901b36038213156106c257600080fd5b634e487b7160e01b600052604160045260246000fd5b6000806000806080858703121561093b57600080fd5b84359350602085013561094d816107d5565b9250604085013561095d816107d5565b9150606085013567ffffffffffffffff8082111561097a57600080fd5b818701915087601f83011261098e57600080fd5b8135818111156109a0576109a061090f565b604051601f8201601f19908116603f011681019083821181831017156109c8576109c861090f565b816040528281528a60208487010111156109e157600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b8183823760009101908152919050565b85815284602082015283604082015260806060820152816080820152600060018060fb1b03831115610a4657600080fd5b8260051b808560a08501379190910160a0019695505050505050565b600060208284031215610a7457600080fd5b8151801515811461080a57600080fd5b60005b83811015610a9f578181015183820152602001610a87565b50506000910152565b60008151808452610ac0816020860160208601610a84565b601f01601f19169290920160200192915050565b8381526001600160a01b0383166020820152606060408201819052600090610afe90830184610aa8565b95945050505050565b60008251610874818460208701610a84565b60208152600061080a6020830184610aa856fea264697066735822122008943fed61b7c9037d83d6de6f81699e05bf9650fa3394883bac4a072bac958b64736f6c63430008110033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106100575760003560e01c806350607b351461005c578063aa209cc314610071578063bd88ea7914610084578063c0857ba0146100bc578063c4d66de8146100e7575b600080fd5b61006f61006a3660046106c9565b6100fa565b005b61006f61007f36600461070b565b610200565b6100a76100923660046107bc565b60016020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6002546100cf906001600160a01b031681565b6040516001600160a01b0390911681526020016100b3565b61006f6100f53660046107ed565b610240565b6002546001600160a01b031661012b5760405162461bcd60e51b815260040161012290610811565b60405180910390fd5b8060005b818110156101fa576101f284848381811061014c5761014c610848565b905060200281019061015e919061085e565b3585858481811061017157610171610848565b9050602002810190610183919061085e565b6020013586868581811061019957610199610848565b90506020028101906101ab919061085e565b6101b990604081019061087e565b8888878181106101cb576101cb610848565b90506020028101906101dd919061085e565b6101eb9060608101906108c5565b60016103d2565b60010161012f565b50505050565b6002546001600160a01b03166102285760405162461bcd60e51b815260040161012290610811565b61023886868686868660006103d2565b505050505050565b600054610100900460ff16158080156102605750600054600160ff909116105b8061027a5750303b15801561027a575060005460ff166001145b6102dd5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610122565b6000805460ff191660011790558015610300576000805461ff0019166101001790555b6001600160a01b0382161580159061032157506001600160a01b0382163b15155b61036d5760405162461bcd60e51b815260206004820152601b60248201527f4578697448656c7065723a20494e56414c49445f4144445245535300000000006044820152606401610122565b600280546001600160a01b0319166001600160a01b03841617905580156103ce576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b60008080806103e3888a018a610925565b935093509350935084156104165760008481526001602052604090205460ff16156104115750505050610674565b610480565b60008481526001602052604090205460ff16156104805760405162461bcd60e51b815260206004820152602260248201527f4578697448656c7065723a20455849545f414c52454144595f50524f43455353604482015261115160f21b6064820152608401610122565b6002546040516001600160a01b03909116906361a02208908d906104a7908d908d90610a05565b6040519081900381206001600160e01b031960e085901b1682526104d492918f908d908d90600401610a15565b602060405180830381865afa1580156104f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105159190610a62565b61055d5760405162461bcd60e51b815260206004820152601960248201527822bc34ba2432b63832b91d1024a72b20a624a22fa82927a7a360391b6044820152606401610122565b6000848152600160208190526040808320805460ff19169092179091555181906001600160a01b0385169061059a90889088908790602401610ad4565b60408051601f198184030181529181526020820180516001600160e01b031663f43cda8b60e01b179052516105cf9190610b07565b6000604051808303816000865af19150503d806000811461060c576040519150601f19603f3d011682016040523d82523d6000602084013e610611565b606091505b509150915081610632576000868152600160205260409020805460ff191690555b811515867f8bbfa0c9bee3785c03700d2a909592286efb83fc7e7002be5764424b9842f7ec836040516106659190610b19565b60405180910390a35050505050505b50505050505050565b60008083601f84011261068f57600080fd5b50813567ffffffffffffffff8111156106a757600080fd5b6020830191508360208260051b85010111156106c257600080fd5b9250929050565b600080602083850312156106dc57600080fd5b823567ffffffffffffffff8111156106f357600080fd5b6106ff8582860161067d565b90969095509350505050565b6000806000806000806080878903121561072457600080fd5b8635955060208701359450604087013567ffffffffffffffff8082111561074a57600080fd5b818901915089601f83011261075e57600080fd5b81358181111561076d57600080fd5b8a602082850101111561077f57600080fd5b60208301965080955050606089013591508082111561079d57600080fd5b506107aa89828a0161067d565b979a9699509497509295939492505050565b6000602082840312156107ce57600080fd5b5035919050565b6001600160a01b03811681146107ea57600080fd5b50565b6000602082840312156107ff57600080fd5b813561080a816107d5565b9392505050565b6020808252601b908201527f4578697448656c7065723a204e4f545f494e495449414c495a45440000000000604082015260600190565b634e487b7160e01b600052603260045260246000fd5b60008235607e1983360301811261087457600080fd5b9190910192915050565b6000808335601e1984360301811261089557600080fd5b83018035915067ffffffffffffffff8211156108b057600080fd5b6020019150368190038213156106c257600080fd5b6000808335601e198436030181126108dc57600080fd5b83018035915067ffffffffffffffff8211156108f757600080fd5b6020019150600581901b36038213156106c257600080fd5b634e487b7160e01b600052604160045260246000fd5b6000806000806080858703121561093b57600080fd5b84359350602085013561094d816107d5565b9250604085013561095d816107d5565b9150606085013567ffffffffffffffff8082111561097a57600080fd5b818701915087601f83011261098e57600080fd5b8135818111156109a0576109a061090f565b604051601f8201601f19908116603f011681019083821181831017156109c8576109c861090f565b816040528281528a60208487010111156109e157600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b8183823760009101908152919050565b85815284602082015283604082015260806060820152816080820152600060018060fb1b03831115610a4657600080fd5b8260051b808560a08501379190910160a0019695505050505050565b600060208284031215610a7457600080fd5b8151801515811461080a57600080fd5b60005b83811015610a9f578181015183820152602001610a87565b50506000910152565b60008151808452610ac0816020860160208601610a84565b601f01601f19169290920160200192915050565b8381526001600160a01b0383166020820152606060408201819052600090610afe90830184610aa8565b95945050505050565b60008251610874818460208701610a84565b60208152600061080a6020830184610aa856fea264697066735822122008943fed61b7c9037d83d6de6f81699e05bf9650fa3394883bac4a072bac958b64736f6c63430008110033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" -var StateSenderArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"StateSender\",\n \"sourceName\": \"contracts/root/StateSender.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"StateSynced\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAX_LENGTH\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"counter\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"syncState\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50610297806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806316f198311461004657806361bc221a1461005b578063a6f9885c14610076575b600080fd5b61005961005436600461017a565b61007f565b005b61006460005481565b60405190815260200160405180910390f35b61006461080081565b6001600160a01b0383166100cd5760405162461bcd60e51b815260206004820152601060248201526f24a72b20a624a22fa922a1a2a4ab22a960811b60448201526064015b60405180910390fd5b6108008111156101145760405162461bcd60e51b815260206004820152601260248201527108ab0868a8a88a6be9a82b0be988a9c8ea8960731b60448201526064016100c4565b826001600160a01b0316336001600160a01b031660008081546101369061020b565b9190508190557fd1d7f6609674cc5871fdb4b0bcd4f0a214118411de9e38983866514f22659165858560405161016d929190610232565b60405180910390a4505050565b60008060006040848603121561018f57600080fd5b83356001600160a01b03811681146101a657600080fd5b9250602084013567ffffffffffffffff808211156101c357600080fd5b818601915086601f8301126101d757600080fd5b8135818111156101e657600080fd5b8760208285010111156101f857600080fd5b6020830194508093505050509250925092565b60006001820161022b57634e487b7160e01b600052601160045260246000fd5b5060010190565b60208152816020820152818360408301376000818301604090810191909152601f909201601f1916010191905056fea264697066735822122001854f5b142666bc44e5f66226d8f0a84e2c503b8ab6002552f648cf58e3336c64736f6c63430008110033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106100415760003560e01c806316f198311461004657806361bc221a1461005b578063a6f9885c14610076575b600080fd5b61005961005436600461017a565b61007f565b005b61006460005481565b60405190815260200160405180910390f35b61006461080081565b6001600160a01b0383166100cd5760405162461bcd60e51b815260206004820152601060248201526f24a72b20a624a22fa922a1a2a4ab22a960811b60448201526064015b60405180910390fd5b6108008111156101145760405162461bcd60e51b815260206004820152601260248201527108ab0868a8a88a6be9a82b0be988a9c8ea8960731b60448201526064016100c4565b826001600160a01b0316336001600160a01b031660008081546101369061020b565b9190508190557fd1d7f6609674cc5871fdb4b0bcd4f0a214118411de9e38983866514f22659165858560405161016d929190610232565b60405180910390a4505050565b60008060006040848603121561018f57600080fd5b83356001600160a01b03811681146101a657600080fd5b9250602084013567ffffffffffffffff808211156101c357600080fd5b818601915086601f8301126101d757600080fd5b8135818111156101e657600080fd5b8760208285010111156101f857600080fd5b6020830194508093505050509250925092565b60006001820161022b57634e487b7160e01b600052601160045260246000fd5b5060010190565b60208152816020820152818360408301376000818301604090810191909152601f909201601f1916010191905056fea264697066735822122001854f5b142666bc44e5f66226d8f0a84e2c503b8ab6002552f648cf58e3336c64736f6c63430008110033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" -var RootERC20PredicateArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"RootERC20Predicate\",\n \"sourceName\": \"contracts/root/RootERC20Predicate.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"depositor\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"ERC20Deposit\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"withdrawer\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"ERC20Withdraw\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"TokenMapped\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAP_TOKEN_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childERC20Predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childTokenTemplate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC20Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"deposit\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC20Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"depositTo\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"exitHelper\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newStateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newExitHelper\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildERC20Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"nativeTokenRootAddress\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC20Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"mapToken\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onL2StateReceive\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"rootTokenToChildToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"stateSender\",\n \"outputs\": [\n {\n \"internalType\": \"contract IStateSender\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b506113c8806100206000396000f3fe608060405234801561001057600080fd5b50600436106100bf5760003560e01c8063cb10f94c1161007c578063cb10f94c1461018d578063d41f1771146101a6578063d57184e4146101cd578063f213159c146101e0578063f43cda8b146101f3578063f4a120f714610206578063f64512551461021957600080fd5b80631459457a146100c457806347e7ef24146100d95780637efab4f5146100ec57806395c7041c14610132578063b176806514610145578063b68ad1e41461017a575b600080fd5b6100d76100d2366004610f4c565b610240565b005b6100d76100e7366004610fbd565b6104ae565b6101156100fa366004610fe9565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b600154610115906001600160a01b031681565b61016c7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b604051908152602001610129565b600354610115906001600160a01b031681565b600054610115906201000090046001600160a01b031681565b61016c7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b600254610115906001600160a01b031681565b6100d76101ee36600461100d565b6104bd565b6100d761020136600461104e565b6104cd565b6100d7610214366004610fe9565b610654565b61016c7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b600054610100900460ff16158080156102605750600054600160ff909116105b8061027a5750303b15801561027a575060005460ff166001145b6102e25760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610305576000805461ff0019166101001790555b6001600160a01b0386161580159061032557506001600160a01b03851615155b801561033957506001600160a01b03841615155b801561034d57506001600160a01b03831615155b6103a85760405162461bcd60e51b815260206004820152602660248201527f526f6f7445524332305072656469636174653a204241445f494e495449414c496044820152652d20aa24a7a760d11b60648201526084016102d9565b6000805462010000600160b01b031916620100006001600160a01b038981169190910291909117909155600180546001600160a01b03199081168884161790915560028054821687841617905560038054909116858316179055821615610460576001600160a01b03821660008181526004602052604080822080546001600160a01b03191661101090811790915590519092917f85920d35e6c72f6b2affffa04298b0cecfeba86e4a9f407df661f1cb8ab5e61791a35b80156104a6576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b6104b9823383610a0b565b5050565b6104c8838383610a0b565b505050565b6001546001600160a01b031633146105335760405162461bcd60e51b8152602060048201526024808201527f526f6f7445524332305072656469636174653a204f4e4c595f455849545f4845604482015263262822a960e11b60648201526084016102d9565b6002546001600160a01b038481169116146105a15760405162461bcd60e51b815260206004820152602860248201527f526f6f7445524332305072656469636174653a204f4e4c595f4348494c445f50604482015267524544494341544560c01b60648201526084016102d9565b7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e9828696105d06020600084866110d7565b6105d991611101565b036105f8576105f36105ee82602081866110d7565b610b90565b61064e565b60405162461bcd60e51b815260206004820152602560248201527f526f6f7445524332305072656469636174653a20494e56414c49445f5349474e604482015264415455524560d81b60648201526084016102d9565b50505050565b6001600160a01b0381166106b45760405162461bcd60e51b815260206004820152602160248201527f526f6f7445524332305072656469636174653a20494e56414c49445f544f4b456044820152602760f91b60648201526084016102d9565b6001600160a01b0381811660009081526004602052604090205416156107275760405162461bcd60e51b815260206004820152602260248201527f526f6f7445524332305072656469636174653a20414c52454144595f4d415050604482015261115160f21b60648201526084016102d9565b60035460408051606084901b6bffffffffffffffffffffffff19166020808301919091528251601481840301815260348301808552815191909201206002546001600160a01b03908116606c8501526f5af43d82803e903d91602b57fd5bf3ff60588501529094166048830152733d602d80600a3d3981f3363d3d373d3d3d363d739052608c81019290925260379082012060ac82015260556077909101206000906001600160a01b03838116600081815260046020819052604080832080546001600160a01b031916878716179055825460025482516306fdde0360e01b81529251979850620100009091048616966316f198319691909116947f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad948a9491936306fdde03938184019390918290030181865afa15801561086d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610895919081019061115a565b876001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156108d3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108fb919081019061115a565b886001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610939573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061095d91906111fc565b60405160200161097195949392919061124b565b6040516020818303038152906040526040518363ffffffff1660e01b815260040161099d92919061129d565b600060405180830381600087803b1580156109b757600080fd5b505af11580156109cb573d6000803e3d6000fd5b50506040516001600160a01b038085169350851691507f85920d35e6c72f6b2affffa04298b0cecfeba86e4a9f407df661f1cb8ab5e61790600090a35050565b6001600160a01b0383811660009081526004602052604090205416610a3357610a3383610654565b6001600160a01b038084166000908152600460205260409020541680610a5b57610a5b6112c1565b610a706001600160a01b038516333085610c48565b600054600254604080517f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82160208201526001600160a01b0388811682840152336060830152878116608083015260a08083018890528351808403909101815260c08301938490526316f1983160e01b909352620100009094048416936316f1983193610b019391169160c40161129d565b600060405180830381600087803b158015610b1b57600080fd5b505af1158015610b2f573d6000803e3d6000fd5b50505050826001600160a01b0316816001600160a01b0316856001600160a01b03167f8be9001bb612c7123a1861dc0d9d94e683261f6cbbd7c7438b708975bc4908a33386604051610b829291906112d7565b60405180910390a450505050565b6000808080610ba1858701876112f0565b6001600160a01b0380851660009081526004602052604090205494985092965090945092501680610bd457610bd46112c1565b610be86001600160a01b0386168484610cb3565b826001600160a01b0316816001600160a01b0316866001600160a01b03167f9c4f744b2e971d7058a9d8f43977e0e17bf7d57a48659f0e18541b7ee3d022e48786604051610c379291906112d7565b60405180910390a450505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261064e9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610cd2565b6104c88363a9059cbb60e01b8484604051602401610c7c9291906112d7565b6000610d27826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610da49092919063ffffffff16565b8051909150156104c85780806020019051810190610d459190611341565b6104c85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016102d9565b6060610db38484600085610dbb565b949350505050565b606082471015610e1c5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016102d9565b600080866001600160a01b03168587604051610e389190611363565b60006040518083038185875af1925050503d8060008114610e75576040519150601f19603f3d011682016040523d82523d6000602084013e610e7a565b606091505b5091509150610e8b87838387610e96565b979650505050505050565b60608315610f05578251600003610efe576001600160a01b0385163b610efe5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102d9565b5081610db3565b610db38383815115610f1a5781518083602001fd5b8060405162461bcd60e51b81526004016102d9919061137f565b6001600160a01b0381168114610f4957600080fd5b50565b600080600080600060a08688031215610f6457600080fd5b8535610f6f81610f34565b94506020860135610f7f81610f34565b93506040860135610f8f81610f34565b92506060860135610f9f81610f34565b91506080860135610faf81610f34565b809150509295509295909350565b60008060408385031215610fd057600080fd5b8235610fdb81610f34565b946020939093013593505050565b600060208284031215610ffb57600080fd5b813561100681610f34565b9392505050565b60008060006060848603121561102257600080fd5b833561102d81610f34565b9250602084013561103d81610f34565b929592945050506040919091013590565b6000806000806060858703121561106457600080fd5b84359350602085013561107681610f34565b9250604085013567ffffffffffffffff8082111561109357600080fd5b818701915087601f8301126110a757600080fd5b8135818111156110b657600080fd5b8860208285010111156110c857600080fd5b95989497505060200194505050565b600080858511156110e757600080fd5b838611156110f457600080fd5b5050820193919092039150565b8035602083101561111a57600019602084900360031b1b165b92915050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015611151578181015183820152602001611139565b50506000910152565b60006020828403121561116c57600080fd5b815167ffffffffffffffff8082111561118457600080fd5b818401915084601f83011261119857600080fd5b8151818111156111aa576111aa611120565b604051601f8201601f19908116603f011681019083821181831017156111d2576111d2611120565b816040528281528760208487010111156111eb57600080fd5b610e8b836020830160208801611136565b60006020828403121561120e57600080fd5b815160ff8116811461100657600080fd5b60008151808452611237816020860160208601611136565b601f01601f19169290920160200192915050565b8581526001600160a01b038516602082015260a0604082018190526000906112759083018661121f565b8281036060840152611287818661121f565b91505060ff831660808301529695505050505050565b6001600160a01b0383168152604060208201819052600090610db39083018461121f565b634e487b7160e01b600052600160045260246000fd5b6001600160a01b03929092168252602082015260400190565b6000806000806080858703121561130657600080fd5b843561131181610f34565b9350602085013561132181610f34565b9250604085013561133181610f34565b9396929550929360600135925050565b60006020828403121561135357600080fd5b8151801515811461100657600080fd5b60008251611375818460208701611136565b9190910192915050565b602081526000611006602083018461121f56fea264697066735822122071186a5f68a0e568193775380eab31143f89ff0d61291b20e262c95a735f1d7b64736f6c63430008110033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106100bf5760003560e01c8063cb10f94c1161007c578063cb10f94c1461018d578063d41f1771146101a6578063d57184e4146101cd578063f213159c146101e0578063f43cda8b146101f3578063f4a120f714610206578063f64512551461021957600080fd5b80631459457a146100c457806347e7ef24146100d95780637efab4f5146100ec57806395c7041c14610132578063b176806514610145578063b68ad1e41461017a575b600080fd5b6100d76100d2366004610f4c565b610240565b005b6100d76100e7366004610fbd565b6104ae565b6101156100fa366004610fe9565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b600154610115906001600160a01b031681565b61016c7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b604051908152602001610129565b600354610115906001600160a01b031681565b600054610115906201000090046001600160a01b031681565b61016c7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b600254610115906001600160a01b031681565b6100d76101ee36600461100d565b6104bd565b6100d761020136600461104e565b6104cd565b6100d7610214366004610fe9565b610654565b61016c7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b600054610100900460ff16158080156102605750600054600160ff909116105b8061027a5750303b15801561027a575060005460ff166001145b6102e25760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610305576000805461ff0019166101001790555b6001600160a01b0386161580159061032557506001600160a01b03851615155b801561033957506001600160a01b03841615155b801561034d57506001600160a01b03831615155b6103a85760405162461bcd60e51b815260206004820152602660248201527f526f6f7445524332305072656469636174653a204241445f494e495449414c496044820152652d20aa24a7a760d11b60648201526084016102d9565b6000805462010000600160b01b031916620100006001600160a01b038981169190910291909117909155600180546001600160a01b03199081168884161790915560028054821687841617905560038054909116858316179055821615610460576001600160a01b03821660008181526004602052604080822080546001600160a01b03191661101090811790915590519092917f85920d35e6c72f6b2affffa04298b0cecfeba86e4a9f407df661f1cb8ab5e61791a35b80156104a6576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b6104b9823383610a0b565b5050565b6104c8838383610a0b565b505050565b6001546001600160a01b031633146105335760405162461bcd60e51b8152602060048201526024808201527f526f6f7445524332305072656469636174653a204f4e4c595f455849545f4845604482015263262822a960e11b60648201526084016102d9565b6002546001600160a01b038481169116146105a15760405162461bcd60e51b815260206004820152602860248201527f526f6f7445524332305072656469636174653a204f4e4c595f4348494c445f50604482015267524544494341544560c01b60648201526084016102d9565b7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e9828696105d06020600084866110d7565b6105d991611101565b036105f8576105f36105ee82602081866110d7565b610b90565b61064e565b60405162461bcd60e51b815260206004820152602560248201527f526f6f7445524332305072656469636174653a20494e56414c49445f5349474e604482015264415455524560d81b60648201526084016102d9565b50505050565b6001600160a01b0381166106b45760405162461bcd60e51b815260206004820152602160248201527f526f6f7445524332305072656469636174653a20494e56414c49445f544f4b456044820152602760f91b60648201526084016102d9565b6001600160a01b0381811660009081526004602052604090205416156107275760405162461bcd60e51b815260206004820152602260248201527f526f6f7445524332305072656469636174653a20414c52454144595f4d415050604482015261115160f21b60648201526084016102d9565b60035460408051606084901b6bffffffffffffffffffffffff19166020808301919091528251601481840301815260348301808552815191909201206002546001600160a01b03908116606c8501526f5af43d82803e903d91602b57fd5bf3ff60588501529094166048830152733d602d80600a3d3981f3363d3d373d3d3d363d739052608c81019290925260379082012060ac82015260556077909101206000906001600160a01b03838116600081815260046020819052604080832080546001600160a01b031916878716179055825460025482516306fdde0360e01b81529251979850620100009091048616966316f198319691909116947f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad948a9491936306fdde03938184019390918290030181865afa15801561086d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610895919081019061115a565b876001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156108d3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108fb919081019061115a565b886001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610939573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061095d91906111fc565b60405160200161097195949392919061124b565b6040516020818303038152906040526040518363ffffffff1660e01b815260040161099d92919061129d565b600060405180830381600087803b1580156109b757600080fd5b505af11580156109cb573d6000803e3d6000fd5b50506040516001600160a01b038085169350851691507f85920d35e6c72f6b2affffa04298b0cecfeba86e4a9f407df661f1cb8ab5e61790600090a35050565b6001600160a01b0383811660009081526004602052604090205416610a3357610a3383610654565b6001600160a01b038084166000908152600460205260409020541680610a5b57610a5b6112c1565b610a706001600160a01b038516333085610c48565b600054600254604080517f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82160208201526001600160a01b0388811682840152336060830152878116608083015260a08083018890528351808403909101815260c08301938490526316f1983160e01b909352620100009094048416936316f1983193610b019391169160c40161129d565b600060405180830381600087803b158015610b1b57600080fd5b505af1158015610b2f573d6000803e3d6000fd5b50505050826001600160a01b0316816001600160a01b0316856001600160a01b03167f8be9001bb612c7123a1861dc0d9d94e683261f6cbbd7c7438b708975bc4908a33386604051610b829291906112d7565b60405180910390a450505050565b6000808080610ba1858701876112f0565b6001600160a01b0380851660009081526004602052604090205494985092965090945092501680610bd457610bd46112c1565b610be86001600160a01b0386168484610cb3565b826001600160a01b0316816001600160a01b0316866001600160a01b03167f9c4f744b2e971d7058a9d8f43977e0e17bf7d57a48659f0e18541b7ee3d022e48786604051610c379291906112d7565b60405180910390a450505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261064e9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610cd2565b6104c88363a9059cbb60e01b8484604051602401610c7c9291906112d7565b6000610d27826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610da49092919063ffffffff16565b8051909150156104c85780806020019051810190610d459190611341565b6104c85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016102d9565b6060610db38484600085610dbb565b949350505050565b606082471015610e1c5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016102d9565b600080866001600160a01b03168587604051610e389190611363565b60006040518083038185875af1925050503d8060008114610e75576040519150601f19603f3d011682016040523d82523d6000602084013e610e7a565b606091505b5091509150610e8b87838387610e96565b979650505050505050565b60608315610f05578251600003610efe576001600160a01b0385163b610efe5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102d9565b5081610db3565b610db38383815115610f1a5781518083602001fd5b8060405162461bcd60e51b81526004016102d9919061137f565b6001600160a01b0381168114610f4957600080fd5b50565b600080600080600060a08688031215610f6457600080fd5b8535610f6f81610f34565b94506020860135610f7f81610f34565b93506040860135610f8f81610f34565b92506060860135610f9f81610f34565b91506080860135610faf81610f34565b809150509295509295909350565b60008060408385031215610fd057600080fd5b8235610fdb81610f34565b946020939093013593505050565b600060208284031215610ffb57600080fd5b813561100681610f34565b9392505050565b60008060006060848603121561102257600080fd5b833561102d81610f34565b9250602084013561103d81610f34565b929592945050506040919091013590565b6000806000806060858703121561106457600080fd5b84359350602085013561107681610f34565b9250604085013567ffffffffffffffff8082111561109357600080fd5b818701915087601f8301126110a757600080fd5b8135818111156110b657600080fd5b8860208285010111156110c857600080fd5b95989497505060200194505050565b600080858511156110e757600080fd5b838611156110f457600080fd5b5050820193919092039150565b8035602083101561111a57600019602084900360031b1b165b92915050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015611151578181015183820152602001611139565b50506000910152565b60006020828403121561116c57600080fd5b815167ffffffffffffffff8082111561118457600080fd5b818401915084601f83011261119857600080fd5b8151818111156111aa576111aa611120565b604051601f8201601f19908116603f011681019083821181831017156111d2576111d2611120565b816040528281528760208487010111156111eb57600080fd5b610e8b836020830160208801611136565b60006020828403121561120e57600080fd5b815160ff8116811461100657600080fd5b60008151808452611237816020860160208601611136565b601f01601f19169290920160200192915050565b8581526001600160a01b038516602082015260a0604082018190526000906112759083018661121f565b8281036060840152611287818661121f565b91505060ff831660808301529695505050505050565b6001600160a01b0383168152604060208201819052600090610db39083018461121f565b634e487b7160e01b600052600160045260246000fd5b6001600160a01b03929092168252602082015260400190565b6000806000806080858703121561130657600080fd5b843561131181610f34565b9350602085013561132181610f34565b9250604085013561133181610f34565b9396929550929360600135925050565b60006020828403121561135357600080fd5b8151801515811461100657600080fd5b60008251611375818460208701611136565b9190910192915050565b602081526000611006602083018461121f56fea264697066735822122071186a5f68a0e568193775380eab31143f89ff0d61291b20e262c95a735f1d7b64736f6c63430008110033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" -var MockERC20Artifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"MockERC20\",\n \"sourceName\": \"contracts/mocks/MockERC20.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Approval\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"Paused\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bytes32\",\n \"name\": \"previousAdminRole\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bytes32\",\n \"name\": \"newAdminRole\",\n \"type\": \"bytes32\"\n }\n ],\n \"name\": \"RoleAdminChanged\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"RoleGranted\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"RoleRevoked\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Transfer\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"Unpaused\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEFAULT_ADMIN_ROLE\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MINTER_ROLE\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"PAUSER_ROLE\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"allowance\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"approve\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"balanceOf\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"burn\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"burnFrom\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"decimals\",\n \"outputs\": [\n {\n \"internalType\": \"uint8\",\n \"name\": \"\",\n \"type\": \"uint8\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"subtractedValue\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"decreaseAllowance\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n }\n ],\n \"name\": \"getRoleAdmin\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"index\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"getRoleMember\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n }\n ],\n \"name\": \"getRoleMemberCount\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"grantRole\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"hasRole\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"addedValue\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"increaseAllowance\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"mint\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"name\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"pause\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"paused\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"renounceRole\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"revokeRole\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes4\",\n \"name\": \"interfaceId\",\n \"type\": \"bytes4\"\n }\n ],\n \"name\": \"supportsInterface\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"symbol\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"totalSupply\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transfer\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transferFrom\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"unpause\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x60806040523480156200001157600080fd5b50604080518082018252600480825263151154d560e21b60208084018290528451808601909552918452908301529081816005620000508382620002e2565b5060066200005f8282620002e2565b50506007805460ff191690555062000079600033620000d9565b620000a57f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a633620000d9565b620000d17f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a33620000d9565b5050620003ae565b620000e58282620000e9565b5050565b6200010082826200012c60201b620008871760201c565b6000828152600160209081526040909120620001279183906200090b620001cc821b17901c565b505050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16620000e5576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620001883390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000620001e3836001600160a01b038416620001ec565b90505b92915050565b60008181526001830160205260408120546200023557508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155620001e6565b506000620001e6565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200026957607f821691505b6020821081036200028a57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200012757600081815260208120601f850160051c81016020861015620002b95750805b601f850160051c820191505b81811015620002da57828155600101620002c5565b505050505050565b81516001600160401b03811115620002fe57620002fe6200023e565b62000316816200030f845462000254565b8462000290565b602080601f8311600181146200034e5760008415620003355750858301515b600019600386901b1c1916600185901b178555620002da565b600085815260208120601f198616915b828110156200037f578886015182559484019460019091019084016200035e565b50858210156200039e5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6117fa80620003be6000396000f3fe608060405234801561001057600080fd5b50600436106101845760003560e01c806370a08231116100d9578063a457c2d711610087578063a457c2d714610336578063a9059cbb14610349578063ca15c8731461035c578063d53913931461036f578063d547741f14610396578063dd62ed3e146103a9578063e63ab1e9146103bc57600080fd5b806370a08231146102a457806379cc6790146102cd5780638456cb59146102e05780639010d07c146102e857806391d148541461031357806395d89b4114610326578063a217fddf1461032e57600080fd5b8063313ce56711610136578063313ce5671461023657806336568abe1461024557806339509351146102585780633f4ba83a1461026b57806340c10f191461027357806342966c68146102865780635c975abb1461029957600080fd5b806301ffc9a71461018957806306fdde03146101b1578063095ea7b3146101c657806318160ddd146101d957806323b872dd146101eb578063248a9ca3146101fe5780632f2ff15d14610221575b600080fd5b61019c610197366004611460565b6103d1565b60405190151581526020015b60405180910390f35b6101b96103fc565b6040516101a891906114ae565b61019c6101d43660046114fd565b61048e565b6004545b6040519081526020016101a8565b61019c6101f9366004611527565b6104a6565b6101dd61020c366004611563565b60009081526020819052604090206001015490565b61023461022f36600461157c565b6104ca565b005b604051601281526020016101a8565b61023461025336600461157c565b6104f4565b61019c6102663660046114fd565b610577565b610234610599565b6102346102813660046114fd565b610617565b610234610294366004611563565b6106a4565b60075460ff1661019c565b6101dd6102b23660046115a8565b6001600160a01b031660009081526002602052604090205490565b6102346102db3660046114fd565b6106b1565b6102346106c6565b6102fb6102f63660046115c3565b610740565b6040516001600160a01b0390911681526020016101a8565b61019c61032136600461157c565b61075f565b6101b9610788565b6101dd600081565b61019c6103443660046114fd565b610797565b61019c6103573660046114fd565b610812565b6101dd61036a366004611563565b610820565b6101dd7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b6102346103a436600461157c565b610837565b6101dd6103b73660046115e5565b61085c565b6101dd60008051602061178583398151915281565b60006001600160e01b03198216635a05180f60e01b14806103f657506103f682610920565b92915050565b60606005805461040b9061160f565b80601f01602080910402602001604051908101604052809291908181526020018280546104379061160f565b80156104845780601f1061045957610100808354040283529160200191610484565b820191906000526020600020905b81548152906001019060200180831161046757829003601f168201915b5050505050905090565b60003361049c818585610955565b5060019392505050565b6000336104b4858285610a79565b6104bf858585610af3565b506001949350505050565b6000828152602081905260409020600101546104e581610c97565b6104ef8383610ca1565b505050565b6001600160a01b03811633146105695760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b6105738282610cc3565b5050565b60003361049c81858561058a838361085c565b610594919061165f565b610955565b6105b16000805160206117858339815191523361075f565b61060d5760405162461bcd60e51b8152602060048201526039602482015260008051602061176583398151915260448201527876652070617573657220726f6c6520746f20756e706175736560381b6064820152608401610560565b610615610ce5565b565b6106417f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a63361075f565b61069a5760405162461bcd60e51b815260206004820152603660248201526000805160206117658339815191526044820152751d99481b5a5b9d195c881c9bdb19481d1bc81b5a5b9d60521b6064820152608401610560565b6105738282610d37565b6106ae3382610df2565b50565b6106bc823383610a79565b6105738282610df2565b6106de6000805160206117858339815191523361075f565b6107385760405162461bcd60e51b8152602060048201526037602482015260008051602061176583398151915260448201527676652070617573657220726f6c6520746f20706175736560481b6064820152608401610560565b610615610f20565b60008281526001602052604081206107589083610f5d565b9392505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60606006805461040b9061160f565b600033816107a5828661085c565b9050838110156108055760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610560565b6104bf8286868403610955565b60003361049c818585610af3565b60008181526001602052604081206103f690610f69565b60008281526020819052604090206001015461085281610c97565b6104ef8383610cc3565b6001600160a01b03918216600090815260036020908152604080832093909416825291909152205490565b610891828261075f565b610573576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556108c73390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000610758836001600160a01b038416610f73565b60006001600160e01b03198216637965db0b60e01b14806103f657506301ffc9a760e01b6001600160e01b03198316146103f6565b6001600160a01b0383166109b75760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610560565b6001600160a01b038216610a185760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610560565b6001600160a01b0383811660008181526003602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6000610a85848461085c565b90506000198114610aed5781811015610ae05760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610560565b610aed8484848403610955565b50505050565b6001600160a01b038316610b575760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610560565b6001600160a01b038216610bb95760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610560565b610bc4838383610fc2565b6001600160a01b03831660009081526002602052604090205481811015610c3c5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610560565b6001600160a01b0380851660008181526002602052604080822086860390559286168082529083902080548601905591516000805160206117a583398151915290610c8a9086815260200190565b60405180910390a3610aed565b6106ae8133610fcd565b610cab8282610887565b60008281526001602052604090206104ef908261090b565b610ccd8282611026565b60008281526001602052604090206104ef908261108b565b610ced6110a0565b6007805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6001600160a01b038216610d8d5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610560565b610d9960008383610fc2565b8060046000828254610dab919061165f565b90915550506001600160a01b0382166000818152600260209081526040808320805486019055518481526000805160206117a5833981519152910160405180910390a35050565b6001600160a01b038216610e525760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610560565b610e5e82600083610fc2565b6001600160a01b03821660009081526002602052604090205481811015610ed25760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610560565b6001600160a01b03831660008181526002602090815260408083208686039055600480548790039055518581529192916000805160206117a5833981519152910160405180910390a3505050565b610f286110e9565b6007805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610d1a3390565b6000610758838361112f565b60006103f6825490565b6000818152600183016020526040812054610fba575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556103f6565b5060006103f6565b6104ef838383611159565b610fd7828261075f565b61057357610fe4816111bf565b610fef8360206111d1565b604051602001611000929190611672565b60408051601f198184030181529082905262461bcd60e51b8252610560916004016114ae565b611030828261075f565b15610573576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000610758836001600160a01b03841661136d565b60075460ff166106155760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610560565b60075460ff16156106155760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610560565b6000826000018281548110611146576111466116e1565b9060005260206000200154905092915050565b60075460ff16156104ef5760405162461bcd60e51b815260206004820152602a60248201527f45524332305061757361626c653a20746f6b656e207472616e736665722077686044820152691a5b19481c185d5cd95960b21b6064820152608401610560565b60606103f66001600160a01b03831660145b606060006111e08360026116f7565b6111eb90600261165f565b67ffffffffffffffff8111156112035761120361170e565b6040519080825280601f01601f19166020018201604052801561122d576020820181803683370190505b509050600360fc1b81600081518110611248576112486116e1565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110611277576112776116e1565b60200101906001600160f81b031916908160001a905350600061129b8460026116f7565b6112a690600161165f565b90505b600181111561131e576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106112da576112da6116e1565b1a60f81b8282815181106112f0576112f06116e1565b60200101906001600160f81b031916908160001a90535060049490941c9361131781611724565b90506112a9565b5083156107585760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610560565b6000818152600183016020526040812054801561145657600061139160018361173b565b85549091506000906113a59060019061173b565b905081811461140a5760008660000182815481106113c5576113c56116e1565b90600052602060002001549050808760000184815481106113e8576113e86116e1565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061141b5761141b61174e565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506103f6565b60009150506103f6565b60006020828403121561147257600080fd5b81356001600160e01b03198116811461075857600080fd5b60005b838110156114a557818101518382015260200161148d565b50506000910152565b60208152600082518060208401526114cd81604085016020870161148a565b601f01601f19169190910160400192915050565b80356001600160a01b03811681146114f857600080fd5b919050565b6000806040838503121561151057600080fd5b611519836114e1565b946020939093013593505050565b60008060006060848603121561153c57600080fd5b611545846114e1565b9250611553602085016114e1565b9150604084013590509250925092565b60006020828403121561157557600080fd5b5035919050565b6000806040838503121561158f57600080fd5b8235915061159f602084016114e1565b90509250929050565b6000602082840312156115ba57600080fd5b610758826114e1565b600080604083850312156115d657600080fd5b50508035926020909101359150565b600080604083850312156115f857600080fd5b611601836114e1565b915061159f602084016114e1565b600181811c9082168061162357607f821691505b60208210810361164357634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156103f6576103f6611649565b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b8152600083516116a481601785016020880161148a565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516116d581602884016020880161148a565b01602801949350505050565b634e487b7160e01b600052603260045260246000fd5b80820281158282048414176103f6576103f6611649565b634e487b7160e01b600052604160045260246000fd5b60008161173357611733611649565b506000190190565b818103818111156103f6576103f6611649565b634e487b7160e01b600052603160045260246000fdfe45524332305072657365744d696e7465725061757365723a206d75737420686165d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862addf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220869bafd8796afcbd2b83d9ab479f7920e24272bf48f6b43b28917d060a789e4d64736f6c63430008110033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101845760003560e01c806370a08231116100d9578063a457c2d711610087578063a457c2d714610336578063a9059cbb14610349578063ca15c8731461035c578063d53913931461036f578063d547741f14610396578063dd62ed3e146103a9578063e63ab1e9146103bc57600080fd5b806370a08231146102a457806379cc6790146102cd5780638456cb59146102e05780639010d07c146102e857806391d148541461031357806395d89b4114610326578063a217fddf1461032e57600080fd5b8063313ce56711610136578063313ce5671461023657806336568abe1461024557806339509351146102585780633f4ba83a1461026b57806340c10f191461027357806342966c68146102865780635c975abb1461029957600080fd5b806301ffc9a71461018957806306fdde03146101b1578063095ea7b3146101c657806318160ddd146101d957806323b872dd146101eb578063248a9ca3146101fe5780632f2ff15d14610221575b600080fd5b61019c610197366004611460565b6103d1565b60405190151581526020015b60405180910390f35b6101b96103fc565b6040516101a891906114ae565b61019c6101d43660046114fd565b61048e565b6004545b6040519081526020016101a8565b61019c6101f9366004611527565b6104a6565b6101dd61020c366004611563565b60009081526020819052604090206001015490565b61023461022f36600461157c565b6104ca565b005b604051601281526020016101a8565b61023461025336600461157c565b6104f4565b61019c6102663660046114fd565b610577565b610234610599565b6102346102813660046114fd565b610617565b610234610294366004611563565b6106a4565b60075460ff1661019c565b6101dd6102b23660046115a8565b6001600160a01b031660009081526002602052604090205490565b6102346102db3660046114fd565b6106b1565b6102346106c6565b6102fb6102f63660046115c3565b610740565b6040516001600160a01b0390911681526020016101a8565b61019c61032136600461157c565b61075f565b6101b9610788565b6101dd600081565b61019c6103443660046114fd565b610797565b61019c6103573660046114fd565b610812565b6101dd61036a366004611563565b610820565b6101dd7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b6102346103a436600461157c565b610837565b6101dd6103b73660046115e5565b61085c565b6101dd60008051602061178583398151915281565b60006001600160e01b03198216635a05180f60e01b14806103f657506103f682610920565b92915050565b60606005805461040b9061160f565b80601f01602080910402602001604051908101604052809291908181526020018280546104379061160f565b80156104845780601f1061045957610100808354040283529160200191610484565b820191906000526020600020905b81548152906001019060200180831161046757829003601f168201915b5050505050905090565b60003361049c818585610955565b5060019392505050565b6000336104b4858285610a79565b6104bf858585610af3565b506001949350505050565b6000828152602081905260409020600101546104e581610c97565b6104ef8383610ca1565b505050565b6001600160a01b03811633146105695760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b6105738282610cc3565b5050565b60003361049c81858561058a838361085c565b610594919061165f565b610955565b6105b16000805160206117858339815191523361075f565b61060d5760405162461bcd60e51b8152602060048201526039602482015260008051602061176583398151915260448201527876652070617573657220726f6c6520746f20756e706175736560381b6064820152608401610560565b610615610ce5565b565b6106417f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a63361075f565b61069a5760405162461bcd60e51b815260206004820152603660248201526000805160206117658339815191526044820152751d99481b5a5b9d195c881c9bdb19481d1bc81b5a5b9d60521b6064820152608401610560565b6105738282610d37565b6106ae3382610df2565b50565b6106bc823383610a79565b6105738282610df2565b6106de6000805160206117858339815191523361075f565b6107385760405162461bcd60e51b8152602060048201526037602482015260008051602061176583398151915260448201527676652070617573657220726f6c6520746f20706175736560481b6064820152608401610560565b610615610f20565b60008281526001602052604081206107589083610f5d565b9392505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60606006805461040b9061160f565b600033816107a5828661085c565b9050838110156108055760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610560565b6104bf8286868403610955565b60003361049c818585610af3565b60008181526001602052604081206103f690610f69565b60008281526020819052604090206001015461085281610c97565b6104ef8383610cc3565b6001600160a01b03918216600090815260036020908152604080832093909416825291909152205490565b610891828261075f565b610573576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556108c73390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000610758836001600160a01b038416610f73565b60006001600160e01b03198216637965db0b60e01b14806103f657506301ffc9a760e01b6001600160e01b03198316146103f6565b6001600160a01b0383166109b75760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610560565b6001600160a01b038216610a185760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610560565b6001600160a01b0383811660008181526003602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6000610a85848461085c565b90506000198114610aed5781811015610ae05760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610560565b610aed8484848403610955565b50505050565b6001600160a01b038316610b575760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610560565b6001600160a01b038216610bb95760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610560565b610bc4838383610fc2565b6001600160a01b03831660009081526002602052604090205481811015610c3c5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610560565b6001600160a01b0380851660008181526002602052604080822086860390559286168082529083902080548601905591516000805160206117a583398151915290610c8a9086815260200190565b60405180910390a3610aed565b6106ae8133610fcd565b610cab8282610887565b60008281526001602052604090206104ef908261090b565b610ccd8282611026565b60008281526001602052604090206104ef908261108b565b610ced6110a0565b6007805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6001600160a01b038216610d8d5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610560565b610d9960008383610fc2565b8060046000828254610dab919061165f565b90915550506001600160a01b0382166000818152600260209081526040808320805486019055518481526000805160206117a5833981519152910160405180910390a35050565b6001600160a01b038216610e525760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610560565b610e5e82600083610fc2565b6001600160a01b03821660009081526002602052604090205481811015610ed25760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610560565b6001600160a01b03831660008181526002602090815260408083208686039055600480548790039055518581529192916000805160206117a5833981519152910160405180910390a3505050565b610f286110e9565b6007805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610d1a3390565b6000610758838361112f565b60006103f6825490565b6000818152600183016020526040812054610fba575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556103f6565b5060006103f6565b6104ef838383611159565b610fd7828261075f565b61057357610fe4816111bf565b610fef8360206111d1565b604051602001611000929190611672565b60408051601f198184030181529082905262461bcd60e51b8252610560916004016114ae565b611030828261075f565b15610573576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000610758836001600160a01b03841661136d565b60075460ff166106155760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610560565b60075460ff16156106155760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610560565b6000826000018281548110611146576111466116e1565b9060005260206000200154905092915050565b60075460ff16156104ef5760405162461bcd60e51b815260206004820152602a60248201527f45524332305061757361626c653a20746f6b656e207472616e736665722077686044820152691a5b19481c185d5cd95960b21b6064820152608401610560565b60606103f66001600160a01b03831660145b606060006111e08360026116f7565b6111eb90600261165f565b67ffffffffffffffff8111156112035761120361170e565b6040519080825280601f01601f19166020018201604052801561122d576020820181803683370190505b509050600360fc1b81600081518110611248576112486116e1565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110611277576112776116e1565b60200101906001600160f81b031916908160001a905350600061129b8460026116f7565b6112a690600161165f565b90505b600181111561131e576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106112da576112da6116e1565b1a60f81b8282815181106112f0576112f06116e1565b60200101906001600160f81b031916908160001a90535060049490941c9361131781611724565b90506112a9565b5083156107585760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610560565b6000818152600183016020526040812054801561145657600061139160018361173b565b85549091506000906113a59060019061173b565b905081811461140a5760008660000182815481106113c5576113c56116e1565b90600052602060002001549050808760000184815481106113e8576113e86116e1565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061141b5761141b61174e565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506103f6565b60009150506103f6565b60006020828403121561147257600080fd5b81356001600160e01b03198116811461075857600080fd5b60005b838110156114a557818101518382015260200161148d565b50506000910152565b60208152600082518060208401526114cd81604085016020870161148a565b601f01601f19169190910160400192915050565b80356001600160a01b03811681146114f857600080fd5b919050565b6000806040838503121561151057600080fd5b611519836114e1565b946020939093013593505050565b60008060006060848603121561153c57600080fd5b611545846114e1565b9250611553602085016114e1565b9150604084013590509250925092565b60006020828403121561157557600080fd5b5035919050565b6000806040838503121561158f57600080fd5b8235915061159f602084016114e1565b90509250929050565b6000602082840312156115ba57600080fd5b610758826114e1565b600080604083850312156115d657600080fd5b50508035926020909101359150565b600080604083850312156115f857600080fd5b611601836114e1565b915061159f602084016114e1565b600181811c9082168061162357607f821691505b60208210810361164357634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156103f6576103f6611649565b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b8152600083516116a481601785016020880161148a565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516116d581602884016020880161148a565b01602801949350505050565b634e487b7160e01b600052603260045260246000fd5b80820281158282048414176103f6576103f6611649565b634e487b7160e01b600052604160045260246000fd5b60008161173357611733611649565b506000190190565b818103818111156103f6576103f6611649565b634e487b7160e01b600052603160045260246000fdfe45524332305072657365744d696e7465725061757365723a206d75737420686165d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862addf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220869bafd8796afcbd2b83d9ab479f7920e24272bf48f6b43b28917d060a789e4d64736f6c63430008110033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var L2StateSenderArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"L2StateSender\",\n \"sourceName\": \"contracts/child/L2StateSender.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"L2StateSynced\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAX_LENGTH\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"counter\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"syncState\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50610297806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806316f198311461004657806361bc221a1461005b578063a6f9885c14610076575b600080fd5b61005961005436600461017a565b61007f565b005b61006460005481565b60405190815260200160405180910390f35b61006461080081565b6001600160a01b0383166100cd5760405162461bcd60e51b815260206004820152601060248201526f24a72b20a624a22fa922a1a2a4ab22a960811b60448201526064015b60405180910390fd5b6108008111156101145760405162461bcd60e51b815260206004820152601260248201527108ab0868a8a88a6be9a82b0be988a9c8ea8960731b60448201526064016100c4565b826001600160a01b0316336001600160a01b031660008081546101369061020b565b9190508190557fedaf3c471ebd67d60c29efe34b639ede7d6a1d92eaeb3f503e784971e67118a5858560405161016d929190610232565b60405180910390a4505050565b60008060006040848603121561018f57600080fd5b83356001600160a01b03811681146101a657600080fd5b9250602084013567ffffffffffffffff808211156101c357600080fd5b818601915086601f8301126101d757600080fd5b8135818111156101e657600080fd5b8760208285010111156101f857600080fd5b6020830194508093505050509250925092565b60006001820161022b57634e487b7160e01b600052601160045260246000fd5b5060010190565b60208152816020820152818360408301376000818301604090810191909152601f909201601f1916010191905056fea264697066735822122041815082e2111df07ce129b83f0000ecca6c4886247dffeae7090f8f048b665164736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106100415760003560e01c806316f198311461004657806361bc221a1461005b578063a6f9885c14610076575b600080fd5b61005961005436600461017a565b61007f565b005b61006460005481565b60405190815260200160405180910390f35b61006461080081565b6001600160a01b0383166100cd5760405162461bcd60e51b815260206004820152601060248201526f24a72b20a624a22fa922a1a2a4ab22a960811b60448201526064015b60405180910390fd5b6108008111156101145760405162461bcd60e51b815260206004820152601260248201527108ab0868a8a88a6be9a82b0be988a9c8ea8960731b60448201526064016100c4565b826001600160a01b0316336001600160a01b031660008081546101369061020b565b9190508190557fedaf3c471ebd67d60c29efe34b639ede7d6a1d92eaeb3f503e784971e67118a5858560405161016d929190610232565b60405180910390a4505050565b60008060006040848603121561018f57600080fd5b83356001600160a01b03811681146101a657600080fd5b9250602084013567ffffffffffffffff808211156101c357600080fd5b818601915086601f8301126101d757600080fd5b8135818111156101e657600080fd5b8760208285010111156101f857600080fd5b6020830194508093505050509250925092565b60006001820161022b57634e487b7160e01b600052601160045260246000fd5b5060010190565b60208152816020820152818360408301376000818301604090810191909152601f909201601f1916010191905056fea264697066735822122041815082e2111df07ce129b83f0000ecca6c4886247dffeae7090f8f048b665164736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var StateReceiverArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"StateReceiver\",\n \"sourceName\": \"contracts/child/StateReceiver.sol\",\n \"abi\": [\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"only\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"Unauthorized\",\n \"type\": \"error\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"startId\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"endId\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bytes32\",\n \"name\": \"root\",\n \"type\": \"bytes32\"\n }\n ],\n \"name\": \"NewCommitment\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"counter\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bool\",\n \"name\": \"status\",\n \"type\": \"bool\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bytes\",\n \"name\": \"message\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"StateSyncResult\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"ALLOWLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"BLOCKLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TOKEN_CONTRACT\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"READ_ADDRESSLIST_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"SYSTEM\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32[][]\",\n \"name\": \"proofs\",\n \"type\": \"bytes32[][]\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"internalType\": \"struct StateReceiver.StateSync[]\",\n \"name\": \"objs\",\n \"type\": \"tuple[]\"\n }\n ],\n \"name\": \"batchExecute\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"components\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"startId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"endId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"root\",\n \"type\": \"bytes32\"\n }\n ],\n \"internalType\": \"struct StateReceiver.StateSyncCommitment\",\n \"name\": \"commitment\",\n \"type\": \"tuple\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"signature\",\n \"type\": \"bytes\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"bitmap\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"commit\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"commitmentCounter\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"commitmentIds\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"commitments\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"startId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"endId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"root\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32[]\",\n \"name\": \"proof\",\n \"type\": \"bytes32[]\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"internalType\": \"struct StateReceiver.StateSync\",\n \"name\": \"obj\",\n \"type\": \"tuple\"\n }\n ],\n \"name\": \"execute\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"getCommitmentByStateSyncId\",\n \"outputs\": [\n {\n \"components\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"startId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"endId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"root\",\n \"type\": \"bytes32\"\n }\n ],\n \"internalType\": \"struct StateReceiver.StateSyncCommitment\",\n \"name\": \"\",\n \"type\": \"tuple\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"getRootByStateSyncId\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"lastCommittedId\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"processedStateSyncs\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b5061148e806100206000396000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c806355b01e4d116100ad578063ad240c2a11610071578063ad240c2a1461026a578063c59a18f714610273578063c6df461714610286578063e0563ab114610299578063eb70ef44146102a257600080fd5b806355b01e4d1461022d5780635ea5df791461023b5780639017c12714610244578063947287cf1461025757806397e5230d1461026057600080fd5b80633b878c22116100f45780633b878c221461018457806349ce89971461018d57806350d5b95b146101d757806351351d53146101ec578063544c5e0f146101fa57600080fd5b806307b3e25214610126578063196f1b2d1461015157806323e281cf14610172578063284017f51461017b575b600080fd5b6101346004600360981b0181565b6040516001600160a01b0390911681526020015b60405180910390f35b61016461015f366004610eee565b6102d7565b604051908152602001610148565b61016460325481565b61013461202081565b61013461101081565b6101bc61019b366004610eee565b60356020526000908152604090208054600182015460029092015490919083565b60408051938452602084019290925290820152606001610148565b6101ea6101e5366004610f52565b610356565b005b6101346002600160a01b0381565b61021d610208366004610eee565b60346020526000908152604090205460ff1681565b6040519015158152602001610148565b6101346004600160991b0181565b61016461138881565b6101ea610252366004610fc1565b61041d565b61016461520881565b610164620249f081565b61016460335481565b610164610281366004610eee565b6105bd565b6101ea61029436600461106d565b6105de565b61013461203081565b6102b56102b0366004610eee565b6107c2565b6040805182518152602080840151908201529181015190820152606001610148565b6000806035816102e8603686610885565b81526020810191909152604001600020600201549050806103505760405162461bcd60e51b815260206004820152601d60248201527f537461746552656365697665723a204e4f5f524f4f545f464f525f494400000060448201526064015b60405180910390fd5b92915050565b600061036282356107c2565b80519091506103d29061037690843561110b565b82516020840151610387919061110b565b61039290600161111e565b83604001518787876040516020016103aa9190611176565b604051602081830303815290604052805190602001206109329095949392919063ffffffff16565b61040e5760405162461bcd60e51b815260206004820152600d60248201526c24a72b20a624a22fa82927a7a360991b6044820152606401610347565b61041782610ace565b50505050565b828181146104805760405162461bcd60e51b815260206004820152602a60248201527f537461746552656365697665723a20554e4d4154434845445f4c454e4754485f604482015269504152414d455445525360b01b6064820152608401610347565b60005b818110156105b55760006104ba8585848181106104a2576104a2611212565b90506020028101906104b49190611228565b356107c2565b9050600061056e82600001518787868181106104d8576104d8611212565b90506020028101906104ea9190611228565b6104f591903561110b565b83516020850151610506919061110b565b61051190600161111e565b84604001518b8b8881811061052857610528611212565b905060200281019061053a9190611248565b8b8b8a81811061054c5761054c611212565b905060200281019061055e9190611228565b6040516020016103aa9190611176565b90508061057f575050600101610483565b6105ab86868581811061059457610594611212565b90506020028101906105a69190611228565b610ace565b5050600101610483565b505050505050565b603681815481106105cd57600080fd5b600091825260209091200154905081565b336002600160a01b03146106225760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b6044820152606401610347565b60335461063090600161111e565b8535146106725760405162461bcd60e51b815260206004820152601060248201526f1253959053125117d4d510549517d25160821b6044820152606401610347565b8435602086013510156106b85760405162461bcd60e51b815260206004820152600e60248201526d1253959053125117d1539117d25160921b6044820152606401610347565b604080518635602080830191909152870135818301529086013560608201526106fd906080016040516020818303038152906040528051906020012085858585610ce9565b6032805486916035916000918261071383611291565b90915550815260208082019290925260409081016000208335815591830135600183015582013560028201555050603680546001810182556000919091526020868101357f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b89092018290556033829055604080519088013581528735917f11efd893530b26afc66d488ff54cb15df117cb6e0e4a08c6dcb166d766c3bf3b910160405180910390a35050505050565b60408051606081018252600080825260208201819052918101829052906107ea603684610885565b603654909150810361084a5760405162461bcd60e51b815260206004820152602360248201527f537461746552656365697665723a204e4f5f434f4d4d49544d454e545f464f5260448201526217d25160ea1b6064820152608401610347565b600090815260356020908152604091829020825160608101845281548152600182015492810192909252600201549181019190915292915050565b8154600090810361089857506000610350565b82546000905b808210156108e55760006108b28383610ded565b600087815260209020909150859082015411156108d1578091506108df565b6108dc81600161111e565b92505b5061089e565b60008211801561091157508361090e8661090060018661110b565b600091825260209091200190565b54145b1561092a5761092160018361110b565b92505050610350565b509392505050565b600081610940866001610e0f565b81146109855760405162461bcd60e51b81526020600482015260146024820152730929cac82989288bea0a49e9e8cbe988a9c8ea8960631b6044820152606401610347565b8587106109c95760405162461bcd60e51b81526020600482015260126024820152710929cac82989288be988a828cbe929c888ab60731b6044820152606401610347565b87610a055760405162461bcd60e51b815260206004820152600c60248201526b24a72b20a624a22fa622a0a360a11b6044820152606401610347565b8760005b82811015610abf576000868683818110610a2557610a25611212565b90506020020135905060028a610a3b91906112c0565b600003610a73576040805160208101859052908101829052606001604051602081830303815290604052805190602001209250610aa0565b60408051602081018390529081018490526060016040516020818303038152906040528051906020012092505b610aab60028b6112d4565b99505080610ab890611291565b9050610a09565b50909414979650505050505050565b803560009081526034602052604090205460ff1615610b3e5760405162461bcd60e51b815260206004820152602660248201527f537461746552656365697665723a2053544154455f53594e435f49535f50524f60448201526510d154d4d15160d21b6064820152608401610347565b610b4e60608201604083016112e8565b6001600160a01b03163b600003610ba2576040805160208082526000908201819052918335917f31c652130602f3ce96ceaf8a4c2b8b49f049166c6fcf2eb31943a75ec7c936ae910160405180910390a350565b8035600090815260346020526040808220805460ff191660011790558190610bd090606085019085016112e8565b6001600160a01b03168335610beb60408601602087016112e8565b610bf86060870187611303565b604051602401610c0b9493929190611349565b60408051601f198184030181529181526020820180516001600160e01b031663eeb4994560e01b17905251610c4091906113a2565b6000604051808303816000865af19150503d8060008114610c7d576040519150601f19603f3d011682016040523d82523d6000602084013e610c82565b606091505b509150915081610ca55782356000908152603460205260409020805460ff191690555b81151583600001357f31c652130602f3ce96ceaf8a4c2b8b49f049166c6fcf2eb31943a75ec7c936ae83604051610cdc91906113b4565b60405180910390a3505050565b6000806120306001600160a01b0316620249f08888888888604051602001610d159594939291906113e7565b60408051601f1981840301815290829052610d2f916113a2565b6000604051808303818686fa925050503d8060008114610d6b576040519150601f19603f3d011682016040523d82523d6000602084013e610d70565b606091505b5091509150600081806020019051810190610d8b9190611420565b9050828015610d975750805b610de35760405162461bcd60e51b815260206004820152601d60248201527f5349474e41545552455f564552494649434154494f4e5f4641494c45440000006044820152606401610347565b5050505050505050565b6000610dfc60028484186112d4565b610e089084841661111e565b9392505050565b600080610e1b84610e5a565b90506001836002811115610e3157610e31611442565b148015610e41575083816001901b105b610e4c576000610e4f565b60015b60ff16019392505050565b600080608083901c15610e6f57608092831c92015b604083901c15610e8157604092831c92015b602083901c15610e9357602092831c92015b601083901c15610ea557601092831c92015b600883901c15610eb757600892831c92015b600483901c15610ec957600492831c92015b600283901c15610edb57600292831c92015b600183901c156103505760010192915050565b600060208284031215610f0057600080fd5b5035919050565b60008083601f840112610f1957600080fd5b5081356001600160401b03811115610f3057600080fd5b6020830191508360208260051b8501011115610f4b57600080fd5b9250929050565b600080600060408486031215610f6757600080fd5b83356001600160401b0380821115610f7e57600080fd5b610f8a87838801610f07565b90955093506020860135915080821115610fa357600080fd5b50840160808187031215610fb657600080fd5b809150509250925092565b60008060008060408587031215610fd757600080fd5b84356001600160401b0380821115610fee57600080fd5b610ffa88838901610f07565b9096509450602087013591508082111561101357600080fd5b5061102087828801610f07565b95989497509550505050565b60008083601f84011261103e57600080fd5b5081356001600160401b0381111561105557600080fd5b602083019150836020828501011115610f4b57600080fd5b600080600080600085870360a081121561108657600080fd5b606081121561109457600080fd5b5085945060608601356001600160401b03808211156110b257600080fd5b6110be89838a0161102c565b909650945060808801359150808211156110d757600080fd5b506110e48882890161102c565b969995985093965092949392505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610350576103506110f5565b80820180821115610350576103506110f5565b80356001600160a01b038116811461114857600080fd5b919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6020815281356020820152600061118f60208401611131565b60018060a01b038082166040850152806111ab60408701611131565b16606085015250506060830135601e198436030181126111ca57600080fd5b83016020810190356001600160401b038111156111e657600080fd5b8036038213156111f557600080fd5b60808085015261120960a08501828461114d565b95945050505050565b634e487b7160e01b600052603260045260246000fd5b60008235607e1983360301811261123e57600080fd5b9190910192915050565b6000808335601e1984360301811261125f57600080fd5b8301803591506001600160401b0382111561127957600080fd5b6020019150600581901b3603821315610f4b57600080fd5b6000600182016112a3576112a36110f5565b5060010190565b634e487b7160e01b600052601260045260246000fd5b6000826112cf576112cf6112aa565b500690565b6000826112e3576112e36112aa565b500490565b6000602082840312156112fa57600080fd5b610e0882611131565b6000808335601e1984360301811261131a57600080fd5b8301803591506001600160401b0382111561133457600080fd5b602001915036819003821315610f4b57600080fd5b8481526001600160a01b0384166020820152606060408201819052600090611374908301848661114d565b9695505050505050565b60005b83811015611399578181015183820152602001611381565b50506000910152565b6000825161123e81846020870161137e565b60208152600082518060208401526113d381604085016020870161137e565b601f01601f19169190910160400192915050565b85815260606020820152600061140160608301868861114d565b828103604084015261141481858761114d565b98975050505050505050565b60006020828403121561143257600080fd5b81518015158114610e0857600080fd5b634e487b7160e01b600052602160045260246000fdfea2646970667358221220b20879873df719d87d6f5bd189c1e73b75a62db3cf5246e748eddebe4b54eacd64736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101215760003560e01c806355b01e4d116100ad578063ad240c2a11610071578063ad240c2a1461026a578063c59a18f714610273578063c6df461714610286578063e0563ab114610299578063eb70ef44146102a257600080fd5b806355b01e4d1461022d5780635ea5df791461023b5780639017c12714610244578063947287cf1461025757806397e5230d1461026057600080fd5b80633b878c22116100f45780633b878c221461018457806349ce89971461018d57806350d5b95b146101d757806351351d53146101ec578063544c5e0f146101fa57600080fd5b806307b3e25214610126578063196f1b2d1461015157806323e281cf14610172578063284017f51461017b575b600080fd5b6101346004600360981b0181565b6040516001600160a01b0390911681526020015b60405180910390f35b61016461015f366004610eee565b6102d7565b604051908152602001610148565b61016460325481565b61013461202081565b61013461101081565b6101bc61019b366004610eee565b60356020526000908152604090208054600182015460029092015490919083565b60408051938452602084019290925290820152606001610148565b6101ea6101e5366004610f52565b610356565b005b6101346002600160a01b0381565b61021d610208366004610eee565b60346020526000908152604090205460ff1681565b6040519015158152602001610148565b6101346004600160991b0181565b61016461138881565b6101ea610252366004610fc1565b61041d565b61016461520881565b610164620249f081565b61016460335481565b610164610281366004610eee565b6105bd565b6101ea61029436600461106d565b6105de565b61013461203081565b6102b56102b0366004610eee565b6107c2565b6040805182518152602080840151908201529181015190820152606001610148565b6000806035816102e8603686610885565b81526020810191909152604001600020600201549050806103505760405162461bcd60e51b815260206004820152601d60248201527f537461746552656365697665723a204e4f5f524f4f545f464f525f494400000060448201526064015b60405180910390fd5b92915050565b600061036282356107c2565b80519091506103d29061037690843561110b565b82516020840151610387919061110b565b61039290600161111e565b83604001518787876040516020016103aa9190611176565b604051602081830303815290604052805190602001206109329095949392919063ffffffff16565b61040e5760405162461bcd60e51b815260206004820152600d60248201526c24a72b20a624a22fa82927a7a360991b6044820152606401610347565b61041782610ace565b50505050565b828181146104805760405162461bcd60e51b815260206004820152602a60248201527f537461746552656365697665723a20554e4d4154434845445f4c454e4754485f604482015269504152414d455445525360b01b6064820152608401610347565b60005b818110156105b55760006104ba8585848181106104a2576104a2611212565b90506020028101906104b49190611228565b356107c2565b9050600061056e82600001518787868181106104d8576104d8611212565b90506020028101906104ea9190611228565b6104f591903561110b565b83516020850151610506919061110b565b61051190600161111e565b84604001518b8b8881811061052857610528611212565b905060200281019061053a9190611248565b8b8b8a81811061054c5761054c611212565b905060200281019061055e9190611228565b6040516020016103aa9190611176565b90508061057f575050600101610483565b6105ab86868581811061059457610594611212565b90506020028101906105a69190611228565b610ace565b5050600101610483565b505050505050565b603681815481106105cd57600080fd5b600091825260209091200154905081565b336002600160a01b03146106225760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b6044820152606401610347565b60335461063090600161111e565b8535146106725760405162461bcd60e51b815260206004820152601060248201526f1253959053125117d4d510549517d25160821b6044820152606401610347565b8435602086013510156106b85760405162461bcd60e51b815260206004820152600e60248201526d1253959053125117d1539117d25160921b6044820152606401610347565b604080518635602080830191909152870135818301529086013560608201526106fd906080016040516020818303038152906040528051906020012085858585610ce9565b6032805486916035916000918261071383611291565b90915550815260208082019290925260409081016000208335815591830135600183015582013560028201555050603680546001810182556000919091526020868101357f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b89092018290556033829055604080519088013581528735917f11efd893530b26afc66d488ff54cb15df117cb6e0e4a08c6dcb166d766c3bf3b910160405180910390a35050505050565b60408051606081018252600080825260208201819052918101829052906107ea603684610885565b603654909150810361084a5760405162461bcd60e51b815260206004820152602360248201527f537461746552656365697665723a204e4f5f434f4d4d49544d454e545f464f5260448201526217d25160ea1b6064820152608401610347565b600090815260356020908152604091829020825160608101845281548152600182015492810192909252600201549181019190915292915050565b8154600090810361089857506000610350565b82546000905b808210156108e55760006108b28383610ded565b600087815260209020909150859082015411156108d1578091506108df565b6108dc81600161111e565b92505b5061089e565b60008211801561091157508361090e8661090060018661110b565b600091825260209091200190565b54145b1561092a5761092160018361110b565b92505050610350565b509392505050565b600081610940866001610e0f565b81146109855760405162461bcd60e51b81526020600482015260146024820152730929cac82989288bea0a49e9e8cbe988a9c8ea8960631b6044820152606401610347565b8587106109c95760405162461bcd60e51b81526020600482015260126024820152710929cac82989288be988a828cbe929c888ab60731b6044820152606401610347565b87610a055760405162461bcd60e51b815260206004820152600c60248201526b24a72b20a624a22fa622a0a360a11b6044820152606401610347565b8760005b82811015610abf576000868683818110610a2557610a25611212565b90506020020135905060028a610a3b91906112c0565b600003610a73576040805160208101859052908101829052606001604051602081830303815290604052805190602001209250610aa0565b60408051602081018390529081018490526060016040516020818303038152906040528051906020012092505b610aab60028b6112d4565b99505080610ab890611291565b9050610a09565b50909414979650505050505050565b803560009081526034602052604090205460ff1615610b3e5760405162461bcd60e51b815260206004820152602660248201527f537461746552656365697665723a2053544154455f53594e435f49535f50524f60448201526510d154d4d15160d21b6064820152608401610347565b610b4e60608201604083016112e8565b6001600160a01b03163b600003610ba2576040805160208082526000908201819052918335917f31c652130602f3ce96ceaf8a4c2b8b49f049166c6fcf2eb31943a75ec7c936ae910160405180910390a350565b8035600090815260346020526040808220805460ff191660011790558190610bd090606085019085016112e8565b6001600160a01b03168335610beb60408601602087016112e8565b610bf86060870187611303565b604051602401610c0b9493929190611349565b60408051601f198184030181529181526020820180516001600160e01b031663eeb4994560e01b17905251610c4091906113a2565b6000604051808303816000865af19150503d8060008114610c7d576040519150601f19603f3d011682016040523d82523d6000602084013e610c82565b606091505b509150915081610ca55782356000908152603460205260409020805460ff191690555b81151583600001357f31c652130602f3ce96ceaf8a4c2b8b49f049166c6fcf2eb31943a75ec7c936ae83604051610cdc91906113b4565b60405180910390a3505050565b6000806120306001600160a01b0316620249f08888888888604051602001610d159594939291906113e7565b60408051601f1981840301815290829052610d2f916113a2565b6000604051808303818686fa925050503d8060008114610d6b576040519150601f19603f3d011682016040523d82523d6000602084013e610d70565b606091505b5091509150600081806020019051810190610d8b9190611420565b9050828015610d975750805b610de35760405162461bcd60e51b815260206004820152601d60248201527f5349474e41545552455f564552494649434154494f4e5f4641494c45440000006044820152606401610347565b5050505050505050565b6000610dfc60028484186112d4565b610e089084841661111e565b9392505050565b600080610e1b84610e5a565b90506001836002811115610e3157610e31611442565b148015610e41575083816001901b105b610e4c576000610e4f565b60015b60ff16019392505050565b600080608083901c15610e6f57608092831c92015b604083901c15610e8157604092831c92015b602083901c15610e9357602092831c92015b601083901c15610ea557601092831c92015b600883901c15610eb757600892831c92015b600483901c15610ec957600492831c92015b600283901c15610edb57600292831c92015b600183901c156103505760010192915050565b600060208284031215610f0057600080fd5b5035919050565b60008083601f840112610f1957600080fd5b5081356001600160401b03811115610f3057600080fd5b6020830191508360208260051b8501011115610f4b57600080fd5b9250929050565b600080600060408486031215610f6757600080fd5b83356001600160401b0380821115610f7e57600080fd5b610f8a87838801610f07565b90955093506020860135915080821115610fa357600080fd5b50840160808187031215610fb657600080fd5b809150509250925092565b60008060008060408587031215610fd757600080fd5b84356001600160401b0380821115610fee57600080fd5b610ffa88838901610f07565b9096509450602087013591508082111561101357600080fd5b5061102087828801610f07565b95989497509550505050565b60008083601f84011261103e57600080fd5b5081356001600160401b0381111561105557600080fd5b602083019150836020828501011115610f4b57600080fd5b600080600080600085870360a081121561108657600080fd5b606081121561109457600080fd5b5085945060608601356001600160401b03808211156110b257600080fd5b6110be89838a0161102c565b909650945060808801359150808211156110d757600080fd5b506110e48882890161102c565b969995985093965092949392505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610350576103506110f5565b80820180821115610350576103506110f5565b80356001600160a01b038116811461114857600080fd5b919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6020815281356020820152600061118f60208401611131565b60018060a01b038082166040850152806111ab60408701611131565b16606085015250506060830135601e198436030181126111ca57600080fd5b83016020810190356001600160401b038111156111e657600080fd5b8036038213156111f557600080fd5b60808085015261120960a08501828461114d565b95945050505050565b634e487b7160e01b600052603260045260246000fd5b60008235607e1983360301811261123e57600080fd5b9190910192915050565b6000808335601e1984360301811261125f57600080fd5b8301803591506001600160401b0382111561127957600080fd5b6020019150600581901b3603821315610f4b57600080fd5b6000600182016112a3576112a36110f5565b5060010190565b634e487b7160e01b600052601260045260246000fd5b6000826112cf576112cf6112aa565b500690565b6000826112e3576112e36112aa565b500490565b6000602082840312156112fa57600080fd5b610e0882611131565b6000808335601e1984360301811261131a57600080fd5b8301803591506001600160401b0382111561133457600080fd5b602001915036819003821315610f4b57600080fd5b8481526001600160a01b0384166020820152606060408201819052600090611374908301848661114d565b9695505050505050565b60005b83811015611399578181015183820152602001611381565b50506000910152565b6000825161123e81846020870161137e565b60208152600082518060208401526113d381604085016020870161137e565b601f01601f19169190910160400192915050565b85815260606020820152600061140160608301868861114d565b828103604084015261141481858761114d565b98975050505050505050565b60006020828403121561143257600080fd5b81518015158114610e0857600080fd5b634e487b7160e01b600052602160045260246000fdfea2646970667358221220b20879873df719d87d6f5bd189c1e73b75a62db3cf5246e748eddebe4b54eacd64736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var NativeERC20Artifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"NativeERC20\",\n \"sourceName\": \"contracts/child/NativeERC20.sol\",\n \"abi\": [\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"only\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"Unauthorized\",\n \"type\": \"error\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Approval\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Transfer\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"ALLOWLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"BLOCKLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TOKEN_CONTRACT\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"READ_ADDRESSLIST_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"SYSTEM\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"allowance\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"approve\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"balanceOf\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"burn\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"decimals\",\n \"outputs\": [\n {\n \"internalType\": \"uint8\",\n \"name\": \"\",\n \"type\": \"uint8\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"subtractedValue\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"decreaseAllowance\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"addedValue\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"increaseAllowance\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"predicate_\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"rootToken_\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"string\",\n \"name\": \"name_\",\n \"type\": \"string\"\n },\n {\n \"internalType\": \"string\",\n \"name\": \"symbol_\",\n \"type\": \"string\"\n },\n {\n \"internalType\": \"uint8\",\n \"name\": \"decimals_\",\n \"type\": \"uint8\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenSupply_\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"mint\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"name\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"rootToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"symbol\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"totalSupply\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transfer\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transferFrom\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b5061121c806100206000396000f3fe608060405234801561001057600080fd5b50600436106101635760003560e01c806355b01e4d116100ce57806397e5230d1161008757806397e5230d146102b85780639dc29fac146102c2578063a457c2d7146102d5578063a9059cbb146102e8578063dd62ed3e146102fb578063e0563ab11461030e578063e61987051461031757600080fd5b806355b01e4d146102605780635ea5df791461026e57806370a0823114610277578063740b08dc14610292578063947287cf146102a757806395d89b41146102b057600080fd5b8063284017f511610120578063284017f514610205578063313ce5671461020e57806339509351146102235780633b878c221461023657806340c10f191461023f57806351351d531461025257600080fd5b806306fdde031461016857806307b3e25214610186578063095ea7b3146101ac57806318160ddd146101cf5780631f2d0065146101e157806323b872dd146101f2575b600080fd5b610170610328565b60405161017d9190610d4d565b60405180910390f35b6101946004600360981b0181565b6040516001600160a01b03909116815260200161017d565b6101bf6101ba366004610d9c565b6103ba565b604051901515815260200161017d565b6034545b60405190815260200161017d565b6036546001600160a01b0316610194565b6101bf610200366004610dc6565b6103d4565b61019461202081565b60395460405160ff909116815260200161017d565b6101bf610231366004610d9c565b6103f8565b61019461101081565b6101bf61024d366004610d9c565b61041a565b6101946002600160a01b0381565b6101946004600160991b0181565b6101d361138881565b6101d3610285366004610e02565b6001600160a01b03163190565b6102a56102a0366004610e6d565b610463565b005b6101d361520881565b610170610618565b6101d3620249f081565b6101bf6102d0366004610d9c565b610627565b6101bf6102e3366004610d9c565b61065e565b6101bf6102f6366004610d9c565b6106d9565b6101d3610309366004610f21565b6106e7565b61019461203081565b6035546001600160a01b0316610194565b60606037805461033790610f54565b80601f016020809104026020016040519081016040528092919081815260200182805461036390610f54565b80156103b05780601f10610385576101008083540402835291602001916103b0565b820191906000526020600020905b81548152906001019060200180831161039357829003601f168201915b5050505050905090565b6000336103c8818585610712565b60019150505b92915050565b6000336103e2858285610836565b6103ed8585856108b0565b506001949350505050565b6000336103c881858561040b83836106e7565b6104159190610fa4565b610712565b6035546000906001600160a01b031633146104505760405162461bcd60e51b815260040161044790610fb7565b60405180910390fd5b61045a8383610a75565b50600192915050565b600054610100900460ff16158080156104835750600054600160ff909116105b8061049d5750303b15801561049d575060005460ff166001145b6105005760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610447565b6000805460ff191660011790558015610523576000805461ff0019166101001790555b336002600160a01b03146105675760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b6044820152606401610447565b603580546001600160a01b03808c166001600160a01b03199283161790925560368054928b169290911691909117905560376105a4878983611060565b5060386105b2858783611060565b506039805460ff191660ff85161790556034829055801561060d576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050505050565b60606038805461033790610f54565b6035546000906001600160a01b031633146106545760405162461bcd60e51b815260040161044790610fb7565b61045a8383610bcf565b6000338161066c82866106e7565b9050838110156106cc5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610447565b6103ed8286868403610712565b6000336103c88185856108b0565b6001600160a01b03918216600090815260336020908152604080832093909416825291909152205490565b6001600160a01b0383166107745760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610447565b6001600160a01b0382166107d55760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610447565b6001600160a01b0383811660008181526033602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061084284846106e7565b905060001981146108aa578181101561089d5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610447565b6108aa8484848403610712565b50505050565b6001600160a01b0383166109145760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610447565b6001600160a01b0382166109765760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610447565b6000806120206001600160a01b031685858560405160200161099a93929190611121565b60408051601f19818403018152908290526109b491611145565b6000604051808303816000865af19150503d80600081146109f1576040519150601f19603f3d011682016040523d82523d6000602084013e6109f6565b606091505b5091509150818015610a17575080806020019051810190610a179190611161565b610a335760405162461bcd60e51b815260040161044790611183565b836001600160a01b0316856001600160a01b03166000805160206111c783398151915285604051610a6691815260200190565b60405180910390a35050505050565b6001600160a01b038216610acb5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610447565b8060346000828254610add9190610fa4565b9091555050604051600090819061202090610b0090839087908790602001611121565b60408051601f1981840301815290829052610b1a91611145565b6000604051808303816000865af19150503d8060008114610b57576040519150601f19603f3d011682016040523d82523d6000602084013e610b5c565b606091505b5091509150818015610b7d575080806020019051810190610b7d9190611161565b610b995760405162461bcd60e51b815260040161044790611183565b6040518381526001600160a01b038516906000906000805160206111c7833981519152906020015b60405180910390a350505050565b6001600160a01b038216610c2f5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610447565b8060346000828254610c4191906111b3565b9091555050604051600090819061202090610c6490869084908790602001611121565b60408051601f1981840301815290829052610c7e91611145565b6000604051808303816000865af19150503d8060008114610cbb576040519150601f19603f3d011682016040523d82523d6000602084013e610cc0565b606091505b5091509150818015610ce1575080806020019051810190610ce19190611161565b610cfd5760405162461bcd60e51b815260040161044790611183565b6040518381526000906001600160a01b038616906000805160206111c783398151915290602001610bc1565b60005b83811015610d44578181015183820152602001610d2c565b50506000910152565b6020815260008251806020840152610d6c816040850160208701610d29565b601f01601f19169190910160400192915050565b80356001600160a01b0381168114610d9757600080fd5b919050565b60008060408385031215610daf57600080fd5b610db883610d80565b946020939093013593505050565b600080600060608486031215610ddb57600080fd5b610de484610d80565b9250610df260208501610d80565b9150604084013590509250925092565b600060208284031215610e1457600080fd5b610e1d82610d80565b9392505050565b60008083601f840112610e3657600080fd5b50813567ffffffffffffffff811115610e4e57600080fd5b602083019150836020828501011115610e6657600080fd5b9250929050565b60008060008060008060008060c0898b031215610e8957600080fd5b610e9289610d80565b9750610ea060208a01610d80565b9650604089013567ffffffffffffffff80821115610ebd57600080fd5b610ec98c838d01610e24565b909850965060608b0135915080821115610ee257600080fd5b50610eef8b828c01610e24565b909550935050608089013560ff81168114610f0957600080fd5b8092505060a089013590509295985092959890939650565b60008060408385031215610f3457600080fd5b610f3d83610d80565b9150610f4b60208401610d80565b90509250929050565b600181811c90821680610f6857607f821691505b602082108103610f8857634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156103ce576103ce610f8e565b60208082526024908201527f4e617469766545524332303a204f6e6c79207072656469636174652063616e2060408201526318d85b1b60e21b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b601f82111561105b57600081815260208120601f850160051c810160208610156110385750805b601f850160051c820191505b8181101561105757828155600101611044565b5050505b505050565b67ffffffffffffffff83111561107857611078610ffb565b61108c836110868354610f54565b83611011565b6000601f8411600181146110c057600085156110a85750838201355b600019600387901b1c1916600186901b17835561111a565b600083815260209020601f19861690835b828110156110f157868501358255602094850194600190920191016110d1565b508682101561110e5760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b60008251611157818460208701610d29565b9190910192915050565b60006020828403121561117357600080fd5b81518015158114610e1d57600080fd5b60208082526016908201527514149150d3d35412531157d0d0531317d1905253115160521b604082015260600190565b818103818111156103ce576103ce610f8e56feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220eff294dba2996c4337f07acdacd5b73dff2185b61e8f1aa3c312a46098b8b16e64736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101635760003560e01c806355b01e4d116100ce57806397e5230d1161008757806397e5230d146102b85780639dc29fac146102c2578063a457c2d7146102d5578063a9059cbb146102e8578063dd62ed3e146102fb578063e0563ab11461030e578063e61987051461031757600080fd5b806355b01e4d146102605780635ea5df791461026e57806370a0823114610277578063740b08dc14610292578063947287cf146102a757806395d89b41146102b057600080fd5b8063284017f511610120578063284017f514610205578063313ce5671461020e57806339509351146102235780633b878c221461023657806340c10f191461023f57806351351d531461025257600080fd5b806306fdde031461016857806307b3e25214610186578063095ea7b3146101ac57806318160ddd146101cf5780631f2d0065146101e157806323b872dd146101f2575b600080fd5b610170610328565b60405161017d9190610d4d565b60405180910390f35b6101946004600360981b0181565b6040516001600160a01b03909116815260200161017d565b6101bf6101ba366004610d9c565b6103ba565b604051901515815260200161017d565b6034545b60405190815260200161017d565b6036546001600160a01b0316610194565b6101bf610200366004610dc6565b6103d4565b61019461202081565b60395460405160ff909116815260200161017d565b6101bf610231366004610d9c565b6103f8565b61019461101081565b6101bf61024d366004610d9c565b61041a565b6101946002600160a01b0381565b6101946004600160991b0181565b6101d361138881565b6101d3610285366004610e02565b6001600160a01b03163190565b6102a56102a0366004610e6d565b610463565b005b6101d361520881565b610170610618565b6101d3620249f081565b6101bf6102d0366004610d9c565b610627565b6101bf6102e3366004610d9c565b61065e565b6101bf6102f6366004610d9c565b6106d9565b6101d3610309366004610f21565b6106e7565b61019461203081565b6035546001600160a01b0316610194565b60606037805461033790610f54565b80601f016020809104026020016040519081016040528092919081815260200182805461036390610f54565b80156103b05780601f10610385576101008083540402835291602001916103b0565b820191906000526020600020905b81548152906001019060200180831161039357829003601f168201915b5050505050905090565b6000336103c8818585610712565b60019150505b92915050565b6000336103e2858285610836565b6103ed8585856108b0565b506001949350505050565b6000336103c881858561040b83836106e7565b6104159190610fa4565b610712565b6035546000906001600160a01b031633146104505760405162461bcd60e51b815260040161044790610fb7565b60405180910390fd5b61045a8383610a75565b50600192915050565b600054610100900460ff16158080156104835750600054600160ff909116105b8061049d5750303b15801561049d575060005460ff166001145b6105005760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610447565b6000805460ff191660011790558015610523576000805461ff0019166101001790555b336002600160a01b03146105675760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b6044820152606401610447565b603580546001600160a01b03808c166001600160a01b03199283161790925560368054928b169290911691909117905560376105a4878983611060565b5060386105b2858783611060565b506039805460ff191660ff85161790556034829055801561060d576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050505050565b60606038805461033790610f54565b6035546000906001600160a01b031633146106545760405162461bcd60e51b815260040161044790610fb7565b61045a8383610bcf565b6000338161066c82866106e7565b9050838110156106cc5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610447565b6103ed8286868403610712565b6000336103c88185856108b0565b6001600160a01b03918216600090815260336020908152604080832093909416825291909152205490565b6001600160a01b0383166107745760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610447565b6001600160a01b0382166107d55760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610447565b6001600160a01b0383811660008181526033602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061084284846106e7565b905060001981146108aa578181101561089d5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610447565b6108aa8484848403610712565b50505050565b6001600160a01b0383166109145760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610447565b6001600160a01b0382166109765760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610447565b6000806120206001600160a01b031685858560405160200161099a93929190611121565b60408051601f19818403018152908290526109b491611145565b6000604051808303816000865af19150503d80600081146109f1576040519150601f19603f3d011682016040523d82523d6000602084013e6109f6565b606091505b5091509150818015610a17575080806020019051810190610a179190611161565b610a335760405162461bcd60e51b815260040161044790611183565b836001600160a01b0316856001600160a01b03166000805160206111c783398151915285604051610a6691815260200190565b60405180910390a35050505050565b6001600160a01b038216610acb5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610447565b8060346000828254610add9190610fa4565b9091555050604051600090819061202090610b0090839087908790602001611121565b60408051601f1981840301815290829052610b1a91611145565b6000604051808303816000865af19150503d8060008114610b57576040519150601f19603f3d011682016040523d82523d6000602084013e610b5c565b606091505b5091509150818015610b7d575080806020019051810190610b7d9190611161565b610b995760405162461bcd60e51b815260040161044790611183565b6040518381526001600160a01b038516906000906000805160206111c7833981519152906020015b60405180910390a350505050565b6001600160a01b038216610c2f5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610447565b8060346000828254610c4191906111b3565b9091555050604051600090819061202090610c6490869084908790602001611121565b60408051601f1981840301815290829052610c7e91611145565b6000604051808303816000865af19150503d8060008114610cbb576040519150601f19603f3d011682016040523d82523d6000602084013e610cc0565b606091505b5091509150818015610ce1575080806020019051810190610ce19190611161565b610cfd5760405162461bcd60e51b815260040161044790611183565b6040518381526000906001600160a01b038616906000805160206111c783398151915290602001610bc1565b60005b83811015610d44578181015183820152602001610d2c565b50506000910152565b6020815260008251806020840152610d6c816040850160208701610d29565b601f01601f19169190910160400192915050565b80356001600160a01b0381168114610d9757600080fd5b919050565b60008060408385031215610daf57600080fd5b610db883610d80565b946020939093013593505050565b600080600060608486031215610ddb57600080fd5b610de484610d80565b9250610df260208501610d80565b9150604084013590509250925092565b600060208284031215610e1457600080fd5b610e1d82610d80565b9392505050565b60008083601f840112610e3657600080fd5b50813567ffffffffffffffff811115610e4e57600080fd5b602083019150836020828501011115610e6657600080fd5b9250929050565b60008060008060008060008060c0898b031215610e8957600080fd5b610e9289610d80565b9750610ea060208a01610d80565b9650604089013567ffffffffffffffff80821115610ebd57600080fd5b610ec98c838d01610e24565b909850965060608b0135915080821115610ee257600080fd5b50610eef8b828c01610e24565b909550935050608089013560ff81168114610f0957600080fd5b8092505060a089013590509295985092959890939650565b60008060408385031215610f3457600080fd5b610f3d83610d80565b9150610f4b60208401610d80565b90509250929050565b600181811c90821680610f6857607f821691505b602082108103610f8857634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156103ce576103ce610f8e565b60208082526024908201527f4e617469766545524332303a204f6e6c79207072656469636174652063616e2060408201526318d85b1b60e21b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b601f82111561105b57600081815260208120601f850160051c810160208610156110385750805b601f850160051c820191505b8181101561105757828155600101611044565b5050505b505050565b67ffffffffffffffff83111561107857611078610ffb565b61108c836110868354610f54565b83611011565b6000601f8411600181146110c057600085156110a85750838201355b600019600387901b1c1916600186901b17835561111a565b600083815260209020601f19861690835b828110156110f157868501358255602094850194600190920191016110d1565b508682101561110e5760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b60008251611157818460208701610d29565b9190910192915050565b60006020828403121561117357600080fd5b81518015158114610e1d57600080fd5b60208082526016908201527514149150d3d35412531157d0d0531317d1905253115160521b604082015260600190565b818103818111156103ce576103ce610f8e56feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220eff294dba2996c4337f07acdacd5b73dff2185b61e8f1aa3c312a46098b8b16e64736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var NativeERC20MintableArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"NativeERC20Mintable\",\n \"sourceName\": \"contracts/child/NativeERC20Mintable.sol\",\n \"abi\": [\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"only\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"Unauthorized\",\n \"type\": \"error\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Approval\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"previousOwner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"OwnershipTransferStarted\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"previousOwner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"OwnershipTransferred\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Transfer\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"ALLOWLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"BLOCKLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TOKEN_CONTRACT\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"READ_ADDRESSLIST_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"SYSTEM\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"acceptOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"allowance\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"approve\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"balanceOf\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"burn\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"decimals\",\n \"outputs\": [\n {\n \"internalType\": \"uint8\",\n \"name\": \"\",\n \"type\": \"uint8\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"subtractedValue\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"decreaseAllowance\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"addedValue\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"increaseAllowance\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"predicate_\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"owner_\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"rootToken_\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"string\",\n \"name\": \"name_\",\n \"type\": \"string\"\n },\n {\n \"internalType\": \"string\",\n \"name\": \"symbol_\",\n \"type\": \"string\"\n },\n {\n \"internalType\": \"uint8\",\n \"name\": \"decimals_\",\n \"type\": \"uint8\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenSupply_\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"mint\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"name\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"owner\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"pendingOwner\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"renounceOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"rootToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"symbol\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"totalSupply\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transfer\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transferFrom\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"transferOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b5061001a3361001f565b61008d565b603480546001600160a01b03191690556100388161003b565b50565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b61150a8061009c6000396000f3fe608060405234801561001057600080fd5b506004361061019a5760003560e01c806370a08231116100e45780639dc29fac116100925780639dc29fac1461031a578063a457c2d71461032d578063a9059cbb14610340578063dd62ed3e14610353578063e0563ab114610366578063e30c39781461036f578063e619870514610380578063f2fde38b1461039157600080fd5b806370a08231146102c3578063715018a6146102de57806379ba5097146102e65780638da5cb5b146102ee578063947287cf146102ff57806395d89b411461030857806397e5230d1461031057600080fd5b8063313ce5671161014c578063313ce56714610245578063395093511461025a5780633b878c221461026d57806340c10f191461027657806351351d531461028957806355b01e4d146102975780635ea5df79146102a55780636091636b146102ae57600080fd5b806306fdde031461019f57806307b3e252146101bd578063095ea7b3146101e357806318160ddd146102065780631f2d00651461021857806323b872dd14610229578063284017f51461023c575b600080fd5b6101a76103a4565b6040516101b49190611022565b60405180910390f35b6101cb6004600360981b0181565b6040516001600160a01b0390911681526020016101b4565b6101f66101f1366004611071565b610436565b60405190151581526020016101b4565b6036545b6040519081526020016101b4565b6038546001600160a01b03166101cb565b6101f661023736600461109b565b610450565b6101cb61202081565b603b5460405160ff90911681526020016101b4565b6101f6610268366004611071565b610474565b6101cb61101081565b6101f6610284366004611071565b610496565b6101cb6002600160a01b0381565b6101cb6004600160991b0181565b61020a61138881565b6102c16102bc366004611120565b6104f4565b005b61020a6102d13660046111e4565b6001600160a01b03163190565b6102c1610714565b6102c1610728565b6033546001600160a01b03166101cb565b61020a61520881565b6101a76107a2565b61020a620249f081565b6101f6610328366004611071565b6107b1565b6101f661033b366004611071565b6107fd565b6101f661034e366004611071565b610878565b61020a610361366004611206565b610886565b6101cb61203081565b6034546001600160a01b03166101cb565b6037546001600160a01b03166101cb565b6102c161039f3660046111e4565b6108b1565b6060603980546103b390611239565b80601f01602080910402602001604051908101604052809291908181526020018280546103df90611239565b801561042c5780601f106104015761010080835404028352916020019161042c565b820191906000526020600020905b81548152906001019060200180831161040f57829003601f168201915b5050505050905090565b600033610444818585610922565b60019150505b92915050565b60003361045e858285610a46565b610469858585610ac0565b506001949350505050565b6000336104448185856104878383610886565b6104919190611289565b610922565b6037546000906001600160a01b03163314806104bc57506033546001600160a01b031633145b6104e15760405162461bcd60e51b81526004016104d89061129c565b60405180910390fd5b6104eb8383610c85565b50600192915050565b600054610100900460ff16158080156105145750600054600160ff909116105b8061052e5750303b15801561052e575060005460ff166001145b6105915760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016104d8565b6000805460ff1916600117905580156105b4576000805461ff0019166101001790555b336002600160a01b03146105f85760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b60448201526064016104d8565b6001600160a01b0389166106595760405162461bcd60e51b815260206004820152602260248201527f4e617469766545524332303a20496e76616c6964206f776e6572206164647265604482015261737360f01b60648201526084016104d8565b603780546001600160a01b03808d166001600160a01b03199283161790925560388054928b1692909116919091179055603961069687898361134e565b50603a6106a485878361134e565b50603b805460ff191660ff851617905560368290556106c289610ddf565b8015610708576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050505050565b61071c610df8565b6107266000610ddf565b565b60345433906001600160a01b031681146107965760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016104d8565b61079f81610ddf565b50565b6060603a80546103b390611239565b6037546000906001600160a01b03163314806107d757506033546001600160a01b031633145b6107f35760405162461bcd60e51b81526004016104d89061129c565b6104eb8383610e52565b6000338161080b8286610886565b90508381101561086b5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016104d8565b6104698286868403610922565b600033610444818585610ac0565b6001600160a01b03918216600090815260356020908152604080832093909416825291909152205490565b6108b9610df8565b603480546001600160a01b0383166001600160a01b031990911681179091556108ea6033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6001600160a01b0383166109845760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016104d8565b6001600160a01b0382166109e55760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016104d8565b6001600160a01b0383811660008181526035602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6000610a528484610886565b90506000198114610aba5781811015610aad5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016104d8565b610aba8484848403610922565b50505050565b6001600160a01b038316610b245760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016104d8565b6001600160a01b038216610b865760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016104d8565b6000806120206001600160a01b0316858585604051602001610baa9392919061140f565b60408051601f1981840301815290829052610bc491611433565b6000604051808303816000865af19150503d8060008114610c01576040519150601f19603f3d011682016040523d82523d6000602084013e610c06565b606091505b5091509150818015610c27575080806020019051810190610c27919061144f565b610c435760405162461bcd60e51b81526004016104d890611471565b836001600160a01b0316856001600160a01b03166000805160206114b583398151915285604051610c7691815260200190565b60405180910390a35050505050565b6001600160a01b038216610cdb5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016104d8565b8060366000828254610ced9190611289565b9091555050604051600090819061202090610d109083908790879060200161140f565b60408051601f1981840301815290829052610d2a91611433565b6000604051808303816000865af19150503d8060008114610d67576040519150601f19603f3d011682016040523d82523d6000602084013e610d6c565b606091505b5091509150818015610d8d575080806020019051810190610d8d919061144f565b610da95760405162461bcd60e51b81526004016104d890611471565b6040518381526001600160a01b038516906000906000805160206114b5833981519152906020015b60405180910390a350505050565b603480546001600160a01b031916905561079f81610fac565b6033546001600160a01b031633146107265760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104d8565b6001600160a01b038216610eb25760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016104d8565b8060366000828254610ec491906114a1565b9091555050604051600090819061202090610ee79086908490879060200161140f565b60408051601f1981840301815290829052610f0191611433565b6000604051808303816000865af19150503d8060008114610f3e576040519150601f19603f3d011682016040523d82523d6000602084013e610f43565b606091505b5091509150818015610f64575080806020019051810190610f64919061144f565b610f805760405162461bcd60e51b81526004016104d890611471565b6040518381526000906001600160a01b038616906000805160206114b583398151915290602001610dd1565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60005b83811015611019578181015183820152602001611001565b50506000910152565b6020815260008251806020840152611041816040850160208701610ffe565b601f01601f19169190910160400192915050565b80356001600160a01b038116811461106c57600080fd5b919050565b6000806040838503121561108457600080fd5b61108d83611055565b946020939093013593505050565b6000806000606084860312156110b057600080fd5b6110b984611055565b92506110c760208501611055565b9150604084013590509250925092565b60008083601f8401126110e957600080fd5b50813567ffffffffffffffff81111561110157600080fd5b60208301915083602082850101111561111957600080fd5b9250929050565b600080600080600080600080600060e08a8c03121561113e57600080fd5b6111478a611055565b985061115560208b01611055565b975061116360408b01611055565b965060608a013567ffffffffffffffff8082111561118057600080fd5b61118c8d838e016110d7565b909850965060808c01359150808211156111a557600080fd5b506111b28c828d016110d7565b90955093505060a08a013560ff811681146111cc57600080fd5b8092505060c08a013590509295985092959850929598565b6000602082840312156111f657600080fd5b6111ff82611055565b9392505050565b6000806040838503121561121957600080fd5b61122283611055565b915061123060208401611055565b90509250929050565b600181811c9082168061124d57607f821691505b60208210810361126d57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561044a5761044a611273565b6020808252602d908201527f4e617469766545524332303a204f6e6c7920707265646963617465206f72206f60408201526c1ddb995c8818d85b8818d85b1b609a1b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b601f82111561134957600081815260208120601f850160051c810160208610156113265750805b601f850160051c820191505b8181101561134557828155600101611332565b5050505b505050565b67ffffffffffffffff831115611366576113666112e9565b61137a836113748354611239565b836112ff565b6000601f8411600181146113ae57600085156113965750838201355b600019600387901b1c1916600186901b178355611408565b600083815260209020601f19861690835b828110156113df57868501358255602094850194600190920191016113bf565b50868210156113fc5760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b60008251611445818460208701610ffe565b9190910192915050565b60006020828403121561146157600080fd5b815180151581146111ff57600080fd5b60208082526016908201527514149150d3d35412531157d0d0531317d1905253115160521b604082015260600190565b8181038181111561044a5761044a61127356feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122019716c645080b1365563f01a6cdf0f363af3491e7cb3880150d6d1f3389f759364736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b506004361061019a5760003560e01c806370a08231116100e45780639dc29fac116100925780639dc29fac1461031a578063a457c2d71461032d578063a9059cbb14610340578063dd62ed3e14610353578063e0563ab114610366578063e30c39781461036f578063e619870514610380578063f2fde38b1461039157600080fd5b806370a08231146102c3578063715018a6146102de57806379ba5097146102e65780638da5cb5b146102ee578063947287cf146102ff57806395d89b411461030857806397e5230d1461031057600080fd5b8063313ce5671161014c578063313ce56714610245578063395093511461025a5780633b878c221461026d57806340c10f191461027657806351351d531461028957806355b01e4d146102975780635ea5df79146102a55780636091636b146102ae57600080fd5b806306fdde031461019f57806307b3e252146101bd578063095ea7b3146101e357806318160ddd146102065780631f2d00651461021857806323b872dd14610229578063284017f51461023c575b600080fd5b6101a76103a4565b6040516101b49190611022565b60405180910390f35b6101cb6004600360981b0181565b6040516001600160a01b0390911681526020016101b4565b6101f66101f1366004611071565b610436565b60405190151581526020016101b4565b6036545b6040519081526020016101b4565b6038546001600160a01b03166101cb565b6101f661023736600461109b565b610450565b6101cb61202081565b603b5460405160ff90911681526020016101b4565b6101f6610268366004611071565b610474565b6101cb61101081565b6101f6610284366004611071565b610496565b6101cb6002600160a01b0381565b6101cb6004600160991b0181565b61020a61138881565b6102c16102bc366004611120565b6104f4565b005b61020a6102d13660046111e4565b6001600160a01b03163190565b6102c1610714565b6102c1610728565b6033546001600160a01b03166101cb565b61020a61520881565b6101a76107a2565b61020a620249f081565b6101f6610328366004611071565b6107b1565b6101f661033b366004611071565b6107fd565b6101f661034e366004611071565b610878565b61020a610361366004611206565b610886565b6101cb61203081565b6034546001600160a01b03166101cb565b6037546001600160a01b03166101cb565b6102c161039f3660046111e4565b6108b1565b6060603980546103b390611239565b80601f01602080910402602001604051908101604052809291908181526020018280546103df90611239565b801561042c5780601f106104015761010080835404028352916020019161042c565b820191906000526020600020905b81548152906001019060200180831161040f57829003601f168201915b5050505050905090565b600033610444818585610922565b60019150505b92915050565b60003361045e858285610a46565b610469858585610ac0565b506001949350505050565b6000336104448185856104878383610886565b6104919190611289565b610922565b6037546000906001600160a01b03163314806104bc57506033546001600160a01b031633145b6104e15760405162461bcd60e51b81526004016104d89061129c565b60405180910390fd5b6104eb8383610c85565b50600192915050565b600054610100900460ff16158080156105145750600054600160ff909116105b8061052e5750303b15801561052e575060005460ff166001145b6105915760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016104d8565b6000805460ff1916600117905580156105b4576000805461ff0019166101001790555b336002600160a01b03146105f85760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b60448201526064016104d8565b6001600160a01b0389166106595760405162461bcd60e51b815260206004820152602260248201527f4e617469766545524332303a20496e76616c6964206f776e6572206164647265604482015261737360f01b60648201526084016104d8565b603780546001600160a01b03808d166001600160a01b03199283161790925560388054928b1692909116919091179055603961069687898361134e565b50603a6106a485878361134e565b50603b805460ff191660ff851617905560368290556106c289610ddf565b8015610708576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050505050565b61071c610df8565b6107266000610ddf565b565b60345433906001600160a01b031681146107965760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016104d8565b61079f81610ddf565b50565b6060603a80546103b390611239565b6037546000906001600160a01b03163314806107d757506033546001600160a01b031633145b6107f35760405162461bcd60e51b81526004016104d89061129c565b6104eb8383610e52565b6000338161080b8286610886565b90508381101561086b5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016104d8565b6104698286868403610922565b600033610444818585610ac0565b6001600160a01b03918216600090815260356020908152604080832093909416825291909152205490565b6108b9610df8565b603480546001600160a01b0383166001600160a01b031990911681179091556108ea6033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6001600160a01b0383166109845760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016104d8565b6001600160a01b0382166109e55760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016104d8565b6001600160a01b0383811660008181526035602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6000610a528484610886565b90506000198114610aba5781811015610aad5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016104d8565b610aba8484848403610922565b50505050565b6001600160a01b038316610b245760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016104d8565b6001600160a01b038216610b865760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016104d8565b6000806120206001600160a01b0316858585604051602001610baa9392919061140f565b60408051601f1981840301815290829052610bc491611433565b6000604051808303816000865af19150503d8060008114610c01576040519150601f19603f3d011682016040523d82523d6000602084013e610c06565b606091505b5091509150818015610c27575080806020019051810190610c27919061144f565b610c435760405162461bcd60e51b81526004016104d890611471565b836001600160a01b0316856001600160a01b03166000805160206114b583398151915285604051610c7691815260200190565b60405180910390a35050505050565b6001600160a01b038216610cdb5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016104d8565b8060366000828254610ced9190611289565b9091555050604051600090819061202090610d109083908790879060200161140f565b60408051601f1981840301815290829052610d2a91611433565b6000604051808303816000865af19150503d8060008114610d67576040519150601f19603f3d011682016040523d82523d6000602084013e610d6c565b606091505b5091509150818015610d8d575080806020019051810190610d8d919061144f565b610da95760405162461bcd60e51b81526004016104d890611471565b6040518381526001600160a01b038516906000906000805160206114b5833981519152906020015b60405180910390a350505050565b603480546001600160a01b031916905561079f81610fac565b6033546001600160a01b031633146107265760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104d8565b6001600160a01b038216610eb25760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016104d8565b8060366000828254610ec491906114a1565b9091555050604051600090819061202090610ee79086908490879060200161140f565b60408051601f1981840301815290829052610f0191611433565b6000604051808303816000865af19150503d8060008114610f3e576040519150601f19603f3d011682016040523d82523d6000602084013e610f43565b606091505b5091509150818015610f64575080806020019051810190610f64919061144f565b610f805760405162461bcd60e51b81526004016104d890611471565b6040518381526000906001600160a01b038616906000805160206114b583398151915290602001610dd1565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60005b83811015611019578181015183820152602001611001565b50506000910152565b6020815260008251806020840152611041816040850160208701610ffe565b601f01601f19169190910160400192915050565b80356001600160a01b038116811461106c57600080fd5b919050565b6000806040838503121561108457600080fd5b61108d83611055565b946020939093013593505050565b6000806000606084860312156110b057600080fd5b6110b984611055565b92506110c760208501611055565b9150604084013590509250925092565b60008083601f8401126110e957600080fd5b50813567ffffffffffffffff81111561110157600080fd5b60208301915083602082850101111561111957600080fd5b9250929050565b600080600080600080600080600060e08a8c03121561113e57600080fd5b6111478a611055565b985061115560208b01611055565b975061116360408b01611055565b965060608a013567ffffffffffffffff8082111561118057600080fd5b61118c8d838e016110d7565b909850965060808c01359150808211156111a557600080fd5b506111b28c828d016110d7565b90955093505060a08a013560ff811681146111cc57600080fd5b8092505060c08a013590509295985092959850929598565b6000602082840312156111f657600080fd5b6111ff82611055565b9392505050565b6000806040838503121561121957600080fd5b61122283611055565b915061123060208401611055565b90509250929050565b600181811c9082168061124d57607f821691505b60208210810361126d57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561044a5761044a611273565b6020808252602d908201527f4e617469766545524332303a204f6e6c7920707265646963617465206f72206f60408201526c1ddb995c8818d85b8818d85b1b609a1b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b601f82111561134957600081815260208120601f850160051c810160208610156113265750805b601f850160051c820191505b8181101561134557828155600101611332565b5050505b505050565b67ffffffffffffffff831115611366576113666112e9565b61137a836113748354611239565b836112ff565b6000601f8411600181146113ae57600085156113965750838201355b600019600387901b1c1916600186901b178355611408565b600083815260209020601f19861690835b828110156113df57868501358255602094850194600190920191016113bf565b50868210156113fc5760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b60008251611445818460208701610ffe565b9190910192915050565b60006020828403121561146157600080fd5b815180151581146111ff57600080fd5b60208082526016908201527514149150d3d35412531157d0d0531317d1905253115160521b604082015260600190565b8181038181111561044a5761044a61127356feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122019716c645080b1365563f01a6cdf0f363af3491e7cb3880150d6d1f3389f759364736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var ChildERC20Artifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"ChildERC20\",\n \"sourceName\": \"contracts/child/ChildERC20.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Approval\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"userAddress\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"relayerAddress\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bytes\",\n \"name\": \"functionSignature\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"MetaTransactionExecuted\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Transfer\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"allowance\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"approve\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"balanceOf\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"burn\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"decimals\",\n \"outputs\": [\n {\n \"internalType\": \"uint8\",\n \"name\": \"\",\n \"type\": \"uint8\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"subtractedValue\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"decreaseAllowance\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"userAddress\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"functionSignature\",\n \"type\": \"bytes\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"sigR\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"sigS\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint8\",\n \"name\": \"sigV\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"executeMetaTransaction\",\n \"outputs\": [\n {\n \"internalType\": \"bytes\",\n \"name\": \"\",\n \"type\": \"bytes\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"getNonce\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"nonce\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"addedValue\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"increaseAllowance\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"rootToken_\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"string\",\n \"name\": \"name_\",\n \"type\": \"string\"\n },\n {\n \"internalType\": \"string\",\n \"name\": \"symbol_\",\n \"type\": \"string\"\n },\n {\n \"internalType\": \"uint8\",\n \"name\": \"decimals_\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"offset\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"invalidateNext\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"mint\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"name\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"rootToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"symbol\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"totalSupply\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transfer\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transferFrom\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50611920806100206000396000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c806340c10f19116100ad578063a457c2d711610071578063a457c2d71461028b578063a9059cbb1461029e578063dd62ed3e146102b1578063e6198705146102c4578063f6d2ee86146102d557600080fd5b806340c10f191461021f57806370a082311461023257806395d89b411461025b5780639b77ef11146102635780639dc29fac1461027857600080fd5b80631f2d0065116100f45780631f2d00651461018c57806323b872dd146101b15780632d0335ab146101c4578063313ce567146101ed578063395093511461020c57600080fd5b806306fdde0314610126578063095ea7b3146101445780630c53c51c1461016757806318160ddd1461017a575b600080fd5b61012e6102e8565b60405161013b9190611395565b60405180910390f35b6101576101523660046113cb565b61037a565b604051901515815260200161013b565b61012e61017536600461144f565b61039e565b60a0545b60405190815260200161013b565b60d1546001600160a01b03165b6040516001600160a01b03909116815260200161013b565b6101576101bf3660046114c5565b610681565b61017e6101d2366004611501565b6001600160a01b031660009081526038602052604090205490565b60d154600160a01b900460ff1660405160ff909116815260200161013b565b61015761021a3660046113cb565b6106af565b61015761022d3660046113cb565b6106db565b61017e610240366004611501565b6001600160a01b03166000908152609e602052604090205490565b61012e61071b565b61027661027136600461151c565b61072a565b005b6101576102863660046113cb565b610751565b6101576102993660046113cb565b610788565b6101576102ac3660046113cb565b61080e565b61017e6102bf366004611535565b610826565b60d0546001600160a01b0316610199565b6102766102e3366004611568565b610851565b606060a180546102f7906115ec565b80601f0160208091040260200160405190810160405280929190818152602001828054610323906115ec565b80156103705780601f1061034557610100808354040283529160200191610370565b820191906000526020600020905b81548152906001019060200180831161035357829003601f168201915b5050505050905090565b600080610385610ad1565b9050610392818585610ae0565b60019150505b92915050565b606060006103e187878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610c0592505050565b90506001600160e01b031960003581169082160361046c5760405162461bcd60e51b815260206004820152603d60248201527f66756e6374696f6e5369676e61747572652063616e206e6f74206265206f662060448201527f657865637574654d6574615472616e73616374696f6e206d6574686f6400000060648201526084015b60405180910390fd5b604080516060810182526001600160a01b038a16600081815260386020908152848220548452808401929092528351601f8b0183900483028101830185528a815290938301918b908b9081908401838280828437600092019190915250505091525090506104dd8982888888610c20565b6105335760405162461bcd60e51b815260206004820152602160248201527f5369676e657220616e64207369676e617475726520646f206e6f74206d6174636044820152600d60fb1b6064820152608401610463565b603860008a6001600160a01b03166001600160a01b031681526020019081526020016000206000815460010191905081905550600080306001600160a01b03168a8a8d60405160200161058893929190611626565b60408051601f19818403018152908290526105a29161164c565b6000604051808303816000865af19150503d80600081146105df576040519150601f19603f3d011682016040523d82523d6000602084013e6105e4565b606091505b5091509150816106365760405162461bcd60e51b815260206004820152601c60248201527f46756e6374696f6e2063616c6c206e6f74207375636365737366756c000000006044820152606401610463565b7f5845892132946850460bff5a0083f71031bc5bf9aadcd40f1de79423eac9b10b8b338c8c60405161066b9493929190611668565b60405180910390a19a9950505050505050505050565b60008061068c610ad1565b9050610699858285610cfc565b6106a4858585610d76565b506001949350505050565b6000806106ba610ad1565b90506103928185856106cc8589610826565b6106d691906116b4565b610ae0565b60d0546000906001600160a01b031633146107085760405162461bcd60e51b8152600401610463906116d5565b6107128383610f0f565b50600192915050565b606060a280546102f7906115ec565b33600090815260386020526040812080548392906107499084906116b4565b909155505050565b60d0546000906001600160a01b0316331461077e5760405162461bcd60e51b8152600401610463906116d5565b6107128383610fbf565b600080610793610ad1565b905060006107a18286610826565b9050838110156108015760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610463565b6106a48286868403610ae0565b600080610819610ad1565b9050610392818585610d76565b6001600160a01b039182166000908152609f6020908152604080832093909416825291909152205490565b606b54610100900460ff16158080156108715750606b54600160ff909116105b8061088b5750303b15801561088b5750606b5460ff166001145b6108ee5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610463565b606b805460ff19166001179055801561091157606b805461ff0019166101001790555b6001600160a01b0387161580159061092857508415155b801561093357508215155b61097f5760405162461bcd60e51b815260206004820152601e60248201527f4368696c6445524332303a204241445f494e495449414c495a4154494f4e00006044820152606401610463565b60d1805460ff8416600160a01b026001600160a81b03199091166001600160a01b038a161717905560d080546001600160a01b03191633179055604080516020601f8801819004810282018101909252868152610a2a91889088908190840183828082843760009201919091525050604080516020601f8a0181900481028201810190925288815292508891508790819084018382808284376000920191909152506110de92505050565b610a8286868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260018152603160f81b6020820152915061110f9050565b8015610ac857606b805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6000610adb61117b565b905090565b6001600160a01b038316610b425760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610463565b6001600160a01b038216610ba35760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610463565b6001600160a01b038381166000818152609f602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b60008151600003610c1857506000919050565b506020015190565b6000806001610c36610c31886111d7565b611254565b6040805160008152602081018083529290925260ff861690820152606081018790526080810186905260a0016020604051602081039080840390855afa158015610c84573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610cdb5760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b6044820152606401610463565b866001600160a01b0316816001600160a01b03161491505095945050505050565b6000610d088484610826565b90506000198114610d705781811015610d635760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610463565b610d708484848403610ae0565b50505050565b6001600160a01b038316610dda5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610463565b6001600160a01b038216610e3c5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610463565b6001600160a01b0383166000908152609e602052604090205481811015610eb45760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610463565b6001600160a01b038085166000818152609e602052604080822086860390559286168082529083902080548601905591516000805160206118cb83398151915290610f029086815260200190565b60405180910390a3610d70565b6001600160a01b038216610f655760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610463565b8060a06000828254610f7791906116b4565b90915550506001600160a01b0382166000818152609e60209081526040808320805486019055518481526000805160206118cb833981519152910160405180910390a35b5050565b6001600160a01b03821661101f5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610463565b6001600160a01b0382166000908152609e6020526040902054818110156110935760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610463565b6001600160a01b0383166000818152609e60209081526040808320868603905560a080548790039055518581529192916000805160206118cb8339815191529101610bf8565b505050565b606b54610100900460ff166111055760405162461bcd60e51b815260040161046390611718565b610fbb8282611281565b815160208084019190912082519183019190912060038290556004819055466001557f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f61115d8184846112c1565b600055600280546001600160a01b0319163017905560055550505050565b60003033036111d157600080368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050503601516001600160a01b031691506111d49050565b50335b90565b60006040518060800160405280604381526020016118886043913980516020918201208351848301516040808701518051908601209051611237950193845260208401929092526001600160a01b03166040830152606082015260800190565b604051602081830303815290604052805190602001209050919050565b600061039861126161130a565b8360405161190160f01b8152600281019290925260228201526042902090565b606b54610100900460ff166112a85760405162461bcd60e51b815260040161046390611718565b60a16112b483826117c7565b5060a26110d982826117c7565b6040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b6002546000906001600160a01b031630148015611328575060015446145b15611334575060005490565b610adb6005546003546004546112c1565b60005b83811015611360578181015183820152602001611348565b50506000910152565b60008151808452611381816020860160208601611345565b601f01601f19169290920160200192915050565b6020815260006113a86020830184611369565b9392505050565b80356001600160a01b03811681146113c657600080fd5b919050565b600080604083850312156113de57600080fd5b6113e7836113af565b946020939093013593505050565b60008083601f84011261140757600080fd5b50813567ffffffffffffffff81111561141f57600080fd5b60208301915083602082850101111561143757600080fd5b9250929050565b803560ff811681146113c657600080fd5b60008060008060008060a0878903121561146857600080fd5b611471876113af565b9550602087013567ffffffffffffffff81111561148d57600080fd5b61149989828a016113f5565b90965094505060408701359250606087013591506114b96080880161143e565b90509295509295509295565b6000806000606084860312156114da57600080fd5b6114e3846113af565b92506114f1602085016113af565b9150604084013590509250925092565b60006020828403121561151357600080fd5b6113a8826113af565b60006020828403121561152e57600080fd5b5035919050565b6000806040838503121561154857600080fd5b611551836113af565b915061155f602084016113af565b90509250929050565b6000806000806000806080878903121561158157600080fd5b61158a876113af565b9550602087013567ffffffffffffffff808211156115a757600080fd5b6115b38a838b016113f5565b909750955060408901359150808211156115cc57600080fd5b506115d989828a016113f5565b90945092506114b990506060880161143e565b600181811c9082168061160057607f821691505b60208210810361162057634e487b7160e01b600052602260045260246000fd5b50919050565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b6000825161165e818460208701611345565b9190910192915050565b6001600160a01b0385811682528416602082015260606040820181905281018290526000828460808401376000608084840101526080601f19601f850116830101905095945050505050565b8082018082111561039857634e487b7160e01b600052601160045260246000fd5b60208082526023908201527f4368696c6445524332303a204f6e6c79207072656469636174652063616e2063604082015262185b1b60ea1b606082015260800190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b601f8211156110d957600081815260208120601f850160051c810160208610156117a05750805b601f850160051c820191505b818110156117bf578281556001016117ac565b505050505050565b815167ffffffffffffffff8111156117e1576117e1611763565b6117f5816117ef84546115ec565b84611779565b602080601f83116001811461182a57600084156118125750858301515b600019600386901b1c1916600185901b1785556117bf565b600085815260208120601f198616915b828110156118595788860151825594840194600190910190840161183a565b50858210156118775787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fe4d6574615472616e73616374696f6e2875696e74323536206e6f6e63652c616464726573732066726f6d2c62797465732066756e6374696f6e5369676e617475726529ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122083d6b7bd85693305a7ba1e1fc5172e26e43168ef3c342fd05cb6ecd683a2bbac64736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101215760003560e01c806340c10f19116100ad578063a457c2d711610071578063a457c2d71461028b578063a9059cbb1461029e578063dd62ed3e146102b1578063e6198705146102c4578063f6d2ee86146102d557600080fd5b806340c10f191461021f57806370a082311461023257806395d89b411461025b5780639b77ef11146102635780639dc29fac1461027857600080fd5b80631f2d0065116100f45780631f2d00651461018c57806323b872dd146101b15780632d0335ab146101c4578063313ce567146101ed578063395093511461020c57600080fd5b806306fdde0314610126578063095ea7b3146101445780630c53c51c1461016757806318160ddd1461017a575b600080fd5b61012e6102e8565b60405161013b9190611395565b60405180910390f35b6101576101523660046113cb565b61037a565b604051901515815260200161013b565b61012e61017536600461144f565b61039e565b60a0545b60405190815260200161013b565b60d1546001600160a01b03165b6040516001600160a01b03909116815260200161013b565b6101576101bf3660046114c5565b610681565b61017e6101d2366004611501565b6001600160a01b031660009081526038602052604090205490565b60d154600160a01b900460ff1660405160ff909116815260200161013b565b61015761021a3660046113cb565b6106af565b61015761022d3660046113cb565b6106db565b61017e610240366004611501565b6001600160a01b03166000908152609e602052604090205490565b61012e61071b565b61027661027136600461151c565b61072a565b005b6101576102863660046113cb565b610751565b6101576102993660046113cb565b610788565b6101576102ac3660046113cb565b61080e565b61017e6102bf366004611535565b610826565b60d0546001600160a01b0316610199565b6102766102e3366004611568565b610851565b606060a180546102f7906115ec565b80601f0160208091040260200160405190810160405280929190818152602001828054610323906115ec565b80156103705780601f1061034557610100808354040283529160200191610370565b820191906000526020600020905b81548152906001019060200180831161035357829003601f168201915b5050505050905090565b600080610385610ad1565b9050610392818585610ae0565b60019150505b92915050565b606060006103e187878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610c0592505050565b90506001600160e01b031960003581169082160361046c5760405162461bcd60e51b815260206004820152603d60248201527f66756e6374696f6e5369676e61747572652063616e206e6f74206265206f662060448201527f657865637574654d6574615472616e73616374696f6e206d6574686f6400000060648201526084015b60405180910390fd5b604080516060810182526001600160a01b038a16600081815260386020908152848220548452808401929092528351601f8b0183900483028101830185528a815290938301918b908b9081908401838280828437600092019190915250505091525090506104dd8982888888610c20565b6105335760405162461bcd60e51b815260206004820152602160248201527f5369676e657220616e64207369676e617475726520646f206e6f74206d6174636044820152600d60fb1b6064820152608401610463565b603860008a6001600160a01b03166001600160a01b031681526020019081526020016000206000815460010191905081905550600080306001600160a01b03168a8a8d60405160200161058893929190611626565b60408051601f19818403018152908290526105a29161164c565b6000604051808303816000865af19150503d80600081146105df576040519150601f19603f3d011682016040523d82523d6000602084013e6105e4565b606091505b5091509150816106365760405162461bcd60e51b815260206004820152601c60248201527f46756e6374696f6e2063616c6c206e6f74207375636365737366756c000000006044820152606401610463565b7f5845892132946850460bff5a0083f71031bc5bf9aadcd40f1de79423eac9b10b8b338c8c60405161066b9493929190611668565b60405180910390a19a9950505050505050505050565b60008061068c610ad1565b9050610699858285610cfc565b6106a4858585610d76565b506001949350505050565b6000806106ba610ad1565b90506103928185856106cc8589610826565b6106d691906116b4565b610ae0565b60d0546000906001600160a01b031633146107085760405162461bcd60e51b8152600401610463906116d5565b6107128383610f0f565b50600192915050565b606060a280546102f7906115ec565b33600090815260386020526040812080548392906107499084906116b4565b909155505050565b60d0546000906001600160a01b0316331461077e5760405162461bcd60e51b8152600401610463906116d5565b6107128383610fbf565b600080610793610ad1565b905060006107a18286610826565b9050838110156108015760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610463565b6106a48286868403610ae0565b600080610819610ad1565b9050610392818585610d76565b6001600160a01b039182166000908152609f6020908152604080832093909416825291909152205490565b606b54610100900460ff16158080156108715750606b54600160ff909116105b8061088b5750303b15801561088b5750606b5460ff166001145b6108ee5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610463565b606b805460ff19166001179055801561091157606b805461ff0019166101001790555b6001600160a01b0387161580159061092857508415155b801561093357508215155b61097f5760405162461bcd60e51b815260206004820152601e60248201527f4368696c6445524332303a204241445f494e495449414c495a4154494f4e00006044820152606401610463565b60d1805460ff8416600160a01b026001600160a81b03199091166001600160a01b038a161717905560d080546001600160a01b03191633179055604080516020601f8801819004810282018101909252868152610a2a91889088908190840183828082843760009201919091525050604080516020601f8a0181900481028201810190925288815292508891508790819084018382808284376000920191909152506110de92505050565b610a8286868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260018152603160f81b6020820152915061110f9050565b8015610ac857606b805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6000610adb61117b565b905090565b6001600160a01b038316610b425760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610463565b6001600160a01b038216610ba35760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610463565b6001600160a01b038381166000818152609f602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b60008151600003610c1857506000919050565b506020015190565b6000806001610c36610c31886111d7565b611254565b6040805160008152602081018083529290925260ff861690820152606081018790526080810186905260a0016020604051602081039080840390855afa158015610c84573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610cdb5760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b6044820152606401610463565b866001600160a01b0316816001600160a01b03161491505095945050505050565b6000610d088484610826565b90506000198114610d705781811015610d635760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610463565b610d708484848403610ae0565b50505050565b6001600160a01b038316610dda5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610463565b6001600160a01b038216610e3c5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610463565b6001600160a01b0383166000908152609e602052604090205481811015610eb45760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610463565b6001600160a01b038085166000818152609e602052604080822086860390559286168082529083902080548601905591516000805160206118cb83398151915290610f029086815260200190565b60405180910390a3610d70565b6001600160a01b038216610f655760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610463565b8060a06000828254610f7791906116b4565b90915550506001600160a01b0382166000818152609e60209081526040808320805486019055518481526000805160206118cb833981519152910160405180910390a35b5050565b6001600160a01b03821661101f5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610463565b6001600160a01b0382166000908152609e6020526040902054818110156110935760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610463565b6001600160a01b0383166000818152609e60209081526040808320868603905560a080548790039055518581529192916000805160206118cb8339815191529101610bf8565b505050565b606b54610100900460ff166111055760405162461bcd60e51b815260040161046390611718565b610fbb8282611281565b815160208084019190912082519183019190912060038290556004819055466001557f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f61115d8184846112c1565b600055600280546001600160a01b0319163017905560055550505050565b60003033036111d157600080368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050503601516001600160a01b031691506111d49050565b50335b90565b60006040518060800160405280604381526020016118886043913980516020918201208351848301516040808701518051908601209051611237950193845260208401929092526001600160a01b03166040830152606082015260800190565b604051602081830303815290604052805190602001209050919050565b600061039861126161130a565b8360405161190160f01b8152600281019290925260228201526042902090565b606b54610100900460ff166112a85760405162461bcd60e51b815260040161046390611718565b60a16112b483826117c7565b5060a26110d982826117c7565b6040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b6002546000906001600160a01b031630148015611328575060015446145b15611334575060005490565b610adb6005546003546004546112c1565b60005b83811015611360578181015183820152602001611348565b50506000910152565b60008151808452611381816020860160208601611345565b601f01601f19169290920160200192915050565b6020815260006113a86020830184611369565b9392505050565b80356001600160a01b03811681146113c657600080fd5b919050565b600080604083850312156113de57600080fd5b6113e7836113af565b946020939093013593505050565b60008083601f84011261140757600080fd5b50813567ffffffffffffffff81111561141f57600080fd5b60208301915083602082850101111561143757600080fd5b9250929050565b803560ff811681146113c657600080fd5b60008060008060008060a0878903121561146857600080fd5b611471876113af565b9550602087013567ffffffffffffffff81111561148d57600080fd5b61149989828a016113f5565b90965094505060408701359250606087013591506114b96080880161143e565b90509295509295509295565b6000806000606084860312156114da57600080fd5b6114e3846113af565b92506114f1602085016113af565b9150604084013590509250925092565b60006020828403121561151357600080fd5b6113a8826113af565b60006020828403121561152e57600080fd5b5035919050565b6000806040838503121561154857600080fd5b611551836113af565b915061155f602084016113af565b90509250929050565b6000806000806000806080878903121561158157600080fd5b61158a876113af565b9550602087013567ffffffffffffffff808211156115a757600080fd5b6115b38a838b016113f5565b909750955060408901359150808211156115cc57600080fd5b506115d989828a016113f5565b90945092506114b990506060880161143e565b600181811c9082168061160057607f821691505b60208210810361162057634e487b7160e01b600052602260045260246000fd5b50919050565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b6000825161165e818460208701611345565b9190910192915050565b6001600160a01b0385811682528416602082015260606040820181905281018290526000828460808401376000608084840101526080601f19601f850116830101905095945050505050565b8082018082111561039857634e487b7160e01b600052601160045260246000fd5b60208082526023908201527f4368696c6445524332303a204f6e6c79207072656469636174652063616e2063604082015262185b1b60ea1b606082015260800190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b601f8211156110d957600081815260208120601f850160051c810160208610156117a05750805b601f850160051c820191505b818110156117bf578281556001016117ac565b505050505050565b815167ffffffffffffffff8111156117e1576117e1611763565b6117f5816117ef84546115ec565b84611779565b602080601f83116001811461182a57600084156118125750858301515b600019600386901b1c1916600185901b1785556117bf565b600085815260208120601f198616915b828110156118595788860151825594840194600190910190840161183a565b50858210156118775787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fe4d6574615472616e73616374696f6e2875696e74323536206e6f6e63652c616464726573732066726f6d2c62797465732066756e6374696f6e5369676e617475726529ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122083d6b7bd85693305a7ba1e1fc5172e26e43168ef3c342fd05cb6ecd683a2bbac64736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var ChildERC20PredicateArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"ChildERC20Predicate\",\n \"sourceName\": \"contracts/child/ChildERC20Predicate.sol\",\n \"abi\": [\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"only\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"Unauthorized\",\n \"type\": \"error\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2ERC20Deposit\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2ERC20Withdraw\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"L2TokenMapped\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"ALLOWLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"BLOCKLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAP_TOKEN_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TOKEN_CONTRACT\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"READ_ADDRESSLIST_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"SYSTEM\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childTokenTemplate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newL2StateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newStateReceiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newRootERC20Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newNativeTokenRootAddress\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"l2StateSender\",\n \"outputs\": [\n {\n \"internalType\": \"contract IStateSender\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onStateReceive\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"rootERC20Predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"rootTokenToChildToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"stateReceiver\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC20\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"withdraw\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC20\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"withdrawTo\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b506114ea806100206000396000f3fe608060405234801561001057600080fd5b50600436106101375760003560e01c80637efab4f5116100b8578063c3b35a7e1161007c578063c3b35a7e14610270578063d41f177114610283578063e0563ab1146102aa578063eeb49945146102b3578063f3fef3a3146102c6578063f6451255146102d957600080fd5b80637efab4f5146101fa578063947287cf1461022357806397e5230d1461022c578063b176806514610236578063b68ad1e41461025d57600080fd5b80633b878c22116100ff5780633b878c22146101ab57806351351d53146101b457806355b01e4d146101c25780635ea5df79146101d057806371cf93b7146101e757600080fd5b806305dc2e8f1461013c57806307b3e2521461016c5780631459457a1461017a5780631bc114ba1461018f578063284017f5146101a2575b600080fd5b60345461014f906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b61014f6004600360981b0181565b61018d610188366004610ff2565b610300565b005b60335461014f906001600160a01b031681565b61014f61202081565b61014f61101081565b61014f6002600160a01b0381565b61014f6004600160991b0181565b6101d961138881565b604051908152602001610163565b60355461014f906001600160a01b031681565b61014f610208366004611063565b6037602052600090815260409020546001600160a01b031681565b6101d961520881565b6101d9620249f081565b6101d97f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b60365461014f906001600160a01b031681565b61018d61027e366004611087565b610464565b6101d97f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b61014f61203081565b61018d6102c13660046110c8565b610474565b61018d6102d4366004611151565b610648565b6101d97f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b336002600160a01b03146103495760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b60448201526064015b60405180910390fd5b600054610100900460ff16158080156103695750600054600160ff909116105b806103835750303b158015610383575060005460ff166001145b6103e65760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610340565b6000805460ff191660011790558015610409576000805461ff0019166101001790555b6104168686868686610657565b801561045c576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b61046f8383836107a7565b505050565b6034546001600160a01b031633146104df5760405162461bcd60e51b815260206004820152602860248201527f4368696c6445524332305072656469636174653a204f4e4c595f53544154455f6044820152672922a1a2a4ab22a960c11b6064820152608401610340565b6035546001600160a01b0384811691161461054d5760405162461bcd60e51b815260206004820152602860248201527f4368696c6445524332305072656469636174653a204f4e4c595f524f4f545f50604482015267524544494341544560c01b6064820152608401610340565b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82161057c60206000848661117d565b610585916111a7565b036105a45761059f61059a826020818661117d565b610b1d565b610642565b7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad6105d360206000848661117d565b6105dc916111a7565b036105eb5761059f8282610dc8565b60405162461bcd60e51b815260206004820152602660248201527f4368696c6445524332305072656469636174653a20494e56414c49445f5349476044820152654e415455524560d01b6064820152608401610340565b50505050565b6106538233836107a7565b5050565b6001600160a01b0385161580159061067757506001600160a01b03841615155b801561068b57506001600160a01b03831615155b801561069f57506001600160a01b03821615155b6106fb5760405162461bcd60e51b815260206004820152602760248201527f4368696c6445524332305072656469636174653a204241445f494e495449414c60448201526624ad20aa24a7a760c91b6064820152608401610340565b603380546001600160a01b03199081166001600160a01b0388811691909117909255603480548216878416179055603580548216868416179055603680549091168483161790558116156107a0576001600160a01b03811660008181526037602052604080822080546001600160a01b03191661101090811790915590519092917f46bd56f98e1b14fd35691959270a6e1edf7cb8fcd489e0f9dda89e46c0d1ff0d91a35b5050505050565b826001600160a01b03163b60000361080b5760405162461bcd60e51b815260206004820152602160248201527f4368696c6445524332305072656469636174653a204e4f545f434f4e545241436044820152601560fa1b6064820152608401610340565b6000836001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa15801561084b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086f91906111c5565b6001600160a01b038181166000908152603760205260409020549192508581169116146108ae5760405162461bcd60e51b8152600401610340906111e2565b6001600160a01b0381166108c4576108c4611225565b306001600160a01b0316846001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa15801561090c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093091906111c5565b6001600160a01b03161461094657610946611225565b604051632770a7eb60e21b81526001600160a01b03851690639dc29fac90610974903390869060040161123b565b6020604051808303816000875af1158015610993573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109b79190611254565b610a035760405162461bcd60e51b815260206004820181905260248201527f4368696c6445524332305072656469636174653a204255524e5f4641494c45446044820152606401610340565b603354603554604080517f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286960208201526001600160a01b0385811682840152336060830152878116608083015260a08083018890528351808403909101815260c08301938490526316f1983160e01b909352938416936316f1983193610a8e9391169160c4016112bc565b600060405180830381600087803b158015610aa857600080fd5b505af1158015610abc573d6000803e3d6000fd5b50505050826001600160a01b0316846001600160a01b0316826001600160a01b03167fa0923f060a16fc784558d43de424ffde7b01643de5e5d335851b9df94c76bb273386604051610b0f92919061123b565b60405180910390a450505050565b6000808080610b2e858701876112e8565b6001600160a01b0380851660009081526037602052604090205494985092965090945092501680610b715760405162461bcd60e51b8152600401610340906111e2565b806001600160a01b03163b600003610b8b57610b8b611225565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bcb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bef91906111c5565b9050856001600160a01b0316816001600160a01b031614610c1257610c12611225565b6001600160a01b038116610c2857610c28611225565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c9491906111c5565b6001600160a01b031614610caa57610caa611225565b6040516340c10f1960e01b81526001600160a01b038316906340c10f1990610cd8908790879060040161123b565b6020604051808303816000875af1158015610cf7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d1b9190611254565b610d675760405162461bcd60e51b815260206004820181905260248201527f4368696c6445524332305072656469636174653a204d494e545f4641494c45446044820152606401610340565b836001600160a01b0316826001600160a01b0316876001600160a01b03167fdf34f3a3ed8bedc14a4b284ebaee5374d55b64bac6a84c270dabe8fd6b4cdafd8887604051610db692919061123b565b60405180910390a45050505050505050565b6000808080610dd9858701876113dc565b92975090955093509150506001600160a01b038416610dfa57610dfa611225565b6001600160a01b038481166000908152603760205260409020541615610e2257610e22611225565b6036546040516bffffffffffffffffffffffff19606087901b166020820152600091610e72916001600160a01b039091169060340160405160208183030381529060405280519060200120610f3d565b6001600160a01b038681166000908152603760205260409081902080546001600160a01b031916928416928317905551637b69774360e11b81529192509063f6d2ee8690610eca908890889088908890600401611469565b600060405180830381600087803b158015610ee457600080fd5b505af1158015610ef8573d6000803e3d6000fd5b50506040516001600160a01b038085169350881691507f46bd56f98e1b14fd35691959270a6e1edf7cb8fcd489e0f9dda89e46c0d1ff0d90600090a350505050505050565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b038116610fd45760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b6044820152606401610340565b92915050565b6001600160a01b0381168114610fef57600080fd5b50565b600080600080600060a0868803121561100a57600080fd5b853561101581610fda565b9450602086013561102581610fda565b9350604086013561103581610fda565b9250606086013561104581610fda565b9150608086013561105581610fda565b809150509295509295909350565b60006020828403121561107557600080fd5b813561108081610fda565b9392505050565b60008060006060848603121561109c57600080fd5b83356110a781610fda565b925060208401356110b781610fda565b929592945050506040919091013590565b600080600080606085870312156110de57600080fd5b8435935060208501356110f081610fda565b9250604085013567ffffffffffffffff8082111561110d57600080fd5b818701915087601f83011261112157600080fd5b81358181111561113057600080fd5b88602082850101111561114257600080fd5b95989497505060200194505050565b6000806040838503121561116457600080fd5b823561116f81610fda565b946020939093013593505050565b6000808585111561118d57600080fd5b8386111561119a57600080fd5b5050820193919092039150565b80356020831015610fd457600019602084900360031b1b1692915050565b6000602082840312156111d757600080fd5b815161108081610fda565b60208082526023908201527f4368696c6445524332305072656469636174653a20554e4d41505045445f544f60408201526225a2a760e91b606082015260800190565b634e487b7160e01b600052600160045260246000fd5b6001600160a01b03929092168252602082015260400190565b60006020828403121561126657600080fd5b8151801515811461108057600080fd5b6000815180845260005b8181101561129c57602081850181015186830182015201611280565b506000602082860101526020601f19601f83011685010191505092915050565b6001600160a01b03831681526040602082018190526000906112e090830184611276565b949350505050565b600080600080608085870312156112fe57600080fd5b843561130981610fda565b9350602085013561131981610fda565b9250604085013561132981610fda565b9396929550929360600135925050565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261136057600080fd5b813567ffffffffffffffff8082111561137b5761137b611339565b604051601f8301601f19908116603f011681019082821181831017156113a3576113a3611339565b816040528381528660208588010111156113bc57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060a086880312156113f457600080fd5b85359450602086013561140681610fda565b9350604086013567ffffffffffffffff8082111561142357600080fd5b61142f89838a0161134f565b9450606088013591508082111561144557600080fd5b506114528882890161134f565b925050608086013560ff8116811461105557600080fd5b6001600160a01b038516815260806020820181905260009061148d90830186611276565b828103604084015261149f8186611276565b91505060ff831660608301529594505050505056fea26469706673582212200a9bd04ce459c321a21b5d2d1e75f54fc0466e0ee822ecf79ffa26d25a1e1f2664736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101375760003560e01c80637efab4f5116100b8578063c3b35a7e1161007c578063c3b35a7e14610270578063d41f177114610283578063e0563ab1146102aa578063eeb49945146102b3578063f3fef3a3146102c6578063f6451255146102d957600080fd5b80637efab4f5146101fa578063947287cf1461022357806397e5230d1461022c578063b176806514610236578063b68ad1e41461025d57600080fd5b80633b878c22116100ff5780633b878c22146101ab57806351351d53146101b457806355b01e4d146101c25780635ea5df79146101d057806371cf93b7146101e757600080fd5b806305dc2e8f1461013c57806307b3e2521461016c5780631459457a1461017a5780631bc114ba1461018f578063284017f5146101a2575b600080fd5b60345461014f906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b61014f6004600360981b0181565b61018d610188366004610ff2565b610300565b005b60335461014f906001600160a01b031681565b61014f61202081565b61014f61101081565b61014f6002600160a01b0381565b61014f6004600160991b0181565b6101d961138881565b604051908152602001610163565b60355461014f906001600160a01b031681565b61014f610208366004611063565b6037602052600090815260409020546001600160a01b031681565b6101d961520881565b6101d9620249f081565b6101d97f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b60365461014f906001600160a01b031681565b61018d61027e366004611087565b610464565b6101d97f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b61014f61203081565b61018d6102c13660046110c8565b610474565b61018d6102d4366004611151565b610648565b6101d97f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b336002600160a01b03146103495760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b60448201526064015b60405180910390fd5b600054610100900460ff16158080156103695750600054600160ff909116105b806103835750303b158015610383575060005460ff166001145b6103e65760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610340565b6000805460ff191660011790558015610409576000805461ff0019166101001790555b6104168686868686610657565b801561045c576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b61046f8383836107a7565b505050565b6034546001600160a01b031633146104df5760405162461bcd60e51b815260206004820152602860248201527f4368696c6445524332305072656469636174653a204f4e4c595f53544154455f6044820152672922a1a2a4ab22a960c11b6064820152608401610340565b6035546001600160a01b0384811691161461054d5760405162461bcd60e51b815260206004820152602860248201527f4368696c6445524332305072656469636174653a204f4e4c595f524f4f545f50604482015267524544494341544560c01b6064820152608401610340565b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82161057c60206000848661117d565b610585916111a7565b036105a45761059f61059a826020818661117d565b610b1d565b610642565b7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad6105d360206000848661117d565b6105dc916111a7565b036105eb5761059f8282610dc8565b60405162461bcd60e51b815260206004820152602660248201527f4368696c6445524332305072656469636174653a20494e56414c49445f5349476044820152654e415455524560d01b6064820152608401610340565b50505050565b6106538233836107a7565b5050565b6001600160a01b0385161580159061067757506001600160a01b03841615155b801561068b57506001600160a01b03831615155b801561069f57506001600160a01b03821615155b6106fb5760405162461bcd60e51b815260206004820152602760248201527f4368696c6445524332305072656469636174653a204241445f494e495449414c60448201526624ad20aa24a7a760c91b6064820152608401610340565b603380546001600160a01b03199081166001600160a01b0388811691909117909255603480548216878416179055603580548216868416179055603680549091168483161790558116156107a0576001600160a01b03811660008181526037602052604080822080546001600160a01b03191661101090811790915590519092917f46bd56f98e1b14fd35691959270a6e1edf7cb8fcd489e0f9dda89e46c0d1ff0d91a35b5050505050565b826001600160a01b03163b60000361080b5760405162461bcd60e51b815260206004820152602160248201527f4368696c6445524332305072656469636174653a204e4f545f434f4e545241436044820152601560fa1b6064820152608401610340565b6000836001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa15801561084b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086f91906111c5565b6001600160a01b038181166000908152603760205260409020549192508581169116146108ae5760405162461bcd60e51b8152600401610340906111e2565b6001600160a01b0381166108c4576108c4611225565b306001600160a01b0316846001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa15801561090c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093091906111c5565b6001600160a01b03161461094657610946611225565b604051632770a7eb60e21b81526001600160a01b03851690639dc29fac90610974903390869060040161123b565b6020604051808303816000875af1158015610993573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109b79190611254565b610a035760405162461bcd60e51b815260206004820181905260248201527f4368696c6445524332305072656469636174653a204255524e5f4641494c45446044820152606401610340565b603354603554604080517f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286960208201526001600160a01b0385811682840152336060830152878116608083015260a08083018890528351808403909101815260c08301938490526316f1983160e01b909352938416936316f1983193610a8e9391169160c4016112bc565b600060405180830381600087803b158015610aa857600080fd5b505af1158015610abc573d6000803e3d6000fd5b50505050826001600160a01b0316846001600160a01b0316826001600160a01b03167fa0923f060a16fc784558d43de424ffde7b01643de5e5d335851b9df94c76bb273386604051610b0f92919061123b565b60405180910390a450505050565b6000808080610b2e858701876112e8565b6001600160a01b0380851660009081526037602052604090205494985092965090945092501680610b715760405162461bcd60e51b8152600401610340906111e2565b806001600160a01b03163b600003610b8b57610b8b611225565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bcb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bef91906111c5565b9050856001600160a01b0316816001600160a01b031614610c1257610c12611225565b6001600160a01b038116610c2857610c28611225565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c9491906111c5565b6001600160a01b031614610caa57610caa611225565b6040516340c10f1960e01b81526001600160a01b038316906340c10f1990610cd8908790879060040161123b565b6020604051808303816000875af1158015610cf7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d1b9190611254565b610d675760405162461bcd60e51b815260206004820181905260248201527f4368696c6445524332305072656469636174653a204d494e545f4641494c45446044820152606401610340565b836001600160a01b0316826001600160a01b0316876001600160a01b03167fdf34f3a3ed8bedc14a4b284ebaee5374d55b64bac6a84c270dabe8fd6b4cdafd8887604051610db692919061123b565b60405180910390a45050505050505050565b6000808080610dd9858701876113dc565b92975090955093509150506001600160a01b038416610dfa57610dfa611225565b6001600160a01b038481166000908152603760205260409020541615610e2257610e22611225565b6036546040516bffffffffffffffffffffffff19606087901b166020820152600091610e72916001600160a01b039091169060340160405160208183030381529060405280519060200120610f3d565b6001600160a01b038681166000908152603760205260409081902080546001600160a01b031916928416928317905551637b69774360e11b81529192509063f6d2ee8690610eca908890889088908890600401611469565b600060405180830381600087803b158015610ee457600080fd5b505af1158015610ef8573d6000803e3d6000fd5b50506040516001600160a01b038085169350881691507f46bd56f98e1b14fd35691959270a6e1edf7cb8fcd489e0f9dda89e46c0d1ff0d90600090a350505050505050565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b038116610fd45760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b6044820152606401610340565b92915050565b6001600160a01b0381168114610fef57600080fd5b50565b600080600080600060a0868803121561100a57600080fd5b853561101581610fda565b9450602086013561102581610fda565b9350604086013561103581610fda565b9250606086013561104581610fda565b9150608086013561105581610fda565b809150509295509295909350565b60006020828403121561107557600080fd5b813561108081610fda565b9392505050565b60008060006060848603121561109c57600080fd5b83356110a781610fda565b925060208401356110b781610fda565b929592945050506040919091013590565b600080600080606085870312156110de57600080fd5b8435935060208501356110f081610fda565b9250604085013567ffffffffffffffff8082111561110d57600080fd5b818701915087601f83011261112157600080fd5b81358181111561113057600080fd5b88602082850101111561114257600080fd5b95989497505060200194505050565b6000806040838503121561116457600080fd5b823561116f81610fda565b946020939093013593505050565b6000808585111561118d57600080fd5b8386111561119a57600080fd5b5050820193919092039150565b80356020831015610fd457600019602084900360031b1b1692915050565b6000602082840312156111d757600080fd5b815161108081610fda565b60208082526023908201527f4368696c6445524332305072656469636174653a20554e4d41505045445f544f60408201526225a2a760e91b606082015260800190565b634e487b7160e01b600052600160045260246000fd5b6001600160a01b03929092168252602082015260400190565b60006020828403121561126657600080fd5b8151801515811461108057600080fd5b6000815180845260005b8181101561129c57602081850181015186830182015201611280565b506000602082860101526020601f19601f83011685010191505092915050565b6001600160a01b03831681526040602082018190526000906112e090830184611276565b949350505050565b600080600080608085870312156112fe57600080fd5b843561130981610fda565b9350602085013561131981610fda565b9250604085013561132981610fda565b9396929550929360600135925050565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261136057600080fd5b813567ffffffffffffffff8082111561137b5761137b611339565b604051601f8301601f19908116603f011681019082821181831017156113a3576113a3611339565b816040528381528660208588010111156113bc57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060a086880312156113f457600080fd5b85359450602086013561140681610fda565b9350604086013567ffffffffffffffff8082111561142357600080fd5b61142f89838a0161134f565b9450606088013591508082111561144557600080fd5b506114528882890161134f565b925050608086013560ff8116811461105557600080fd5b6001600160a01b038516815260806020820181905260009061148d90830186611276565b828103604084015261149f8186611276565b91505060ff831660608301529594505050505056fea26469706673582212200a9bd04ce459c321a21b5d2d1e75f54fc0466e0ee822ecf79ffa26d25a1e1f2664736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var ChildERC20PredicateACLArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"ChildERC20PredicateAccessList\",\n \"sourceName\": \"contracts/child/ChildERC20PredicateAccessList.sol\",\n \"abi\": [\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"only\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"Unauthorized\",\n \"type\": \"error\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"block\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bool\",\n \"name\": \"status\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"AllowListUsageSet\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"block\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bool\",\n \"name\": \"status\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"BlockListUsageSet\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2ERC20Deposit\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2ERC20Withdraw\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"L2TokenMapped\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"previousOwner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"OwnershipTransferStarted\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"previousOwner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"OwnershipTransferred\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"ALLOWLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"BLOCKLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAP_TOKEN_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TOKEN_CONTRACT\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"READ_ADDRESSLIST_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"SYSTEM\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"acceptOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childTokenTemplate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newL2StateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newStateReceiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newRootERC20Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newNativeTokenRootAddress\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseAllowList\",\n \"type\": \"bool\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseBlockList\",\n \"type\": \"bool\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newL2StateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newStateReceiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newRootERC20Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newNativeTokenRootAddress\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"l2StateSender\",\n \"outputs\": [\n {\n \"internalType\": \"contract IStateSender\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onStateReceive\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"owner\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"pendingOwner\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"renounceOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"rootERC20Predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"rootTokenToChildToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseAllowList\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"setAllowList\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseBlockList\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"setBlockList\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"stateReceiver\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"transferOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC20\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"withdraw\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC20\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"withdrawTo\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50611c8e806100206000396000f3fe608060405234801561001057600080fd5b506004361061018f5760003560e01c80638da5cb5b116100e4578063c5e4683a11610092578063c5e4683a14610323578063d41f177114610336578063e0563ab11461035d578063e30c397814610366578063eeb4994514610377578063f2fde38b1461038a578063f3fef3a31461039d578063f6451255146103b057600080fd5b80638da5cb5b1461029f578063947287cf146102b057806397e5230d146102b9578063b1768065146102c3578063b68ad1e4146102ea578063c1225a20146102fd578063c3b35a7e1461031057600080fd5b806354f8abad1161014157806354f8abad1461021a57806355b01e4d1461022d5780635ea5df791461023b578063715018a61461025257806371cf93b71461025a57806379ba50971461026d5780637efab4f51461027557600080fd5b806305dc2e8f1461019457806307b3e252146101c45780631459457a146101d25780631bc114ba146101e7578063284017f5146101fa5780633b878c221461020357806351351d531461020c575b600080fd5b60fd546101a7906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101a76004600360981b0181565b6101e56101e0366004611616565b6103d7565b005b60fc546101a7906001600160a01b031681565b6101a761202081565b6101a761101081565b6101a76002600160a01b0381565b6101e5610228366004611695565b6104db565b6101a76004600160991b0181565b61024461138881565b6040519081526020016101bb565b6101e56105fe565b60fe546101a7906001600160a01b031681565b6101e5610612565b6101a761028336600461173e565b610100602052600090815260409020546001600160a01b031681565b6033546001600160a01b03166101a7565b61024461520881565b610244620249f081565b6102447f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b60ff546101a7906001600160a01b031681565b6101e561030b366004611762565b61068c565b6101e561031e36600461177f565b6106db565b6101e5610331366004611762565b6106f3565b6102447f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b6101a761203081565b6065546001600160a01b03166101a7565b6101e56103853660046117c0565b61073a565b6101e561039836600461173e565b61090e565b6101e56103ab366004611849565b61097f565b6102447f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b336002600160a01b03146104075760405163973d02cb60e01b81526004016103fe90611875565b60405180910390fd5b600054610100900460ff16158080156104275750600054600160ff909116105b806104415750303b158015610441575060005460ff166001145b61045d5760405162461bcd60e51b81526004016103fe90611899565b6000805460ff191660011790558015610480576000805461ff0019166101001790555b61048d8686868686610996565b80156104d3576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b336002600160a01b03146105025760405163973d02cb60e01b81526004016103fe90611875565b600054610100900460ff16158080156105225750600054600160ff909116105b8061053c5750303b15801561053c575060005460ff166001145b6105585760405162461bcd60e51b81526004016103fe90611899565b6000805460ff19166001179055801561057b576000805461ff0019166101001790555b6105888989898989610996565b60c9805461ffff191685151561ff00191617610100851515021790556105ad82610ae7565b80156105f3576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050505050565b610606610b00565b6106106000610ae7565b565b60655433906001600160a01b031681146106805760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016103fe565b61068981610ae7565b50565b610694610b00565b60c9805461ff0019166101008315159081029190911790915560405143907f61d574757cde41a357d030b39b2705796ccd699578037ab9a1cfd8117d82bf8690600090a350565b6106e3610b5a565b6106ee838383610b62565b505050565b6106fb610b00565b60c9805460ff191682151590811790915560405143907fe0a0f0fa52db091cb71c202d80420311430ce1ae2e7794149877b6720ce8bf0b90600090a350565b60fd546001600160a01b031633146107a55760405162461bcd60e51b815260206004820152602860248201527f4368696c6445524332305072656469636174653a204f4e4c595f53544154455f6044820152672922a1a2a4ab22a960c11b60648201526084016103fe565b60fe546001600160a01b038481169116146108135760405162461bcd60e51b815260206004820152602860248201527f4368696c6445524332305072656469636174653a204f4e4c595f524f4f545f50604482015267524544494341544560c01b60648201526084016103fe565b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f8216108426020600084866118e7565b61084b91611911565b0361086a5761086561086082602081866118e7565b610ed9565b610908565b7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad6108996020600084866118e7565b6108a291611911565b036108b1576108658282611185565b60405162461bcd60e51b815260206004820152602660248201527f4368696c6445524332305072656469636174653a20494e56414c49445f5349476044820152654e415455524560d01b60648201526084016103fe565b50505050565b610916610b00565b606580546001600160a01b0383166001600160a01b031990911681179091556109476033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b610987610b5a565b610992823383610b62565b5050565b6001600160a01b038516158015906109b657506001600160a01b03841615155b80156109ca57506001600160a01b03831615155b80156109de57506001600160a01b03821615155b610a3a5760405162461bcd60e51b815260206004820152602760248201527f4368696c6445524332305072656469636174653a204241445f494e495449414c60448201526624ad20aa24a7a760c91b60648201526084016103fe565b60fc80546001600160a01b03199081166001600160a01b038881169190911790925560fd8054821687841617905560fe8054821686841617905560ff8054909116848316179055811615610ae0576001600160a01b0381166000818152610100602052604080822080546001600160a01b03191661101090811790915590519092917f46bd56f98e1b14fd35691959270a6e1edf7cb8fcd489e0f9dda89e46c0d1ff0d91a35b5050505050565b606580546001600160a01b0319169055610689816112fc565b6033546001600160a01b031633146106105760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103fe565b61061061134e565b826001600160a01b03163b600003610bc65760405162461bcd60e51b815260206004820152602160248201527f4368696c6445524332305072656469636174653a204e4f545f434f4e545241436044820152601560fa1b60648201526084016103fe565b6000836001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2a919061192f565b6001600160a01b0381811660009081526101006020526040902054919250858116911614610c6a5760405162461bcd60e51b81526004016103fe9061194c565b6001600160a01b038116610c8057610c8061198f565b306001600160a01b0316846001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cec919061192f565b6001600160a01b031614610d0257610d0261198f565b604051632770a7eb60e21b81526001600160a01b03851690639dc29fac90610d3090339086906004016119a5565b6020604051808303816000875af1158015610d4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d7391906119be565b610dbf5760405162461bcd60e51b815260206004820181905260248201527f4368696c6445524332305072656469636174653a204255524e5f4641494c454460448201526064016103fe565b60fc5460fe54604080517f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286960208201526001600160a01b0385811682840152336060830152878116608083015260a08083018890528351808403909101815260c08301938490526316f1983160e01b909352938416936316f1983193610e4a9391169160c401611a2b565b600060405180830381600087803b158015610e6457600080fd5b505af1158015610e78573d6000803e3d6000fd5b50505050826001600160a01b0316846001600160a01b0316826001600160a01b03167fa0923f060a16fc784558d43de424ffde7b01643de5e5d335851b9df94c76bb273386604051610ecb9291906119a5565b60405180910390a450505050565b6000808080610eea85870187611a57565b6001600160a01b038085166000908152610100602052604090205494985092965090945092501680610f2e5760405162461bcd60e51b81526004016103fe9061194c565b806001600160a01b03163b600003610f4857610f4861198f565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fac919061192f565b9050856001600160a01b0316816001600160a01b031614610fcf57610fcf61198f565b6001600160a01b038116610fe557610fe561198f565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa15801561102d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611051919061192f565b6001600160a01b0316146110675761106761198f565b6040516340c10f1960e01b81526001600160a01b038316906340c10f199061109590879087906004016119a5565b6020604051808303816000875af11580156110b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110d891906119be565b6111245760405162461bcd60e51b815260206004820181905260248201527f4368696c6445524332305072656469636174653a204d494e545f4641494c454460448201526064016103fe565b836001600160a01b0316826001600160a01b0316876001600160a01b03167fdf34f3a3ed8bedc14a4b284ebaee5374d55b64bac6a84c270dabe8fd6b4cdafd88876040516111739291906119a5565b60405180910390a45050505050505050565b600080808061119685870187611b4b565b92975090955093509150506001600160a01b0384166111b7576111b761198f565b6001600160a01b038481166000908152610100602052604090205416156111e0576111e061198f565b60ff546040516bffffffffffffffffffffffff19606087901b166020820152600091611230916001600160a01b039091169060340160405160208183030381529060405280519060200120611564565b6001600160a01b03868116600090815261010060205260409081902080546001600160a01b031916928416928317905551637b69774360e11b81529192509063f6d2ee8690611289908890889088908890600401611bd8565b600060405180830381600087803b1580156112a357600080fd5b505af11580156112b7573d6000803e3d6000fd5b50506040516001600160a01b038085169350881691507f46bd56f98e1b14fd35691959270a6e1edf7cb8fcd489e0f9dda89e46c0d1ff0d90600090a350505050505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60c95460ff161561145957604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600160991b0191611388916113b09190611c23565b6000604051808303818686fa925050503d80600081146113ec576040519150601f19603f3d011682016040523d82523d6000602084013e6113f1565b606091505b509150915081801561141657506000818060200190518101906114149190611c3f565b115b6114565760405162461bcd60e51b81526020600482015260116024820152702224a9a0a62627aba2a22fa9a2a72222a960791b60448201526064016103fe565b50505b60c954610100900460ff161561061057604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600360981b0191611388916114c09190611c23565b6000604051808303818686fa925050503d80600081146114fc576040519150601f19603f3d011682016040523d82523d6000602084013e611501565b606091505b50915091508180156115275750808060200190518101906115229190611c3f565b600114155b6109925760405162461bcd60e51b815260206004820152600e60248201526d212627a1a5a2a22fa9a2a72222a960911b60448201526064016103fe565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b0381166115fb5760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b60448201526064016103fe565b92915050565b6001600160a01b038116811461068957600080fd5b600080600080600060a0868803121561162e57600080fd5b853561163981611601565b9450602086013561164981611601565b9350604086013561165981611601565b9250606086013561166981611601565b9150608086013561167981611601565b809150509295509295909350565b801515811461068957600080fd5b600080600080600080600080610100898b0312156116b257600080fd5b88356116bd81611601565b975060208901356116cd81611601565b965060408901356116dd81611601565b955060608901356116ed81611601565b945060808901356116fd81611601565b935060a089013561170d81611687565b925060c089013561171d81611687565b915060e089013561172d81611601565b809150509295985092959890939650565b60006020828403121561175057600080fd5b813561175b81611601565b9392505050565b60006020828403121561177457600080fd5b813561175b81611687565b60008060006060848603121561179457600080fd5b833561179f81611601565b925060208401356117af81611601565b929592945050506040919091013590565b600080600080606085870312156117d657600080fd5b8435935060208501356117e881611601565b9250604085013567ffffffffffffffff8082111561180557600080fd5b818701915087601f83011261181957600080fd5b81358181111561182857600080fd5b88602082850101111561183a57600080fd5b95989497505060200194505050565b6000806040838503121561185c57600080fd5b823561186781611601565b946020939093013593505050565b6020808252600a908201526914d654d5115350d0531360b21b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b600080858511156118f757600080fd5b8386111561190457600080fd5b5050820193919092039150565b803560208310156115fb57600019602084900360031b1b1692915050565b60006020828403121561194157600080fd5b815161175b81611601565b60208082526023908201527f4368696c6445524332305072656469636174653a20554e4d41505045445f544f60408201526225a2a760e91b606082015260800190565b634e487b7160e01b600052600160045260246000fd5b6001600160a01b03929092168252602082015260400190565b6000602082840312156119d057600080fd5b815161175b81611687565b60005b838110156119f65781810151838201526020016119de565b50506000910152565b60008151808452611a178160208601602086016119db565b601f01601f19169290920160200192915050565b6001600160a01b0383168152604060208201819052600090611a4f908301846119ff565b949350505050565b60008060008060808587031215611a6d57600080fd5b8435611a7881611601565b93506020850135611a8881611601565b92506040850135611a9881611601565b9396929550929360600135925050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112611acf57600080fd5b813567ffffffffffffffff80821115611aea57611aea611aa8565b604051601f8301601f19908116603f01168101908282118183101715611b1257611b12611aa8565b81604052838152866020858801011115611b2b57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060a08688031215611b6357600080fd5b853594506020860135611b7581611601565b9350604086013567ffffffffffffffff80821115611b9257600080fd5b611b9e89838a01611abe565b94506060880135915080821115611bb457600080fd5b50611bc188828901611abe565b925050608086013560ff8116811461167957600080fd5b6001600160a01b0385168152608060208201819052600090611bfc908301866119ff565b8281036040840152611c0e81866119ff565b91505060ff8316606083015295945050505050565b60008251611c358184602087016119db565b9190910192915050565b600060208284031215611c5157600080fd5b505191905056fea26469706673582212206cf96fe411dad9394c135358686b98cae9a19f7df3e05cbb3962783ddc9e15a964736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b506004361061018f5760003560e01c80638da5cb5b116100e4578063c5e4683a11610092578063c5e4683a14610323578063d41f177114610336578063e0563ab11461035d578063e30c397814610366578063eeb4994514610377578063f2fde38b1461038a578063f3fef3a31461039d578063f6451255146103b057600080fd5b80638da5cb5b1461029f578063947287cf146102b057806397e5230d146102b9578063b1768065146102c3578063b68ad1e4146102ea578063c1225a20146102fd578063c3b35a7e1461031057600080fd5b806354f8abad1161014157806354f8abad1461021a57806355b01e4d1461022d5780635ea5df791461023b578063715018a61461025257806371cf93b71461025a57806379ba50971461026d5780637efab4f51461027557600080fd5b806305dc2e8f1461019457806307b3e252146101c45780631459457a146101d25780631bc114ba146101e7578063284017f5146101fa5780633b878c221461020357806351351d531461020c575b600080fd5b60fd546101a7906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101a76004600360981b0181565b6101e56101e0366004611616565b6103d7565b005b60fc546101a7906001600160a01b031681565b6101a761202081565b6101a761101081565b6101a76002600160a01b0381565b6101e5610228366004611695565b6104db565b6101a76004600160991b0181565b61024461138881565b6040519081526020016101bb565b6101e56105fe565b60fe546101a7906001600160a01b031681565b6101e5610612565b6101a761028336600461173e565b610100602052600090815260409020546001600160a01b031681565b6033546001600160a01b03166101a7565b61024461520881565b610244620249f081565b6102447f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b60ff546101a7906001600160a01b031681565b6101e561030b366004611762565b61068c565b6101e561031e36600461177f565b6106db565b6101e5610331366004611762565b6106f3565b6102447f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b6101a761203081565b6065546001600160a01b03166101a7565b6101e56103853660046117c0565b61073a565b6101e561039836600461173e565b61090e565b6101e56103ab366004611849565b61097f565b6102447f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b336002600160a01b03146104075760405163973d02cb60e01b81526004016103fe90611875565b60405180910390fd5b600054610100900460ff16158080156104275750600054600160ff909116105b806104415750303b158015610441575060005460ff166001145b61045d5760405162461bcd60e51b81526004016103fe90611899565b6000805460ff191660011790558015610480576000805461ff0019166101001790555b61048d8686868686610996565b80156104d3576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b336002600160a01b03146105025760405163973d02cb60e01b81526004016103fe90611875565b600054610100900460ff16158080156105225750600054600160ff909116105b8061053c5750303b15801561053c575060005460ff166001145b6105585760405162461bcd60e51b81526004016103fe90611899565b6000805460ff19166001179055801561057b576000805461ff0019166101001790555b6105888989898989610996565b60c9805461ffff191685151561ff00191617610100851515021790556105ad82610ae7565b80156105f3576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050505050565b610606610b00565b6106106000610ae7565b565b60655433906001600160a01b031681146106805760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016103fe565b61068981610ae7565b50565b610694610b00565b60c9805461ff0019166101008315159081029190911790915560405143907f61d574757cde41a357d030b39b2705796ccd699578037ab9a1cfd8117d82bf8690600090a350565b6106e3610b5a565b6106ee838383610b62565b505050565b6106fb610b00565b60c9805460ff191682151590811790915560405143907fe0a0f0fa52db091cb71c202d80420311430ce1ae2e7794149877b6720ce8bf0b90600090a350565b60fd546001600160a01b031633146107a55760405162461bcd60e51b815260206004820152602860248201527f4368696c6445524332305072656469636174653a204f4e4c595f53544154455f6044820152672922a1a2a4ab22a960c11b60648201526084016103fe565b60fe546001600160a01b038481169116146108135760405162461bcd60e51b815260206004820152602860248201527f4368696c6445524332305072656469636174653a204f4e4c595f524f4f545f50604482015267524544494341544560c01b60648201526084016103fe565b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f8216108426020600084866118e7565b61084b91611911565b0361086a5761086561086082602081866118e7565b610ed9565b610908565b7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad6108996020600084866118e7565b6108a291611911565b036108b1576108658282611185565b60405162461bcd60e51b815260206004820152602660248201527f4368696c6445524332305072656469636174653a20494e56414c49445f5349476044820152654e415455524560d01b60648201526084016103fe565b50505050565b610916610b00565b606580546001600160a01b0383166001600160a01b031990911681179091556109476033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b610987610b5a565b610992823383610b62565b5050565b6001600160a01b038516158015906109b657506001600160a01b03841615155b80156109ca57506001600160a01b03831615155b80156109de57506001600160a01b03821615155b610a3a5760405162461bcd60e51b815260206004820152602760248201527f4368696c6445524332305072656469636174653a204241445f494e495449414c60448201526624ad20aa24a7a760c91b60648201526084016103fe565b60fc80546001600160a01b03199081166001600160a01b038881169190911790925560fd8054821687841617905560fe8054821686841617905560ff8054909116848316179055811615610ae0576001600160a01b0381166000818152610100602052604080822080546001600160a01b03191661101090811790915590519092917f46bd56f98e1b14fd35691959270a6e1edf7cb8fcd489e0f9dda89e46c0d1ff0d91a35b5050505050565b606580546001600160a01b0319169055610689816112fc565b6033546001600160a01b031633146106105760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103fe565b61061061134e565b826001600160a01b03163b600003610bc65760405162461bcd60e51b815260206004820152602160248201527f4368696c6445524332305072656469636174653a204e4f545f434f4e545241436044820152601560fa1b60648201526084016103fe565b6000836001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2a919061192f565b6001600160a01b0381811660009081526101006020526040902054919250858116911614610c6a5760405162461bcd60e51b81526004016103fe9061194c565b6001600160a01b038116610c8057610c8061198f565b306001600160a01b0316846001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cec919061192f565b6001600160a01b031614610d0257610d0261198f565b604051632770a7eb60e21b81526001600160a01b03851690639dc29fac90610d3090339086906004016119a5565b6020604051808303816000875af1158015610d4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d7391906119be565b610dbf5760405162461bcd60e51b815260206004820181905260248201527f4368696c6445524332305072656469636174653a204255524e5f4641494c454460448201526064016103fe565b60fc5460fe54604080517f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286960208201526001600160a01b0385811682840152336060830152878116608083015260a08083018890528351808403909101815260c08301938490526316f1983160e01b909352938416936316f1983193610e4a9391169160c401611a2b565b600060405180830381600087803b158015610e6457600080fd5b505af1158015610e78573d6000803e3d6000fd5b50505050826001600160a01b0316846001600160a01b0316826001600160a01b03167fa0923f060a16fc784558d43de424ffde7b01643de5e5d335851b9df94c76bb273386604051610ecb9291906119a5565b60405180910390a450505050565b6000808080610eea85870187611a57565b6001600160a01b038085166000908152610100602052604090205494985092965090945092501680610f2e5760405162461bcd60e51b81526004016103fe9061194c565b806001600160a01b03163b600003610f4857610f4861198f565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fac919061192f565b9050856001600160a01b0316816001600160a01b031614610fcf57610fcf61198f565b6001600160a01b038116610fe557610fe561198f565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa15801561102d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611051919061192f565b6001600160a01b0316146110675761106761198f565b6040516340c10f1960e01b81526001600160a01b038316906340c10f199061109590879087906004016119a5565b6020604051808303816000875af11580156110b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110d891906119be565b6111245760405162461bcd60e51b815260206004820181905260248201527f4368696c6445524332305072656469636174653a204d494e545f4641494c454460448201526064016103fe565b836001600160a01b0316826001600160a01b0316876001600160a01b03167fdf34f3a3ed8bedc14a4b284ebaee5374d55b64bac6a84c270dabe8fd6b4cdafd88876040516111739291906119a5565b60405180910390a45050505050505050565b600080808061119685870187611b4b565b92975090955093509150506001600160a01b0384166111b7576111b761198f565b6001600160a01b038481166000908152610100602052604090205416156111e0576111e061198f565b60ff546040516bffffffffffffffffffffffff19606087901b166020820152600091611230916001600160a01b039091169060340160405160208183030381529060405280519060200120611564565b6001600160a01b03868116600090815261010060205260409081902080546001600160a01b031916928416928317905551637b69774360e11b81529192509063f6d2ee8690611289908890889088908890600401611bd8565b600060405180830381600087803b1580156112a357600080fd5b505af11580156112b7573d6000803e3d6000fd5b50506040516001600160a01b038085169350881691507f46bd56f98e1b14fd35691959270a6e1edf7cb8fcd489e0f9dda89e46c0d1ff0d90600090a350505050505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60c95460ff161561145957604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600160991b0191611388916113b09190611c23565b6000604051808303818686fa925050503d80600081146113ec576040519150601f19603f3d011682016040523d82523d6000602084013e6113f1565b606091505b509150915081801561141657506000818060200190518101906114149190611c3f565b115b6114565760405162461bcd60e51b81526020600482015260116024820152702224a9a0a62627aba2a22fa9a2a72222a960791b60448201526064016103fe565b50505b60c954610100900460ff161561061057604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600360981b0191611388916114c09190611c23565b6000604051808303818686fa925050503d80600081146114fc576040519150601f19603f3d011682016040523d82523d6000602084013e611501565b606091505b50915091508180156115275750808060200190518101906115229190611c3f565b600114155b6109925760405162461bcd60e51b815260206004820152600e60248201526d212627a1a5a2a22fa9a2a72222a960911b60448201526064016103fe565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b0381166115fb5760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b60448201526064016103fe565b92915050565b6001600160a01b038116811461068957600080fd5b600080600080600060a0868803121561162e57600080fd5b853561163981611601565b9450602086013561164981611601565b9350604086013561165981611601565b9250606086013561166981611601565b9150608086013561167981611601565b809150509295509295909350565b801515811461068957600080fd5b600080600080600080600080610100898b0312156116b257600080fd5b88356116bd81611601565b975060208901356116cd81611601565b965060408901356116dd81611601565b955060608901356116ed81611601565b945060808901356116fd81611601565b935060a089013561170d81611687565b925060c089013561171d81611687565b915060e089013561172d81611601565b809150509295985092959890939650565b60006020828403121561175057600080fd5b813561175b81611601565b9392505050565b60006020828403121561177457600080fd5b813561175b81611687565b60008060006060848603121561179457600080fd5b833561179f81611601565b925060208401356117af81611601565b929592945050506040919091013590565b600080600080606085870312156117d657600080fd5b8435935060208501356117e881611601565b9250604085013567ffffffffffffffff8082111561180557600080fd5b818701915087601f83011261181957600080fd5b81358181111561182857600080fd5b88602082850101111561183a57600080fd5b95989497505060200194505050565b6000806040838503121561185c57600080fd5b823561186781611601565b946020939093013593505050565b6020808252600a908201526914d654d5115350d0531360b21b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b600080858511156118f757600080fd5b8386111561190457600080fd5b5050820193919092039150565b803560208310156115fb57600019602084900360031b1b1692915050565b60006020828403121561194157600080fd5b815161175b81611601565b60208082526023908201527f4368696c6445524332305072656469636174653a20554e4d41505045445f544f60408201526225a2a760e91b606082015260800190565b634e487b7160e01b600052600160045260246000fd5b6001600160a01b03929092168252602082015260400190565b6000602082840312156119d057600080fd5b815161175b81611687565b60005b838110156119f65781810151838201526020016119de565b50506000910152565b60008151808452611a178160208601602086016119db565b601f01601f19169290920160200192915050565b6001600160a01b0383168152604060208201819052600090611a4f908301846119ff565b949350505050565b60008060008060808587031215611a6d57600080fd5b8435611a7881611601565b93506020850135611a8881611601565b92506040850135611a9881611601565b9396929550929360600135925050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112611acf57600080fd5b813567ffffffffffffffff80821115611aea57611aea611aa8565b604051601f8301601f19908116603f01168101908282118183101715611b1257611b12611aa8565b81604052838152866020858801011115611b2b57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060a08688031215611b6357600080fd5b853594506020860135611b7581611601565b9350604086013567ffffffffffffffff80821115611b9257600080fd5b611b9e89838a01611abe565b94506060880135915080821115611bb457600080fd5b50611bc188828901611abe565b925050608086013560ff8116811461167957600080fd5b6001600160a01b0385168152608060208201819052600090611bfc908301866119ff565b8281036040840152611c0e81866119ff565b91505060ff8316606083015295945050505050565b60008251611c358184602087016119db565b9190910192915050565b600060208284031215611c5157600080fd5b505191905056fea26469706673582212206cf96fe411dad9394c135358686b98cae9a19f7df3e05cbb3962783ddc9e15a964736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}" +var RootMintableERC20PredicateArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"RootMintableERC20Predicate\",\n \"sourceName\": \"contracts/child/RootMintableERC20Predicate.sol\",\n \"abi\": [\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"only\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"Unauthorized\",\n \"type\": \"error\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"depositor\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2MintableERC20Deposit\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"withdrawer\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2MintableERC20Withdraw\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"L2MintableTokenMapped\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"ALLOWLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"BLOCKLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAP_TOKEN_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TOKEN_CONTRACT\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"READ_ADDRESSLIST_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"SYSTEM\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childERC20Predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childTokenTemplate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC20Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"deposit\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC20Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"depositTo\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newL2StateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newStateReceiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildERC20Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"l2StateSender\",\n \"outputs\": [\n {\n \"internalType\": \"contract IStateSender\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC20Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"mapToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onStateReceive\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"rootTokenToChildToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"stateReceiver\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b5061149f806100206000396000f3fe608060405234801561001057600080fd5b50600436106101425760003560e01c806397e5230d116100b8578063e0563ab11161007c578063e0563ab1146102a2578063eeb49945146102ab578063f213159c146102be578063f4a120f7146102d1578063f6451255146102e4578063f8c8765e1461030b57600080fd5b806397e5230d14610224578063b17680651461022e578063b68ad1e414610255578063d41f177114610268578063d57184e41461028f57600080fd5b806347e7ef241161010a57806347e7ef24146101aa57806351351d53146101bf57806355b01e4d146101cd5780635ea5df79146101db5780637efab4f5146101f2578063947287cf1461021b57600080fd5b806305dc2e8f1461014757806307b3e252146101775780631bc114ba14610185578063284017f5146101985780633b878c22146101a1575b600080fd5b60345461015a906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b61015a6004600360981b0181565b60335461015a906001600160a01b031681565b61015a61202081565b61015a61101081565b6101bd6101b8366004611038565b61031e565b005b61015a6002600160a01b0381565b61015a6004600160991b0181565b6101e461138881565b60405190815260200161016e565b61015a610200366004611064565b6037602052600090815260409020546001600160a01b031681565b6101e461520881565b6101e4620249f081565b6101e47f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b60365461015a906001600160a01b031681565b6101e47f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b60355461015a906001600160a01b031681565b61015a61203081565b6101bd6102b9366004611088565b61032d565b6101bd6102cc366004611111565b6104d5565b61015a6102df366004611064565b6104e5565b6101e47f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b6101bd610319366004611152565b6108b1565b610329823383610a0e565b5050565b6034546001600160a01b031633146103a45760405162461bcd60e51b815260206004820152602f60248201527f526f6f744d696e7461626c6545524332305072656469636174653a204f4e4c5960448201526e2fa9aa20aa22afa922a1a2a4ab22a960891b60648201526084015b60405180910390fd5b6035546001600160a01b0384811691161461041a5760405162461bcd60e51b815260206004820152603060248201527f526f6f744d696e7461626c6545524332305072656469636174653a204f4e4c5960448201526f5f4348494c445f50524544494341544560801b606482015260840161039b565b7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e9828696104496020600084866111ae565b610452916111d8565b036104715761046c61046782602081866111ae565b610b7e565b6104cf565b60405162461bcd60e51b815260206004820152602d60248201527f526f6f744d696e7461626c6545524332305072656469636174653a20494e564160448201526c4c49445f5349474e415455524560981b606482015260840161039b565b50505050565b6104e0838383610a0e565b505050565b60006001600160a01b03821661054f5760405162461bcd60e51b815260206004820152602960248201527f526f6f744d696e7461626c6545524332305072656469636174653a20494e56416044820152682624a22faa27a5a2a760b91b606482015260840161039b565b6001600160a01b0382811660009081526037602052604090205416156105ca5760405162461bcd60e51b815260206004820152602a60248201527f526f6f744d696e7461626c6545524332305072656469636174653a20414c524560448201526910511657d3505414115160b21b606482015260840161039b565b6035546036546040516bffffffffffffffffffffffff19606086901b1660208201526001600160a01b039283169260009261067892911690603401604051602081830303815290604052805190602001208460405160388101919091526f5af43d82803e903d91602b57fd5bf3ff60248201526014810192909252733d602d80600a3d3981f3363d3d373d3d3d363d73825260588201526037600c8201206078820152605560439091012090565b6001600160a01b0385811660008181526037602052604080822080546001600160a01b03191686861617905560335481516306fdde0360e01b81529151959650909316936316f198319387937f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad938b9391926306fdde0392600480830193928290030181865afa158015610710573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107389190810190611231565b896001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610776573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261079e9190810190611231565b8a6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107dc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061080091906112d3565b604051602001610814959493929190611322565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610840929190611374565b600060405180830381600087803b15801561085a57600080fd5b505af115801561086e573d6000803e3d6000fd5b50506040516001600160a01b038085169350871691507fb96a191bae4e25ffdff7f4136994eb0dec75d263750a07c035202c348c9515f090600090a39392505050565b336002600160a01b03146108f55760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b604482015260640161039b565b600054610100900460ff16158080156109155750600054600160ff909116105b8061092f5750303b15801561092f575060005460ff166001145b6109925760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161039b565b6000805460ff1916600117905580156109b5576000805461ff0019166101001790555b6109c185858585610c36565b8015610a07576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b6001600160a01b038084166000908152603760205260409020541680610a3a57610a37846104e5565b90505b6001600160a01b038116610a5057610a50611398565b610a656001600160a01b038516333085610d31565b603354603554604080517f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82160208201526001600160a01b0388811682840152336060830152878116608083015260a08083018890528351808403909101815260c08301938490526316f1983160e01b909352938416936316f1983193610af09391169160c401611374565b600060405180830381600087803b158015610b0a57600080fd5b505af1158015610b1e573d6000803e3d6000fd5b50505050826001600160a01b0316816001600160a01b0316856001600160a01b03167f1666a3f7b8a7494f2ebcebe646a5187ae55b1db3a068097377d90cd64a258ce93386604051610b719291906113ae565b60405180910390a46104cf565b6000808080610b8f858701876113c7565b6001600160a01b0380851660009081526037602052604090205494985092965090945092501680610bc257610bc2611398565b610bd66001600160a01b0386168484610d9c565b826001600160a01b0316816001600160a01b0316866001600160a01b03167fb9f935478aae5b1da868de596dafe0a2b41eeb61311fdd60c6dbbe46a1debee88786604051610c259291906113ae565b60405180910390a450505050505050565b6001600160a01b03841615801590610c5657506001600160a01b03831615155b8015610c6a57506001600160a01b03821615155b8015610c7e57506001600160a01b03811615155b610ce15760405162461bcd60e51b815260206004820152602e60248201527f526f6f744d696e7461626c6545524332305072656469636174653a204241445f60448201526d24a724aa24a0a624ad20aa24a7a760911b606482015260840161039b565b603380546001600160a01b039586166001600160a01b0319918216179091556034805494861694821694909417909355603580549285169284169290921790915560368054919093169116179055565b6040516001600160a01b03808516602483015283166044820152606481018290526104cf9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610dbb565b6104e08363a9059cbb60e01b8484604051602401610d659291906113ae565b6000610e10826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610e909092919063ffffffff16565b9050805160001480610e31575080806020019051810190610e319190611418565b6104e05760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161039b565b6060610e9f8484600085610ea7565b949350505050565b606082471015610f085760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161039b565b600080866001600160a01b03168587604051610f24919061143a565b60006040518083038185875af1925050503d8060008114610f61576040519150601f19603f3d011682016040523d82523d6000602084013e610f66565b606091505b5091509150610f7787838387610f82565b979650505050505050565b60608315610ff1578251600003610fea576001600160a01b0385163b610fea5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161039b565b5081610e9f565b610e9f83838151156110065781518083602001fd5b8060405162461bcd60e51b815260040161039b9190611456565b6001600160a01b038116811461103557600080fd5b50565b6000806040838503121561104b57600080fd5b823561105681611020565b946020939093013593505050565b60006020828403121561107657600080fd5b813561108181611020565b9392505050565b6000806000806060858703121561109e57600080fd5b8435935060208501356110b081611020565b9250604085013567ffffffffffffffff808211156110cd57600080fd5b818701915087601f8301126110e157600080fd5b8135818111156110f057600080fd5b88602082850101111561110257600080fd5b95989497505060200194505050565b60008060006060848603121561112657600080fd5b833561113181611020565b9250602084013561114181611020565b929592945050506040919091013590565b6000806000806080858703121561116857600080fd5b843561117381611020565b9350602085013561118381611020565b9250604085013561119381611020565b915060608501356111a381611020565b939692955090935050565b600080858511156111be57600080fd5b838611156111cb57600080fd5b5050820193919092039150565b803560208310156111f157600019602084900360031b1b165b92915050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015611228578181015183820152602001611210565b50506000910152565b60006020828403121561124357600080fd5b815167ffffffffffffffff8082111561125b57600080fd5b818401915084601f83011261126f57600080fd5b815181811115611281576112816111f7565b604051601f8201601f19908116603f011681019083821181831017156112a9576112a96111f7565b816040528281528760208487010111156112c257600080fd5b610f7783602083016020880161120d565b6000602082840312156112e557600080fd5b815160ff8116811461108157600080fd5b6000815180845261130e81602086016020860161120d565b601f01601f19169290920160200192915050565b8581526001600160a01b038516602082015260a06040820181905260009061134c908301866112f6565b828103606084015261135e81866112f6565b91505060ff831660808301529695505050505050565b6001600160a01b0383168152604060208201819052600090610e9f908301846112f6565b634e487b7160e01b600052600160045260246000fd5b6001600160a01b03929092168252602082015260400190565b600080600080608085870312156113dd57600080fd5b84356113e881611020565b935060208501356113f881611020565b9250604085013561140881611020565b9396929550929360600135925050565b60006020828403121561142a57600080fd5b8151801515811461108157600080fd5b6000825161144c81846020870161120d565b9190910192915050565b60208152600061108160208301846112f656fea26469706673582212208702e16b20ba9010d9192a951f06043b831a88e90ebd7657e3470c54f66e57f064736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101425760003560e01c806397e5230d116100b8578063e0563ab11161007c578063e0563ab1146102a2578063eeb49945146102ab578063f213159c146102be578063f4a120f7146102d1578063f6451255146102e4578063f8c8765e1461030b57600080fd5b806397e5230d14610224578063b17680651461022e578063b68ad1e414610255578063d41f177114610268578063d57184e41461028f57600080fd5b806347e7ef241161010a57806347e7ef24146101aa57806351351d53146101bf57806355b01e4d146101cd5780635ea5df79146101db5780637efab4f5146101f2578063947287cf1461021b57600080fd5b806305dc2e8f1461014757806307b3e252146101775780631bc114ba14610185578063284017f5146101985780633b878c22146101a1575b600080fd5b60345461015a906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b61015a6004600360981b0181565b60335461015a906001600160a01b031681565b61015a61202081565b61015a61101081565b6101bd6101b8366004611038565b61031e565b005b61015a6002600160a01b0381565b61015a6004600160991b0181565b6101e461138881565b60405190815260200161016e565b61015a610200366004611064565b6037602052600090815260409020546001600160a01b031681565b6101e461520881565b6101e4620249f081565b6101e47f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b60365461015a906001600160a01b031681565b6101e47f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b60355461015a906001600160a01b031681565b61015a61203081565b6101bd6102b9366004611088565b61032d565b6101bd6102cc366004611111565b6104d5565b61015a6102df366004611064565b6104e5565b6101e47f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b6101bd610319366004611152565b6108b1565b610329823383610a0e565b5050565b6034546001600160a01b031633146103a45760405162461bcd60e51b815260206004820152602f60248201527f526f6f744d696e7461626c6545524332305072656469636174653a204f4e4c5960448201526e2fa9aa20aa22afa922a1a2a4ab22a960891b60648201526084015b60405180910390fd5b6035546001600160a01b0384811691161461041a5760405162461bcd60e51b815260206004820152603060248201527f526f6f744d696e7461626c6545524332305072656469636174653a204f4e4c5960448201526f5f4348494c445f50524544494341544560801b606482015260840161039b565b7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e9828696104496020600084866111ae565b610452916111d8565b036104715761046c61046782602081866111ae565b610b7e565b6104cf565b60405162461bcd60e51b815260206004820152602d60248201527f526f6f744d696e7461626c6545524332305072656469636174653a20494e564160448201526c4c49445f5349474e415455524560981b606482015260840161039b565b50505050565b6104e0838383610a0e565b505050565b60006001600160a01b03821661054f5760405162461bcd60e51b815260206004820152602960248201527f526f6f744d696e7461626c6545524332305072656469636174653a20494e56416044820152682624a22faa27a5a2a760b91b606482015260840161039b565b6001600160a01b0382811660009081526037602052604090205416156105ca5760405162461bcd60e51b815260206004820152602a60248201527f526f6f744d696e7461626c6545524332305072656469636174653a20414c524560448201526910511657d3505414115160b21b606482015260840161039b565b6035546036546040516bffffffffffffffffffffffff19606086901b1660208201526001600160a01b039283169260009261067892911690603401604051602081830303815290604052805190602001208460405160388101919091526f5af43d82803e903d91602b57fd5bf3ff60248201526014810192909252733d602d80600a3d3981f3363d3d373d3d3d363d73825260588201526037600c8201206078820152605560439091012090565b6001600160a01b0385811660008181526037602052604080822080546001600160a01b03191686861617905560335481516306fdde0360e01b81529151959650909316936316f198319387937f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad938b9391926306fdde0392600480830193928290030181865afa158015610710573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107389190810190611231565b896001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610776573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261079e9190810190611231565b8a6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107dc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061080091906112d3565b604051602001610814959493929190611322565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610840929190611374565b600060405180830381600087803b15801561085a57600080fd5b505af115801561086e573d6000803e3d6000fd5b50506040516001600160a01b038085169350871691507fb96a191bae4e25ffdff7f4136994eb0dec75d263750a07c035202c348c9515f090600090a39392505050565b336002600160a01b03146108f55760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b604482015260640161039b565b600054610100900460ff16158080156109155750600054600160ff909116105b8061092f5750303b15801561092f575060005460ff166001145b6109925760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161039b565b6000805460ff1916600117905580156109b5576000805461ff0019166101001790555b6109c185858585610c36565b8015610a07576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b6001600160a01b038084166000908152603760205260409020541680610a3a57610a37846104e5565b90505b6001600160a01b038116610a5057610a50611398565b610a656001600160a01b038516333085610d31565b603354603554604080517f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82160208201526001600160a01b0388811682840152336060830152878116608083015260a08083018890528351808403909101815260c08301938490526316f1983160e01b909352938416936316f1983193610af09391169160c401611374565b600060405180830381600087803b158015610b0a57600080fd5b505af1158015610b1e573d6000803e3d6000fd5b50505050826001600160a01b0316816001600160a01b0316856001600160a01b03167f1666a3f7b8a7494f2ebcebe646a5187ae55b1db3a068097377d90cd64a258ce93386604051610b719291906113ae565b60405180910390a46104cf565b6000808080610b8f858701876113c7565b6001600160a01b0380851660009081526037602052604090205494985092965090945092501680610bc257610bc2611398565b610bd66001600160a01b0386168484610d9c565b826001600160a01b0316816001600160a01b0316866001600160a01b03167fb9f935478aae5b1da868de596dafe0a2b41eeb61311fdd60c6dbbe46a1debee88786604051610c259291906113ae565b60405180910390a450505050505050565b6001600160a01b03841615801590610c5657506001600160a01b03831615155b8015610c6a57506001600160a01b03821615155b8015610c7e57506001600160a01b03811615155b610ce15760405162461bcd60e51b815260206004820152602e60248201527f526f6f744d696e7461626c6545524332305072656469636174653a204241445f60448201526d24a724aa24a0a624ad20aa24a7a760911b606482015260840161039b565b603380546001600160a01b039586166001600160a01b0319918216179091556034805494861694821694909417909355603580549285169284169290921790915560368054919093169116179055565b6040516001600160a01b03808516602483015283166044820152606481018290526104cf9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610dbb565b6104e08363a9059cbb60e01b8484604051602401610d659291906113ae565b6000610e10826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610e909092919063ffffffff16565b9050805160001480610e31575080806020019051810190610e319190611418565b6104e05760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161039b565b6060610e9f8484600085610ea7565b949350505050565b606082471015610f085760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161039b565b600080866001600160a01b03168587604051610f24919061143a565b60006040518083038185875af1925050503d8060008114610f61576040519150601f19603f3d011682016040523d82523d6000602084013e610f66565b606091505b5091509150610f7787838387610f82565b979650505050505050565b60608315610ff1578251600003610fea576001600160a01b0385163b610fea5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161039b565b5081610e9f565b610e9f83838151156110065781518083602001fd5b8060405162461bcd60e51b815260040161039b9190611456565b6001600160a01b038116811461103557600080fd5b50565b6000806040838503121561104b57600080fd5b823561105681611020565b946020939093013593505050565b60006020828403121561107657600080fd5b813561108181611020565b9392505050565b6000806000806060858703121561109e57600080fd5b8435935060208501356110b081611020565b9250604085013567ffffffffffffffff808211156110cd57600080fd5b818701915087601f8301126110e157600080fd5b8135818111156110f057600080fd5b88602082850101111561110257600080fd5b95989497505060200194505050565b60008060006060848603121561112657600080fd5b833561113181611020565b9250602084013561114181611020565b929592945050506040919091013590565b6000806000806080858703121561116857600080fd5b843561117381611020565b9350602085013561118381611020565b9250604085013561119381611020565b915060608501356111a381611020565b939692955090935050565b600080858511156111be57600080fd5b838611156111cb57600080fd5b5050820193919092039150565b803560208310156111f157600019602084900360031b1b165b92915050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015611228578181015183820152602001611210565b50506000910152565b60006020828403121561124357600080fd5b815167ffffffffffffffff8082111561125b57600080fd5b818401915084601f83011261126f57600080fd5b815181811115611281576112816111f7565b604051601f8201601f19908116603f011681019083821181831017156112a9576112a96111f7565b816040528281528760208487010111156112c257600080fd5b610f7783602083016020880161120d565b6000602082840312156112e557600080fd5b815160ff8116811461108157600080fd5b6000815180845261130e81602086016020860161120d565b601f01601f19169290920160200192915050565b8581526001600160a01b038516602082015260a06040820181905260009061134c908301866112f6565b828103606084015261135e81866112f6565b91505060ff831660808301529695505050505050565b6001600160a01b0383168152604060208201819052600090610e9f908301846112f6565b634e487b7160e01b600052600160045260246000fd5b6001600160a01b03929092168252602082015260400190565b600080600080608085870312156113dd57600080fd5b84356113e881611020565b935060208501356113f881611020565b9250604085013561140881611020565b9396929550929360600135925050565b60006020828403121561142a57600080fd5b8151801515811461108157600080fd5b6000825161144c81846020870161120d565b9190910192915050565b60208152600061108160208301846112f656fea26469706673582212208702e16b20ba9010d9192a951f06043b831a88e90ebd7657e3470c54f66e57f064736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var RootMintableERC20PredicateACLArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"RootMintableERC20PredicateAccessList\",\n \"sourceName\": \"contracts/child/RootMintableERC20PredicateAccessList.sol\",\n \"abi\": [\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"only\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"Unauthorized\",\n \"type\": \"error\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"block\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bool\",\n \"name\": \"status\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"AllowListUsageSet\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"block\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bool\",\n \"name\": \"status\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"BlockListUsageSet\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"depositor\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2MintableERC20Deposit\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"withdrawer\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2MintableERC20Withdraw\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"L2MintableTokenMapped\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"previousOwner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"OwnershipTransferStarted\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"previousOwner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"OwnershipTransferred\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"ALLOWLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"BLOCKLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAP_TOKEN_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TOKEN_CONTRACT\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"READ_ADDRESSLIST_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"SYSTEM\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"acceptOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childERC20Predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childTokenTemplate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC20Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"deposit\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC20Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"depositTo\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newL2StateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newStateReceiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildERC20Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseAllowList\",\n \"type\": \"bool\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseBlockList\",\n \"type\": \"bool\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newL2StateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newStateReceiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildERC20Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"l2StateSender\",\n \"outputs\": [\n {\n \"internalType\": \"contract IStateSender\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC20Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"mapToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onStateReceive\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"owner\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"pendingOwner\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"renounceOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"rootTokenToChildToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseAllowList\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"setAllowList\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseBlockList\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"setBlockList\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"stateReceiver\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"transferOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50611bfb806100206000396000f3fe608060405234801561001057600080fd5b506004361061019a5760003560e01c8063b1768065116100e4578063e0563ab111610092578063e0563ab114610355578063e30c39781461035e578063eeb499451461036f578063f213159c14610382578063f2fde38b14610395578063f4a120f7146103a8578063f6451255146103bb578063f8c8765e146103e257600080fd5b8063b1768065146102a8578063b68ad1e4146102cf578063c1225a20146102e2578063c5e4683a146102f5578063d41f177114610308578063d57184e41461032f578063d8dd17731461034257600080fd5b806355b01e4d1161014c57806355b01e4d146102255780635ea5df7914610233578063715018a61461024a57806379ba5097146102525780637efab4f51461025a5780638da5cb5b14610284578063947287cf1461029557806397e5230d1461029e57600080fd5b806305dc2e8f1461019f57806307b3e252146101cf5780631bc114ba146101dd578063284017f5146101f05780633b878c22146101f957806347e7ef241461020257806351351d5314610217575b600080fd5b60fd546101b2906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101b26004600360981b0181565b60fc546101b2906001600160a01b031681565b6101b261202081565b6101b261101081565b61021561021036600461164d565b6103f5565b005b6101b26002600160a01b0381565b6101b26004600160991b0181565b61023c61138881565b6040519081526020016101c6565b610215610404565b610215610418565b6101b2610268366004611679565b610100602052600090815260409020546001600160a01b031681565b6033546001600160a01b03166101b2565b61023c61520881565b61023c620249f081565b61023c7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b60ff546101b2906001600160a01b031681565b6102156102f03660046116ab565b610497565b6102156103033660046116ab565b6104e6565b61023c7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b60fe546101b2906001600160a01b031681565b6102156103503660046116c8565b61052d565b6101b261203081565b6065546001600160a01b03166101b2565b61021561037d36600461175e565b61064e565b6102156103903660046117e7565b6107f1565b6102156103a3366004611679565b610801565b6101b26103b6366004611679565b610872565b61023c7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b6102156103f0366004611828565b610c40565b610400823383610d39565b5050565b61040c610eb2565b6104166000610f0c565b565b60655433906001600160a01b0316811461048b5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084015b60405180910390fd5b61049481610f0c565b50565b61049f610eb2565b60c9805461ff0019166101008315159081029190911790915560405143907f61d574757cde41a357d030b39b2705796ccd699578037ab9a1cfd8117d82bf8690600090a350565b6104ee610eb2565b60c9805460ff191682151590811790915560405143907fe0a0f0fa52db091cb71c202d80420311430ce1ae2e7794149877b6720ce8bf0b90600090a350565b336002600160a01b03146105545760405163973d02cb60e01b815260040161048290611884565b600054610100900460ff16158080156105745750600054600160ff909116105b8061058e5750303b15801561058e575060005460ff166001145b6105aa5760405162461bcd60e51b8152600401610482906118a8565b6000805460ff1916600117905580156105cd576000805461ff0019166101001790555b6105d988888888610f25565b60c9805461ffff191685151561ff00191617610100851515021790556105fe82610f0c565b8015610644576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b60fd546001600160a01b031633146106c05760405162461bcd60e51b815260206004820152602f60248201527f526f6f744d696e7461626c6545524332305072656469636174653a204f4e4c5960448201526e2fa9aa20aa22afa922a1a2a4ab22a960891b6064820152608401610482565b60fe546001600160a01b038481169116146107365760405162461bcd60e51b815260206004820152603060248201527f526f6f744d696e7461626c6545524332305072656469636174653a204f4e4c5960448201526f5f4348494c445f50524544494341544560801b6064820152608401610482565b7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e9828696107656020600084866118f6565b61076e91611920565b0361078d5761078861078382602081866118f6565b611020565b6107eb565b60405162461bcd60e51b815260206004820152602d60248201527f526f6f744d696e7461626c6545524332305072656469636174653a20494e564160448201526c4c49445f5349474e415455524560981b6064820152608401610482565b50505050565b6107fc838383610d39565b505050565b610809610eb2565b606580546001600160a01b0383166001600160a01b0319909116811790915561083a6033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60006001600160a01b0382166108dc5760405162461bcd60e51b815260206004820152602960248201527f526f6f744d696e7461626c6545524332305072656469636174653a20494e56416044820152682624a22faa27a5a2a760b91b6064820152608401610482565b6001600160a01b038281166000908152610100602052604090205416156109585760405162461bcd60e51b815260206004820152602a60248201527f526f6f744d696e7461626c6545524332305072656469636174653a20414c524560448201526910511657d3505414115160b21b6064820152608401610482565b60fe5460ff546040516bffffffffffffffffffffffff19606086901b1660208201526001600160a01b0392831692600092610a0692911690603401604051602081830303815290604052805190602001208460405160388101919091526f5af43d82803e903d91602b57fd5bf3ff60248201526014810192909252733d602d80600a3d3981f3363d3d373d3d3d363d73825260588201526037600c8201206078820152605560439091012090565b6001600160a01b038581166000818152610100602052604080822080546001600160a01b03191686861617905560fc5481516306fdde0360e01b81529151959650909316936316f198319387937f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad938b9391926306fdde0392600480830193928290030181865afa158015610a9f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ac79190810190611979565b896001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610b05573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b2d9190810190611979565b8a6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8f9190611a1b565b604051602001610ba3959493929190611a6a565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610bcf929190611abc565b600060405180830381600087803b158015610be957600080fd5b505af1158015610bfd573d6000803e3d6000fd5b50506040516001600160a01b038085169350871691507fb96a191bae4e25ffdff7f4136994eb0dec75d263750a07c035202c348c9515f090600090a39392505050565b336002600160a01b0314610c675760405163973d02cb60e01b815260040161048290611884565b600054610100900460ff1615808015610c875750600054600160ff909116105b80610ca15750303b158015610ca1575060005460ff166001145b610cbd5760405162461bcd60e51b8152600401610482906118a8565b6000805460ff191660011790558015610ce0576000805461ff0019166101001790555b610cec85858585610f25565b8015610d32576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b610d416110d9565b6001600160a01b03808416600090815261010060205260409020541680610d6e57610d6b84610872565b90505b6001600160a01b038116610d8457610d84611ae0565b610d996001600160a01b0385163330856110e1565b60fc5460fe54604080517f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82160208201526001600160a01b0388811682840152336060830152878116608083015260a08083018890528351808403909101815260c08301938490526316f1983160e01b909352938416936316f1983193610e249391169160c401611abc565b600060405180830381600087803b158015610e3e57600080fd5b505af1158015610e52573d6000803e3d6000fd5b50505050826001600160a01b0316816001600160a01b0316856001600160a01b03167f1666a3f7b8a7494f2ebcebe646a5187ae55b1db3a068097377d90cd64a258ce93386604051610ea5929190611af6565b60405180910390a46107eb565b6033546001600160a01b031633146104165760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610482565b606580546001600160a01b03191690556104948161114c565b6001600160a01b03841615801590610f4557506001600160a01b03831615155b8015610f5957506001600160a01b03821615155b8015610f6d57506001600160a01b03811615155b610fd05760405162461bcd60e51b815260206004820152602e60248201527f526f6f744d696e7461626c6545524332305072656469636174653a204241445f60448201526d24a724aa24a0a624ad20aa24a7a760911b6064820152608401610482565b60fc80546001600160a01b039586166001600160a01b03199182161790915560fd80549486169482169490941790935560fe80549285169284169290921790915560ff8054919093169116179055565b600080808061103185870187611b0f565b6001600160a01b03808516600090815261010060205260409020549498509296509094509250168061106557611065611ae0565b6110796001600160a01b038616848461119e565b826001600160a01b0316816001600160a01b0316866001600160a01b03167fb9f935478aae5b1da868de596dafe0a2b41eeb61311fdd60c6dbbe46a1debee887866040516110c8929190611af6565b60405180910390a450505050505050565b6104166111bd565b6040516001600160a01b03808516602483015283166044820152606481018290526107eb9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526113d3565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6107fc8363a9059cbb60e01b8484604051602401611115929190611af6565b60c95460ff16156112c857604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600160991b01916113889161121f9190611b60565b6000604051808303818686fa925050503d806000811461125b576040519150601f19603f3d011682016040523d82523d6000602084013e611260565b606091505b509150915081801561128557506000818060200190518101906112839190611b7c565b115b6112c55760405162461bcd60e51b81526020600482015260116024820152702224a9a0a62627aba2a22fa9a2a72222a960791b6044820152606401610482565b50505b60c954610100900460ff161561041657604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600360981b01916113889161132f9190611b60565b6000604051808303818686fa925050503d806000811461136b576040519150601f19603f3d011682016040523d82523d6000602084013e611370565b606091505b50915091508180156113965750808060200190518101906113919190611b7c565b600114155b6104005760405162461bcd60e51b815260206004820152600e60248201526d212627a1a5a2a22fa9a2a72222a960911b6044820152606401610482565b6000611428826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166114a89092919063ffffffff16565b90508051600014806114495750808060200190518101906114499190611b95565b6107fc5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610482565b60606114b784846000856114bf565b949350505050565b6060824710156115205760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610482565b600080866001600160a01b0316858760405161153c9190611b60565b60006040518083038185875af1925050503d8060008114611579576040519150601f19603f3d011682016040523d82523d6000602084013e61157e565b606091505b509150915061158f8783838761159a565b979650505050505050565b60608315611609578251600003611602576001600160a01b0385163b6116025760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610482565b50816114b7565b6114b7838381511561161e5781518083602001fd5b8060405162461bcd60e51b81526004016104829190611bb2565b6001600160a01b038116811461049457600080fd5b6000806040838503121561166057600080fd5b823561166b81611638565b946020939093013593505050565b60006020828403121561168b57600080fd5b813561169681611638565b9392505050565b801515811461049457600080fd5b6000602082840312156116bd57600080fd5b81356116968161169d565b600080600080600080600060e0888a0312156116e357600080fd5b87356116ee81611638565b965060208801356116fe81611638565b9550604088013561170e81611638565b9450606088013561171e81611638565b9350608088013561172e8161169d565b925060a088013561173e8161169d565b915060c088013561174e81611638565b8091505092959891949750929550565b6000806000806060858703121561177457600080fd5b84359350602085013561178681611638565b9250604085013567ffffffffffffffff808211156117a357600080fd5b818701915087601f8301126117b757600080fd5b8135818111156117c657600080fd5b8860208285010111156117d857600080fd5b95989497505060200194505050565b6000806000606084860312156117fc57600080fd5b833561180781611638565b9250602084013561181781611638565b929592945050506040919091013590565b6000806000806080858703121561183e57600080fd5b843561184981611638565b9350602085013561185981611638565b9250604085013561186981611638565b9150606085013561187981611638565b939692955090935050565b6020808252600a908201526914d654d5115350d0531360b21b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6000808585111561190657600080fd5b8386111561191357600080fd5b5050820193919092039150565b8035602083101561193957600019602084900360031b1b165b92915050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015611970578181015183820152602001611958565b50506000910152565b60006020828403121561198b57600080fd5b815167ffffffffffffffff808211156119a357600080fd5b818401915084601f8301126119b757600080fd5b8151818111156119c9576119c961193f565b604051601f8201601f19908116603f011681019083821181831017156119f1576119f161193f565b81604052828152876020848701011115611a0a57600080fd5b61158f836020830160208801611955565b600060208284031215611a2d57600080fd5b815160ff8116811461169657600080fd5b60008151808452611a56816020860160208601611955565b601f01601f19169290920160200192915050565b8581526001600160a01b038516602082015260a060408201819052600090611a9490830186611a3e565b8281036060840152611aa68186611a3e565b91505060ff831660808301529695505050505050565b6001600160a01b03831681526040602082018190526000906114b790830184611a3e565b634e487b7160e01b600052600160045260246000fd5b6001600160a01b03929092168252602082015260400190565b60008060008060808587031215611b2557600080fd5b8435611b3081611638565b93506020850135611b4081611638565b92506040850135611b5081611638565b9396929550929360600135925050565b60008251611b72818460208701611955565b9190910192915050565b600060208284031215611b8e57600080fd5b5051919050565b600060208284031215611ba757600080fd5b81516116968161169d565b6020815260006116966020830184611a3e56fea264697066735822122046fe624d67d8c63ac14f4e051a861c827d5567a4754eee6b34a8b0d710c884d664736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b506004361061019a5760003560e01c8063b1768065116100e4578063e0563ab111610092578063e0563ab114610355578063e30c39781461035e578063eeb499451461036f578063f213159c14610382578063f2fde38b14610395578063f4a120f7146103a8578063f6451255146103bb578063f8c8765e146103e257600080fd5b8063b1768065146102a8578063b68ad1e4146102cf578063c1225a20146102e2578063c5e4683a146102f5578063d41f177114610308578063d57184e41461032f578063d8dd17731461034257600080fd5b806355b01e4d1161014c57806355b01e4d146102255780635ea5df7914610233578063715018a61461024a57806379ba5097146102525780637efab4f51461025a5780638da5cb5b14610284578063947287cf1461029557806397e5230d1461029e57600080fd5b806305dc2e8f1461019f57806307b3e252146101cf5780631bc114ba146101dd578063284017f5146101f05780633b878c22146101f957806347e7ef241461020257806351351d5314610217575b600080fd5b60fd546101b2906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101b26004600360981b0181565b60fc546101b2906001600160a01b031681565b6101b261202081565b6101b261101081565b61021561021036600461164d565b6103f5565b005b6101b26002600160a01b0381565b6101b26004600160991b0181565b61023c61138881565b6040519081526020016101c6565b610215610404565b610215610418565b6101b2610268366004611679565b610100602052600090815260409020546001600160a01b031681565b6033546001600160a01b03166101b2565b61023c61520881565b61023c620249f081565b61023c7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b60ff546101b2906001600160a01b031681565b6102156102f03660046116ab565b610497565b6102156103033660046116ab565b6104e6565b61023c7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b60fe546101b2906001600160a01b031681565b6102156103503660046116c8565b61052d565b6101b261203081565b6065546001600160a01b03166101b2565b61021561037d36600461175e565b61064e565b6102156103903660046117e7565b6107f1565b6102156103a3366004611679565b610801565b6101b26103b6366004611679565b610872565b61023c7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b6102156103f0366004611828565b610c40565b610400823383610d39565b5050565b61040c610eb2565b6104166000610f0c565b565b60655433906001600160a01b0316811461048b5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084015b60405180910390fd5b61049481610f0c565b50565b61049f610eb2565b60c9805461ff0019166101008315159081029190911790915560405143907f61d574757cde41a357d030b39b2705796ccd699578037ab9a1cfd8117d82bf8690600090a350565b6104ee610eb2565b60c9805460ff191682151590811790915560405143907fe0a0f0fa52db091cb71c202d80420311430ce1ae2e7794149877b6720ce8bf0b90600090a350565b336002600160a01b03146105545760405163973d02cb60e01b815260040161048290611884565b600054610100900460ff16158080156105745750600054600160ff909116105b8061058e5750303b15801561058e575060005460ff166001145b6105aa5760405162461bcd60e51b8152600401610482906118a8565b6000805460ff1916600117905580156105cd576000805461ff0019166101001790555b6105d988888888610f25565b60c9805461ffff191685151561ff00191617610100851515021790556105fe82610f0c565b8015610644576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b60fd546001600160a01b031633146106c05760405162461bcd60e51b815260206004820152602f60248201527f526f6f744d696e7461626c6545524332305072656469636174653a204f4e4c5960448201526e2fa9aa20aa22afa922a1a2a4ab22a960891b6064820152608401610482565b60fe546001600160a01b038481169116146107365760405162461bcd60e51b815260206004820152603060248201527f526f6f744d696e7461626c6545524332305072656469636174653a204f4e4c5960448201526f5f4348494c445f50524544494341544560801b6064820152608401610482565b7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e9828696107656020600084866118f6565b61076e91611920565b0361078d5761078861078382602081866118f6565b611020565b6107eb565b60405162461bcd60e51b815260206004820152602d60248201527f526f6f744d696e7461626c6545524332305072656469636174653a20494e564160448201526c4c49445f5349474e415455524560981b6064820152608401610482565b50505050565b6107fc838383610d39565b505050565b610809610eb2565b606580546001600160a01b0383166001600160a01b0319909116811790915561083a6033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60006001600160a01b0382166108dc5760405162461bcd60e51b815260206004820152602960248201527f526f6f744d696e7461626c6545524332305072656469636174653a20494e56416044820152682624a22faa27a5a2a760b91b6064820152608401610482565b6001600160a01b038281166000908152610100602052604090205416156109585760405162461bcd60e51b815260206004820152602a60248201527f526f6f744d696e7461626c6545524332305072656469636174653a20414c524560448201526910511657d3505414115160b21b6064820152608401610482565b60fe5460ff546040516bffffffffffffffffffffffff19606086901b1660208201526001600160a01b0392831692600092610a0692911690603401604051602081830303815290604052805190602001208460405160388101919091526f5af43d82803e903d91602b57fd5bf3ff60248201526014810192909252733d602d80600a3d3981f3363d3d373d3d3d363d73825260588201526037600c8201206078820152605560439091012090565b6001600160a01b038581166000818152610100602052604080822080546001600160a01b03191686861617905560fc5481516306fdde0360e01b81529151959650909316936316f198319387937f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad938b9391926306fdde0392600480830193928290030181865afa158015610a9f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ac79190810190611979565b896001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610b05573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b2d9190810190611979565b8a6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8f9190611a1b565b604051602001610ba3959493929190611a6a565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610bcf929190611abc565b600060405180830381600087803b158015610be957600080fd5b505af1158015610bfd573d6000803e3d6000fd5b50506040516001600160a01b038085169350871691507fb96a191bae4e25ffdff7f4136994eb0dec75d263750a07c035202c348c9515f090600090a39392505050565b336002600160a01b0314610c675760405163973d02cb60e01b815260040161048290611884565b600054610100900460ff1615808015610c875750600054600160ff909116105b80610ca15750303b158015610ca1575060005460ff166001145b610cbd5760405162461bcd60e51b8152600401610482906118a8565b6000805460ff191660011790558015610ce0576000805461ff0019166101001790555b610cec85858585610f25565b8015610d32576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b610d416110d9565b6001600160a01b03808416600090815261010060205260409020541680610d6e57610d6b84610872565b90505b6001600160a01b038116610d8457610d84611ae0565b610d996001600160a01b0385163330856110e1565b60fc5460fe54604080517f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82160208201526001600160a01b0388811682840152336060830152878116608083015260a08083018890528351808403909101815260c08301938490526316f1983160e01b909352938416936316f1983193610e249391169160c401611abc565b600060405180830381600087803b158015610e3e57600080fd5b505af1158015610e52573d6000803e3d6000fd5b50505050826001600160a01b0316816001600160a01b0316856001600160a01b03167f1666a3f7b8a7494f2ebcebe646a5187ae55b1db3a068097377d90cd64a258ce93386604051610ea5929190611af6565b60405180910390a46107eb565b6033546001600160a01b031633146104165760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610482565b606580546001600160a01b03191690556104948161114c565b6001600160a01b03841615801590610f4557506001600160a01b03831615155b8015610f5957506001600160a01b03821615155b8015610f6d57506001600160a01b03811615155b610fd05760405162461bcd60e51b815260206004820152602e60248201527f526f6f744d696e7461626c6545524332305072656469636174653a204241445f60448201526d24a724aa24a0a624ad20aa24a7a760911b6064820152608401610482565b60fc80546001600160a01b039586166001600160a01b03199182161790915560fd80549486169482169490941790935560fe80549285169284169290921790915560ff8054919093169116179055565b600080808061103185870187611b0f565b6001600160a01b03808516600090815261010060205260409020549498509296509094509250168061106557611065611ae0565b6110796001600160a01b038616848461119e565b826001600160a01b0316816001600160a01b0316866001600160a01b03167fb9f935478aae5b1da868de596dafe0a2b41eeb61311fdd60c6dbbe46a1debee887866040516110c8929190611af6565b60405180910390a450505050505050565b6104166111bd565b6040516001600160a01b03808516602483015283166044820152606481018290526107eb9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526113d3565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6107fc8363a9059cbb60e01b8484604051602401611115929190611af6565b60c95460ff16156112c857604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600160991b01916113889161121f9190611b60565b6000604051808303818686fa925050503d806000811461125b576040519150601f19603f3d011682016040523d82523d6000602084013e611260565b606091505b509150915081801561128557506000818060200190518101906112839190611b7c565b115b6112c55760405162461bcd60e51b81526020600482015260116024820152702224a9a0a62627aba2a22fa9a2a72222a960791b6044820152606401610482565b50505b60c954610100900460ff161561041657604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600360981b01916113889161132f9190611b60565b6000604051808303818686fa925050503d806000811461136b576040519150601f19603f3d011682016040523d82523d6000602084013e611370565b606091505b50915091508180156113965750808060200190518101906113919190611b7c565b600114155b6104005760405162461bcd60e51b815260206004820152600e60248201526d212627a1a5a2a22fa9a2a72222a960911b6044820152606401610482565b6000611428826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166114a89092919063ffffffff16565b90508051600014806114495750808060200190518101906114499190611b95565b6107fc5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610482565b60606114b784846000856114bf565b949350505050565b6060824710156115205760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610482565b600080866001600160a01b0316858760405161153c9190611b60565b60006040518083038185875af1925050503d8060008114611579576040519150601f19603f3d011682016040523d82523d6000602084013e61157e565b606091505b509150915061158f8783838761159a565b979650505050505050565b60608315611609578251600003611602576001600160a01b0385163b6116025760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610482565b50816114b7565b6114b7838381511561161e5781518083602001fd5b8060405162461bcd60e51b81526004016104829190611bb2565b6001600160a01b038116811461049457600080fd5b6000806040838503121561166057600080fd5b823561166b81611638565b946020939093013593505050565b60006020828403121561168b57600080fd5b813561169681611638565b9392505050565b801515811461049457600080fd5b6000602082840312156116bd57600080fd5b81356116968161169d565b600080600080600080600060e0888a0312156116e357600080fd5b87356116ee81611638565b965060208801356116fe81611638565b9550604088013561170e81611638565b9450606088013561171e81611638565b9350608088013561172e8161169d565b925060a088013561173e8161169d565b915060c088013561174e81611638565b8091505092959891949750929550565b6000806000806060858703121561177457600080fd5b84359350602085013561178681611638565b9250604085013567ffffffffffffffff808211156117a357600080fd5b818701915087601f8301126117b757600080fd5b8135818111156117c657600080fd5b8860208285010111156117d857600080fd5b95989497505060200194505050565b6000806000606084860312156117fc57600080fd5b833561180781611638565b9250602084013561181781611638565b929592945050506040919091013590565b6000806000806080858703121561183e57600080fd5b843561184981611638565b9350602085013561185981611638565b9250604085013561186981611638565b9150606085013561187981611638565b939692955090935050565b6020808252600a908201526914d654d5115350d0531360b21b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6000808585111561190657600080fd5b8386111561191357600080fd5b5050820193919092039150565b8035602083101561193957600019602084900360031b1b165b92915050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015611970578181015183820152602001611958565b50506000910152565b60006020828403121561198b57600080fd5b815167ffffffffffffffff808211156119a357600080fd5b818401915084601f8301126119b757600080fd5b8151818111156119c9576119c961193f565b604051601f8201601f19908116603f011681019083821181831017156119f1576119f161193f565b81604052828152876020848701011115611a0a57600080fd5b61158f836020830160208801611955565b600060208284031215611a2d57600080fd5b815160ff8116811461169657600080fd5b60008151808452611a56816020860160208601611955565b601f01601f19169290920160200192915050565b8581526001600160a01b038516602082015260a060408201819052600090611a9490830186611a3e565b8281036060840152611aa68186611a3e565b91505060ff831660808301529695505050505050565b6001600160a01b03831681526040602082018190526000906114b790830184611a3e565b634e487b7160e01b600052600160045260246000fd5b6001600160a01b03929092168252602082015260400190565b60008060008060808587031215611b2557600080fd5b8435611b3081611638565b93506020850135611b4081611638565b92506040850135611b5081611638565b9396929550929360600135925050565b60008251611b72818460208701611955565b9190910192915050565b600060208284031215611b8e57600080fd5b5051919050565b600060208284031215611ba757600080fd5b81516116968161169d565b6020815260006116966020830184611a3e56fea264697066735822122046fe624d67d8c63ac14f4e051a861c827d5567a4754eee6b34a8b0d710c884d664736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var ChildERC721Artifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"ChildERC721\",\n \"sourceName\": \"contracts/child/ChildERC721.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"approved\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Approval\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"operator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bool\",\n \"name\": \"approved\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"ApprovalForAll\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"userAddress\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"relayerAddress\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bytes\",\n \"name\": \"functionSignature\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"MetaTransactionExecuted\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Transfer\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"approve\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"balanceOf\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"burn\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"burnBatch\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"userAddress\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"functionSignature\",\n \"type\": \"bytes\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"sigR\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"sigS\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint8\",\n \"name\": \"sigV\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"executeMetaTransaction\",\n \"outputs\": [\n {\n \"internalType\": \"bytes\",\n \"name\": \"\",\n \"type\": \"bytes\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"getApproved\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"getNonce\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"nonce\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"rootToken_\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"string\",\n \"name\": \"name_\",\n \"type\": \"string\"\n },\n {\n \"internalType\": \"string\",\n \"name\": \"symbol_\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"offset\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"invalidateNext\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"operator\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"isApprovedForAll\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"mint\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address[]\",\n \"name\": \"accounts\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"mintBatch\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"name\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"ownerOf\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"rootToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"safeTransferFrom\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"safeTransferFrom\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"operator\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"approved\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"setApprovalForAll\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes4\",\n \"name\": \"interfaceId\",\n \"type\": \"bytes4\"\n }\n ],\n \"name\": \"supportsInterface\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"symbol\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"tokenURI\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transferFrom\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50612488806100206000396000f3fe608060405234801561001057600080fd5b506004361061014d5760003560e01c806370a08231116100c3578063a22cb4651161007c578063a22cb465146102de578063b2dc5dc3146102f1578063b88d4fde14610304578063c87b56dd14610317578063e61987051461032a578063e985e9c51461033c57600080fd5b806370a08231146102775780637c88e3d91461028a578063906571471461029d57806395d89b41146102b05780639b77ef11146102b85780639dc29fac146102cb57600080fd5b80631f2d0065116101155780631f2d0065146101e257806323b872dd146101f45780632d0335ab1461020757806340c10f191461023e57806342842e0e146102515780636352211e1461026457600080fd5b806301ffc9a71461015257806306fdde031461017a578063081812fc1461018f578063095ea7b3146101ba5780630c53c51c146101cf575b600080fd5b610165610160366004611a73565b61034f565b60405190151581526020015b60405180910390f35b6101826103a1565b6040516101719190611ae0565b6101a261019d366004611af3565b610433565b6040516001600160a01b039091168152602001610171565b6101cd6101c8366004611b28565b61045a565b005b6101826101dd366004611b9a565b610586565b610103546001600160a01b03166101a2565b6101cd610202366004611c19565b610864565b610230610215366004611c55565b6001600160a01b031660009081526038602052604090205490565b604051908152602001610171565b61016561024c366004611b28565b61089c565b6101cd61025f366004611c19565b6108dd565b6101a2610272366004611af3565b6108f8565b610230610285366004611c55565b61092d565b610165610298366004611cb4565b6109b3565b6101cd6102ab366004611d1f565b610a9b565b610182610d0b565b6101cd6102c6366004611af3565b610d1a565b6101656102d9366004611b28565b610d41565b6101cd6102ec366004611d9f565b610db1565b6101656102ff366004611ddb565b610dc7565b6101cd610312366004611e43565b610e75565b610182610325366004611af3565b610eb4565b610102546001600160a01b03166101a2565b61016561034a366004611f1e565b610f28565b60006001600160e01b031982166380ac58cd60e01b148061038057506001600160e01b03198216635b5e139f60e01b145b8061039b57506301ffc9a760e01b6001600160e01b03198316145b92915050565b606060d080546103b090611f51565b80601f01602080910402602001604051908101604052809291908181526020018280546103dc90611f51565b80156104295780601f106103fe57610100808354040283529160200191610429565b820191906000526020600020905b81548152906001019060200180831161040c57829003601f168201915b5050505050905090565b600061043e82610f56565b50600090815260d460205260409020546001600160a01b031690565b6000610465826108f8565b9050806001600160a01b0316836001600160a01b0316036104d75760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b806001600160a01b03166104e9610f7e565b6001600160a01b0316148061050557506105058161034a610f7e565b6105775760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c00000060648201526084016104ce565b6105818383610f8d565b505050565b606060006105c987878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610ffb92505050565b90506001600160e01b031960003581169082160361064f5760405162461bcd60e51b815260206004820152603d60248201527f66756e6374696f6e5369676e61747572652063616e206e6f74206265206f662060448201527f657865637574654d6574615472616e73616374696f6e206d6574686f6400000060648201526084016104ce565b604080516060810182526001600160a01b038a16600081815260386020908152848220548452808401929092528351601f8b0183900483028101830185528a815290938301918b908b9081908401838280828437600092019190915250505091525090506106c08982888888611016565b6107165760405162461bcd60e51b815260206004820152602160248201527f5369676e657220616e64207369676e617475726520646f206e6f74206d6174636044820152600d60fb1b60648201526084016104ce565b603860008a6001600160a01b03166001600160a01b031681526020019081526020016000206000815460010191905081905550600080306001600160a01b03168a8a8d60405160200161076b93929190611f8b565b60408051601f198184030181529082905261078591611fb1565b6000604051808303816000865af19150503d80600081146107c2576040519150601f19603f3d011682016040523d82523d6000602084013e6107c7565b606091505b5091509150816108195760405162461bcd60e51b815260206004820152601c60248201527f46756e6374696f6e2063616c6c206e6f74207375636365737366756c0000000060448201526064016104ce565b7f5845892132946850460bff5a0083f71031bc5bf9aadcd40f1de79423eac9b10b8b338c8c60405161084e9493929190611fcd565b60405180910390a19a9950505050505050505050565b61087561086f610f7e565b826110f2565b6108915760405162461bcd60e51b81526004016104ce90612019565b610581838383611150565b610102546000906001600160a01b031633146108ca5760405162461bcd60e51b81526004016104ce90612066565b6108d483836112a2565b50600192915050565b61058183838360405180602001604052806000815250610e75565b600081815260d260205260408120546001600160a01b03168061039b5760405162461bcd60e51b81526004016104ce906120aa565b60006001600160a01b0382166109975760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b60648201526084016104ce565b506001600160a01b0316600090815260d3602052604090205490565b610102546000906001600160a01b031633146109e15760405162461bcd60e51b81526004016104ce90612066565b83828114610a315760405162461bcd60e51b815260206004820152601f60248201527f4368696c644552433732313a204172726179206c656e206d69736d617463680060448201526064016104ce565b60005b81811015610a8c57610a84878783818110610a5157610a516120dc565b9050602002016020810190610a669190611c55565b868684818110610a7857610a786120dc565b905060200201356112a2565b600101610a34565b5060019150505b949350505050565b606b54610100900460ff1615808015610abb5750606b54600160ff909116105b80610ad55750303b158015610ad55750606b5460ff166001145b610b385760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016104ce565b606b805460ff191660011790558015610b5b57606b805461ff0019166101001790555b6001600160a01b03861615801590610b7257508315155b8015610b7d57508115155b610bc95760405162461bcd60e51b815260206004820152601f60248201527f4368696c644552433732313a2042616420696e697469616c697a6174696f6e0060448201526064016104ce565b61010380546001600160a01b0388166001600160a01b031991821617909155610102805490911633179055604080516020601f8701819004810282018101909252858152610c6591879087908190840183828082843760009201919091525050604080516020601f890181900481028201810190925287815292508791508690819084018382808284376000920191909152506112bc92505050565b610cbd85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260018152603160f81b602082015291506112ed9050565b8015610d0357606b805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b606060d180546103b090611f51565b3360009081526038602052604081208054839290610d399084906120f2565b909155505050565b610102546000906001600160a01b03163314610d6f5760405162461bcd60e51b81526004016104ce90612066565b610d78826108f8565b6001600160a01b0316836001600160a01b031614610da85760405162461bcd60e51b81526004016104ce90612113565b6108d482611359565b610dc3610dbc610f7e565b83836113dc565b5050565b610102546000906001600160a01b03163314610df55760405162461bcd60e51b81526004016104ce90612066565b8160005b81811015610e69576000858583818110610e1557610e156120dc565b905060200201359050610e27816108f8565b6001600160a01b0316876001600160a01b031614610e575760405162461bcd60e51b81526004016104ce90612113565b610e6081611359565b50600101610df9565b50600195945050505050565b610e86610e80610f7e565b836110f2565b610ea25760405162461bcd60e51b81526004016104ce90612019565b610eae848484846114a6565b50505050565b6060610ebf82610f56565b6000610ed660408051602081019091526000815290565b90506000815111610ef65760405180602001604052806000815250610f21565b80610f00846114d9565b604051602001610f11929190612148565b6040516020818303038152906040525b9392505050565b6001600160a01b03918216600090815260d56020908152604080832093909416825291909152205460ff1690565b610f5f8161156b565b610f7b5760405162461bcd60e51b81526004016104ce906120aa565b50565b6000610f88611588565b905090565b600081815260d46020526040902080546001600160a01b0319166001600160a01b0384169081179091558190610fc2826108f8565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000815160000361100e57506000919050565b506020015190565b600080600161102c611027886115e4565b611661565b6040805160008152602081018083529290925260ff861690820152606081018790526080810186905260a0016020604051602081039080840390855afa15801561107a573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166110d15760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b60448201526064016104ce565b866001600160a01b0316816001600160a01b03161491505095945050505050565b6000806110fe836108f8565b9050806001600160a01b0316846001600160a01b0316148061112557506111258185610f28565b80610a935750836001600160a01b031661113e84610433565b6001600160a01b031614949350505050565b826001600160a01b0316611163826108f8565b6001600160a01b0316146111895760405162461bcd60e51b81526004016104ce90612177565b6001600160a01b0382166111eb5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b60648201526084016104ce565b826001600160a01b03166111fe826108f8565b6001600160a01b0316146112245760405162461bcd60e51b81526004016104ce90612177565b600081815260d46020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260d3855283862080546000190190559087168086528386208054600101905586865260d2909452828520805490921684179091559051849360008051602061243383398151915291a4505050565b610dc382826040518060200160405280600081525061168e565b606b54610100900460ff166112e35760405162461bcd60e51b81526004016104ce906121bc565b610dc382826116c1565b815160208084019190912082519183019190912060038290556004819055466001557f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f61133b818484611701565b600055600280546001600160a01b0319163017905560055550505050565b6000611364826108f8565b905061136f826108f8565b600083815260d46020908152604080832080546001600160a01b03199081169091556001600160a01b03851680855260d38452828520805460001901905587855260d290935281842080549091169055519293508492600080516020612433833981519152908390a45050565b816001600160a01b0316836001600160a01b0316036114395760405162461bcd60e51b815260206004820152601960248201527822a9219b99189d1030b8383937bb32903a379031b0b63632b960391b60448201526064016104ce565b6001600160a01b03838116600081815260d56020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6114b1848484611150565b6114bd8484848461174a565b610eae5760405162461bcd60e51b81526004016104ce90612207565b606060006114e68361184f565b60010190506000816001600160401b0381111561150557611505611e2d565b6040519080825280601f01601f19166020018201604052801561152f576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461153957509392505050565b600090815260d260205260409020546001600160a01b0316151590565b60003033036115de57600080368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050503601516001600160a01b031691506115e19050565b50335b90565b60006040518060800160405280604381526020016123f06043913980516020918201208351848301516040808701518051908601209051611644950193845260208401929092526001600160a01b03166040830152606082015260800190565b604051602081830303815290604052805190602001209050919050565b600061039b61166e611927565b8360405161190160f01b8152600281019290925260228201526042902090565b6116988383611962565b6116a5600084848461174a565b6105815760405162461bcd60e51b81526004016104ce90612207565b606b54610100900460ff166116e85760405162461bcd60e51b81526004016104ce906121bc565b60d06116f4838261229f565b5060d1610581828261229f565b6040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b60006001600160a01b0384163b1561184757836001600160a01b031663150b7a02611773610f7e565b8786866040518563ffffffff1660e01b8152600401611795949392919061235e565b6020604051808303816000875af19250505080156117d0575060408051601f3d908101601f191682019092526117cd9181019061239b565b60015b61182d573d8080156117fe576040519150601f19603f3d011682016040523d82523d6000602084013e611803565b606091505b5080516000036118255760405162461bcd60e51b81526004016104ce90612207565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050610a93565b506001610a93565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061188e5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106118ba576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106118d857662386f26fc10000830492506010015b6305f5e10083106118f0576305f5e100830492506008015b612710831061190457612710830492506004015b60648310611916576064830492506002015b600a831061039b5760010192915050565b6002546000906001600160a01b031630148015611945575060015446145b15611951575060005490565b610f88600554600354600454611701565b6001600160a01b0382166119b85760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f206164647265737360448201526064016104ce565b6119c18161156b565b156119de5760405162461bcd60e51b81526004016104ce906123b8565b6119e78161156b565b15611a045760405162461bcd60e51b81526004016104ce906123b8565b6001600160a01b038216600081815260d3602090815260408083208054600101905584835260d290915280822080546001600160a01b031916841790555183929190600080516020612433833981519152908290a45050565b6001600160e01b031981168114610f7b57600080fd5b600060208284031215611a8557600080fd5b8135610f2181611a5d565b60005b83811015611aab578181015183820152602001611a93565b50506000910152565b60008151808452611acc816020860160208601611a90565b601f01601f19169290920160200192915050565b602081526000610f216020830184611ab4565b600060208284031215611b0557600080fd5b5035919050565b80356001600160a01b0381168114611b2357600080fd5b919050565b60008060408385031215611b3b57600080fd5b611b4483611b0c565b946020939093013593505050565b60008083601f840112611b6457600080fd5b5081356001600160401b03811115611b7b57600080fd5b602083019150836020828501011115611b9357600080fd5b9250929050565b60008060008060008060a08789031215611bb357600080fd5b611bbc87611b0c565b955060208701356001600160401b03811115611bd757600080fd5b611be389828a01611b52565b9096509450506040870135925060608701359150608087013560ff81168114611c0b57600080fd5b809150509295509295509295565b600080600060608486031215611c2e57600080fd5b611c3784611b0c565b9250611c4560208501611b0c565b9150604084013590509250925092565b600060208284031215611c6757600080fd5b610f2182611b0c565b60008083601f840112611c8257600080fd5b5081356001600160401b03811115611c9957600080fd5b6020830191508360208260051b8501011115611b9357600080fd5b60008060008060408587031215611cca57600080fd5b84356001600160401b0380821115611ce157600080fd5b611ced88838901611c70565b90965094506020870135915080821115611d0657600080fd5b50611d1387828801611c70565b95989497509550505050565b600080600080600060608688031215611d3757600080fd5b611d4086611b0c565b945060208601356001600160401b0380821115611d5c57600080fd5b611d6889838a01611b52565b90965094506040880135915080821115611d8157600080fd5b50611d8e88828901611b52565b969995985093965092949392505050565b60008060408385031215611db257600080fd5b611dbb83611b0c565b915060208301358015158114611dd057600080fd5b809150509250929050565b600080600060408486031215611df057600080fd5b611df984611b0c565b925060208401356001600160401b03811115611e1457600080fd5b611e2086828701611c70565b9497909650939450505050565b634e487b7160e01b600052604160045260246000fd5b60008060008060808587031215611e5957600080fd5b611e6285611b0c565b9350611e7060208601611b0c565b92506040850135915060608501356001600160401b0380821115611e9357600080fd5b818701915087601f830112611ea757600080fd5b813581811115611eb957611eb9611e2d565b604051601f8201601f19908116603f01168101908382118183101715611ee157611ee1611e2d565b816040528281528a6020848701011115611efa57600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b60008060408385031215611f3157600080fd5b611f3a83611b0c565b9150611f4860208401611b0c565b90509250929050565b600181811c90821680611f6557607f821691505b602082108103611f8557634e487b7160e01b600052602260045260246000fd5b50919050565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b60008251611fc3818460208701611a90565b9190910192915050565b6001600160a01b0385811682528416602082015260606040820181905281018290526000828460808401376000608084840101526080601f19601f850116830101905095945050505050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b60208082526024908201527f4368696c644552433732313a204f6e6c79207072656469636174652063616e2060408201526318d85b1b60e21b606082015260800190565b602080825260189082015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b8082018082111561039b57634e487b7160e01b600052601160045260246000fd5b6020808252818101527f4368696c644552433732313a204f6e6c79206f776e65722063616e206275726e604082015260600190565b6000835161215a818460208801611a90565b83519083019061216e818360208801611a90565b01949350505050565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b601f82111561058157600081815260208120601f850160051c810160208610156122805750805b601f850160051c820191505b81811015610d035782815560010161228c565b81516001600160401b038111156122b8576122b8611e2d565b6122cc816122c68454611f51565b84612259565b602080601f83116001811461230157600084156122e95750858301515b600019600386901b1c1916600185901b178555610d03565b600085815260208120601f198616915b8281101561233057888601518255948401946001909101908401612311565b508582101561234e5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061239190830184611ab4565b9695505050505050565b6000602082840312156123ad57600080fd5b8151610f2181611a5d565b6020808252601c908201527f4552433732313a20746f6b656e20616c7265616479206d696e7465640000000060408201526060019056fe4d6574615472616e73616374696f6e2875696e74323536206e6f6e63652c616464726573732066726f6d2c62797465732066756e6374696f6e5369676e617475726529ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220f91f642808324bd8531abbaf91281f9e3d4bf524dfff70328f58ead32897596764736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b506004361061014d5760003560e01c806370a08231116100c3578063a22cb4651161007c578063a22cb465146102de578063b2dc5dc3146102f1578063b88d4fde14610304578063c87b56dd14610317578063e61987051461032a578063e985e9c51461033c57600080fd5b806370a08231146102775780637c88e3d91461028a578063906571471461029d57806395d89b41146102b05780639b77ef11146102b85780639dc29fac146102cb57600080fd5b80631f2d0065116101155780631f2d0065146101e257806323b872dd146101f45780632d0335ab1461020757806340c10f191461023e57806342842e0e146102515780636352211e1461026457600080fd5b806301ffc9a71461015257806306fdde031461017a578063081812fc1461018f578063095ea7b3146101ba5780630c53c51c146101cf575b600080fd5b610165610160366004611a73565b61034f565b60405190151581526020015b60405180910390f35b6101826103a1565b6040516101719190611ae0565b6101a261019d366004611af3565b610433565b6040516001600160a01b039091168152602001610171565b6101cd6101c8366004611b28565b61045a565b005b6101826101dd366004611b9a565b610586565b610103546001600160a01b03166101a2565b6101cd610202366004611c19565b610864565b610230610215366004611c55565b6001600160a01b031660009081526038602052604090205490565b604051908152602001610171565b61016561024c366004611b28565b61089c565b6101cd61025f366004611c19565b6108dd565b6101a2610272366004611af3565b6108f8565b610230610285366004611c55565b61092d565b610165610298366004611cb4565b6109b3565b6101cd6102ab366004611d1f565b610a9b565b610182610d0b565b6101cd6102c6366004611af3565b610d1a565b6101656102d9366004611b28565b610d41565b6101cd6102ec366004611d9f565b610db1565b6101656102ff366004611ddb565b610dc7565b6101cd610312366004611e43565b610e75565b610182610325366004611af3565b610eb4565b610102546001600160a01b03166101a2565b61016561034a366004611f1e565b610f28565b60006001600160e01b031982166380ac58cd60e01b148061038057506001600160e01b03198216635b5e139f60e01b145b8061039b57506301ffc9a760e01b6001600160e01b03198316145b92915050565b606060d080546103b090611f51565b80601f01602080910402602001604051908101604052809291908181526020018280546103dc90611f51565b80156104295780601f106103fe57610100808354040283529160200191610429565b820191906000526020600020905b81548152906001019060200180831161040c57829003601f168201915b5050505050905090565b600061043e82610f56565b50600090815260d460205260409020546001600160a01b031690565b6000610465826108f8565b9050806001600160a01b0316836001600160a01b0316036104d75760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b806001600160a01b03166104e9610f7e565b6001600160a01b0316148061050557506105058161034a610f7e565b6105775760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c00000060648201526084016104ce565b6105818383610f8d565b505050565b606060006105c987878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610ffb92505050565b90506001600160e01b031960003581169082160361064f5760405162461bcd60e51b815260206004820152603d60248201527f66756e6374696f6e5369676e61747572652063616e206e6f74206265206f662060448201527f657865637574654d6574615472616e73616374696f6e206d6574686f6400000060648201526084016104ce565b604080516060810182526001600160a01b038a16600081815260386020908152848220548452808401929092528351601f8b0183900483028101830185528a815290938301918b908b9081908401838280828437600092019190915250505091525090506106c08982888888611016565b6107165760405162461bcd60e51b815260206004820152602160248201527f5369676e657220616e64207369676e617475726520646f206e6f74206d6174636044820152600d60fb1b60648201526084016104ce565b603860008a6001600160a01b03166001600160a01b031681526020019081526020016000206000815460010191905081905550600080306001600160a01b03168a8a8d60405160200161076b93929190611f8b565b60408051601f198184030181529082905261078591611fb1565b6000604051808303816000865af19150503d80600081146107c2576040519150601f19603f3d011682016040523d82523d6000602084013e6107c7565b606091505b5091509150816108195760405162461bcd60e51b815260206004820152601c60248201527f46756e6374696f6e2063616c6c206e6f74207375636365737366756c0000000060448201526064016104ce565b7f5845892132946850460bff5a0083f71031bc5bf9aadcd40f1de79423eac9b10b8b338c8c60405161084e9493929190611fcd565b60405180910390a19a9950505050505050505050565b61087561086f610f7e565b826110f2565b6108915760405162461bcd60e51b81526004016104ce90612019565b610581838383611150565b610102546000906001600160a01b031633146108ca5760405162461bcd60e51b81526004016104ce90612066565b6108d483836112a2565b50600192915050565b61058183838360405180602001604052806000815250610e75565b600081815260d260205260408120546001600160a01b03168061039b5760405162461bcd60e51b81526004016104ce906120aa565b60006001600160a01b0382166109975760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b60648201526084016104ce565b506001600160a01b0316600090815260d3602052604090205490565b610102546000906001600160a01b031633146109e15760405162461bcd60e51b81526004016104ce90612066565b83828114610a315760405162461bcd60e51b815260206004820152601f60248201527f4368696c644552433732313a204172726179206c656e206d69736d617463680060448201526064016104ce565b60005b81811015610a8c57610a84878783818110610a5157610a516120dc565b9050602002016020810190610a669190611c55565b868684818110610a7857610a786120dc565b905060200201356112a2565b600101610a34565b5060019150505b949350505050565b606b54610100900460ff1615808015610abb5750606b54600160ff909116105b80610ad55750303b158015610ad55750606b5460ff166001145b610b385760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016104ce565b606b805460ff191660011790558015610b5b57606b805461ff0019166101001790555b6001600160a01b03861615801590610b7257508315155b8015610b7d57508115155b610bc95760405162461bcd60e51b815260206004820152601f60248201527f4368696c644552433732313a2042616420696e697469616c697a6174696f6e0060448201526064016104ce565b61010380546001600160a01b0388166001600160a01b031991821617909155610102805490911633179055604080516020601f8701819004810282018101909252858152610c6591879087908190840183828082843760009201919091525050604080516020601f890181900481028201810190925287815292508791508690819084018382808284376000920191909152506112bc92505050565b610cbd85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260018152603160f81b602082015291506112ed9050565b8015610d0357606b805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b606060d180546103b090611f51565b3360009081526038602052604081208054839290610d399084906120f2565b909155505050565b610102546000906001600160a01b03163314610d6f5760405162461bcd60e51b81526004016104ce90612066565b610d78826108f8565b6001600160a01b0316836001600160a01b031614610da85760405162461bcd60e51b81526004016104ce90612113565b6108d482611359565b610dc3610dbc610f7e565b83836113dc565b5050565b610102546000906001600160a01b03163314610df55760405162461bcd60e51b81526004016104ce90612066565b8160005b81811015610e69576000858583818110610e1557610e156120dc565b905060200201359050610e27816108f8565b6001600160a01b0316876001600160a01b031614610e575760405162461bcd60e51b81526004016104ce90612113565b610e6081611359565b50600101610df9565b50600195945050505050565b610e86610e80610f7e565b836110f2565b610ea25760405162461bcd60e51b81526004016104ce90612019565b610eae848484846114a6565b50505050565b6060610ebf82610f56565b6000610ed660408051602081019091526000815290565b90506000815111610ef65760405180602001604052806000815250610f21565b80610f00846114d9565b604051602001610f11929190612148565b6040516020818303038152906040525b9392505050565b6001600160a01b03918216600090815260d56020908152604080832093909416825291909152205460ff1690565b610f5f8161156b565b610f7b5760405162461bcd60e51b81526004016104ce906120aa565b50565b6000610f88611588565b905090565b600081815260d46020526040902080546001600160a01b0319166001600160a01b0384169081179091558190610fc2826108f8565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000815160000361100e57506000919050565b506020015190565b600080600161102c611027886115e4565b611661565b6040805160008152602081018083529290925260ff861690820152606081018790526080810186905260a0016020604051602081039080840390855afa15801561107a573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166110d15760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b60448201526064016104ce565b866001600160a01b0316816001600160a01b03161491505095945050505050565b6000806110fe836108f8565b9050806001600160a01b0316846001600160a01b0316148061112557506111258185610f28565b80610a935750836001600160a01b031661113e84610433565b6001600160a01b031614949350505050565b826001600160a01b0316611163826108f8565b6001600160a01b0316146111895760405162461bcd60e51b81526004016104ce90612177565b6001600160a01b0382166111eb5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b60648201526084016104ce565b826001600160a01b03166111fe826108f8565b6001600160a01b0316146112245760405162461bcd60e51b81526004016104ce90612177565b600081815260d46020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260d3855283862080546000190190559087168086528386208054600101905586865260d2909452828520805490921684179091559051849360008051602061243383398151915291a4505050565b610dc382826040518060200160405280600081525061168e565b606b54610100900460ff166112e35760405162461bcd60e51b81526004016104ce906121bc565b610dc382826116c1565b815160208084019190912082519183019190912060038290556004819055466001557f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f61133b818484611701565b600055600280546001600160a01b0319163017905560055550505050565b6000611364826108f8565b905061136f826108f8565b600083815260d46020908152604080832080546001600160a01b03199081169091556001600160a01b03851680855260d38452828520805460001901905587855260d290935281842080549091169055519293508492600080516020612433833981519152908390a45050565b816001600160a01b0316836001600160a01b0316036114395760405162461bcd60e51b815260206004820152601960248201527822a9219b99189d1030b8383937bb32903a379031b0b63632b960391b60448201526064016104ce565b6001600160a01b03838116600081815260d56020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6114b1848484611150565b6114bd8484848461174a565b610eae5760405162461bcd60e51b81526004016104ce90612207565b606060006114e68361184f565b60010190506000816001600160401b0381111561150557611505611e2d565b6040519080825280601f01601f19166020018201604052801561152f576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461153957509392505050565b600090815260d260205260409020546001600160a01b0316151590565b60003033036115de57600080368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050503601516001600160a01b031691506115e19050565b50335b90565b60006040518060800160405280604381526020016123f06043913980516020918201208351848301516040808701518051908601209051611644950193845260208401929092526001600160a01b03166040830152606082015260800190565b604051602081830303815290604052805190602001209050919050565b600061039b61166e611927565b8360405161190160f01b8152600281019290925260228201526042902090565b6116988383611962565b6116a5600084848461174a565b6105815760405162461bcd60e51b81526004016104ce90612207565b606b54610100900460ff166116e85760405162461bcd60e51b81526004016104ce906121bc565b60d06116f4838261229f565b5060d1610581828261229f565b6040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b60006001600160a01b0384163b1561184757836001600160a01b031663150b7a02611773610f7e565b8786866040518563ffffffff1660e01b8152600401611795949392919061235e565b6020604051808303816000875af19250505080156117d0575060408051601f3d908101601f191682019092526117cd9181019061239b565b60015b61182d573d8080156117fe576040519150601f19603f3d011682016040523d82523d6000602084013e611803565b606091505b5080516000036118255760405162461bcd60e51b81526004016104ce90612207565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050610a93565b506001610a93565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061188e5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106118ba576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106118d857662386f26fc10000830492506010015b6305f5e10083106118f0576305f5e100830492506008015b612710831061190457612710830492506004015b60648310611916576064830492506002015b600a831061039b5760010192915050565b6002546000906001600160a01b031630148015611945575060015446145b15611951575060005490565b610f88600554600354600454611701565b6001600160a01b0382166119b85760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f206164647265737360448201526064016104ce565b6119c18161156b565b156119de5760405162461bcd60e51b81526004016104ce906123b8565b6119e78161156b565b15611a045760405162461bcd60e51b81526004016104ce906123b8565b6001600160a01b038216600081815260d3602090815260408083208054600101905584835260d290915280822080546001600160a01b031916841790555183929190600080516020612433833981519152908290a45050565b6001600160e01b031981168114610f7b57600080fd5b600060208284031215611a8557600080fd5b8135610f2181611a5d565b60005b83811015611aab578181015183820152602001611a93565b50506000910152565b60008151808452611acc816020860160208601611a90565b601f01601f19169290920160200192915050565b602081526000610f216020830184611ab4565b600060208284031215611b0557600080fd5b5035919050565b80356001600160a01b0381168114611b2357600080fd5b919050565b60008060408385031215611b3b57600080fd5b611b4483611b0c565b946020939093013593505050565b60008083601f840112611b6457600080fd5b5081356001600160401b03811115611b7b57600080fd5b602083019150836020828501011115611b9357600080fd5b9250929050565b60008060008060008060a08789031215611bb357600080fd5b611bbc87611b0c565b955060208701356001600160401b03811115611bd757600080fd5b611be389828a01611b52565b9096509450506040870135925060608701359150608087013560ff81168114611c0b57600080fd5b809150509295509295509295565b600080600060608486031215611c2e57600080fd5b611c3784611b0c565b9250611c4560208501611b0c565b9150604084013590509250925092565b600060208284031215611c6757600080fd5b610f2182611b0c565b60008083601f840112611c8257600080fd5b5081356001600160401b03811115611c9957600080fd5b6020830191508360208260051b8501011115611b9357600080fd5b60008060008060408587031215611cca57600080fd5b84356001600160401b0380821115611ce157600080fd5b611ced88838901611c70565b90965094506020870135915080821115611d0657600080fd5b50611d1387828801611c70565b95989497509550505050565b600080600080600060608688031215611d3757600080fd5b611d4086611b0c565b945060208601356001600160401b0380821115611d5c57600080fd5b611d6889838a01611b52565b90965094506040880135915080821115611d8157600080fd5b50611d8e88828901611b52565b969995985093965092949392505050565b60008060408385031215611db257600080fd5b611dbb83611b0c565b915060208301358015158114611dd057600080fd5b809150509250929050565b600080600060408486031215611df057600080fd5b611df984611b0c565b925060208401356001600160401b03811115611e1457600080fd5b611e2086828701611c70565b9497909650939450505050565b634e487b7160e01b600052604160045260246000fd5b60008060008060808587031215611e5957600080fd5b611e6285611b0c565b9350611e7060208601611b0c565b92506040850135915060608501356001600160401b0380821115611e9357600080fd5b818701915087601f830112611ea757600080fd5b813581811115611eb957611eb9611e2d565b604051601f8201601f19908116603f01168101908382118183101715611ee157611ee1611e2d565b816040528281528a6020848701011115611efa57600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b60008060408385031215611f3157600080fd5b611f3a83611b0c565b9150611f4860208401611b0c565b90509250929050565b600181811c90821680611f6557607f821691505b602082108103611f8557634e487b7160e01b600052602260045260246000fd5b50919050565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b60008251611fc3818460208701611a90565b9190910192915050565b6001600160a01b0385811682528416602082015260606040820181905281018290526000828460808401376000608084840101526080601f19601f850116830101905095945050505050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b60208082526024908201527f4368696c644552433732313a204f6e6c79207072656469636174652063616e2060408201526318d85b1b60e21b606082015260800190565b602080825260189082015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b8082018082111561039b57634e487b7160e01b600052601160045260246000fd5b6020808252818101527f4368696c644552433732313a204f6e6c79206f776e65722063616e206275726e604082015260600190565b6000835161215a818460208801611a90565b83519083019061216e818360208801611a90565b01949350505050565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b601f82111561058157600081815260208120601f850160051c810160208610156122805750805b601f850160051c820191505b81811015610d035782815560010161228c565b81516001600160401b038111156122b8576122b8611e2d565b6122cc816122c68454611f51565b84612259565b602080601f83116001811461230157600084156122e95750858301515b600019600386901b1c1916600185901b178555610d03565b600085815260208120601f198616915b8281101561233057888601518255948401946001909101908401612311565b508582101561234e5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061239190830184611ab4565b9695505050505050565b6000602082840312156123ad57600080fd5b8151610f2181611a5d565b6020808252601c908201527f4552433732313a20746f6b656e20616c7265616479206d696e7465640000000060408201526060019056fe4d6574615472616e73616374696f6e2875696e74323536206e6f6e63652c616464726573732066726f6d2c62797465732066756e6374696f6e5369676e617475726529ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220f91f642808324bd8531abbaf91281f9e3d4bf524dfff70328f58ead32897596764736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var ChildERC721PredicateArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"ChildERC721Predicate\",\n \"sourceName\": \"contracts/child/ChildERC721Predicate.sol\",\n \"abi\": [\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"only\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"Unauthorized\",\n \"type\": \"error\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2ERC721Deposit\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"L2ERC721DepositBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2ERC721Withdraw\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"L2ERC721WithdrawBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"L2TokenMapped\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"ALLOWLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"BLOCKLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAP_TOKEN_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TOKEN_CONTRACT\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"READ_ADDRESSLIST_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"SYSTEM\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childTokenTemplate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newL2StateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newStateReceiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newRootERC721Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"l2StateSender\",\n \"outputs\": [\n {\n \"internalType\": \"contract IStateSender\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onStateReceive\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"rootERC721Predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"rootTokenToChildToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"stateReceiver\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC721\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"withdraw\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC721\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"withdrawBatch\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC721\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"withdrawTo\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50611fc4806100206000396000f3fe608060405234801561001057600080fd5b50600436106101585760003560e01c8063b1768065116100c3578063e0563ab11161007c578063e0563ab114610306578063eeb499451461030f578063f3fef3a314610322578063f645125514610335578063f691325c1461035c578063f8c8765e1461036f57600080fd5b8063b176806514610244578063b68ad1e41461026b578063c3b35a7e1461027e578063c5ac2b1c14610291578063d41f1771146102b8578063d7c9e3ec146102df57600080fd5b806355b01e4d1161011557806355b01e4d146101ce5780635ea5df79146101dc5780636f33e695146101f35780637efab4f514610208578063947287cf1461023157806397e5230d1461023a57600080fd5b806305dc2e8f1461015d57806307b3e2521461018d5780631bc114ba1461019b578063284017f5146101ae5780633b878c22146101b757806351351d53146101c0575b600080fd5b603454610170906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101706004600360981b0181565b603354610170906001600160a01b031681565b61017061202081565b61017061101081565b6101706002600160a01b0381565b6101706004600160991b0181565b6101e561138881565b604051908152602001610184565b61020661020136600461166f565b610382565b005b6101706102163660046116f1565b6037602052600090815260409020546001600160a01b031681565b6101e561520881565b6101e5620249f081565b6101e57f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b603654610170906001600160a01b031681565b61020661028c366004611715565b610396565b6101e57faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b6101e57f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b6101e57f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b61017061203081565b61020661031d366004611756565b6103a6565b6102066103303660046117de565b6105c9565b6101e57f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b603554610170906001600160a01b031681565b61020661037d36600461180a565b6105d8565b61038f8585858585610734565b5050505050565b6103a1838383610a98565b505050565b6034546001600160a01b031633146104175760405162461bcd60e51b815260206004820152602960248201527f4368696c644552433732315072656469636174653a204f4e4c595f53544154456044820152682fa922a1a2a4ab22a960b91b60648201526084015b60405180910390fd5b6035546001600160a01b038481169116146104865760405162461bcd60e51b815260206004820152602960248201527f4368696c644552433732315072656469636174653a204f4e4c595f524f4f545f60448201526850524544494341544560b81b606482015260840161040e565b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f8216104b5602060008486611866565b6104be91611890565b036104dd576104d86104d38260208186611866565b610da1565b6105c3565b7faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1861050c602060008486611866565b61051591611890565b03610524576104d88282611017565b7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad610553602060008486611866565b61055c91611890565b0361056b576104d8828261127d565b60405162461bcd60e51b815260206004820152602760248201527f4368696c644552433732315072656469636174653a20494e56414c49445f5349604482015266474e415455524560c81b606482015260840161040e565b50505050565b6105d4823383610a98565b5050565b336002600160a01b031461061c5760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b604482015260640161040e565b600054610100900460ff161580801561063c5750600054600160ff909116105b806106565750303b158015610656575060005460ff166001145b6106b95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161040e565b6000805460ff1916600117905580156106dc576000805461ff0019166101001790555b6106e8858585856113eb565b801561038f576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050565b8461073e816114e0565b61075a5760405162461bcd60e51b815260040161040e906118ae565b6000866001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa15801561079a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107be91906118f0565b6001600160a01b038181166000908152603760205260409020549192508881169116146107fd5760405162461bcd60e51b815260040161040e9061190d565b6001600160a01b03811661081357610813611951565b306001600160a01b0316876001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa15801561085b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087f91906118f0565b6001600160a01b03161461089557610895611951565b8483146108f05760405162461bcd60e51b8152602060048201526024808201527f4368696c644552433732315072656469636174653a20494e56414c49445f4c4560448201526309c8ea8960e31b606482015260840161040e565b60405163b2dc5dc360e01b81526001600160a01b0388169063b2dc5dc39061092090339088908890600401611999565b6020604051808303816000875af115801561093f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096391906119c7565b61097f5760405162461bcd60e51b815260040161040e906119e9565b6033546035546040516001600160a01b03928316926316f198319216906109d6907f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed290869033908d908d908d908d90602001611a73565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610a02929190611b0d565b600060405180830381600087803b158015610a1c57600080fd5b505af1158015610a30573d6000803e3d6000fd5b50505050336001600160a01b0316876001600160a01b0316826001600160a01b03167fa80bc76d6e1849a9088a9c00a2aeaa54eeb78f15565a18da3e8873438976f52289898989604051610a879493929190611b39565b60405180910390a450505050505050565b82610aa2816114e0565b610abe5760405162461bcd60e51b815260040161040e906118ae565b6000846001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610afe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2291906118f0565b6001600160a01b03818116600090815260376020526040902054919250868116911614610b615760405162461bcd60e51b815260040161040e9061190d565b6001600160a01b038116610b7757610b77611951565b306001600160a01b0316856001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610be391906118f0565b6001600160a01b031614610bf957610bf9611951565b604051632770a7eb60e21b81526001600160a01b03861690639dc29fac90610c279033908790600401611b6b565b6020604051808303816000875af1158015610c46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c6a91906119c7565b610c865760405162461bcd60e51b815260040161040e906119e9565b603354603554604080517f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286960208201526001600160a01b0385811682840152336060830152888116608083015260a08083018990528351808403909101815260c08301938490526316f1983160e01b909352938416936316f1983193610d119391169160c401611b0d565b600060405180830381600087803b158015610d2b57600080fd5b505af1158015610d3f573d6000803e3d6000fd5b50505050836001600160a01b0316856001600160a01b0316826001600160a01b03167f1e0ef6131232b1090efc3ec1cf7b53aa17f4b7cd8a4f9e033b49ee237379b0133387604051610d92929190611b6b565b60405180910390a45050505050565b6000808080610db285870187611b84565b6001600160a01b0380851660009081526037602052604090205494985092965090945092501680610df55760405162461bcd60e51b815260040161040e9061190d565b610dfe816114e0565b610e0a57610e0a611951565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e6e91906118f0565b9050856001600160a01b0316816001600160a01b031614610e9157610e91611951565b6001600160a01b038116610ea757610ea7611951565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610eef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1391906118f0565b6001600160a01b031614610f2957610f29611951565b6040516340c10f1960e01b81526001600160a01b038316906340c10f1990610f579087908790600401611b6b565b6020604051808303816000875af1158015610f76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f9a91906119c7565b610fb65760405162461bcd60e51b815260040161040e90611bd5565b836001600160a01b0316826001600160a01b0316876001600160a01b03167f37589fd8c906c19ea68eeb7e6b3e03efc06ff8aa4b1830588eba75f4375b16118887604051611005929190611b6b565b60405180910390a45050505050505050565b600080808061102885870187611cea565b6001600160a01b0380851660009081526037602052604090205494995092975090955093501690508061106d5760405162461bcd60e51b815260040161040e9061190d565b611076816114e0565b61108257611082611951565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e691906118f0565b9050856001600160a01b0316816001600160a01b03161461110957611109611951565b6001600160a01b03811661111f5761111f611951565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015611167573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061118b91906118f0565b6001600160a01b0316146111a1576111a1611951565b604051637c88e3d960e01b81526001600160a01b03831690637c88e3d9906111cf9087908790600401611ddc565b6020604051808303816000875af11580156111ee573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061121291906119c7565b61122e5760405162461bcd60e51b815260040161040e90611bd5565b846001600160a01b0316826001600160a01b0316876001600160a01b03167fc1b1a5c1b97cc8e5ac82b47496f5ebdadf9c7d119b30a116e2bdafd56f6ed4758787604051611005929190611ddc565b6000808061128d84860186611ecf565b91955093509150506001600160a01b0383166112ab576112ab611951565b6001600160a01b0383811660009081526037602052604090205416156112d3576112d3611951565b6036546040516bffffffffffffffffffffffff19606086901b166020820152600091611323916001600160a01b039091169060340160405160208183030381529060405280519060200120611575565b6001600160a01b038581166000908152603760205260409081902080546001600160a01b031916928416928317905551639065714760e01b81529192509063906571479061137990879087908790600401611f4e565b600060405180830381600087803b15801561139357600080fd5b505af11580156113a7573d6000803e3d6000fd5b50506040516001600160a01b038085169350871691507f46bd56f98e1b14fd35691959270a6e1edf7cb8fcd489e0f9dda89e46c0d1ff0d90600090a3505050505050565b6001600160a01b0384161580159061140b57506001600160a01b03831615155b801561141f57506001600160a01b03821615155b801561143357506001600160a01b03811615155b6114905760405162461bcd60e51b815260206004820152602860248201527f4368696c644552433732315072656469636174653a204241445f494e495449416044820152672624ad20aa24a7a760c11b606482015260840161040e565b603380546001600160a01b039586166001600160a01b0319918216179091556034805494861694821694909417909355603580549285169284169290921790915560368054919093169116179055565b6000816001600160a01b03163b6000036114fc57506000919050565b6040516301ffc9a760e01b81526380ac58cd60e01b60048201526001600160a01b038316906301ffc9a790602401602060405180830381865afa925050508015611563575060408051601f3d908101601f19168201909252611560918101906119c7565b60015b61156f57506000919050565b92915050565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b03811661156f5760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b604482015260640161040e565b6001600160a01b038116811461162157600080fd5b50565b60008083601f84011261163657600080fd5b5081356001600160401b0381111561164d57600080fd5b6020830191508360208260051b850101111561166857600080fd5b9250929050565b60008060008060006060868803121561168757600080fd5b85356116928161160c565b945060208601356001600160401b03808211156116ae57600080fd5b6116ba89838a01611624565b909650945060408801359150808211156116d357600080fd5b506116e088828901611624565b969995985093965092949392505050565b60006020828403121561170357600080fd5b813561170e8161160c565b9392505050565b60008060006060848603121561172a57600080fd5b83356117358161160c565b925060208401356117458161160c565b929592945050506040919091013590565b6000806000806060858703121561176c57600080fd5b84359350602085013561177e8161160c565b925060408501356001600160401b038082111561179a57600080fd5b818701915087601f8301126117ae57600080fd5b8135818111156117bd57600080fd5b8860208285010111156117cf57600080fd5b95989497505060200194505050565b600080604083850312156117f157600080fd5b82356117fc8161160c565b946020939093013593505050565b6000806000806080858703121561182057600080fd5b843561182b8161160c565b9350602085013561183b8161160c565b9250604085013561184b8161160c565b9150606085013561185b8161160c565b939692955090935050565b6000808585111561187657600080fd5b8386111561188357600080fd5b5050820193919092039150565b8035602083101561156f57600019602084900360031b1b1692915050565b60208082526022908201527f4368696c644552433732315072656469636174653a204e4f545f434f4e54524160408201526110d560f21b606082015260800190565b60006020828403121561190257600080fd5b815161170e8161160c565b60208082526024908201527f4368696c644552433732315072656469636174653a20554e4d41505045445f5460408201526327a5a2a760e11b606082015260800190565b634e487b7160e01b600052600160045260246000fd5b81835260006001600160fb1b0383111561198057600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b03841681526040602082018190526000906119be9083018486611967565b95945050505050565b6000602082840312156119d957600080fd5b8151801515811461170e57600080fd5b60208082526021908201527f4368696c644552433732315072656469636174653a204255524e5f4641494c456040820152601160fa1b606082015260800190565b8183526000602080850194508260005b85811015611a68578135611a4d8161160c565b6001600160a01b031687529582019590820190600101611a3a565b509495945050505050565b8781526001600160a01b0387811660208301528616604082015260a060608201819052600090611aa69083018688611a2a565b8281036080840152611ab9818587611967565b9a9950505050505050505050565b6000815180845260005b81811015611aed57602081850181015186830182015201611ad1565b506000602082860101526020601f19601f83011685010191505092915050565b6001600160a01b0383168152604060208201819052600090611b3190830184611ac7565b949350505050565b604081526000611b4d604083018688611a2a565b8281036020840152611b60818587611967565b979650505050505050565b6001600160a01b03929092168252602082015260400190565b60008060008060808587031215611b9a57600080fd5b8435611ba58161160c565b93506020850135611bb58161160c565b92506040850135611bc58161160c565b9396929550929360600135925050565b60208082526021908201527f4368696c644552433732315072656469636174653a204d494e545f4641494c456040820152601160fa1b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715611c5457611c54611c16565b604052919050565b60006001600160401b03821115611c7557611c75611c16565b5060051b60200190565b600082601f830112611c9057600080fd5b81356020611ca5611ca083611c5c565b611c2c565b82815260059290921b84018101918181019086841115611cc457600080fd5b8286015b84811015611cdf5780358352918301918301611cc8565b509695505050505050565b600080600080600060a08688031215611d0257600080fd5b85359450602080870135611d158161160c565b94506040870135611d258161160c565b935060608701356001600160401b0380821115611d4157600080fd5b818901915089601f830112611d5557600080fd5b8135611d63611ca082611c5c565b81815260059190911b8301840190848101908c831115611d8257600080fd5b938501935b82851015611da9578435611d9a8161160c565b82529385019390850190611d87565b965050506080890135925080831115611dc157600080fd5b5050611dcf88828901611c7f565b9150509295509295909350565b604080825283519082018190526000906020906060840190828701845b82811015611e1e5781516001600160a01b031684529284019290840190600101611df9565b5050508381038285015284518082528583019183019060005b81811015611e5357835183529284019291840191600101611e37565b5090979650505050505050565b600082601f830112611e7157600080fd5b81356001600160401b03811115611e8a57611e8a611c16565b611e9d601f8201601f1916602001611c2c565b818152846020838601011115611eb257600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215611ee557600080fd5b843593506020850135611ef78161160c565b925060408501356001600160401b0380821115611f1357600080fd5b611f1f88838901611e60565b93506060870135915080821115611f3557600080fd5b50611f4287828801611e60565b91505092959194509250565b6001600160a01b0384168152606060208201819052600090611f7290830185611ac7565b8281036040840152611f848185611ac7565b969550505050505056fea264697066735822122033c05283a28fb22a3fea46c8e88f9a833d7c53490442d56ec5e0108de332c5a964736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101585760003560e01c8063b1768065116100c3578063e0563ab11161007c578063e0563ab114610306578063eeb499451461030f578063f3fef3a314610322578063f645125514610335578063f691325c1461035c578063f8c8765e1461036f57600080fd5b8063b176806514610244578063b68ad1e41461026b578063c3b35a7e1461027e578063c5ac2b1c14610291578063d41f1771146102b8578063d7c9e3ec146102df57600080fd5b806355b01e4d1161011557806355b01e4d146101ce5780635ea5df79146101dc5780636f33e695146101f35780637efab4f514610208578063947287cf1461023157806397e5230d1461023a57600080fd5b806305dc2e8f1461015d57806307b3e2521461018d5780631bc114ba1461019b578063284017f5146101ae5780633b878c22146101b757806351351d53146101c0575b600080fd5b603454610170906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101706004600360981b0181565b603354610170906001600160a01b031681565b61017061202081565b61017061101081565b6101706002600160a01b0381565b6101706004600160991b0181565b6101e561138881565b604051908152602001610184565b61020661020136600461166f565b610382565b005b6101706102163660046116f1565b6037602052600090815260409020546001600160a01b031681565b6101e561520881565b6101e5620249f081565b6101e57f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b603654610170906001600160a01b031681565b61020661028c366004611715565b610396565b6101e57faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b6101e57f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b6101e57f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b61017061203081565b61020661031d366004611756565b6103a6565b6102066103303660046117de565b6105c9565b6101e57f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b603554610170906001600160a01b031681565b61020661037d36600461180a565b6105d8565b61038f8585858585610734565b5050505050565b6103a1838383610a98565b505050565b6034546001600160a01b031633146104175760405162461bcd60e51b815260206004820152602960248201527f4368696c644552433732315072656469636174653a204f4e4c595f53544154456044820152682fa922a1a2a4ab22a960b91b60648201526084015b60405180910390fd5b6035546001600160a01b038481169116146104865760405162461bcd60e51b815260206004820152602960248201527f4368696c644552433732315072656469636174653a204f4e4c595f524f4f545f60448201526850524544494341544560b81b606482015260840161040e565b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f8216104b5602060008486611866565b6104be91611890565b036104dd576104d86104d38260208186611866565b610da1565b6105c3565b7faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1861050c602060008486611866565b61051591611890565b03610524576104d88282611017565b7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad610553602060008486611866565b61055c91611890565b0361056b576104d8828261127d565b60405162461bcd60e51b815260206004820152602760248201527f4368696c644552433732315072656469636174653a20494e56414c49445f5349604482015266474e415455524560c81b606482015260840161040e565b50505050565b6105d4823383610a98565b5050565b336002600160a01b031461061c5760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b604482015260640161040e565b600054610100900460ff161580801561063c5750600054600160ff909116105b806106565750303b158015610656575060005460ff166001145b6106b95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161040e565b6000805460ff1916600117905580156106dc576000805461ff0019166101001790555b6106e8858585856113eb565b801561038f576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050565b8461073e816114e0565b61075a5760405162461bcd60e51b815260040161040e906118ae565b6000866001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa15801561079a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107be91906118f0565b6001600160a01b038181166000908152603760205260409020549192508881169116146107fd5760405162461bcd60e51b815260040161040e9061190d565b6001600160a01b03811661081357610813611951565b306001600160a01b0316876001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa15801561085b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087f91906118f0565b6001600160a01b03161461089557610895611951565b8483146108f05760405162461bcd60e51b8152602060048201526024808201527f4368696c644552433732315072656469636174653a20494e56414c49445f4c4560448201526309c8ea8960e31b606482015260840161040e565b60405163b2dc5dc360e01b81526001600160a01b0388169063b2dc5dc39061092090339088908890600401611999565b6020604051808303816000875af115801561093f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096391906119c7565b61097f5760405162461bcd60e51b815260040161040e906119e9565b6033546035546040516001600160a01b03928316926316f198319216906109d6907f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed290869033908d908d908d908d90602001611a73565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610a02929190611b0d565b600060405180830381600087803b158015610a1c57600080fd5b505af1158015610a30573d6000803e3d6000fd5b50505050336001600160a01b0316876001600160a01b0316826001600160a01b03167fa80bc76d6e1849a9088a9c00a2aeaa54eeb78f15565a18da3e8873438976f52289898989604051610a879493929190611b39565b60405180910390a450505050505050565b82610aa2816114e0565b610abe5760405162461bcd60e51b815260040161040e906118ae565b6000846001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610afe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2291906118f0565b6001600160a01b03818116600090815260376020526040902054919250868116911614610b615760405162461bcd60e51b815260040161040e9061190d565b6001600160a01b038116610b7757610b77611951565b306001600160a01b0316856001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610be391906118f0565b6001600160a01b031614610bf957610bf9611951565b604051632770a7eb60e21b81526001600160a01b03861690639dc29fac90610c279033908790600401611b6b565b6020604051808303816000875af1158015610c46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c6a91906119c7565b610c865760405162461bcd60e51b815260040161040e906119e9565b603354603554604080517f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286960208201526001600160a01b0385811682840152336060830152888116608083015260a08083018990528351808403909101815260c08301938490526316f1983160e01b909352938416936316f1983193610d119391169160c401611b0d565b600060405180830381600087803b158015610d2b57600080fd5b505af1158015610d3f573d6000803e3d6000fd5b50505050836001600160a01b0316856001600160a01b0316826001600160a01b03167f1e0ef6131232b1090efc3ec1cf7b53aa17f4b7cd8a4f9e033b49ee237379b0133387604051610d92929190611b6b565b60405180910390a45050505050565b6000808080610db285870187611b84565b6001600160a01b0380851660009081526037602052604090205494985092965090945092501680610df55760405162461bcd60e51b815260040161040e9061190d565b610dfe816114e0565b610e0a57610e0a611951565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e6e91906118f0565b9050856001600160a01b0316816001600160a01b031614610e9157610e91611951565b6001600160a01b038116610ea757610ea7611951565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610eef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1391906118f0565b6001600160a01b031614610f2957610f29611951565b6040516340c10f1960e01b81526001600160a01b038316906340c10f1990610f579087908790600401611b6b565b6020604051808303816000875af1158015610f76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f9a91906119c7565b610fb65760405162461bcd60e51b815260040161040e90611bd5565b836001600160a01b0316826001600160a01b0316876001600160a01b03167f37589fd8c906c19ea68eeb7e6b3e03efc06ff8aa4b1830588eba75f4375b16118887604051611005929190611b6b565b60405180910390a45050505050505050565b600080808061102885870187611cea565b6001600160a01b0380851660009081526037602052604090205494995092975090955093501690508061106d5760405162461bcd60e51b815260040161040e9061190d565b611076816114e0565b61108257611082611951565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e691906118f0565b9050856001600160a01b0316816001600160a01b03161461110957611109611951565b6001600160a01b03811661111f5761111f611951565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015611167573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061118b91906118f0565b6001600160a01b0316146111a1576111a1611951565b604051637c88e3d960e01b81526001600160a01b03831690637c88e3d9906111cf9087908790600401611ddc565b6020604051808303816000875af11580156111ee573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061121291906119c7565b61122e5760405162461bcd60e51b815260040161040e90611bd5565b846001600160a01b0316826001600160a01b0316876001600160a01b03167fc1b1a5c1b97cc8e5ac82b47496f5ebdadf9c7d119b30a116e2bdafd56f6ed4758787604051611005929190611ddc565b6000808061128d84860186611ecf565b91955093509150506001600160a01b0383166112ab576112ab611951565b6001600160a01b0383811660009081526037602052604090205416156112d3576112d3611951565b6036546040516bffffffffffffffffffffffff19606086901b166020820152600091611323916001600160a01b039091169060340160405160208183030381529060405280519060200120611575565b6001600160a01b038581166000908152603760205260409081902080546001600160a01b031916928416928317905551639065714760e01b81529192509063906571479061137990879087908790600401611f4e565b600060405180830381600087803b15801561139357600080fd5b505af11580156113a7573d6000803e3d6000fd5b50506040516001600160a01b038085169350871691507f46bd56f98e1b14fd35691959270a6e1edf7cb8fcd489e0f9dda89e46c0d1ff0d90600090a3505050505050565b6001600160a01b0384161580159061140b57506001600160a01b03831615155b801561141f57506001600160a01b03821615155b801561143357506001600160a01b03811615155b6114905760405162461bcd60e51b815260206004820152602860248201527f4368696c644552433732315072656469636174653a204241445f494e495449416044820152672624ad20aa24a7a760c11b606482015260840161040e565b603380546001600160a01b039586166001600160a01b0319918216179091556034805494861694821694909417909355603580549285169284169290921790915560368054919093169116179055565b6000816001600160a01b03163b6000036114fc57506000919050565b6040516301ffc9a760e01b81526380ac58cd60e01b60048201526001600160a01b038316906301ffc9a790602401602060405180830381865afa925050508015611563575060408051601f3d908101601f19168201909252611560918101906119c7565b60015b61156f57506000919050565b92915050565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b03811661156f5760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b604482015260640161040e565b6001600160a01b038116811461162157600080fd5b50565b60008083601f84011261163657600080fd5b5081356001600160401b0381111561164d57600080fd5b6020830191508360208260051b850101111561166857600080fd5b9250929050565b60008060008060006060868803121561168757600080fd5b85356116928161160c565b945060208601356001600160401b03808211156116ae57600080fd5b6116ba89838a01611624565b909650945060408801359150808211156116d357600080fd5b506116e088828901611624565b969995985093965092949392505050565b60006020828403121561170357600080fd5b813561170e8161160c565b9392505050565b60008060006060848603121561172a57600080fd5b83356117358161160c565b925060208401356117458161160c565b929592945050506040919091013590565b6000806000806060858703121561176c57600080fd5b84359350602085013561177e8161160c565b925060408501356001600160401b038082111561179a57600080fd5b818701915087601f8301126117ae57600080fd5b8135818111156117bd57600080fd5b8860208285010111156117cf57600080fd5b95989497505060200194505050565b600080604083850312156117f157600080fd5b82356117fc8161160c565b946020939093013593505050565b6000806000806080858703121561182057600080fd5b843561182b8161160c565b9350602085013561183b8161160c565b9250604085013561184b8161160c565b9150606085013561185b8161160c565b939692955090935050565b6000808585111561187657600080fd5b8386111561188357600080fd5b5050820193919092039150565b8035602083101561156f57600019602084900360031b1b1692915050565b60208082526022908201527f4368696c644552433732315072656469636174653a204e4f545f434f4e54524160408201526110d560f21b606082015260800190565b60006020828403121561190257600080fd5b815161170e8161160c565b60208082526024908201527f4368696c644552433732315072656469636174653a20554e4d41505045445f5460408201526327a5a2a760e11b606082015260800190565b634e487b7160e01b600052600160045260246000fd5b81835260006001600160fb1b0383111561198057600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b03841681526040602082018190526000906119be9083018486611967565b95945050505050565b6000602082840312156119d957600080fd5b8151801515811461170e57600080fd5b60208082526021908201527f4368696c644552433732315072656469636174653a204255524e5f4641494c456040820152601160fa1b606082015260800190565b8183526000602080850194508260005b85811015611a68578135611a4d8161160c565b6001600160a01b031687529582019590820190600101611a3a565b509495945050505050565b8781526001600160a01b0387811660208301528616604082015260a060608201819052600090611aa69083018688611a2a565b8281036080840152611ab9818587611967565b9a9950505050505050505050565b6000815180845260005b81811015611aed57602081850181015186830182015201611ad1565b506000602082860101526020601f19601f83011685010191505092915050565b6001600160a01b0383168152604060208201819052600090611b3190830184611ac7565b949350505050565b604081526000611b4d604083018688611a2a565b8281036020840152611b60818587611967565b979650505050505050565b6001600160a01b03929092168252602082015260400190565b60008060008060808587031215611b9a57600080fd5b8435611ba58161160c565b93506020850135611bb58161160c565b92506040850135611bc58161160c565b9396929550929360600135925050565b60208082526021908201527f4368696c644552433732315072656469636174653a204d494e545f4641494c456040820152601160fa1b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715611c5457611c54611c16565b604052919050565b60006001600160401b03821115611c7557611c75611c16565b5060051b60200190565b600082601f830112611c9057600080fd5b81356020611ca5611ca083611c5c565b611c2c565b82815260059290921b84018101918181019086841115611cc457600080fd5b8286015b84811015611cdf5780358352918301918301611cc8565b509695505050505050565b600080600080600060a08688031215611d0257600080fd5b85359450602080870135611d158161160c565b94506040870135611d258161160c565b935060608701356001600160401b0380821115611d4157600080fd5b818901915089601f830112611d5557600080fd5b8135611d63611ca082611c5c565b81815260059190911b8301840190848101908c831115611d8257600080fd5b938501935b82851015611da9578435611d9a8161160c565b82529385019390850190611d87565b965050506080890135925080831115611dc157600080fd5b5050611dcf88828901611c7f565b9150509295509295909350565b604080825283519082018190526000906020906060840190828701845b82811015611e1e5781516001600160a01b031684529284019290840190600101611df9565b5050508381038285015284518082528583019183019060005b81811015611e5357835183529284019291840191600101611e37565b5090979650505050505050565b600082601f830112611e7157600080fd5b81356001600160401b03811115611e8a57611e8a611c16565b611e9d601f8201601f1916602001611c2c565b818152846020838601011115611eb257600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215611ee557600080fd5b843593506020850135611ef78161160c565b925060408501356001600160401b0380821115611f1357600080fd5b611f1f88838901611e60565b93506060870135915080821115611f3557600080fd5b50611f4287828801611e60565b91505092959194509250565b6001600160a01b0384168152606060208201819052600090611f7290830185611ac7565b8281036040840152611f848185611ac7565b969550505050505056fea264697066735822122033c05283a28fb22a3fea46c8e88f9a833d7c53490442d56ec5e0108de332c5a964736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var ChildERC721PredicateACLArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"ChildERC721PredicateAccessList\",\n \"sourceName\": \"contracts/child/ChildERC721PredicateAccessList.sol\",\n \"abi\": [\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"only\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"Unauthorized\",\n \"type\": \"error\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"block\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bool\",\n \"name\": \"status\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"AllowListUsageSet\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"block\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bool\",\n \"name\": \"status\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"BlockListUsageSet\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2ERC721Deposit\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"L2ERC721DepositBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2ERC721Withdraw\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"L2ERC721WithdrawBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"L2TokenMapped\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"previousOwner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"OwnershipTransferStarted\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"previousOwner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"OwnershipTransferred\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"ALLOWLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"BLOCKLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAP_TOKEN_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TOKEN_CONTRACT\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"READ_ADDRESSLIST_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"SYSTEM\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"acceptOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childTokenTemplate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newL2StateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newStateReceiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newRootERC721Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseAllowList\",\n \"type\": \"bool\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseBlockList\",\n \"type\": \"bool\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newL2StateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newStateReceiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newRootERC721Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"l2StateSender\",\n \"outputs\": [\n {\n \"internalType\": \"contract IStateSender\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onStateReceive\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"owner\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"pendingOwner\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"renounceOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"rootERC721Predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"rootTokenToChildToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseAllowList\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"setAllowList\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseBlockList\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"setBlockList\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"stateReceiver\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"transferOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC721\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"withdraw\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC721\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"withdrawBatch\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC721\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"withdrawTo\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50612758806100206000396000f3fe608060405234801561001057600080fd5b50600436106101b05760003560e01c8063b68ad1e4116100ef578063e0563ab111610092578063e0563ab1146103b9578063e30c3978146103c2578063eeb49945146103d3578063f2fde38b146103e6578063f3fef3a3146103f9578063f64512551461040c578063f691325c14610433578063f8c8765e1461044657600080fd5b8063b68ad1e4146102e5578063c1225a20146102f8578063c3b35a7e1461030b578063c5ac2b1c1461031e578063c5e4683a14610345578063d41f177114610358578063d7c9e3ec1461037f578063d8dd1773146103a657600080fd5b80636f33e695116101575780636f33e6951461024b578063715018a61461026057806379ba5097146102685780637efab4f5146102705780638da5cb5b1461029a578063947287cf146102ab57806397e5230d146102b4578063b1768065146102be57600080fd5b806305dc2e8f146101b557806307b3e252146101e55780631bc114ba146101f3578063284017f5146102065780633b878c221461020f57806351351d531461021857806355b01e4d146102265780635ea5df7914610234575b600080fd5b60fd546101c8906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101c86004600360981b0181565b60fc546101c8906001600160a01b031681565b6101c861202081565b6101c861101081565b6101c86002600160a01b0381565b6101c86004600160991b0181565b61023d61138881565b6040519081526020016101dc565b61025e610259366004611c96565b610459565b005b61025e610475565b61025e610489565b6101c861027e366004611d18565b610100602052600090815260409020546001600160a01b031681565b6033546001600160a01b03166101c8565b61023d61520881565b61023d620249f081565b61023d7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b60ff546101c8906001600160a01b031681565b61025e610306366004611d4a565b610508565b61025e610319366004611d67565b610557565b61023d7faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b61025e610353366004611d4a565b61056f565b61023d7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b61023d7f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b61025e6103b4366004611da8565b6105b6565b6101c861203081565b6065546001600160a01b03166101c8565b61025e6103e1366004611e3e565b6106d7565b61025e6103f4366004611d18565b6108f5565b61025e610407366004611ec6565b610966565b61023d7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b60fe546101c8906001600160a01b031681565b61025e610454366004611ef2565b61097d565b610461610a75565b61046e8585858585610a7d565b5050505050565b61047d610de2565b6104876000610e3c565b565b60655433906001600160a01b031681146104fc5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084015b60405180910390fd5b61050581610e3c565b50565b610510610de2565b60c9805461ff0019166101008315159081029190911790915560405143907f61d574757cde41a357d030b39b2705796ccd699578037ab9a1cfd8117d82bf8690600090a350565b61055f610a75565b61056a838383610e55565b505050565b610577610de2565b60c9805460ff191682151590811790915560405143907fe0a0f0fa52db091cb71c202d80420311430ce1ae2e7794149877b6720ce8bf0b90600090a350565b336002600160a01b03146105dd5760405163973d02cb60e01b81526004016104f390611f4e565b600054610100900460ff16158080156105fd5750600054600160ff909116105b806106175750303b158015610617575060005460ff166001145b6106335760405162461bcd60e51b81526004016104f390611f72565b6000805460ff191660011790558015610656576000805461ff0019166101001790555b6106628888888861115f565b60c9805461ffff191685151561ff001916176101008515150217905561068782610e3c565b80156106cd576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b60fd546001600160a01b031633146107435760405162461bcd60e51b815260206004820152602960248201527f4368696c644552433732315072656469636174653a204f4e4c595f53544154456044820152682fa922a1a2a4ab22a960b91b60648201526084016104f3565b60fe546001600160a01b038481169116146107b25760405162461bcd60e51b815260206004820152602960248201527f4368696c644552433732315072656469636174653a204f4e4c595f524f4f545f60448201526850524544494341544560b81b60648201526084016104f3565b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f8216107e1602060008486611fc0565b6107ea91611fea565b03610809576108046107ff8260208186611fc0565b611254565b6108ef565b7faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d18610838602060008486611fc0565b61084191611fea565b036108505761080482826114cb565b7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad61087f602060008486611fc0565b61088891611fea565b03610897576108048282611732565b60405162461bcd60e51b815260206004820152602760248201527f4368696c644552433732315072656469636174653a20494e56414c49445f5349604482015266474e415455524560c81b60648201526084016104f3565b50505050565b6108fd610de2565b606580546001600160a01b0383166001600160a01b0319909116811790915561092e6033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b61096e610a75565b610979823383610e55565b5050565b336002600160a01b03146109a45760405163973d02cb60e01b81526004016104f390611f4e565b600054610100900460ff16158080156109c45750600054600160ff909116105b806109de5750303b1580156109de575060005460ff166001145b6109fa5760405162461bcd60e51b81526004016104f390611f72565b6000805460ff191660011790558015610a1d576000805461ff0019166101001790555b610a298585858561115f565b801561046e576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050565b6104876118a2565b84610a8781611ab8565b610aa35760405162461bcd60e51b81526004016104f390612008565b6000866001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ae3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b07919061204a565b6001600160a01b0381811660009081526101006020526040902054919250888116911614610b475760405162461bcd60e51b81526004016104f390612067565b6001600160a01b038116610b5d57610b5d6120ab565b306001600160a01b0316876001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ba5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc9919061204a565b6001600160a01b031614610bdf57610bdf6120ab565b848314610c3a5760405162461bcd60e51b8152602060048201526024808201527f4368696c644552433732315072656469636174653a20494e56414c49445f4c4560448201526309c8ea8960e31b60648201526084016104f3565b60405163b2dc5dc360e01b81526001600160a01b0388169063b2dc5dc390610c6a903390889088906004016120f3565b6020604051808303816000875af1158015610c89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cad9190612121565b610cc95760405162461bcd60e51b81526004016104f39061213e565b60fc5460fe546040516001600160a01b03928316926316f19831921690610d20907f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed290869033908d908d908d908d906020016121c8565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610d4c92919061226c565b600060405180830381600087803b158015610d6657600080fd5b505af1158015610d7a573d6000803e3d6000fd5b50505050336001600160a01b0316876001600160a01b0316826001600160a01b03167fa80bc76d6e1849a9088a9c00a2aeaa54eeb78f15565a18da3e8873438976f52289898989604051610dd19493929190612298565b60405180910390a450505050505050565b6033546001600160a01b031633146104875760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104f3565b606580546001600160a01b031916905561050581611b4d565b82610e5f81611ab8565b610e7b5760405162461bcd60e51b81526004016104f390612008565b6000846001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ebb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610edf919061204a565b6001600160a01b0381811660009081526101006020526040902054919250868116911614610f1f5760405162461bcd60e51b81526004016104f390612067565b6001600160a01b038116610f3557610f356120ab565b306001600160a01b0316856001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa1919061204a565b6001600160a01b031614610fb757610fb76120ab565b604051632770a7eb60e21b81526001600160a01b03861690639dc29fac90610fe590339087906004016122ca565b6020604051808303816000875af1158015611004573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110289190612121565b6110445760405162461bcd60e51b81526004016104f39061213e565b60fc5460fe54604080517f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286960208201526001600160a01b0385811682840152336060830152888116608083015260a08083018990528351808403909101815260c08301938490526316f1983160e01b909352938416936316f19831936110cf9391169160c40161226c565b600060405180830381600087803b1580156110e957600080fd5b505af11580156110fd573d6000803e3d6000fd5b50505050836001600160a01b0316856001600160a01b0316826001600160a01b03167f1e0ef6131232b1090efc3ec1cf7b53aa17f4b7cd8a4f9e033b49ee237379b01333876040516111509291906122ca565b60405180910390a45050505050565b6001600160a01b0384161580159061117f57506001600160a01b03831615155b801561119357506001600160a01b03821615155b80156111a757506001600160a01b03811615155b6112045760405162461bcd60e51b815260206004820152602860248201527f4368696c644552433732315072656469636174653a204241445f494e495449416044820152672624ad20aa24a7a760c11b60648201526084016104f3565b60fc80546001600160a01b039586166001600160a01b03199182161790915560fd80549486169482169490941790935560fe80549285169284169290921790915560ff8054919093169116179055565b6000808080611265858701876122e3565b6001600160a01b0380851660009081526101006020526040902054949850929650909450925016806112a95760405162461bcd60e51b81526004016104f390612067565b6112b281611ab8565b6112be576112be6120ab565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611322919061204a565b9050856001600160a01b0316816001600160a01b031614611345576113456120ab565b6001600160a01b03811661135b5761135b6120ab565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c7919061204a565b6001600160a01b0316146113dd576113dd6120ab565b6040516340c10f1960e01b81526001600160a01b038316906340c10f199061140b90879087906004016122ca565b6020604051808303816000875af115801561142a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061144e9190612121565b61146a5760405162461bcd60e51b81526004016104f390612334565b836001600160a01b0316826001600160a01b0316876001600160a01b03167f37589fd8c906c19ea68eeb7e6b3e03efc06ff8aa4b1830588eba75f4375b161188876040516114b99291906122ca565b60405180910390a45050505050505050565b60008080806114dc85870187612449565b6001600160a01b03808516600090815261010060205260409020549499509297509095509350169050806115225760405162461bcd60e51b81526004016104f390612067565b61152b81611ab8565b611537576115376120ab565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015611577573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159b919061204a565b9050856001600160a01b0316816001600160a01b0316146115be576115be6120ab565b6001600160a01b0381166115d4576115d46120ab565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa15801561161c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611640919061204a565b6001600160a01b031614611656576116566120ab565b604051637c88e3d960e01b81526001600160a01b03831690637c88e3d990611684908790879060040161253b565b6020604051808303816000875af11580156116a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116c79190612121565b6116e35760405162461bcd60e51b81526004016104f390612334565b846001600160a01b0316826001600160a01b0316876001600160a01b03167fc1b1a5c1b97cc8e5ac82b47496f5ebdadf9c7d119b30a116e2bdafd56f6ed47587876040516114b992919061253b565b600080806117428486018661262e565b91955093509150506001600160a01b038316611760576117606120ab565b6001600160a01b03838116600090815261010060205260409020541615611789576117896120ab565b60ff546040516bffffffffffffffffffffffff19606086901b1660208201526000916117d9916001600160a01b039091169060340160405160208183030381529060405280519060200120611b9f565b6001600160a01b03858116600090815261010060205260409081902080546001600160a01b031916928416928317905551639065714760e01b815291925090639065714790611830908790879087906004016126ad565b600060405180830381600087803b15801561184a57600080fd5b505af115801561185e573d6000803e3d6000fd5b50506040516001600160a01b038085169350871691507f46bd56f98e1b14fd35691959270a6e1edf7cb8fcd489e0f9dda89e46c0d1ff0d90600090a3505050505050565b60c95460ff16156119ad57604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600160991b01916113889161190491906126ed565b6000604051808303818686fa925050503d8060008114611940576040519150601f19603f3d011682016040523d82523d6000602084013e611945565b606091505b509150915081801561196a57506000818060200190518101906119689190612709565b115b6119aa5760405162461bcd60e51b81526020600482015260116024820152702224a9a0a62627aba2a22fa9a2a72222a960791b60448201526064016104f3565b50505b60c954610100900460ff161561048757604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600360981b019161138891611a1491906126ed565b6000604051808303818686fa925050503d8060008114611a50576040519150601f19603f3d011682016040523d82523d6000602084013e611a55565b606091505b5091509150818015611a7b575080806020019051810190611a769190612709565b600114155b6109795760405162461bcd60e51b815260206004820152600e60248201526d212627a1a5a2a22fa9a2a72222a960911b60448201526064016104f3565b6000816001600160a01b03163b600003611ad457506000919050565b6040516301ffc9a760e01b81526380ac58cd60e01b60048201526001600160a01b038316906301ffc9a790602401602060405180830381865afa925050508015611b3b575060408051601f3d908101601f19168201909252611b3891810190612121565b60015b611b4757506000919050565b92915050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b038116611b475760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b60448201526064016104f3565b6001600160a01b038116811461050557600080fd5b60008083601f840112611c5d57600080fd5b5081356001600160401b03811115611c7457600080fd5b6020830191508360208260051b8501011115611c8f57600080fd5b9250929050565b600080600080600060608688031215611cae57600080fd5b8535611cb981611c36565b945060208601356001600160401b0380821115611cd557600080fd5b611ce189838a01611c4b565b90965094506040880135915080821115611cfa57600080fd5b50611d0788828901611c4b565b969995985093965092949392505050565b600060208284031215611d2a57600080fd5b8135611d3581611c36565b9392505050565b801515811461050557600080fd5b600060208284031215611d5c57600080fd5b8135611d3581611d3c565b600080600060608486031215611d7c57600080fd5b8335611d8781611c36565b92506020840135611d9781611c36565b929592945050506040919091013590565b600080600080600080600060e0888a031215611dc357600080fd5b8735611dce81611c36565b96506020880135611dde81611c36565b95506040880135611dee81611c36565b94506060880135611dfe81611c36565b93506080880135611e0e81611d3c565b925060a0880135611e1e81611d3c565b915060c0880135611e2e81611c36565b8091505092959891949750929550565b60008060008060608587031215611e5457600080fd5b843593506020850135611e6681611c36565b925060408501356001600160401b0380821115611e8257600080fd5b818701915087601f830112611e9657600080fd5b813581811115611ea557600080fd5b886020828501011115611eb757600080fd5b95989497505060200194505050565b60008060408385031215611ed957600080fd5b8235611ee481611c36565b946020939093013593505050565b60008060008060808587031215611f0857600080fd5b8435611f1381611c36565b93506020850135611f2381611c36565b92506040850135611f3381611c36565b91506060850135611f4381611c36565b939692955090935050565b6020808252600a908201526914d654d5115350d0531360b21b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b60008085851115611fd057600080fd5b83861115611fdd57600080fd5b5050820193919092039150565b80356020831015611b4757600019602084900360031b1b1692915050565b60208082526022908201527f4368696c644552433732315072656469636174653a204e4f545f434f4e54524160408201526110d560f21b606082015260800190565b60006020828403121561205c57600080fd5b8151611d3581611c36565b60208082526024908201527f4368696c644552433732315072656469636174653a20554e4d41505045445f5460408201526327a5a2a760e11b606082015260800190565b634e487b7160e01b600052600160045260246000fd5b81835260006001600160fb1b038311156120da57600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b038416815260406020820181905260009061211890830184866120c1565b95945050505050565b60006020828403121561213357600080fd5b8151611d3581611d3c565b60208082526021908201527f4368696c644552433732315072656469636174653a204255524e5f4641494c456040820152601160fa1b606082015260800190565b8183526000602080850194508260005b858110156121bd5781356121a281611c36565b6001600160a01b03168752958201959082019060010161218f565b509495945050505050565b8781526001600160a01b0387811660208301528616604082015260a0606082018190526000906121fb908301868861217f565b828103608084015261220e8185876120c1565b9a9950505050505050505050565b60005b8381101561223757818101518382015260200161221f565b50506000910152565b6000815180845261225881602086016020860161221c565b601f01601f19169290920160200192915050565b6001600160a01b038316815260406020820181905260009061229090830184612240565b949350505050565b6040815260006122ac60408301868861217f565b82810360208401526122bf8185876120c1565b979650505050505050565b6001600160a01b03929092168252602082015260400190565b600080600080608085870312156122f957600080fd5b843561230481611c36565b9350602085013561231481611c36565b9250604085013561232481611c36565b9396929550929360600135925050565b60208082526021908201527f4368696c644552433732315072656469636174653a204d494e545f4641494c456040820152601160fa1b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156123b3576123b3612375565b604052919050565b60006001600160401b038211156123d4576123d4612375565b5060051b60200190565b600082601f8301126123ef57600080fd5b813560206124046123ff836123bb565b61238b565b82815260059290921b8401810191818101908684111561242357600080fd5b8286015b8481101561243e5780358352918301918301612427565b509695505050505050565b600080600080600060a0868803121561246157600080fd5b8535945060208087013561247481611c36565b9450604087013561248481611c36565b935060608701356001600160401b03808211156124a057600080fd5b818901915089601f8301126124b457600080fd5b81356124c26123ff826123bb565b81815260059190911b8301840190848101908c8311156124e157600080fd5b938501935b828510156125085784356124f981611c36565b825293850193908501906124e6565b96505050608089013592508083111561252057600080fd5b505061252e888289016123de565b9150509295509295909350565b604080825283519082018190526000906020906060840190828701845b8281101561257d5781516001600160a01b031684529284019290840190600101612558565b5050508381038285015284518082528583019183019060005b818110156125b257835183529284019291840191600101612596565b5090979650505050505050565b600082601f8301126125d057600080fd5b81356001600160401b038111156125e9576125e9612375565b6125fc601f8201601f191660200161238b565b81815284602083860101111561261157600080fd5b816020850160208301376000918101602001919091529392505050565b6000806000806080858703121561264457600080fd5b84359350602085013561265681611c36565b925060408501356001600160401b038082111561267257600080fd5b61267e888389016125bf565b9350606087013591508082111561269457600080fd5b506126a1878288016125bf565b91505092959194509250565b6001600160a01b03841681526060602082018190526000906126d190830185612240565b82810360408401526126e38185612240565b9695505050505050565b600082516126ff81846020870161221c565b9190910192915050565b60006020828403121561271b57600080fd5b505191905056fea2646970667358221220f432dec92e2b851cf09a10edc80bb08d14c91bd93d7311308f4149c24ce2c61d64736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101b05760003560e01c8063b68ad1e4116100ef578063e0563ab111610092578063e0563ab1146103b9578063e30c3978146103c2578063eeb49945146103d3578063f2fde38b146103e6578063f3fef3a3146103f9578063f64512551461040c578063f691325c14610433578063f8c8765e1461044657600080fd5b8063b68ad1e4146102e5578063c1225a20146102f8578063c3b35a7e1461030b578063c5ac2b1c1461031e578063c5e4683a14610345578063d41f177114610358578063d7c9e3ec1461037f578063d8dd1773146103a657600080fd5b80636f33e695116101575780636f33e6951461024b578063715018a61461026057806379ba5097146102685780637efab4f5146102705780638da5cb5b1461029a578063947287cf146102ab57806397e5230d146102b4578063b1768065146102be57600080fd5b806305dc2e8f146101b557806307b3e252146101e55780631bc114ba146101f3578063284017f5146102065780633b878c221461020f57806351351d531461021857806355b01e4d146102265780635ea5df7914610234575b600080fd5b60fd546101c8906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101c86004600360981b0181565b60fc546101c8906001600160a01b031681565b6101c861202081565b6101c861101081565b6101c86002600160a01b0381565b6101c86004600160991b0181565b61023d61138881565b6040519081526020016101dc565b61025e610259366004611c96565b610459565b005b61025e610475565b61025e610489565b6101c861027e366004611d18565b610100602052600090815260409020546001600160a01b031681565b6033546001600160a01b03166101c8565b61023d61520881565b61023d620249f081565b61023d7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b60ff546101c8906001600160a01b031681565b61025e610306366004611d4a565b610508565b61025e610319366004611d67565b610557565b61023d7faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b61025e610353366004611d4a565b61056f565b61023d7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b61023d7f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b61025e6103b4366004611da8565b6105b6565b6101c861203081565b6065546001600160a01b03166101c8565b61025e6103e1366004611e3e565b6106d7565b61025e6103f4366004611d18565b6108f5565b61025e610407366004611ec6565b610966565b61023d7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b60fe546101c8906001600160a01b031681565b61025e610454366004611ef2565b61097d565b610461610a75565b61046e8585858585610a7d565b5050505050565b61047d610de2565b6104876000610e3c565b565b60655433906001600160a01b031681146104fc5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084015b60405180910390fd5b61050581610e3c565b50565b610510610de2565b60c9805461ff0019166101008315159081029190911790915560405143907f61d574757cde41a357d030b39b2705796ccd699578037ab9a1cfd8117d82bf8690600090a350565b61055f610a75565b61056a838383610e55565b505050565b610577610de2565b60c9805460ff191682151590811790915560405143907fe0a0f0fa52db091cb71c202d80420311430ce1ae2e7794149877b6720ce8bf0b90600090a350565b336002600160a01b03146105dd5760405163973d02cb60e01b81526004016104f390611f4e565b600054610100900460ff16158080156105fd5750600054600160ff909116105b806106175750303b158015610617575060005460ff166001145b6106335760405162461bcd60e51b81526004016104f390611f72565b6000805460ff191660011790558015610656576000805461ff0019166101001790555b6106628888888861115f565b60c9805461ffff191685151561ff001916176101008515150217905561068782610e3c565b80156106cd576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b60fd546001600160a01b031633146107435760405162461bcd60e51b815260206004820152602960248201527f4368696c644552433732315072656469636174653a204f4e4c595f53544154456044820152682fa922a1a2a4ab22a960b91b60648201526084016104f3565b60fe546001600160a01b038481169116146107b25760405162461bcd60e51b815260206004820152602960248201527f4368696c644552433732315072656469636174653a204f4e4c595f524f4f545f60448201526850524544494341544560b81b60648201526084016104f3565b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f8216107e1602060008486611fc0565b6107ea91611fea565b03610809576108046107ff8260208186611fc0565b611254565b6108ef565b7faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d18610838602060008486611fc0565b61084191611fea565b036108505761080482826114cb565b7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad61087f602060008486611fc0565b61088891611fea565b03610897576108048282611732565b60405162461bcd60e51b815260206004820152602760248201527f4368696c644552433732315072656469636174653a20494e56414c49445f5349604482015266474e415455524560c81b60648201526084016104f3565b50505050565b6108fd610de2565b606580546001600160a01b0383166001600160a01b0319909116811790915561092e6033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b61096e610a75565b610979823383610e55565b5050565b336002600160a01b03146109a45760405163973d02cb60e01b81526004016104f390611f4e565b600054610100900460ff16158080156109c45750600054600160ff909116105b806109de5750303b1580156109de575060005460ff166001145b6109fa5760405162461bcd60e51b81526004016104f390611f72565b6000805460ff191660011790558015610a1d576000805461ff0019166101001790555b610a298585858561115f565b801561046e576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050565b6104876118a2565b84610a8781611ab8565b610aa35760405162461bcd60e51b81526004016104f390612008565b6000866001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ae3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b07919061204a565b6001600160a01b0381811660009081526101006020526040902054919250888116911614610b475760405162461bcd60e51b81526004016104f390612067565b6001600160a01b038116610b5d57610b5d6120ab565b306001600160a01b0316876001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ba5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc9919061204a565b6001600160a01b031614610bdf57610bdf6120ab565b848314610c3a5760405162461bcd60e51b8152602060048201526024808201527f4368696c644552433732315072656469636174653a20494e56414c49445f4c4560448201526309c8ea8960e31b60648201526084016104f3565b60405163b2dc5dc360e01b81526001600160a01b0388169063b2dc5dc390610c6a903390889088906004016120f3565b6020604051808303816000875af1158015610c89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cad9190612121565b610cc95760405162461bcd60e51b81526004016104f39061213e565b60fc5460fe546040516001600160a01b03928316926316f19831921690610d20907f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed290869033908d908d908d908d906020016121c8565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610d4c92919061226c565b600060405180830381600087803b158015610d6657600080fd5b505af1158015610d7a573d6000803e3d6000fd5b50505050336001600160a01b0316876001600160a01b0316826001600160a01b03167fa80bc76d6e1849a9088a9c00a2aeaa54eeb78f15565a18da3e8873438976f52289898989604051610dd19493929190612298565b60405180910390a450505050505050565b6033546001600160a01b031633146104875760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104f3565b606580546001600160a01b031916905561050581611b4d565b82610e5f81611ab8565b610e7b5760405162461bcd60e51b81526004016104f390612008565b6000846001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ebb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610edf919061204a565b6001600160a01b0381811660009081526101006020526040902054919250868116911614610f1f5760405162461bcd60e51b81526004016104f390612067565b6001600160a01b038116610f3557610f356120ab565b306001600160a01b0316856001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa1919061204a565b6001600160a01b031614610fb757610fb76120ab565b604051632770a7eb60e21b81526001600160a01b03861690639dc29fac90610fe590339087906004016122ca565b6020604051808303816000875af1158015611004573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110289190612121565b6110445760405162461bcd60e51b81526004016104f39061213e565b60fc5460fe54604080517f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286960208201526001600160a01b0385811682840152336060830152888116608083015260a08083018990528351808403909101815260c08301938490526316f1983160e01b909352938416936316f19831936110cf9391169160c40161226c565b600060405180830381600087803b1580156110e957600080fd5b505af11580156110fd573d6000803e3d6000fd5b50505050836001600160a01b0316856001600160a01b0316826001600160a01b03167f1e0ef6131232b1090efc3ec1cf7b53aa17f4b7cd8a4f9e033b49ee237379b01333876040516111509291906122ca565b60405180910390a45050505050565b6001600160a01b0384161580159061117f57506001600160a01b03831615155b801561119357506001600160a01b03821615155b80156111a757506001600160a01b03811615155b6112045760405162461bcd60e51b815260206004820152602860248201527f4368696c644552433732315072656469636174653a204241445f494e495449416044820152672624ad20aa24a7a760c11b60648201526084016104f3565b60fc80546001600160a01b039586166001600160a01b03199182161790915560fd80549486169482169490941790935560fe80549285169284169290921790915560ff8054919093169116179055565b6000808080611265858701876122e3565b6001600160a01b0380851660009081526101006020526040902054949850929650909450925016806112a95760405162461bcd60e51b81526004016104f390612067565b6112b281611ab8565b6112be576112be6120ab565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611322919061204a565b9050856001600160a01b0316816001600160a01b031614611345576113456120ab565b6001600160a01b03811661135b5761135b6120ab565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c7919061204a565b6001600160a01b0316146113dd576113dd6120ab565b6040516340c10f1960e01b81526001600160a01b038316906340c10f199061140b90879087906004016122ca565b6020604051808303816000875af115801561142a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061144e9190612121565b61146a5760405162461bcd60e51b81526004016104f390612334565b836001600160a01b0316826001600160a01b0316876001600160a01b03167f37589fd8c906c19ea68eeb7e6b3e03efc06ff8aa4b1830588eba75f4375b161188876040516114b99291906122ca565b60405180910390a45050505050505050565b60008080806114dc85870187612449565b6001600160a01b03808516600090815261010060205260409020549499509297509095509350169050806115225760405162461bcd60e51b81526004016104f390612067565b61152b81611ab8565b611537576115376120ab565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015611577573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159b919061204a565b9050856001600160a01b0316816001600160a01b0316146115be576115be6120ab565b6001600160a01b0381166115d4576115d46120ab565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa15801561161c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611640919061204a565b6001600160a01b031614611656576116566120ab565b604051637c88e3d960e01b81526001600160a01b03831690637c88e3d990611684908790879060040161253b565b6020604051808303816000875af11580156116a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116c79190612121565b6116e35760405162461bcd60e51b81526004016104f390612334565b846001600160a01b0316826001600160a01b0316876001600160a01b03167fc1b1a5c1b97cc8e5ac82b47496f5ebdadf9c7d119b30a116e2bdafd56f6ed47587876040516114b992919061253b565b600080806117428486018661262e565b91955093509150506001600160a01b038316611760576117606120ab565b6001600160a01b03838116600090815261010060205260409020541615611789576117896120ab565b60ff546040516bffffffffffffffffffffffff19606086901b1660208201526000916117d9916001600160a01b039091169060340160405160208183030381529060405280519060200120611b9f565b6001600160a01b03858116600090815261010060205260409081902080546001600160a01b031916928416928317905551639065714760e01b815291925090639065714790611830908790879087906004016126ad565b600060405180830381600087803b15801561184a57600080fd5b505af115801561185e573d6000803e3d6000fd5b50506040516001600160a01b038085169350871691507f46bd56f98e1b14fd35691959270a6e1edf7cb8fcd489e0f9dda89e46c0d1ff0d90600090a3505050505050565b60c95460ff16156119ad57604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600160991b01916113889161190491906126ed565b6000604051808303818686fa925050503d8060008114611940576040519150601f19603f3d011682016040523d82523d6000602084013e611945565b606091505b509150915081801561196a57506000818060200190518101906119689190612709565b115b6119aa5760405162461bcd60e51b81526020600482015260116024820152702224a9a0a62627aba2a22fa9a2a72222a960791b60448201526064016104f3565b50505b60c954610100900460ff161561048757604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600360981b019161138891611a1491906126ed565b6000604051808303818686fa925050503d8060008114611a50576040519150601f19603f3d011682016040523d82523d6000602084013e611a55565b606091505b5091509150818015611a7b575080806020019051810190611a769190612709565b600114155b6109795760405162461bcd60e51b815260206004820152600e60248201526d212627a1a5a2a22fa9a2a72222a960911b60448201526064016104f3565b6000816001600160a01b03163b600003611ad457506000919050565b6040516301ffc9a760e01b81526380ac58cd60e01b60048201526001600160a01b038316906301ffc9a790602401602060405180830381865afa925050508015611b3b575060408051601f3d908101601f19168201909252611b3891810190612121565b60015b611b4757506000919050565b92915050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b038116611b475760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b60448201526064016104f3565b6001600160a01b038116811461050557600080fd5b60008083601f840112611c5d57600080fd5b5081356001600160401b03811115611c7457600080fd5b6020830191508360208260051b8501011115611c8f57600080fd5b9250929050565b600080600080600060608688031215611cae57600080fd5b8535611cb981611c36565b945060208601356001600160401b0380821115611cd557600080fd5b611ce189838a01611c4b565b90965094506040880135915080821115611cfa57600080fd5b50611d0788828901611c4b565b969995985093965092949392505050565b600060208284031215611d2a57600080fd5b8135611d3581611c36565b9392505050565b801515811461050557600080fd5b600060208284031215611d5c57600080fd5b8135611d3581611d3c565b600080600060608486031215611d7c57600080fd5b8335611d8781611c36565b92506020840135611d9781611c36565b929592945050506040919091013590565b600080600080600080600060e0888a031215611dc357600080fd5b8735611dce81611c36565b96506020880135611dde81611c36565b95506040880135611dee81611c36565b94506060880135611dfe81611c36565b93506080880135611e0e81611d3c565b925060a0880135611e1e81611d3c565b915060c0880135611e2e81611c36565b8091505092959891949750929550565b60008060008060608587031215611e5457600080fd5b843593506020850135611e6681611c36565b925060408501356001600160401b0380821115611e8257600080fd5b818701915087601f830112611e9657600080fd5b813581811115611ea557600080fd5b886020828501011115611eb757600080fd5b95989497505060200194505050565b60008060408385031215611ed957600080fd5b8235611ee481611c36565b946020939093013593505050565b60008060008060808587031215611f0857600080fd5b8435611f1381611c36565b93506020850135611f2381611c36565b92506040850135611f3381611c36565b91506060850135611f4381611c36565b939692955090935050565b6020808252600a908201526914d654d5115350d0531360b21b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b60008085851115611fd057600080fd5b83861115611fdd57600080fd5b5050820193919092039150565b80356020831015611b4757600019602084900360031b1b1692915050565b60208082526022908201527f4368696c644552433732315072656469636174653a204e4f545f434f4e54524160408201526110d560f21b606082015260800190565b60006020828403121561205c57600080fd5b8151611d3581611c36565b60208082526024908201527f4368696c644552433732315072656469636174653a20554e4d41505045445f5460408201526327a5a2a760e11b606082015260800190565b634e487b7160e01b600052600160045260246000fd5b81835260006001600160fb1b038311156120da57600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b038416815260406020820181905260009061211890830184866120c1565b95945050505050565b60006020828403121561213357600080fd5b8151611d3581611d3c565b60208082526021908201527f4368696c644552433732315072656469636174653a204255524e5f4641494c456040820152601160fa1b606082015260800190565b8183526000602080850194508260005b858110156121bd5781356121a281611c36565b6001600160a01b03168752958201959082019060010161218f565b509495945050505050565b8781526001600160a01b0387811660208301528616604082015260a0606082018190526000906121fb908301868861217f565b828103608084015261220e8185876120c1565b9a9950505050505050505050565b60005b8381101561223757818101518382015260200161221f565b50506000910152565b6000815180845261225881602086016020860161221c565b601f01601f19169290920160200192915050565b6001600160a01b038316815260406020820181905260009061229090830184612240565b949350505050565b6040815260006122ac60408301868861217f565b82810360208401526122bf8185876120c1565b979650505050505050565b6001600160a01b03929092168252602082015260400190565b600080600080608085870312156122f957600080fd5b843561230481611c36565b9350602085013561231481611c36565b9250604085013561232481611c36565b9396929550929360600135925050565b60208082526021908201527f4368696c644552433732315072656469636174653a204d494e545f4641494c456040820152601160fa1b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156123b3576123b3612375565b604052919050565b60006001600160401b038211156123d4576123d4612375565b5060051b60200190565b600082601f8301126123ef57600080fd5b813560206124046123ff836123bb565b61238b565b82815260059290921b8401810191818101908684111561242357600080fd5b8286015b8481101561243e5780358352918301918301612427565b509695505050505050565b600080600080600060a0868803121561246157600080fd5b8535945060208087013561247481611c36565b9450604087013561248481611c36565b935060608701356001600160401b03808211156124a057600080fd5b818901915089601f8301126124b457600080fd5b81356124c26123ff826123bb565b81815260059190911b8301840190848101908c8311156124e157600080fd5b938501935b828510156125085784356124f981611c36565b825293850193908501906124e6565b96505050608089013592508083111561252057600080fd5b505061252e888289016123de565b9150509295509295909350565b604080825283519082018190526000906020906060840190828701845b8281101561257d5781516001600160a01b031684529284019290840190600101612558565b5050508381038285015284518082528583019183019060005b818110156125b257835183529284019291840191600101612596565b5090979650505050505050565b600082601f8301126125d057600080fd5b81356001600160401b038111156125e9576125e9612375565b6125fc601f8201601f191660200161238b565b81815284602083860101111561261157600080fd5b816020850160208301376000918101602001919091529392505050565b6000806000806080858703121561264457600080fd5b84359350602085013561265681611c36565b925060408501356001600160401b038082111561267257600080fd5b61267e888389016125bf565b9350606087013591508082111561269457600080fd5b506126a1878288016125bf565b91505092959194509250565b6001600160a01b03841681526060602082018190526000906126d190830185612240565b82810360408401526126e38185612240565b9695505050505050565b600082516126ff81846020870161221c565b9190910192915050565b60006020828403121561271b57600080fd5b505191905056fea2646970667358221220f432dec92e2b851cf09a10edc80bb08d14c91bd93d7311308f4149c24ce2c61d64736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var RootMintableERC721PredicateArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"RootMintableERC721Predicate\",\n \"sourceName\": \"contracts/child/RootMintableERC721Predicate.sol\",\n \"abi\": [\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"only\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"Unauthorized\",\n \"type\": \"error\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"depositor\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2MintableERC721Deposit\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"depositor\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"L2MintableERC721DepositBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"withdrawer\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2MintableERC721Withdraw\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"withdrawer\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"L2MintableERC721WithdrawBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"L2MintableTokenMapped\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"ALLOWLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"BLOCKLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAP_TOKEN_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TOKEN_CONTRACT\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"READ_ADDRESSLIST_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"SYSTEM\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childERC721Predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childTokenTemplate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC721Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"deposit\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC721Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"depositBatch\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC721Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"depositTo\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newL2StateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newStateReceiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildERC721Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"l2StateSender\",\n \"outputs\": [\n {\n \"internalType\": \"contract IStateSender\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC721Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"mapToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onERC721Received\",\n \"outputs\": [\n {\n \"internalType\": \"bytes4\",\n \"name\": \"\",\n \"type\": \"bytes4\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onStateReceive\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"rootTokenToChildToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"stateReceiver\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50611a8f806100206000396000f3fe608060405234801561001057600080fd5b506004361061016e5760003560e01c806397e5230d116100ce578063e0563ab111610087578063e0563ab114610353578063eeb499451461035c578063f213159c1461036f578063f4a120f714610382578063f645125514610395578063f8c8765e146103bc578063ff6f870c146103cf57600080fd5b806397e5230d1461029a578063b1768065146102a4578063b68ad1e4146102cb578063c5ac2b1c146102de578063d41f177114610305578063d7c9e3ec1461032c57600080fd5b806347e7ef241161012b57806347e7ef241461020d5780634fdca69d1461022257806351351d531461023557806355b01e4d146102435780635ea5df79146102515780637efab4f514610268578063947287cf1461029157600080fd5b806305dc2e8f1461017357806307b3e252146101a3578063150b7a02146101b15780631bc114ba146101e8578063284017f5146101fb5780633b878c2214610204575b600080fd5b603454610186906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101866004600360981b0181565b6101cf6101bf366004611231565b630a85bd0160e11b949350505050565b6040516001600160e01b0319909116815260200161019a565b603354610186906001600160a01b031681565b61018661202081565b61018661101081565b61022061021b3660046112df565b6103e2565b005b603554610186906001600160a01b031681565b6101866002600160a01b0381565b6101866004600160991b0181565b61025a61138881565b60405190815260200161019a565b61018661027636600461130b565b6037602052600090815260409020546001600160a01b031681565b61025a61520881565b61025a620249f081565b61025a7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b603654610186906001600160a01b031681565b61025a7faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b61025a7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b61025a7f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b61018661203081565b61022061036a36600461132f565b6103f1565b61022061037d3660046113b7565b6105d1565b61018661039036600461130b565b6105e1565b61025a7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b6102206103ca3660046113f8565b61093a565b6102206103dd36600461149f565b610a97565b6103ed823383610af5565b5050565b6034546001600160a01b031633146104695760405162461bcd60e51b815260206004820152603060248201527f526f6f744d696e7461626c654552433732315072656469636174653a204f4e4c60448201526f2cafa9aa20aa22afa922a1a2a4ab22a960811b60648201526084015b60405180910390fd5b6035546001600160a01b038481169116146104e05760405162461bcd60e51b815260206004820152603160248201527f526f6f744d696e7461626c654552433732315072656469636174653a204f4e4c604482015270595f4348494c445f50524544494341544560781b6064820152608401610460565b7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286961050f602060008486611521565b6105189161154b565b036105375761053261052d8260208186611521565b610c74565b6105cb565b7f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed2610566602060008486611521565b61056f9161154b565b0361057e576105328282610d72565b60405162461bcd60e51b815260206004820152602e6024820152600080516020611a3a83398151915260448201526d414c49445f5349474e415455524560901b6064820152608401610460565b50505050565b6105dc838383610af5565b505050565b60006001600160a01b03821661063a5760405162461bcd60e51b815260206004820152602a6024820152600080516020611a3a83398151915260448201526920a624a22faa27a5a2a760b11b6064820152608401610460565b6001600160a01b0382811660009081526037602052604090205416156106b65760405162461bcd60e51b815260206004820152602b60248201527f526f6f744d696e7461626c654552433732315072656469636174653a20414c5260448201526a1150511657d3505414115160aa1b6064820152608401610460565b6035546036546040516bffffffffffffffffffffffff19606086901b1660208201526001600160a01b039283169260009261076492911690603401604051602081830303815290604052805190602001208460405160388101919091526f5af43d82803e903d91602b57fd5bf3ff60248201526014810192909252733d602d80600a3d3981f3363d3d373d3d3d363d73825260588201526037600c8201206078820152605560439091012090565b6001600160a01b0385811660008181526037602052604080822080546001600160a01b03191686861617905560335481516306fdde0360e01b81529151959650909316936316f198319387937f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad938b9391926306fdde0392600480830193928290030181865afa1580156107fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610824919081019061158e565b896001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610862573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261088a919081019061158e565b60405160200161089d9493929190611630565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016108c9929190611677565b600060405180830381600087803b1580156108e357600080fd5b505af11580156108f7573d6000803e3d6000fd5b50506040516001600160a01b038085169350871691507fb96a191bae4e25ffdff7f4136994eb0dec75d263750a07c035202c348c9515f090600090a39392505050565b336002600160a01b031461097e5760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b6044820152606401610460565b600054610100900460ff161580801561099e5750600054600160ff909116105b806109b85750303b1580156109b8575060005460ff166001145b610a1b5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610460565b6000805460ff191660011790558015610a3e576000805461ff0019166101001790555b610a4a85858585610eb3565b8015610a90576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b828114610ae85760405162461bcd60e51b815260206004820152602b6024820152600080516020611a3a83398151915260448201526a082989288be988a9c8ea8960ab1b6064820152608401610460565b610a908585858585610faf565b6000610b0084611165565b604051632142170760e11b81529091506001600160a01b038516906342842e0e90610b33903390309087906004016116a3565b600060405180830381600087803b158015610b4d57600080fd5b505af1158015610b61573d6000803e3d6000fd5b5050603354603554604080517f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82160208201526001600160a01b038a811682840152336060830152898116608083015260a08083018a90528351808403909101815260c08301938490526316f1983160e01b90935293841695506316f198319450610bf1939092169160c401611677565b600060405180830381600087803b158015610c0b57600080fd5b505af1158015610c1f573d6000803e3d6000fd5b505060408051338152602081018690526001600160a01b03808816945085811693508816917fe3abb9ec195b50242582cc6cb7abc990ac26439b9ed7635ed72f7bd720e7477a910160405180910390a46105cb565b6000808080610c85858701876116c7565b6001600160a01b0380851660009081526037602052604090205494985092965090945092501680610cb857610cb8611718565b604051632142170760e11b81526001600160a01b038616906342842e0e90610ce8903090879087906004016116a3565b600060405180830381600087803b158015610d0257600080fd5b505af1158015610d16573d6000803e3d6000fd5b5050604080516001600160a01b03888116825260208201879052808816945085811693508916917f80afffd84aa825dd9b3c1ba262eb55eef58f78616634437a367a263f3c48fe3d91015b60405180910390a450505050505050565b6000808080610d83858701876117b7565b6001600160a01b03808516600090815260376020526040902054949950929750909550935016905080610db857610db8611718565b60005b8251811015610e6357856001600160a01b03166342842e0e30868481518110610de657610de66118a9565b6020026020010151868581518110610e0057610e006118a9565b60200260200101516040518463ffffffff1660e01b8152600401610e26939291906116a3565b600060405180830381600087803b158015610e4057600080fd5b505af1158015610e54573d6000803e3d6000fd5b50505050806001019050610dbb565b50836001600160a01b0316816001600160a01b0316866001600160a01b03167ff64537485d843fa8a1f4354cb9937954c64282de0828be9f096355006222186b8686604051610d619291906118bf565b6001600160a01b03841615801590610ed357506001600160a01b03831615155b8015610ee757506001600160a01b03821615155b8015610efb57506001600160a01b03811615155b610f5f5760405162461bcd60e51b815260206004820152602f60248201527f526f6f744d696e7461626c654552433732315072656469636174653a2042414460448201526e2fa4a724aa24a0a624ad20aa24a7a760891b6064820152608401610460565b603380546001600160a01b039586166001600160a01b0319918216179091556034805494861694821694909417909355603580549285169284169290921790915560368054919093169116179055565b6000610fba86611165565b905060005b8281101561104c57866001600160a01b03166342842e0e3330878786818110610fea57610fea6118a9565b905060200201356040518463ffffffff1660e01b815260040161100f939291906116a3565b600060405180830381600087803b15801561102957600080fd5b505af115801561103d573d6000803e3d6000fd5b50505050806001019050610fbf565b506033546035546040516001600160a01b03928316926316f198319216906110a4907faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d18908b9033908c908c908c908c906020016119be565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016110d0929190611677565b600060405180830381600087803b1580156110ea57600080fd5b505af11580156110fe573d6000803e3d6000fd5b50505050336001600160a01b0316816001600160a01b0316876001600160a01b03167f0ca5d99e0f7e7651c00c76347baa68a333790cbc9fb039a10843d1bd61f578c5888888886040516111559493929190611a12565b60405180910390a4505050505050565b6001600160a01b0380821660009081526037602052604090205416806111915761118e826105e1565b90505b6001600160a01b0381166111a7576111a7611718565b919050565b6001600160a01b03811681146111c157600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715611202576112026111c4565b604052919050565b60006001600160401b03821115611223576112236111c4565b50601f01601f191660200190565b6000806000806080858703121561124757600080fd5b8435611252816111ac565b93506020850135611262816111ac565b92506040850135915060608501356001600160401b0381111561128457600080fd5b8501601f8101871361129557600080fd5b80356112a86112a38261120a565b6111da565b8181528860208385010111156112bd57600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b600080604083850312156112f257600080fd5b82356112fd816111ac565b946020939093013593505050565b60006020828403121561131d57600080fd5b8135611328816111ac565b9392505050565b6000806000806060858703121561134557600080fd5b843593506020850135611357816111ac565b925060408501356001600160401b038082111561137357600080fd5b818701915087601f83011261138757600080fd5b81358181111561139657600080fd5b8860208285010111156113a857600080fd5b95989497505060200194505050565b6000806000606084860312156113cc57600080fd5b83356113d7816111ac565b925060208401356113e7816111ac565b929592945050506040919091013590565b6000806000806080858703121561140e57600080fd5b8435611419816111ac565b93506020850135611429816111ac565b92506040850135611439816111ac565b91506060850135611449816111ac565b939692955090935050565b60008083601f84011261146657600080fd5b5081356001600160401b0381111561147d57600080fd5b6020830191508360208260051b850101111561149857600080fd5b9250929050565b6000806000806000606086880312156114b757600080fd5b85356114c2816111ac565b945060208601356001600160401b03808211156114de57600080fd5b6114ea89838a01611454565b9096509450604088013591508082111561150357600080fd5b5061151088828901611454565b969995985093965092949392505050565b6000808585111561153157600080fd5b8386111561153e57600080fd5b5050820193919092039150565b8035602083101561156457600019602084900360031b1b165b92915050565b60005b8381101561158557818101518382015260200161156d565b50506000910152565b6000602082840312156115a057600080fd5b81516001600160401b038111156115b657600080fd5b8201601f810184136115c757600080fd5b80516115d56112a38261120a565b8181528560208385010111156115ea57600080fd5b6115fb82602083016020860161156a565b95945050505050565b6000815180845261161c81602086016020860161156a565b601f01601f19169290920160200192915050565b8481526001600160a01b038416602082015260806040820181905260009061165a90830185611604565b828103606084015261166c8185611604565b979650505050505050565b6001600160a01b038316815260406020820181905260009061169b90830184611604565b949350505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b600080600080608085870312156116dd57600080fd5b84356116e8816111ac565b935060208501356116f8816111ac565b92506040850135611708816111ac565b9396929550929360600135925050565b634e487b7160e01b600052600160045260246000fd5b60006001600160401b03821115611747576117476111c4565b5060051b60200190565b600082601f83011261176257600080fd5b813560206117726112a38361172e565b82815260059290921b8401810191818101908684111561179157600080fd5b8286015b848110156117ac5780358352918301918301611795565b509695505050505050565b600080600080600060a086880312156117cf57600080fd5b853594506020808701356117e2816111ac565b945060408701356117f2816111ac565b935060608701356001600160401b038082111561180e57600080fd5b818901915089601f83011261182257600080fd5b81356118306112a38261172e565b81815260059190911b8301840190848101908c83111561184f57600080fd5b938501935b82851015611876578435611867816111ac565b82529385019390850190611854565b96505050608089013592508083111561188e57600080fd5b505061189c88828901611751565b9150509295509295909350565b634e487b7160e01b600052603260045260246000fd5b604080825283519082018190526000906020906060840190828701845b828110156119015781516001600160a01b0316845292840192908401906001016118dc565b5050508381038285015284518082528583019183019060005b818110156119365783518352928401929184019160010161191a565b5090979650505050505050565b8183526000602080850194508260005b85811015611981578135611966816111ac565b6001600160a01b031687529582019590820190600101611953565b509495945050505050565b81835260006001600160fb1b038311156119a557600080fd5b8260051b80836020870137939093016020019392505050565b8781526001600160a01b0387811660208301528616604082015260a0606082018190526000906119f19083018688611943565b8281036080840152611a0481858761198c565b9a9950505050505050505050565b604081526000611a26604083018688611943565b828103602084015261166c81858761198c56fe526f6f744d696e7461626c654552433732315072656469636174653a20494e56a2646970667358221220baff62909a0428581d96b1def4713f00df6c8f95df1a380d9a2e4487899aa7f464736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b506004361061016e5760003560e01c806397e5230d116100ce578063e0563ab111610087578063e0563ab114610353578063eeb499451461035c578063f213159c1461036f578063f4a120f714610382578063f645125514610395578063f8c8765e146103bc578063ff6f870c146103cf57600080fd5b806397e5230d1461029a578063b1768065146102a4578063b68ad1e4146102cb578063c5ac2b1c146102de578063d41f177114610305578063d7c9e3ec1461032c57600080fd5b806347e7ef241161012b57806347e7ef241461020d5780634fdca69d1461022257806351351d531461023557806355b01e4d146102435780635ea5df79146102515780637efab4f514610268578063947287cf1461029157600080fd5b806305dc2e8f1461017357806307b3e252146101a3578063150b7a02146101b15780631bc114ba146101e8578063284017f5146101fb5780633b878c2214610204575b600080fd5b603454610186906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101866004600360981b0181565b6101cf6101bf366004611231565b630a85bd0160e11b949350505050565b6040516001600160e01b0319909116815260200161019a565b603354610186906001600160a01b031681565b61018661202081565b61018661101081565b61022061021b3660046112df565b6103e2565b005b603554610186906001600160a01b031681565b6101866002600160a01b0381565b6101866004600160991b0181565b61025a61138881565b60405190815260200161019a565b61018661027636600461130b565b6037602052600090815260409020546001600160a01b031681565b61025a61520881565b61025a620249f081565b61025a7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b603654610186906001600160a01b031681565b61025a7faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b61025a7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b61025a7f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b61018661203081565b61022061036a36600461132f565b6103f1565b61022061037d3660046113b7565b6105d1565b61018661039036600461130b565b6105e1565b61025a7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b6102206103ca3660046113f8565b61093a565b6102206103dd36600461149f565b610a97565b6103ed823383610af5565b5050565b6034546001600160a01b031633146104695760405162461bcd60e51b815260206004820152603060248201527f526f6f744d696e7461626c654552433732315072656469636174653a204f4e4c60448201526f2cafa9aa20aa22afa922a1a2a4ab22a960811b60648201526084015b60405180910390fd5b6035546001600160a01b038481169116146104e05760405162461bcd60e51b815260206004820152603160248201527f526f6f744d696e7461626c654552433732315072656469636174653a204f4e4c604482015270595f4348494c445f50524544494341544560781b6064820152608401610460565b7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286961050f602060008486611521565b6105189161154b565b036105375761053261052d8260208186611521565b610c74565b6105cb565b7f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed2610566602060008486611521565b61056f9161154b565b0361057e576105328282610d72565b60405162461bcd60e51b815260206004820152602e6024820152600080516020611a3a83398151915260448201526d414c49445f5349474e415455524560901b6064820152608401610460565b50505050565b6105dc838383610af5565b505050565b60006001600160a01b03821661063a5760405162461bcd60e51b815260206004820152602a6024820152600080516020611a3a83398151915260448201526920a624a22faa27a5a2a760b11b6064820152608401610460565b6001600160a01b0382811660009081526037602052604090205416156106b65760405162461bcd60e51b815260206004820152602b60248201527f526f6f744d696e7461626c654552433732315072656469636174653a20414c5260448201526a1150511657d3505414115160aa1b6064820152608401610460565b6035546036546040516bffffffffffffffffffffffff19606086901b1660208201526001600160a01b039283169260009261076492911690603401604051602081830303815290604052805190602001208460405160388101919091526f5af43d82803e903d91602b57fd5bf3ff60248201526014810192909252733d602d80600a3d3981f3363d3d373d3d3d363d73825260588201526037600c8201206078820152605560439091012090565b6001600160a01b0385811660008181526037602052604080822080546001600160a01b03191686861617905560335481516306fdde0360e01b81529151959650909316936316f198319387937f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad938b9391926306fdde0392600480830193928290030181865afa1580156107fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610824919081019061158e565b896001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610862573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261088a919081019061158e565b60405160200161089d9493929190611630565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016108c9929190611677565b600060405180830381600087803b1580156108e357600080fd5b505af11580156108f7573d6000803e3d6000fd5b50506040516001600160a01b038085169350871691507fb96a191bae4e25ffdff7f4136994eb0dec75d263750a07c035202c348c9515f090600090a39392505050565b336002600160a01b031461097e5760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b6044820152606401610460565b600054610100900460ff161580801561099e5750600054600160ff909116105b806109b85750303b1580156109b8575060005460ff166001145b610a1b5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610460565b6000805460ff191660011790558015610a3e576000805461ff0019166101001790555b610a4a85858585610eb3565b8015610a90576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b828114610ae85760405162461bcd60e51b815260206004820152602b6024820152600080516020611a3a83398151915260448201526a082989288be988a9c8ea8960ab1b6064820152608401610460565b610a908585858585610faf565b6000610b0084611165565b604051632142170760e11b81529091506001600160a01b038516906342842e0e90610b33903390309087906004016116a3565b600060405180830381600087803b158015610b4d57600080fd5b505af1158015610b61573d6000803e3d6000fd5b5050603354603554604080517f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82160208201526001600160a01b038a811682840152336060830152898116608083015260a08083018a90528351808403909101815260c08301938490526316f1983160e01b90935293841695506316f198319450610bf1939092169160c401611677565b600060405180830381600087803b158015610c0b57600080fd5b505af1158015610c1f573d6000803e3d6000fd5b505060408051338152602081018690526001600160a01b03808816945085811693508816917fe3abb9ec195b50242582cc6cb7abc990ac26439b9ed7635ed72f7bd720e7477a910160405180910390a46105cb565b6000808080610c85858701876116c7565b6001600160a01b0380851660009081526037602052604090205494985092965090945092501680610cb857610cb8611718565b604051632142170760e11b81526001600160a01b038616906342842e0e90610ce8903090879087906004016116a3565b600060405180830381600087803b158015610d0257600080fd5b505af1158015610d16573d6000803e3d6000fd5b5050604080516001600160a01b03888116825260208201879052808816945085811693508916917f80afffd84aa825dd9b3c1ba262eb55eef58f78616634437a367a263f3c48fe3d91015b60405180910390a450505050505050565b6000808080610d83858701876117b7565b6001600160a01b03808516600090815260376020526040902054949950929750909550935016905080610db857610db8611718565b60005b8251811015610e6357856001600160a01b03166342842e0e30868481518110610de657610de66118a9565b6020026020010151868581518110610e0057610e006118a9565b60200260200101516040518463ffffffff1660e01b8152600401610e26939291906116a3565b600060405180830381600087803b158015610e4057600080fd5b505af1158015610e54573d6000803e3d6000fd5b50505050806001019050610dbb565b50836001600160a01b0316816001600160a01b0316866001600160a01b03167ff64537485d843fa8a1f4354cb9937954c64282de0828be9f096355006222186b8686604051610d619291906118bf565b6001600160a01b03841615801590610ed357506001600160a01b03831615155b8015610ee757506001600160a01b03821615155b8015610efb57506001600160a01b03811615155b610f5f5760405162461bcd60e51b815260206004820152602f60248201527f526f6f744d696e7461626c654552433732315072656469636174653a2042414460448201526e2fa4a724aa24a0a624ad20aa24a7a760891b6064820152608401610460565b603380546001600160a01b039586166001600160a01b0319918216179091556034805494861694821694909417909355603580549285169284169290921790915560368054919093169116179055565b6000610fba86611165565b905060005b8281101561104c57866001600160a01b03166342842e0e3330878786818110610fea57610fea6118a9565b905060200201356040518463ffffffff1660e01b815260040161100f939291906116a3565b600060405180830381600087803b15801561102957600080fd5b505af115801561103d573d6000803e3d6000fd5b50505050806001019050610fbf565b506033546035546040516001600160a01b03928316926316f198319216906110a4907faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d18908b9033908c908c908c908c906020016119be565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016110d0929190611677565b600060405180830381600087803b1580156110ea57600080fd5b505af11580156110fe573d6000803e3d6000fd5b50505050336001600160a01b0316816001600160a01b0316876001600160a01b03167f0ca5d99e0f7e7651c00c76347baa68a333790cbc9fb039a10843d1bd61f578c5888888886040516111559493929190611a12565b60405180910390a4505050505050565b6001600160a01b0380821660009081526037602052604090205416806111915761118e826105e1565b90505b6001600160a01b0381166111a7576111a7611718565b919050565b6001600160a01b03811681146111c157600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715611202576112026111c4565b604052919050565b60006001600160401b03821115611223576112236111c4565b50601f01601f191660200190565b6000806000806080858703121561124757600080fd5b8435611252816111ac565b93506020850135611262816111ac565b92506040850135915060608501356001600160401b0381111561128457600080fd5b8501601f8101871361129557600080fd5b80356112a86112a38261120a565b6111da565b8181528860208385010111156112bd57600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b600080604083850312156112f257600080fd5b82356112fd816111ac565b946020939093013593505050565b60006020828403121561131d57600080fd5b8135611328816111ac565b9392505050565b6000806000806060858703121561134557600080fd5b843593506020850135611357816111ac565b925060408501356001600160401b038082111561137357600080fd5b818701915087601f83011261138757600080fd5b81358181111561139657600080fd5b8860208285010111156113a857600080fd5b95989497505060200194505050565b6000806000606084860312156113cc57600080fd5b83356113d7816111ac565b925060208401356113e7816111ac565b929592945050506040919091013590565b6000806000806080858703121561140e57600080fd5b8435611419816111ac565b93506020850135611429816111ac565b92506040850135611439816111ac565b91506060850135611449816111ac565b939692955090935050565b60008083601f84011261146657600080fd5b5081356001600160401b0381111561147d57600080fd5b6020830191508360208260051b850101111561149857600080fd5b9250929050565b6000806000806000606086880312156114b757600080fd5b85356114c2816111ac565b945060208601356001600160401b03808211156114de57600080fd5b6114ea89838a01611454565b9096509450604088013591508082111561150357600080fd5b5061151088828901611454565b969995985093965092949392505050565b6000808585111561153157600080fd5b8386111561153e57600080fd5b5050820193919092039150565b8035602083101561156457600019602084900360031b1b165b92915050565b60005b8381101561158557818101518382015260200161156d565b50506000910152565b6000602082840312156115a057600080fd5b81516001600160401b038111156115b657600080fd5b8201601f810184136115c757600080fd5b80516115d56112a38261120a565b8181528560208385010111156115ea57600080fd5b6115fb82602083016020860161156a565b95945050505050565b6000815180845261161c81602086016020860161156a565b601f01601f19169290920160200192915050565b8481526001600160a01b038416602082015260806040820181905260009061165a90830185611604565b828103606084015261166c8185611604565b979650505050505050565b6001600160a01b038316815260406020820181905260009061169b90830184611604565b949350505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b600080600080608085870312156116dd57600080fd5b84356116e8816111ac565b935060208501356116f8816111ac565b92506040850135611708816111ac565b9396929550929360600135925050565b634e487b7160e01b600052600160045260246000fd5b60006001600160401b03821115611747576117476111c4565b5060051b60200190565b600082601f83011261176257600080fd5b813560206117726112a38361172e565b82815260059290921b8401810191818101908684111561179157600080fd5b8286015b848110156117ac5780358352918301918301611795565b509695505050505050565b600080600080600060a086880312156117cf57600080fd5b853594506020808701356117e2816111ac565b945060408701356117f2816111ac565b935060608701356001600160401b038082111561180e57600080fd5b818901915089601f83011261182257600080fd5b81356118306112a38261172e565b81815260059190911b8301840190848101908c83111561184f57600080fd5b938501935b82851015611876578435611867816111ac565b82529385019390850190611854565b96505050608089013592508083111561188e57600080fd5b505061189c88828901611751565b9150509295509295909350565b634e487b7160e01b600052603260045260246000fd5b604080825283519082018190526000906020906060840190828701845b828110156119015781516001600160a01b0316845292840192908401906001016118dc565b5050508381038285015284518082528583019183019060005b818110156119365783518352928401929184019160010161191a565b5090979650505050505050565b8183526000602080850194508260005b85811015611981578135611966816111ac565b6001600160a01b031687529582019590820190600101611953565b509495945050505050565b81835260006001600160fb1b038311156119a557600080fd5b8260051b80836020870137939093016020019392505050565b8781526001600160a01b0387811660208301528616604082015260a0606082018190526000906119f19083018688611943565b8281036080840152611a0481858761198c565b9a9950505050505050505050565b604081526000611a26604083018688611943565b828103602084015261166c81858761198c56fe526f6f744d696e7461626c654552433732315072656469636174653a20494e56a2646970667358221220baff62909a0428581d96b1def4713f00df6c8f95df1a380d9a2e4487899aa7f464736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var RootMintableERC721PredicateACLArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"RootMintableERC721PredicateAccessList\",\n \"sourceName\": \"contracts/child/RootMintableERC721PredicateAccessList.sol\",\n \"abi\": [\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"only\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"Unauthorized\",\n \"type\": \"error\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"block\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bool\",\n \"name\": \"status\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"AllowListUsageSet\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"block\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bool\",\n \"name\": \"status\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"BlockListUsageSet\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"depositor\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2MintableERC721Deposit\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"depositor\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"L2MintableERC721DepositBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"withdrawer\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2MintableERC721Withdraw\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"withdrawer\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"L2MintableERC721WithdrawBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"L2MintableTokenMapped\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"previousOwner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"OwnershipTransferStarted\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"previousOwner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"OwnershipTransferred\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"ALLOWLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"BLOCKLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAP_TOKEN_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TOKEN_CONTRACT\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"READ_ADDRESSLIST_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"SYSTEM\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"acceptOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childERC721Predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childTokenTemplate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC721Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"deposit\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC721Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"depositBatch\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC721Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"depositTo\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newL2StateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newStateReceiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildERC721Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseAllowList\",\n \"type\": \"bool\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseBlockList\",\n \"type\": \"bool\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newL2StateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newStateReceiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildERC721Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"l2StateSender\",\n \"outputs\": [\n {\n \"internalType\": \"contract IStateSender\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC721Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"mapToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onERC721Received\",\n \"outputs\": [\n {\n \"internalType\": \"bytes4\",\n \"name\": \"\",\n \"type\": \"bytes4\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onStateReceive\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"owner\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"pendingOwner\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"renounceOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"rootTokenToChildToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseAllowList\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"setAllowList\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseBlockList\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"setBlockList\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"stateReceiver\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"transferOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50612231806100206000396000f3fe608060405234801561001057600080fd5b50600436106101e65760003560e01c8063b17680651161010a578063e0563ab1116100ad578063f2fde38b1161007c578063f2fde38b14610466578063f4a120f714610479578063f64512551461048c578063f8c8765e146104b3578063ff6f870c146104c657600080fd5b8063e0563ab114610426578063e30c39781461042f578063eeb4994514610440578063f213159c1461045357600080fd5b8063b17680651461033e578063b68ad1e414610365578063c1225a2014610378578063c5ac2b1c1461038b578063c5e4683a146103b2578063d41f1771146103c5578063d7c9e3ec146103ec578063d8dd17731461041357600080fd5b806351351d531161018d57806379ba50971161015c57806379ba5097146102e85780637efab4f5146102f05780638da5cb5b1461031a578063947287cf1461032b57806397e5230d1461033457600080fd5b806351351d53146102ad57806355b01e4d146102bb5780635ea5df79146102c9578063715018a6146102e057600080fd5b806305dc2e8f146101eb57806307b3e2521461021b578063150b7a02146102295780631bc114ba14610260578063284017f5146102735780633b878c221461027c57806347e7ef24146102855780634fdca69d1461029a575b600080fd5b60fd546101fe906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101fe6004600360981b0181565b61024761023736600461186f565b630a85bd0160e11b949350505050565b6040516001600160e01b03199091168152602001610212565b60fc546101fe906001600160a01b031681565b6101fe61202081565b6101fe61101081565b61029861029336600461191d565b6104d9565b005b60fe546101fe906001600160a01b031681565b6101fe6002600160a01b0381565b6101fe6004600160991b0181565b6102d261138881565b604051908152602001610212565b6102986104e8565b6102986104fc565b6101fe6102fe366004611949565b610100602052600090815260409020546001600160a01b031681565b6033546001600160a01b03166101fe565b6102d261520881565b6102d2620249f081565b6102d27f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b60ff546101fe906001600160a01b031681565b61029861038636600461197d565b61057b565b6102d27faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b6102986103c036600461197d565b6105ca565b6102d27f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b6102d27f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b610298610421366004611998565b610611565b6101fe61203081565b6065546001600160a01b03166101fe565b61029861044e366004611a2a565b610732565b610298610461366004611ab2565b61090d565b610298610474366004611949565b61091d565b6101fe610487366004611949565b61098e565b6102d27f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b6102986104c1366004611af3565b610ce9565b6102986104d4366004611b9a565b610de2565b6104e4823383610e40565b5050565b6104f0610fc7565b6104fa6000611021565b565b60655433906001600160a01b0316811461056f5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084015b60405180910390fd5b61057881611021565b50565b610583610fc7565b60c9805461ff0019166101008315159081029190911790915560405143907f61d574757cde41a357d030b39b2705796ccd699578037ab9a1cfd8117d82bf8690600090a350565b6105d2610fc7565b60c9805460ff191682151590811790915560405143907fe0a0f0fa52db091cb71c202d80420311430ce1ae2e7794149877b6720ce8bf0b90600090a350565b336002600160a01b03146106385760405163973d02cb60e01b815260040161056690611c1c565b600054610100900460ff16158080156106585750600054600160ff909116105b806106725750303b158015610672575060005460ff166001145b61068e5760405162461bcd60e51b815260040161056690611c40565b6000805460ff1916600117905580156106b1576000805461ff0019166101001790555b6106bd8888888861103a565b60c9805461ffff191685151561ff00191617610100851515021790556106e282611021565b8015610728576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b60fd546001600160a01b031633146107a55760405162461bcd60e51b815260206004820152603060248201527f526f6f744d696e7461626c654552433732315072656469636174653a204f4e4c60448201526f2cafa9aa20aa22afa922a1a2a4ab22a960811b6064820152608401610566565b60fe546001600160a01b0384811691161461081c5760405162461bcd60e51b815260206004820152603160248201527f526f6f744d696e7461626c654552433732315072656469636174653a204f4e4c604482015270595f4348494c445f50524544494341544560781b6064820152608401610566565b7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286961084b602060008486611c8e565b61085491611cb8565b036108735761086e6108698260208186611c8e565b611136565b610907565b7f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed26108a2602060008486611c8e565b6108ab91611cb8565b036108ba5761086e8282611235565b60405162461bcd60e51b815260206004820152602e60248201526000805160206121dc83398151915260448201526d414c49445f5349474e415455524560901b6064820152608401610566565b50505050565b610918838383610e40565b505050565b610925610fc7565b606580546001600160a01b0383166001600160a01b031990911681179091556109566033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60006001600160a01b0382166109e75760405162461bcd60e51b815260206004820152602a60248201526000805160206121dc83398151915260448201526920a624a22faa27a5a2a760b11b6064820152608401610566565b6001600160a01b03828116600090815261010060205260409020541615610a645760405162461bcd60e51b815260206004820152602b60248201527f526f6f744d696e7461626c654552433732315072656469636174653a20414c5260448201526a1150511657d3505414115160aa1b6064820152608401610566565b60fe5460ff546040516bffffffffffffffffffffffff19606086901b1660208201526001600160a01b0392831692600092610b1292911690603401604051602081830303815290604052805190602001208460405160388101919091526f5af43d82803e903d91602b57fd5bf3ff60248201526014810192909252733d602d80600a3d3981f3363d3d373d3d3d363d73825260588201526037600c8201206078820152605560439091012090565b6001600160a01b038581166000818152610100602052604080822080546001600160a01b03191686861617905560fc5481516306fdde0360e01b81529151959650909316936316f198319387937f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad938b9391926306fdde0392600480830193928290030181865afa158015610bab573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610bd39190810190611cfb565b896001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610c11573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c399190810190611cfb565b604051602001610c4c9493929190611d9d565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610c78929190611de4565b600060405180830381600087803b158015610c9257600080fd5b505af1158015610ca6573d6000803e3d6000fd5b50506040516001600160a01b038085169350871691507fb96a191bae4e25ffdff7f4136994eb0dec75d263750a07c035202c348c9515f090600090a39392505050565b336002600160a01b0314610d105760405163973d02cb60e01b815260040161056690611c1c565b600054610100900460ff1615808015610d305750600054600160ff909116105b80610d4a5750303b158015610d4a575060005460ff166001145b610d665760405162461bcd60e51b815260040161056690611c40565b6000805460ff191660011790558015610d89576000805461ff0019166101001790555b610d958585858561103a565b8015610ddb576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b828114610e335760405162461bcd60e51b815260206004820152602b60248201526000805160206121dc83398151915260448201526a082989288be988a9c8ea8960ab1b6064820152608401610566565b610ddb8585858585611377565b610e48611535565b6000610e538461153d565b604051632142170760e11b81529091506001600160a01b038516906342842e0e90610e8690339030908790600401611e10565b600060405180830381600087803b158015610ea057600080fd5b505af1158015610eb4573d6000803e3d6000fd5b505060fc5460fe54604080517f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82160208201526001600160a01b038a811682840152336060830152898116608083015260a08083018a90528351808403909101815260c08301938490526316f1983160e01b90935293841695506316f198319450610f44939092169160c401611de4565b600060405180830381600087803b158015610f5e57600080fd5b505af1158015610f72573d6000803e3d6000fd5b505060408051338152602081018690526001600160a01b03808816945085811693508816917fe3abb9ec195b50242582cc6cb7abc990ac26439b9ed7635ed72f7bd720e7477a910160405180910390a4610907565b6033546001600160a01b031633146104fa5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610566565b606580546001600160a01b031916905561057881611585565b6001600160a01b0384161580159061105a57506001600160a01b03831615155b801561106e57506001600160a01b03821615155b801561108257506001600160a01b03811615155b6110e65760405162461bcd60e51b815260206004820152602f60248201527f526f6f744d696e7461626c654552433732315072656469636174653a2042414460448201526e2fa4a724aa24a0a624ad20aa24a7a760891b6064820152608401610566565b60fc80546001600160a01b039586166001600160a01b03199182161790915560fd80549486169482169490941790935560fe80549285169284169290921790915560ff8054919093169116179055565b600080808061114785870187611e34565b6001600160a01b03808516600090815261010060205260409020549498509296509094509250168061117b5761117b611e85565b604051632142170760e11b81526001600160a01b038616906342842e0e906111ab90309087908790600401611e10565b600060405180830381600087803b1580156111c557600080fd5b505af11580156111d9573d6000803e3d6000fd5b5050604080516001600160a01b03888116825260208201879052808816945085811693508916917f80afffd84aa825dd9b3c1ba262eb55eef58f78616634437a367a263f3c48fe3d91015b60405180910390a450505050505050565b600080808061124685870187611f24565b6001600160a01b038085166000908152610100602052604090205494995092975090955093501690508061127c5761127c611e85565b60005b825181101561132757856001600160a01b03166342842e0e308684815181106112aa576112aa612016565b60200260200101518685815181106112c4576112c4612016565b60200260200101516040518463ffffffff1660e01b81526004016112ea93929190611e10565b600060405180830381600087803b15801561130457600080fd5b505af1158015611318573d6000803e3d6000fd5b5050505080600101905061127f565b50836001600160a01b0316816001600160a01b0316866001600160a01b03167ff64537485d843fa8a1f4354cb9937954c64282de0828be9f096355006222186b868660405161122492919061202c565b61137f611535565b600061138a8661153d565b905060005b8281101561141c57866001600160a01b03166342842e0e33308787868181106113ba576113ba612016565b905060200201356040518463ffffffff1660e01b81526004016113df93929190611e10565b600060405180830381600087803b1580156113f957600080fd5b505af115801561140d573d6000803e3d6000fd5b5050505080600101905061138f565b5060fc5460fe546040516001600160a01b03928316926316f19831921690611474907faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d18908b9033908c908c908c908c9060200161212b565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016114a0929190611de4565b600060405180830381600087803b1580156114ba57600080fd5b505af11580156114ce573d6000803e3d6000fd5b50505050336001600160a01b0316816001600160a01b0316876001600160a01b03167f0ca5d99e0f7e7651c00c76347baa68a333790cbc9fb039a10843d1bd61f578c588888888604051611525949392919061217f565b60405180910390a4505050505050565b6104fa6115d7565b6001600160a01b0380821660009081526101006020526040902054168061156a576115678261098e565b90505b6001600160a01b03811661158057611580611e85565b919050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60c95460ff16156116e257604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600160991b01916113889161163991906121a6565b6000604051808303818686fa925050503d8060008114611675576040519150601f19603f3d011682016040523d82523d6000602084013e61167a565b606091505b509150915081801561169f575060008180602001905181019061169d91906121c2565b115b6116df5760405162461bcd60e51b81526020600482015260116024820152702224a9a0a62627aba2a22fa9a2a72222a960791b6044820152606401610566565b50505b60c954610100900460ff16156104fa57604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600360981b01916113889161174991906121a6565b6000604051808303818686fa925050503d8060008114611785576040519150601f19603f3d011682016040523d82523d6000602084013e61178a565b606091505b50915091508180156117b05750808060200190518101906117ab91906121c2565b600114155b6104e45760405162461bcd60e51b815260206004820152600e60248201526d212627a1a5a2a22fa9a2a72222a960911b6044820152606401610566565b6001600160a01b038116811461057857600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561184057611840611802565b604052919050565b60006001600160401b0382111561186157611861611802565b50601f01601f191660200190565b6000806000806080858703121561188557600080fd5b8435611890816117ed565b935060208501356118a0816117ed565b92506040850135915060608501356001600160401b038111156118c257600080fd5b8501601f810187136118d357600080fd5b80356118e66118e182611848565b611818565b8181528860208385010111156118fb57600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b6000806040838503121561193057600080fd5b823561193b816117ed565b946020939093013593505050565b60006020828403121561195b57600080fd5b8135611966816117ed565b9392505050565b8035801515811461158057600080fd5b60006020828403121561198f57600080fd5b6119668261196d565b600080600080600080600060e0888a0312156119b357600080fd5b87356119be816117ed565b965060208801356119ce816117ed565b955060408801356119de816117ed565b945060608801356119ee816117ed565b93506119fc6080890161196d565b9250611a0a60a0890161196d565b915060c0880135611a1a816117ed565b8091505092959891949750929550565b60008060008060608587031215611a4057600080fd5b843593506020850135611a52816117ed565b925060408501356001600160401b0380821115611a6e57600080fd5b818701915087601f830112611a8257600080fd5b813581811115611a9157600080fd5b886020828501011115611aa357600080fd5b95989497505060200194505050565b600080600060608486031215611ac757600080fd5b8335611ad2816117ed565b92506020840135611ae2816117ed565b929592945050506040919091013590565b60008060008060808587031215611b0957600080fd5b8435611b14816117ed565b93506020850135611b24816117ed565b92506040850135611b34816117ed565b91506060850135611b44816117ed565b939692955090935050565b60008083601f840112611b6157600080fd5b5081356001600160401b03811115611b7857600080fd5b6020830191508360208260051b8501011115611b9357600080fd5b9250929050565b600080600080600060608688031215611bb257600080fd5b8535611bbd816117ed565b945060208601356001600160401b0380821115611bd957600080fd5b611be589838a01611b4f565b90965094506040880135915080821115611bfe57600080fd5b50611c0b88828901611b4f565b969995985093965092949392505050565b6020808252600a908201526914d654d5115350d0531360b21b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b60008085851115611c9e57600080fd5b83861115611cab57600080fd5b5050820193919092039150565b80356020831015611cd157600019602084900360031b1b165b92915050565b60005b83811015611cf2578181015183820152602001611cda565b50506000910152565b600060208284031215611d0d57600080fd5b81516001600160401b03811115611d2357600080fd5b8201601f81018413611d3457600080fd5b8051611d426118e182611848565b818152856020838501011115611d5757600080fd5b611d68826020830160208601611cd7565b95945050505050565b60008151808452611d89816020860160208601611cd7565b601f01601f19169290920160200192915050565b8481526001600160a01b0384166020820152608060408201819052600090611dc790830185611d71565b8281036060840152611dd98185611d71565b979650505050505050565b6001600160a01b0383168152604060208201819052600090611e0890830184611d71565b949350505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b60008060008060808587031215611e4a57600080fd5b8435611e55816117ed565b93506020850135611e65816117ed565b92506040850135611e75816117ed565b9396929550929360600135925050565b634e487b7160e01b600052600160045260246000fd5b60006001600160401b03821115611eb457611eb4611802565b5060051b60200190565b600082601f830112611ecf57600080fd5b81356020611edf6118e183611e9b565b82815260059290921b84018101918181019086841115611efe57600080fd5b8286015b84811015611f195780358352918301918301611f02565b509695505050505050565b600080600080600060a08688031215611f3c57600080fd5b85359450602080870135611f4f816117ed565b94506040870135611f5f816117ed565b935060608701356001600160401b0380821115611f7b57600080fd5b818901915089601f830112611f8f57600080fd5b8135611f9d6118e182611e9b565b81815260059190911b8301840190848101908c831115611fbc57600080fd5b938501935b82851015611fe3578435611fd4816117ed565b82529385019390850190611fc1565b965050506080890135925080831115611ffb57600080fd5b505061200988828901611ebe565b9150509295509295909350565b634e487b7160e01b600052603260045260246000fd5b604080825283519082018190526000906020906060840190828701845b8281101561206e5781516001600160a01b031684529284019290840190600101612049565b5050508381038285015284518082528583019183019060005b818110156120a357835183529284019291840191600101612087565b5090979650505050505050565b8183526000602080850194508260005b858110156120ee5781356120d3816117ed565b6001600160a01b0316875295820195908201906001016120c0565b509495945050505050565b81835260006001600160fb1b0383111561211257600080fd5b8260051b80836020870137939093016020019392505050565b8781526001600160a01b0387811660208301528616604082015260a06060820181905260009061215e90830186886120b0565b82810360808401526121718185876120f9565b9a9950505050505050505050565b6040815260006121936040830186886120b0565b8281036020840152611dd98185876120f9565b600082516121b8818460208701611cd7565b9190910192915050565b6000602082840312156121d457600080fd5b505191905056fe526f6f744d696e7461626c654552433732315072656469636174653a20494e56a2646970667358221220d1bfc2912b6d936204f8bcd526922cd1de25280dfe606eaddf8c127bfcff177364736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101e65760003560e01c8063b17680651161010a578063e0563ab1116100ad578063f2fde38b1161007c578063f2fde38b14610466578063f4a120f714610479578063f64512551461048c578063f8c8765e146104b3578063ff6f870c146104c657600080fd5b8063e0563ab114610426578063e30c39781461042f578063eeb4994514610440578063f213159c1461045357600080fd5b8063b17680651461033e578063b68ad1e414610365578063c1225a2014610378578063c5ac2b1c1461038b578063c5e4683a146103b2578063d41f1771146103c5578063d7c9e3ec146103ec578063d8dd17731461041357600080fd5b806351351d531161018d57806379ba50971161015c57806379ba5097146102e85780637efab4f5146102f05780638da5cb5b1461031a578063947287cf1461032b57806397e5230d1461033457600080fd5b806351351d53146102ad57806355b01e4d146102bb5780635ea5df79146102c9578063715018a6146102e057600080fd5b806305dc2e8f146101eb57806307b3e2521461021b578063150b7a02146102295780631bc114ba14610260578063284017f5146102735780633b878c221461027c57806347e7ef24146102855780634fdca69d1461029a575b600080fd5b60fd546101fe906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101fe6004600360981b0181565b61024761023736600461186f565b630a85bd0160e11b949350505050565b6040516001600160e01b03199091168152602001610212565b60fc546101fe906001600160a01b031681565b6101fe61202081565b6101fe61101081565b61029861029336600461191d565b6104d9565b005b60fe546101fe906001600160a01b031681565b6101fe6002600160a01b0381565b6101fe6004600160991b0181565b6102d261138881565b604051908152602001610212565b6102986104e8565b6102986104fc565b6101fe6102fe366004611949565b610100602052600090815260409020546001600160a01b031681565b6033546001600160a01b03166101fe565b6102d261520881565b6102d2620249f081565b6102d27f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b60ff546101fe906001600160a01b031681565b61029861038636600461197d565b61057b565b6102d27faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b6102986103c036600461197d565b6105ca565b6102d27f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b6102d27f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b610298610421366004611998565b610611565b6101fe61203081565b6065546001600160a01b03166101fe565b61029861044e366004611a2a565b610732565b610298610461366004611ab2565b61090d565b610298610474366004611949565b61091d565b6101fe610487366004611949565b61098e565b6102d27f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b6102986104c1366004611af3565b610ce9565b6102986104d4366004611b9a565b610de2565b6104e4823383610e40565b5050565b6104f0610fc7565b6104fa6000611021565b565b60655433906001600160a01b0316811461056f5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084015b60405180910390fd5b61057881611021565b50565b610583610fc7565b60c9805461ff0019166101008315159081029190911790915560405143907f61d574757cde41a357d030b39b2705796ccd699578037ab9a1cfd8117d82bf8690600090a350565b6105d2610fc7565b60c9805460ff191682151590811790915560405143907fe0a0f0fa52db091cb71c202d80420311430ce1ae2e7794149877b6720ce8bf0b90600090a350565b336002600160a01b03146106385760405163973d02cb60e01b815260040161056690611c1c565b600054610100900460ff16158080156106585750600054600160ff909116105b806106725750303b158015610672575060005460ff166001145b61068e5760405162461bcd60e51b815260040161056690611c40565b6000805460ff1916600117905580156106b1576000805461ff0019166101001790555b6106bd8888888861103a565b60c9805461ffff191685151561ff00191617610100851515021790556106e282611021565b8015610728576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b60fd546001600160a01b031633146107a55760405162461bcd60e51b815260206004820152603060248201527f526f6f744d696e7461626c654552433732315072656469636174653a204f4e4c60448201526f2cafa9aa20aa22afa922a1a2a4ab22a960811b6064820152608401610566565b60fe546001600160a01b0384811691161461081c5760405162461bcd60e51b815260206004820152603160248201527f526f6f744d696e7461626c654552433732315072656469636174653a204f4e4c604482015270595f4348494c445f50524544494341544560781b6064820152608401610566565b7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286961084b602060008486611c8e565b61085491611cb8565b036108735761086e6108698260208186611c8e565b611136565b610907565b7f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed26108a2602060008486611c8e565b6108ab91611cb8565b036108ba5761086e8282611235565b60405162461bcd60e51b815260206004820152602e60248201526000805160206121dc83398151915260448201526d414c49445f5349474e415455524560901b6064820152608401610566565b50505050565b610918838383610e40565b505050565b610925610fc7565b606580546001600160a01b0383166001600160a01b031990911681179091556109566033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60006001600160a01b0382166109e75760405162461bcd60e51b815260206004820152602a60248201526000805160206121dc83398151915260448201526920a624a22faa27a5a2a760b11b6064820152608401610566565b6001600160a01b03828116600090815261010060205260409020541615610a645760405162461bcd60e51b815260206004820152602b60248201527f526f6f744d696e7461626c654552433732315072656469636174653a20414c5260448201526a1150511657d3505414115160aa1b6064820152608401610566565b60fe5460ff546040516bffffffffffffffffffffffff19606086901b1660208201526001600160a01b0392831692600092610b1292911690603401604051602081830303815290604052805190602001208460405160388101919091526f5af43d82803e903d91602b57fd5bf3ff60248201526014810192909252733d602d80600a3d3981f3363d3d373d3d3d363d73825260588201526037600c8201206078820152605560439091012090565b6001600160a01b038581166000818152610100602052604080822080546001600160a01b03191686861617905560fc5481516306fdde0360e01b81529151959650909316936316f198319387937f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad938b9391926306fdde0392600480830193928290030181865afa158015610bab573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610bd39190810190611cfb565b896001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610c11573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c399190810190611cfb565b604051602001610c4c9493929190611d9d565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610c78929190611de4565b600060405180830381600087803b158015610c9257600080fd5b505af1158015610ca6573d6000803e3d6000fd5b50506040516001600160a01b038085169350871691507fb96a191bae4e25ffdff7f4136994eb0dec75d263750a07c035202c348c9515f090600090a39392505050565b336002600160a01b0314610d105760405163973d02cb60e01b815260040161056690611c1c565b600054610100900460ff1615808015610d305750600054600160ff909116105b80610d4a5750303b158015610d4a575060005460ff166001145b610d665760405162461bcd60e51b815260040161056690611c40565b6000805460ff191660011790558015610d89576000805461ff0019166101001790555b610d958585858561103a565b8015610ddb576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b828114610e335760405162461bcd60e51b815260206004820152602b60248201526000805160206121dc83398151915260448201526a082989288be988a9c8ea8960ab1b6064820152608401610566565b610ddb8585858585611377565b610e48611535565b6000610e538461153d565b604051632142170760e11b81529091506001600160a01b038516906342842e0e90610e8690339030908790600401611e10565b600060405180830381600087803b158015610ea057600080fd5b505af1158015610eb4573d6000803e3d6000fd5b505060fc5460fe54604080517f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82160208201526001600160a01b038a811682840152336060830152898116608083015260a08083018a90528351808403909101815260c08301938490526316f1983160e01b90935293841695506316f198319450610f44939092169160c401611de4565b600060405180830381600087803b158015610f5e57600080fd5b505af1158015610f72573d6000803e3d6000fd5b505060408051338152602081018690526001600160a01b03808816945085811693508816917fe3abb9ec195b50242582cc6cb7abc990ac26439b9ed7635ed72f7bd720e7477a910160405180910390a4610907565b6033546001600160a01b031633146104fa5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610566565b606580546001600160a01b031916905561057881611585565b6001600160a01b0384161580159061105a57506001600160a01b03831615155b801561106e57506001600160a01b03821615155b801561108257506001600160a01b03811615155b6110e65760405162461bcd60e51b815260206004820152602f60248201527f526f6f744d696e7461626c654552433732315072656469636174653a2042414460448201526e2fa4a724aa24a0a624ad20aa24a7a760891b6064820152608401610566565b60fc80546001600160a01b039586166001600160a01b03199182161790915560fd80549486169482169490941790935560fe80549285169284169290921790915560ff8054919093169116179055565b600080808061114785870187611e34565b6001600160a01b03808516600090815261010060205260409020549498509296509094509250168061117b5761117b611e85565b604051632142170760e11b81526001600160a01b038616906342842e0e906111ab90309087908790600401611e10565b600060405180830381600087803b1580156111c557600080fd5b505af11580156111d9573d6000803e3d6000fd5b5050604080516001600160a01b03888116825260208201879052808816945085811693508916917f80afffd84aa825dd9b3c1ba262eb55eef58f78616634437a367a263f3c48fe3d91015b60405180910390a450505050505050565b600080808061124685870187611f24565b6001600160a01b038085166000908152610100602052604090205494995092975090955093501690508061127c5761127c611e85565b60005b825181101561132757856001600160a01b03166342842e0e308684815181106112aa576112aa612016565b60200260200101518685815181106112c4576112c4612016565b60200260200101516040518463ffffffff1660e01b81526004016112ea93929190611e10565b600060405180830381600087803b15801561130457600080fd5b505af1158015611318573d6000803e3d6000fd5b5050505080600101905061127f565b50836001600160a01b0316816001600160a01b0316866001600160a01b03167ff64537485d843fa8a1f4354cb9937954c64282de0828be9f096355006222186b868660405161122492919061202c565b61137f611535565b600061138a8661153d565b905060005b8281101561141c57866001600160a01b03166342842e0e33308787868181106113ba576113ba612016565b905060200201356040518463ffffffff1660e01b81526004016113df93929190611e10565b600060405180830381600087803b1580156113f957600080fd5b505af115801561140d573d6000803e3d6000fd5b5050505080600101905061138f565b5060fc5460fe546040516001600160a01b03928316926316f19831921690611474907faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d18908b9033908c908c908c908c9060200161212b565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016114a0929190611de4565b600060405180830381600087803b1580156114ba57600080fd5b505af11580156114ce573d6000803e3d6000fd5b50505050336001600160a01b0316816001600160a01b0316876001600160a01b03167f0ca5d99e0f7e7651c00c76347baa68a333790cbc9fb039a10843d1bd61f578c588888888604051611525949392919061217f565b60405180910390a4505050505050565b6104fa6115d7565b6001600160a01b0380821660009081526101006020526040902054168061156a576115678261098e565b90505b6001600160a01b03811661158057611580611e85565b919050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60c95460ff16156116e257604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600160991b01916113889161163991906121a6565b6000604051808303818686fa925050503d8060008114611675576040519150601f19603f3d011682016040523d82523d6000602084013e61167a565b606091505b509150915081801561169f575060008180602001905181019061169d91906121c2565b115b6116df5760405162461bcd60e51b81526020600482015260116024820152702224a9a0a62627aba2a22fa9a2a72222a960791b6044820152606401610566565b50505b60c954610100900460ff16156104fa57604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600360981b01916113889161174991906121a6565b6000604051808303818686fa925050503d8060008114611785576040519150601f19603f3d011682016040523d82523d6000602084013e61178a565b606091505b50915091508180156117b05750808060200190518101906117ab91906121c2565b600114155b6104e45760405162461bcd60e51b815260206004820152600e60248201526d212627a1a5a2a22fa9a2a72222a960911b6044820152606401610566565b6001600160a01b038116811461057857600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561184057611840611802565b604052919050565b60006001600160401b0382111561186157611861611802565b50601f01601f191660200190565b6000806000806080858703121561188557600080fd5b8435611890816117ed565b935060208501356118a0816117ed565b92506040850135915060608501356001600160401b038111156118c257600080fd5b8501601f810187136118d357600080fd5b80356118e66118e182611848565b611818565b8181528860208385010111156118fb57600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b6000806040838503121561193057600080fd5b823561193b816117ed565b946020939093013593505050565b60006020828403121561195b57600080fd5b8135611966816117ed565b9392505050565b8035801515811461158057600080fd5b60006020828403121561198f57600080fd5b6119668261196d565b600080600080600080600060e0888a0312156119b357600080fd5b87356119be816117ed565b965060208801356119ce816117ed565b955060408801356119de816117ed565b945060608801356119ee816117ed565b93506119fc6080890161196d565b9250611a0a60a0890161196d565b915060c0880135611a1a816117ed565b8091505092959891949750929550565b60008060008060608587031215611a4057600080fd5b843593506020850135611a52816117ed565b925060408501356001600160401b0380821115611a6e57600080fd5b818701915087601f830112611a8257600080fd5b813581811115611a9157600080fd5b886020828501011115611aa357600080fd5b95989497505060200194505050565b600080600060608486031215611ac757600080fd5b8335611ad2816117ed565b92506020840135611ae2816117ed565b929592945050506040919091013590565b60008060008060808587031215611b0957600080fd5b8435611b14816117ed565b93506020850135611b24816117ed565b92506040850135611b34816117ed565b91506060850135611b44816117ed565b939692955090935050565b60008083601f840112611b6157600080fd5b5081356001600160401b03811115611b7857600080fd5b6020830191508360208260051b8501011115611b9357600080fd5b9250929050565b600080600080600060608688031215611bb257600080fd5b8535611bbd816117ed565b945060208601356001600160401b0380821115611bd957600080fd5b611be589838a01611b4f565b90965094506040880135915080821115611bfe57600080fd5b50611c0b88828901611b4f565b969995985093965092949392505050565b6020808252600a908201526914d654d5115350d0531360b21b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b60008085851115611c9e57600080fd5b83861115611cab57600080fd5b5050820193919092039150565b80356020831015611cd157600019602084900360031b1b165b92915050565b60005b83811015611cf2578181015183820152602001611cda565b50506000910152565b600060208284031215611d0d57600080fd5b81516001600160401b03811115611d2357600080fd5b8201601f81018413611d3457600080fd5b8051611d426118e182611848565b818152856020838501011115611d5757600080fd5b611d68826020830160208601611cd7565b95945050505050565b60008151808452611d89816020860160208601611cd7565b601f01601f19169290920160200192915050565b8481526001600160a01b0384166020820152608060408201819052600090611dc790830185611d71565b8281036060840152611dd98185611d71565b979650505050505050565b6001600160a01b0383168152604060208201819052600090611e0890830184611d71565b949350505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b60008060008060808587031215611e4a57600080fd5b8435611e55816117ed565b93506020850135611e65816117ed565b92506040850135611e75816117ed565b9396929550929360600135925050565b634e487b7160e01b600052600160045260246000fd5b60006001600160401b03821115611eb457611eb4611802565b5060051b60200190565b600082601f830112611ecf57600080fd5b81356020611edf6118e183611e9b565b82815260059290921b84018101918181019086841115611efe57600080fd5b8286015b84811015611f195780358352918301918301611f02565b509695505050505050565b600080600080600060a08688031215611f3c57600080fd5b85359450602080870135611f4f816117ed565b94506040870135611f5f816117ed565b935060608701356001600160401b0380821115611f7b57600080fd5b818901915089601f830112611f8f57600080fd5b8135611f9d6118e182611e9b565b81815260059190911b8301840190848101908c831115611fbc57600080fd5b938501935b82851015611fe3578435611fd4816117ed565b82529385019390850190611fc1565b965050506080890135925080831115611ffb57600080fd5b505061200988828901611ebe565b9150509295509295909350565b634e487b7160e01b600052603260045260246000fd5b604080825283519082018190526000906020906060840190828701845b8281101561206e5781516001600160a01b031684529284019290840190600101612049565b5050508381038285015284518082528583019183019060005b818110156120a357835183529284019291840191600101612087565b5090979650505050505050565b8183526000602080850194508260005b858110156120ee5781356120d3816117ed565b6001600160a01b0316875295820195908201906001016120c0565b509495945050505050565b81835260006001600160fb1b0383111561211257600080fd5b8260051b80836020870137939093016020019392505050565b8781526001600160a01b0387811660208301528616604082015260a06060820181905260009061215e90830186886120b0565b82810360808401526121718185876120f9565b9a9950505050505050505050565b6040815260006121936040830186886120b0565b8281036020840152611dd98185876120f9565b600082516121b8818460208701611cd7565b9190910192915050565b6000602082840312156121d457600080fd5b505191905056fe526f6f744d696e7461626c654552433732315072656469636174653a20494e56a2646970667358221220d1bfc2912b6d936204f8bcd526922cd1de25280dfe606eaddf8c127bfcff177364736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var ChildERC1155Artifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"ChildERC1155\",\n \"sourceName\": \"contracts/child/ChildERC1155.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"operator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bool\",\n \"name\": \"approved\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"ApprovalForAll\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"userAddress\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"relayerAddress\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bytes\",\n \"name\": \"functionSignature\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"MetaTransactionExecuted\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"operator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"ids\",\n \"type\": \"uint256[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"values\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"TransferBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"operator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"TransferSingle\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"string\",\n \"name\": \"value\",\n \"type\": \"string\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"URI\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"balanceOf\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address[]\",\n \"name\": \"accounts\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"ids\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"balanceOfBatch\",\n \"outputs\": [\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"\",\n \"type\": \"uint256[]\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"burn\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"amounts\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"burnBatch\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"userAddress\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"functionSignature\",\n \"type\": \"bytes\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"sigR\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"sigS\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint8\",\n \"name\": \"sigV\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"executeMetaTransaction\",\n \"outputs\": [\n {\n \"internalType\": \"bytes\",\n \"name\": \"\",\n \"type\": \"bytes\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"user\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"getNonce\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"nonce\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"rootToken_\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"string\",\n \"name\": \"uri_\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"offset\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"invalidateNext\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"operator\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"isApprovedForAll\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"mint\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address[]\",\n \"name\": \"accounts\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"amounts\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"mintBatch\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"rootToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"ids\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"amounts\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"safeBatchTransferFrom\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"safeTransferFrom\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"operator\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"approved\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"setApprovalForAll\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes4\",\n \"name\": \"interfaceId\",\n \"type\": \"bytes4\"\n }\n ],\n \"name\": \"supportsInterface\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"uri\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50612b8b806100206000396000f3fe608060405234801561001057600080fd5b50600436106101155760003560e01c806357128683116100a2578063e619870511610071578063e619870514610279578063e985e9c51461028b578063f242432a146102c7578063f399e22e146102da578063f5298aca146102ed57600080fd5b8063571286831461022d5780636b20c454146102405780639b77ef1114610253578063a22cb4651461026657600080fd5b8063156e29f6116100e9578063156e29f6146101965780631f2d0065146101a95780632d0335ab146101cf5780632eb2c2d6146101f85780634e1273f41461020d57600080fd5b8062fdd58e1461011a57806301ffc9a7146101405780630c53c51c146101635780630e89341c14610183575b600080fd5b61012d610128366004611cd5565b610300565b6040519081526020015b60405180910390f35b61015361014e366004611d15565b61039b565b6040519015158152602001610137565b610176610171366004611d7a565b6103eb565b6040516101379190611e49565b610176610191366004611e5c565b6106c9565b6101536101a4366004611e75565b61075d565b610103546001600160a01b03165b6040516001600160a01b039091168152602001610137565b61012d6101dd366004611ea8565b6001600160a01b031660009081526038602052604090205490565b61020b61020636600461200c565b6107b0565b005b61022061021b3660046120b5565b61080e565b60405161013791906121ba565b61015361023b366004612211565b610937565b61015361024e3660046122aa565b610a53565b61020b610261366004611e5c565b610afb565b61020b61027436600461232a565b610b22565b610102546001600160a01b03166101b7565b610153610299366004612366565b6001600160a01b03918216600090815260d16020908152604080832093909416825291909152205460ff1690565b61020b6102d5366004612399565b610b38565b61020b6102e83660046123fd565b610b8f565b6101536102fb366004611e75565b610da5565b60006001600160a01b0383166103705760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201526930b634b21037bbb732b960b11b60648201526084015b60405180910390fd5b50600081815260d0602090815260408083206001600160a01b03861684529091529020545b92915050565b60006001600160e01b03198216636cdb3d1360e11b14806103cc57506001600160e01b031982166303a24d0760e21b145b8061039557506301ffc9a760e01b6001600160e01b0319831614610395565b6060600061042e87878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610dde92505050565b90506001600160e01b03196000358116908216036104b45760405162461bcd60e51b815260206004820152603d60248201527f66756e6374696f6e5369676e61747572652063616e206e6f74206265206f662060448201527f657865637574654d6574615472616e73616374696f6e206d6574686f640000006064820152608401610367565b604080516060810182526001600160a01b038a16600081815260386020908152848220548452808401929092528351601f8b0183900483028101830185528a815290938301918b908b9081908401838280828437600092019190915250505091525090506105258982888888610df9565b61057b5760405162461bcd60e51b815260206004820152602160248201527f5369676e657220616e64207369676e617475726520646f206e6f74206d6174636044820152600d60fb1b6064820152608401610367565b603860008a6001600160a01b03166001600160a01b031681526020019081526020016000206000815460010191905081905550600080306001600160a01b03168a8a8d6040516020016105d09392919061244f565b60408051601f19818403018152908290526105ea91612475565b6000604051808303816000865af19150503d8060008114610627576040519150601f19603f3d011682016040523d82523d6000602084013e61062c565b606091505b50915091508161067e5760405162461bcd60e51b815260206004820152601c60248201527f46756e6374696f6e2063616c6c206e6f74207375636365737366756c000000006044820152606401610367565b7f5845892132946850460bff5a0083f71031bc5bf9aadcd40f1de79423eac9b10b8b338c8c6040516106b39493929190612491565b60405180910390a19a9950505050505050505050565b606060d280546106d8906124dd565b80601f0160208091040260200160405190810160405280929190818152602001828054610704906124dd565b80156107515780601f1061072657610100808354040283529160200191610751565b820191906000526020600020905b81548152906001019060200180831161073457829003601f168201915b50505050509050919050565b610102546000906001600160a01b0316331461078b5760405162461bcd60e51b815260040161036790612517565b6107a684848460405180602001604052806000815250610ed5565b5060019392505050565b6107b8610fe4565b6001600160a01b0316856001600160a01b031614806107de57506107de85610299610fe4565b6107fa5760405162461bcd60e51b81526004016103679061255c565b6108078585858585610ff3565b5050505050565b606081518351146108735760405162461bcd60e51b815260206004820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e677468604482015268040dad2e6dac2e8c6d60bb1b6064820152608401610367565b600083516001600160401b0381111561088e5761088e611ec3565b6040519080825280602002602001820160405280156108b7578160200160208202803683370190505b50905060005b845181101561092f576109028582815181106108db576108db6125aa565b60200260200101518583815181106108f5576108f56125aa565b6020026020010151610300565b828281518110610914576109146125aa565b6020908102919091010152610928816125d6565b90506108bd565b509392505050565b610102546000906001600160a01b031633146109655760405162461bcd60e51b815260040161036790612517565b85848114801561097457508083145b6109c05760405162461bcd60e51b815260206004820181905260248201527f4368696c64455243313135353a206172726179206c656e206d69736d617463686044820152606401610367565b60005b81811015610a4457610a3c8989838181106109e0576109e06125aa565b90506020020160208101906109f59190611ea8565b888884818110610a0757610a076125aa565b90506020020135878785818110610a2057610a206125aa565b9050602002013560405180602001604052806000815250610ed5565b6001016109c3565b50600198975050505050505050565b610102546000906001600160a01b03163314610a815760405162461bcd60e51b815260040161036790612517565b610aef8686868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a0282810182019093528982529093508992508891829185019084908082843760009201919091525061119d92505050565b50600195945050505050565b3360009081526038602052604081208054839290610b1a9084906125ef565b909155505050565b610b34610b2d610fe4565b8383611334565b5050565b610b40610fe4565b6001600160a01b0316856001600160a01b03161480610b665750610b6685610299610fe4565b610b825760405162461bcd60e51b81526004016103679061255c565b6108078585858585611414565b606b54610100900460ff1615808015610baf5750606b54600160ff909116105b80610bc95750303b158015610bc95750606b5460ff166001145b610c2c5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610367565b606b805460ff191660011790558015610c4f57606b805461ff0019166101001790555b6001600160a01b038416610ca55760405162461bcd60e51b815260206004820181905260248201527f4368696c64455243313135353a204241445f494e495449414c495a4154494f4e6044820152606401610367565b61010380546001600160a01b0386166001600160a01b031991821617909155610102805490911633179055604080516020601f8501819004810282018101909252838152610d0d91859085908190840183828082843760009201919091525061153b92505050565b610d59610d22856001600160a01b031661156e565b604051602001610d329190612602565b60408051601f1981840301815282820190915260018252603160f81b602083015290611584565b8015610d9f57606b805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b610102546000906001600160a01b03163314610dd35760405162461bcd60e51b815260040161036790612517565b6107a68484846115f0565b60008151600003610df157506000919050565b506020015190565b6000806001610e0f610e0a886116f0565b61176d565b6040805160008152602081018083529290925260ff861690820152606081018790526080810186905260a0016020604051602081039080840390855afa158015610e5d573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610eb45760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b6044820152606401610367565b866001600160a01b0316816001600160a01b03161491505095945050505050565b6001600160a01b038416610f355760405162461bcd60e51b815260206004820152602160248201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736044820152607360f81b6064820152608401610367565b6000610f3f610fe4565b90506000610f4c8561179a565b90506000610f598561179a565b9050600086815260d0602090815260408083206001600160a01b038b16845290915281208054879290610f8d9084906125ef565b909155505060408051878152602081018790526001600160a01b03808a169260009291871691600080516020612af3833981519152910160405180910390a4610fdb836000898989896117e5565b50505050505050565b6000610fee611940565b905090565b81518351146110145760405162461bcd60e51b815260040161036790612637565b6001600160a01b03841661103a5760405162461bcd60e51b81526004016103679061267f565b6000611044610fe4565b905060005b845181101561112f576000858281518110611066576110666125aa565b602002602001015190506000858381518110611084576110846125aa565b602090810291909101810151600084815260d0835260408082206001600160a01b038e1683529093529190912054909150818110156110d55760405162461bcd60e51b8152600401610367906126c4565b600083815260d0602090815260408083206001600160a01b038e8116855292528083208585039055908b168252812080548492906111149084906125ef565b9250508190555050505080611128906125d6565b9050611049565b50846001600160a01b0316866001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb878760405161117f92919061270e565b60405180910390a461119581878787878761199c565b505050505050565b6001600160a01b0383166111c35760405162461bcd60e51b81526004016103679061273c565b80518251146111e45760405162461bcd60e51b815260040161036790612637565b60006111ee610fe4565b604080516020810190915260009052905060005b83518110156112c757600084828151811061121f5761121f6125aa565b60200260200101519050600084838151811061123d5761123d6125aa565b602090810291909101810151600084815260d0835260408082206001600160a01b038c16835290935291909120549091508181101561128e5760405162461bcd60e51b81526004016103679061277f565b600092835260d0602090815260408085206001600160a01b038b16865290915290922091039055806112bf816125d6565b915050611202565b5060006001600160a01b0316846001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb868660405161131892919061270e565b60405180910390a4604080516020810190915260009052610d9f565b816001600160a01b0316836001600160a01b0316036113a75760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b6064820152608401610367565b6001600160a01b03838116600081815260d16020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b03841661143a5760405162461bcd60e51b81526004016103679061267f565b6000611444610fe4565b905060006114518561179a565b9050600061145e8561179a565b9050600086815260d0602090815260408083206001600160a01b038c168452909152902054858110156114a35760405162461bcd60e51b8152600401610367906126c4565b600087815260d0602090815260408083206001600160a01b038d8116855292528083208985039055908a168252812080548892906114e29084906125ef565b909155505060408051888152602081018890526001600160a01b03808b16928c82169291881691600080516020612af3833981519152910160405180910390a4611530848a8a8a8a8a6117e5565b505050505050505050565b606b54610100900460ff166115625760405162461bcd60e51b8152600401610367906127c3565b61156b81611a57565b50565b60606103956001600160a01b0383166014611a87565b815160208084019190912082519183019190912060038290556004819055466001557f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6115d2818484611c29565b600055600280546001600160a01b0319163017905560055550505050565b6001600160a01b0383166116165760405162461bcd60e51b81526004016103679061273c565b6000611620610fe4565b9050600061162d8461179a565b9050600061163a8461179a565b604080516020808201835260009182905288825260d081528282206001600160a01b038b16835290522054909150848110156116885760405162461bcd60e51b81526004016103679061277f565b600086815260d0602090815260408083206001600160a01b038b81168086529184528285208a8703905582518b81529384018a9052909290881691600080516020612af3833981519152910160405180910390a4604080516020810190915260009052610fdb565b6000604051806080016040528060438152602001612b136043913980516020918201208351848301516040808701518051908601209051611750950193845260208401929092526001600160a01b03166040830152606082015260800190565b604051602081830303815290604052805190602001209050919050565b600061039561177a611c72565b8360405161190160f01b8152600281019290925260228201526042902090565b604080516001808252818301909252606091600091906020808301908036833701905050905082816000815181106117d4576117d46125aa565b602090810291909101015292915050565b6001600160a01b0384163b156111955760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e6190611829908990899088908890889060040161280e565b6020604051808303816000875af1925050508015611864575060408051601f3d908101601f1916820190925261186191810190612853565b60015b61191057611870612870565b806308c379a0036118a9575061188461288b565b8061188f57506118ab565b8060405162461bcd60e51b81526004016103679190611e49565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e2d455243313135356044820152732932b1b2b4bb32b91034b6b83632b6b2b73a32b960611b6064820152608401610367565b6001600160e01b0319811663f23a6e6160e01b14610fdb5760405162461bcd60e51b815260040161036790612914565b600030330361199657600080368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050503601516001600160a01b031691506119999050565b50335b90565b6001600160a01b0384163b156111955760405163bc197c8160e01b81526001600160a01b0385169063bc197c81906119e0908990899088908890889060040161295c565b6020604051808303816000875af1925050508015611a1b575060408051601f3d908101601f19168201909252611a1891810190612853565b60015b611a2757611870612870565b6001600160e01b0319811663bc197c8160e01b14610fdb5760405162461bcd60e51b815260040161036790612914565b606b54610100900460ff16611a7e5760405162461bcd60e51b8152600401610367906127c3565b61156b81611cad565b60606000611a968360026129ba565b611aa19060026125ef565b6001600160401b03811115611ab857611ab8611ec3565b6040519080825280601f01601f191660200182016040528015611ae2576020820181803683370190505b509050600360fc1b81600081518110611afd57611afd6125aa565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110611b2c57611b2c6125aa565b60200101906001600160f81b031916908160001a9053506000611b508460026129ba565b611b5b9060016125ef565b90505b6001811115611bd3576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110611b8f57611b8f6125aa565b1a60f81b828281518110611ba557611ba56125aa565b60200101906001600160f81b031916908160001a90535060049490941c93611bcc816129d1565b9050611b5e565b508315611c225760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610367565b9392505050565b6040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b6002546000906001600160a01b031630148015611c90575060015446145b15611c9c575060005490565b610fee600554600354600454611c29565b60d2610b348282612a33565b80356001600160a01b0381168114611cd057600080fd5b919050565b60008060408385031215611ce857600080fd5b611cf183611cb9565b946020939093013593505050565b6001600160e01b03198116811461156b57600080fd5b600060208284031215611d2757600080fd5b8135611c2281611cff565b60008083601f840112611d4457600080fd5b5081356001600160401b03811115611d5b57600080fd5b602083019150836020828501011115611d7357600080fd5b9250929050565b60008060008060008060a08789031215611d9357600080fd5b611d9c87611cb9565b955060208701356001600160401b03811115611db757600080fd5b611dc389828a01611d32565b9096509450506040870135925060608701359150608087013560ff81168114611deb57600080fd5b809150509295509295509295565b60005b83811015611e14578181015183820152602001611dfc565b50506000910152565b60008151808452611e35816020860160208601611df9565b601f01601f19169290920160200192915050565b602081526000611c226020830184611e1d565b600060208284031215611e6e57600080fd5b5035919050565b600080600060608486031215611e8a57600080fd5b611e9384611cb9565b95602085013595506040909401359392505050565b600060208284031215611eba57600080fd5b611c2282611cb9565b634e487b7160e01b600052604160045260246000fd5b601f8201601f191681016001600160401b0381118282101715611efe57611efe611ec3565b6040525050565b60006001600160401b03821115611f1e57611f1e611ec3565b5060051b60200190565b600082601f830112611f3957600080fd5b81356020611f4682611f05565b604051611f538282611ed9565b83815260059390931b8501820192828101915086841115611f7357600080fd5b8286015b84811015611f8e5780358352918301918301611f77565b509695505050505050565b600082601f830112611faa57600080fd5b81356001600160401b03811115611fc357611fc3611ec3565b604051611fda601f8301601f191660200182611ed9565b818152846020838601011115611fef57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a0868803121561202457600080fd5b61202d86611cb9565b945061203b60208701611cb9565b935060408601356001600160401b038082111561205757600080fd5b61206389838a01611f28565b9450606088013591508082111561207957600080fd5b61208589838a01611f28565b9350608088013591508082111561209b57600080fd5b506120a888828901611f99565b9150509295509295909350565b600080604083850312156120c857600080fd5b82356001600160401b03808211156120df57600080fd5b818501915085601f8301126120f357600080fd5b8135602061210082611f05565b60405161210d8282611ed9565b83815260059390931b850182019282810191508984111561212d57600080fd5b948201945b838610156121525761214386611cb9565b82529482019490820190612132565b9650508601359250508082111561216857600080fd5b5061217585828601611f28565b9150509250929050565b600081518084526020808501945080840160005b838110156121af57815187529582019590820190600101612193565b509495945050505050565b602081526000611c22602083018461217f565b60008083601f8401126121df57600080fd5b5081356001600160401b038111156121f657600080fd5b6020830191508360208260051b8501011115611d7357600080fd5b6000806000806000806060878903121561222a57600080fd5b86356001600160401b038082111561224157600080fd5b61224d8a838b016121cd565b9098509650602089013591508082111561226657600080fd5b6122728a838b016121cd565b9096509450604089013591508082111561228b57600080fd5b5061229889828a016121cd565b979a9699509497509295939492505050565b6000806000806000606086880312156122c257600080fd5b6122cb86611cb9565b945060208601356001600160401b03808211156122e757600080fd5b6122f389838a016121cd565b9096509450604088013591508082111561230c57600080fd5b50612319888289016121cd565b969995985093965092949392505050565b6000806040838503121561233d57600080fd5b61234683611cb9565b91506020830135801515811461235b57600080fd5b809150509250929050565b6000806040838503121561237957600080fd5b61238283611cb9565b915061239060208401611cb9565b90509250929050565b600080600080600060a086880312156123b157600080fd5b6123ba86611cb9565b94506123c860208701611cb9565b9350604086013592506060860135915060808601356001600160401b038111156123f157600080fd5b6120a888828901611f99565b60008060006040848603121561241257600080fd5b61241b84611cb9565b925060208401356001600160401b0381111561243657600080fd5b61244286828701611d32565b9497909650939450505050565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b60008251612487818460208701611df9565b9190910192915050565b6001600160a01b0385811682528416602082015260606040820181905281018290526000828460808401376000608084840101526080601f19601f850116830101905095945050505050565b600181811c908216806124f157607f821691505b60208210810361251157634e487b7160e01b600052602260045260246000fd5b50919050565b60208082526025908201527f4368696c64455243313135353a204f6e6c79207072656469636174652063616e6040820152640818d85b1b60da1b606082015260800190565b6020808252602e908201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60408201526d195c881bdc88185c1c1c9bdd995960921b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016125e8576125e86125c0565b5060010190565b80820180821115610395576103956125c0565b6c4368696c64455243313135352d60981b81526000825161262a81600d850160208701611df9565b91909101600d0192915050565b60208082526028908201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206040820152670dad2e6dac2e8c6d60c31b606082015260800190565b60208082526025908201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604082015264647265737360d81b606082015260800190565b6020808252602a908201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60408201526939103a3930b739b332b960b11b606082015260800190565b604081526000612721604083018561217f565b8281036020840152612733818561217f565b95945050505050565b60208082526023908201527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260408201526265737360e81b606082015260800190565b60208082526024908201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604082015263616e636560e01b606082015260800190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160a01b03868116825285166020820152604081018490526060810183905260a06080820181905260009061284890830184611e1d565b979650505050505050565b60006020828403121561286557600080fd5b8151611c2281611cff565b600060033d11156119995760046000803e5060005160e01c90565b600060443d10156128995790565b6040516003193d81016004833e81513d6001600160401b0381602484011181841117156128c857505050505090565b82850191508151818111156128e05750505050505090565b843d87010160208285010111156128fa5750505050505090565b61290960208286010187611ed9565b509095945050505050565b60208082526028908201527f455243313135353a204552433131353552656365697665722072656a656374656040820152676420746f6b656e7360c01b606082015260800190565b6001600160a01b0386811682528516602082015260a0604082018190526000906129889083018661217f565b828103606084015261299a818661217f565b905082810360808401526129ae8185611e1d565b98975050505050505050565b8082028115828204841417610395576103956125c0565b6000816129e0576129e06125c0565b506000190190565b601f821115612a2e57600081815260208120601f850160051c81016020861015612a0f5750805b601f850160051c820191505b8181101561119557828155600101612a1b565b505050565b81516001600160401b03811115612a4c57612a4c611ec3565b612a6081612a5a84546124dd565b846129e8565b602080601f831160018114612a955760008415612a7d5750858301515b600019600386901b1c1916600185901b178555611195565b600085815260208120601f198616915b82811015612ac457888601518255948401946001909101908401612aa5565b5085821015612ae25787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fec3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f624d6574615472616e73616374696f6e2875696e74323536206e6f6e63652c616464726573732066726f6d2c62797465732066756e6374696f6e5369676e617475726529a2646970667358221220e461f7064aa6c6c6ffa4776432fb8d1d9904257257018fc2ec1efb0abb81165064736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101155760003560e01c806357128683116100a2578063e619870511610071578063e619870514610279578063e985e9c51461028b578063f242432a146102c7578063f399e22e146102da578063f5298aca146102ed57600080fd5b8063571286831461022d5780636b20c454146102405780639b77ef1114610253578063a22cb4651461026657600080fd5b8063156e29f6116100e9578063156e29f6146101965780631f2d0065146101a95780632d0335ab146101cf5780632eb2c2d6146101f85780634e1273f41461020d57600080fd5b8062fdd58e1461011a57806301ffc9a7146101405780630c53c51c146101635780630e89341c14610183575b600080fd5b61012d610128366004611cd5565b610300565b6040519081526020015b60405180910390f35b61015361014e366004611d15565b61039b565b6040519015158152602001610137565b610176610171366004611d7a565b6103eb565b6040516101379190611e49565b610176610191366004611e5c565b6106c9565b6101536101a4366004611e75565b61075d565b610103546001600160a01b03165b6040516001600160a01b039091168152602001610137565b61012d6101dd366004611ea8565b6001600160a01b031660009081526038602052604090205490565b61020b61020636600461200c565b6107b0565b005b61022061021b3660046120b5565b61080e565b60405161013791906121ba565b61015361023b366004612211565b610937565b61015361024e3660046122aa565b610a53565b61020b610261366004611e5c565b610afb565b61020b61027436600461232a565b610b22565b610102546001600160a01b03166101b7565b610153610299366004612366565b6001600160a01b03918216600090815260d16020908152604080832093909416825291909152205460ff1690565b61020b6102d5366004612399565b610b38565b61020b6102e83660046123fd565b610b8f565b6101536102fb366004611e75565b610da5565b60006001600160a01b0383166103705760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201526930b634b21037bbb732b960b11b60648201526084015b60405180910390fd5b50600081815260d0602090815260408083206001600160a01b03861684529091529020545b92915050565b60006001600160e01b03198216636cdb3d1360e11b14806103cc57506001600160e01b031982166303a24d0760e21b145b8061039557506301ffc9a760e01b6001600160e01b0319831614610395565b6060600061042e87878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610dde92505050565b90506001600160e01b03196000358116908216036104b45760405162461bcd60e51b815260206004820152603d60248201527f66756e6374696f6e5369676e61747572652063616e206e6f74206265206f662060448201527f657865637574654d6574615472616e73616374696f6e206d6574686f640000006064820152608401610367565b604080516060810182526001600160a01b038a16600081815260386020908152848220548452808401929092528351601f8b0183900483028101830185528a815290938301918b908b9081908401838280828437600092019190915250505091525090506105258982888888610df9565b61057b5760405162461bcd60e51b815260206004820152602160248201527f5369676e657220616e64207369676e617475726520646f206e6f74206d6174636044820152600d60fb1b6064820152608401610367565b603860008a6001600160a01b03166001600160a01b031681526020019081526020016000206000815460010191905081905550600080306001600160a01b03168a8a8d6040516020016105d09392919061244f565b60408051601f19818403018152908290526105ea91612475565b6000604051808303816000865af19150503d8060008114610627576040519150601f19603f3d011682016040523d82523d6000602084013e61062c565b606091505b50915091508161067e5760405162461bcd60e51b815260206004820152601c60248201527f46756e6374696f6e2063616c6c206e6f74207375636365737366756c000000006044820152606401610367565b7f5845892132946850460bff5a0083f71031bc5bf9aadcd40f1de79423eac9b10b8b338c8c6040516106b39493929190612491565b60405180910390a19a9950505050505050505050565b606060d280546106d8906124dd565b80601f0160208091040260200160405190810160405280929190818152602001828054610704906124dd565b80156107515780601f1061072657610100808354040283529160200191610751565b820191906000526020600020905b81548152906001019060200180831161073457829003601f168201915b50505050509050919050565b610102546000906001600160a01b0316331461078b5760405162461bcd60e51b815260040161036790612517565b6107a684848460405180602001604052806000815250610ed5565b5060019392505050565b6107b8610fe4565b6001600160a01b0316856001600160a01b031614806107de57506107de85610299610fe4565b6107fa5760405162461bcd60e51b81526004016103679061255c565b6108078585858585610ff3565b5050505050565b606081518351146108735760405162461bcd60e51b815260206004820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e677468604482015268040dad2e6dac2e8c6d60bb1b6064820152608401610367565b600083516001600160401b0381111561088e5761088e611ec3565b6040519080825280602002602001820160405280156108b7578160200160208202803683370190505b50905060005b845181101561092f576109028582815181106108db576108db6125aa565b60200260200101518583815181106108f5576108f56125aa565b6020026020010151610300565b828281518110610914576109146125aa565b6020908102919091010152610928816125d6565b90506108bd565b509392505050565b610102546000906001600160a01b031633146109655760405162461bcd60e51b815260040161036790612517565b85848114801561097457508083145b6109c05760405162461bcd60e51b815260206004820181905260248201527f4368696c64455243313135353a206172726179206c656e206d69736d617463686044820152606401610367565b60005b81811015610a4457610a3c8989838181106109e0576109e06125aa565b90506020020160208101906109f59190611ea8565b888884818110610a0757610a076125aa565b90506020020135878785818110610a2057610a206125aa565b9050602002013560405180602001604052806000815250610ed5565b6001016109c3565b50600198975050505050505050565b610102546000906001600160a01b03163314610a815760405162461bcd60e51b815260040161036790612517565b610aef8686868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a0282810182019093528982529093508992508891829185019084908082843760009201919091525061119d92505050565b50600195945050505050565b3360009081526038602052604081208054839290610b1a9084906125ef565b909155505050565b610b34610b2d610fe4565b8383611334565b5050565b610b40610fe4565b6001600160a01b0316856001600160a01b03161480610b665750610b6685610299610fe4565b610b825760405162461bcd60e51b81526004016103679061255c565b6108078585858585611414565b606b54610100900460ff1615808015610baf5750606b54600160ff909116105b80610bc95750303b158015610bc95750606b5460ff166001145b610c2c5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610367565b606b805460ff191660011790558015610c4f57606b805461ff0019166101001790555b6001600160a01b038416610ca55760405162461bcd60e51b815260206004820181905260248201527f4368696c64455243313135353a204241445f494e495449414c495a4154494f4e6044820152606401610367565b61010380546001600160a01b0386166001600160a01b031991821617909155610102805490911633179055604080516020601f8501819004810282018101909252838152610d0d91859085908190840183828082843760009201919091525061153b92505050565b610d59610d22856001600160a01b031661156e565b604051602001610d329190612602565b60408051601f1981840301815282820190915260018252603160f81b602083015290611584565b8015610d9f57606b805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b610102546000906001600160a01b03163314610dd35760405162461bcd60e51b815260040161036790612517565b6107a68484846115f0565b60008151600003610df157506000919050565b506020015190565b6000806001610e0f610e0a886116f0565b61176d565b6040805160008152602081018083529290925260ff861690820152606081018790526080810186905260a0016020604051602081039080840390855afa158015610e5d573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610eb45760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b6044820152606401610367565b866001600160a01b0316816001600160a01b03161491505095945050505050565b6001600160a01b038416610f355760405162461bcd60e51b815260206004820152602160248201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736044820152607360f81b6064820152608401610367565b6000610f3f610fe4565b90506000610f4c8561179a565b90506000610f598561179a565b9050600086815260d0602090815260408083206001600160a01b038b16845290915281208054879290610f8d9084906125ef565b909155505060408051878152602081018790526001600160a01b03808a169260009291871691600080516020612af3833981519152910160405180910390a4610fdb836000898989896117e5565b50505050505050565b6000610fee611940565b905090565b81518351146110145760405162461bcd60e51b815260040161036790612637565b6001600160a01b03841661103a5760405162461bcd60e51b81526004016103679061267f565b6000611044610fe4565b905060005b845181101561112f576000858281518110611066576110666125aa565b602002602001015190506000858381518110611084576110846125aa565b602090810291909101810151600084815260d0835260408082206001600160a01b038e1683529093529190912054909150818110156110d55760405162461bcd60e51b8152600401610367906126c4565b600083815260d0602090815260408083206001600160a01b038e8116855292528083208585039055908b168252812080548492906111149084906125ef565b9250508190555050505080611128906125d6565b9050611049565b50846001600160a01b0316866001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb878760405161117f92919061270e565b60405180910390a461119581878787878761199c565b505050505050565b6001600160a01b0383166111c35760405162461bcd60e51b81526004016103679061273c565b80518251146111e45760405162461bcd60e51b815260040161036790612637565b60006111ee610fe4565b604080516020810190915260009052905060005b83518110156112c757600084828151811061121f5761121f6125aa565b60200260200101519050600084838151811061123d5761123d6125aa565b602090810291909101810151600084815260d0835260408082206001600160a01b038c16835290935291909120549091508181101561128e5760405162461bcd60e51b81526004016103679061277f565b600092835260d0602090815260408085206001600160a01b038b16865290915290922091039055806112bf816125d6565b915050611202565b5060006001600160a01b0316846001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb868660405161131892919061270e565b60405180910390a4604080516020810190915260009052610d9f565b816001600160a01b0316836001600160a01b0316036113a75760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b6064820152608401610367565b6001600160a01b03838116600081815260d16020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b03841661143a5760405162461bcd60e51b81526004016103679061267f565b6000611444610fe4565b905060006114518561179a565b9050600061145e8561179a565b9050600086815260d0602090815260408083206001600160a01b038c168452909152902054858110156114a35760405162461bcd60e51b8152600401610367906126c4565b600087815260d0602090815260408083206001600160a01b038d8116855292528083208985039055908a168252812080548892906114e29084906125ef565b909155505060408051888152602081018890526001600160a01b03808b16928c82169291881691600080516020612af3833981519152910160405180910390a4611530848a8a8a8a8a6117e5565b505050505050505050565b606b54610100900460ff166115625760405162461bcd60e51b8152600401610367906127c3565b61156b81611a57565b50565b60606103956001600160a01b0383166014611a87565b815160208084019190912082519183019190912060038290556004819055466001557f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6115d2818484611c29565b600055600280546001600160a01b0319163017905560055550505050565b6001600160a01b0383166116165760405162461bcd60e51b81526004016103679061273c565b6000611620610fe4565b9050600061162d8461179a565b9050600061163a8461179a565b604080516020808201835260009182905288825260d081528282206001600160a01b038b16835290522054909150848110156116885760405162461bcd60e51b81526004016103679061277f565b600086815260d0602090815260408083206001600160a01b038b81168086529184528285208a8703905582518b81529384018a9052909290881691600080516020612af3833981519152910160405180910390a4604080516020810190915260009052610fdb565b6000604051806080016040528060438152602001612b136043913980516020918201208351848301516040808701518051908601209051611750950193845260208401929092526001600160a01b03166040830152606082015260800190565b604051602081830303815290604052805190602001209050919050565b600061039561177a611c72565b8360405161190160f01b8152600281019290925260228201526042902090565b604080516001808252818301909252606091600091906020808301908036833701905050905082816000815181106117d4576117d46125aa565b602090810291909101015292915050565b6001600160a01b0384163b156111955760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e6190611829908990899088908890889060040161280e565b6020604051808303816000875af1925050508015611864575060408051601f3d908101601f1916820190925261186191810190612853565b60015b61191057611870612870565b806308c379a0036118a9575061188461288b565b8061188f57506118ab565b8060405162461bcd60e51b81526004016103679190611e49565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e2d455243313135356044820152732932b1b2b4bb32b91034b6b83632b6b2b73a32b960611b6064820152608401610367565b6001600160e01b0319811663f23a6e6160e01b14610fdb5760405162461bcd60e51b815260040161036790612914565b600030330361199657600080368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050503601516001600160a01b031691506119999050565b50335b90565b6001600160a01b0384163b156111955760405163bc197c8160e01b81526001600160a01b0385169063bc197c81906119e0908990899088908890889060040161295c565b6020604051808303816000875af1925050508015611a1b575060408051601f3d908101601f19168201909252611a1891810190612853565b60015b611a2757611870612870565b6001600160e01b0319811663bc197c8160e01b14610fdb5760405162461bcd60e51b815260040161036790612914565b606b54610100900460ff16611a7e5760405162461bcd60e51b8152600401610367906127c3565b61156b81611cad565b60606000611a968360026129ba565b611aa19060026125ef565b6001600160401b03811115611ab857611ab8611ec3565b6040519080825280601f01601f191660200182016040528015611ae2576020820181803683370190505b509050600360fc1b81600081518110611afd57611afd6125aa565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110611b2c57611b2c6125aa565b60200101906001600160f81b031916908160001a9053506000611b508460026129ba565b611b5b9060016125ef565b90505b6001811115611bd3576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110611b8f57611b8f6125aa565b1a60f81b828281518110611ba557611ba56125aa565b60200101906001600160f81b031916908160001a90535060049490941c93611bcc816129d1565b9050611b5e565b508315611c225760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610367565b9392505050565b6040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b6002546000906001600160a01b031630148015611c90575060015446145b15611c9c575060005490565b610fee600554600354600454611c29565b60d2610b348282612a33565b80356001600160a01b0381168114611cd057600080fd5b919050565b60008060408385031215611ce857600080fd5b611cf183611cb9565b946020939093013593505050565b6001600160e01b03198116811461156b57600080fd5b600060208284031215611d2757600080fd5b8135611c2281611cff565b60008083601f840112611d4457600080fd5b5081356001600160401b03811115611d5b57600080fd5b602083019150836020828501011115611d7357600080fd5b9250929050565b60008060008060008060a08789031215611d9357600080fd5b611d9c87611cb9565b955060208701356001600160401b03811115611db757600080fd5b611dc389828a01611d32565b9096509450506040870135925060608701359150608087013560ff81168114611deb57600080fd5b809150509295509295509295565b60005b83811015611e14578181015183820152602001611dfc565b50506000910152565b60008151808452611e35816020860160208601611df9565b601f01601f19169290920160200192915050565b602081526000611c226020830184611e1d565b600060208284031215611e6e57600080fd5b5035919050565b600080600060608486031215611e8a57600080fd5b611e9384611cb9565b95602085013595506040909401359392505050565b600060208284031215611eba57600080fd5b611c2282611cb9565b634e487b7160e01b600052604160045260246000fd5b601f8201601f191681016001600160401b0381118282101715611efe57611efe611ec3565b6040525050565b60006001600160401b03821115611f1e57611f1e611ec3565b5060051b60200190565b600082601f830112611f3957600080fd5b81356020611f4682611f05565b604051611f538282611ed9565b83815260059390931b8501820192828101915086841115611f7357600080fd5b8286015b84811015611f8e5780358352918301918301611f77565b509695505050505050565b600082601f830112611faa57600080fd5b81356001600160401b03811115611fc357611fc3611ec3565b604051611fda601f8301601f191660200182611ed9565b818152846020838601011115611fef57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a0868803121561202457600080fd5b61202d86611cb9565b945061203b60208701611cb9565b935060408601356001600160401b038082111561205757600080fd5b61206389838a01611f28565b9450606088013591508082111561207957600080fd5b61208589838a01611f28565b9350608088013591508082111561209b57600080fd5b506120a888828901611f99565b9150509295509295909350565b600080604083850312156120c857600080fd5b82356001600160401b03808211156120df57600080fd5b818501915085601f8301126120f357600080fd5b8135602061210082611f05565b60405161210d8282611ed9565b83815260059390931b850182019282810191508984111561212d57600080fd5b948201945b838610156121525761214386611cb9565b82529482019490820190612132565b9650508601359250508082111561216857600080fd5b5061217585828601611f28565b9150509250929050565b600081518084526020808501945080840160005b838110156121af57815187529582019590820190600101612193565b509495945050505050565b602081526000611c22602083018461217f565b60008083601f8401126121df57600080fd5b5081356001600160401b038111156121f657600080fd5b6020830191508360208260051b8501011115611d7357600080fd5b6000806000806000806060878903121561222a57600080fd5b86356001600160401b038082111561224157600080fd5b61224d8a838b016121cd565b9098509650602089013591508082111561226657600080fd5b6122728a838b016121cd565b9096509450604089013591508082111561228b57600080fd5b5061229889828a016121cd565b979a9699509497509295939492505050565b6000806000806000606086880312156122c257600080fd5b6122cb86611cb9565b945060208601356001600160401b03808211156122e757600080fd5b6122f389838a016121cd565b9096509450604088013591508082111561230c57600080fd5b50612319888289016121cd565b969995985093965092949392505050565b6000806040838503121561233d57600080fd5b61234683611cb9565b91506020830135801515811461235b57600080fd5b809150509250929050565b6000806040838503121561237957600080fd5b61238283611cb9565b915061239060208401611cb9565b90509250929050565b600080600080600060a086880312156123b157600080fd5b6123ba86611cb9565b94506123c860208701611cb9565b9350604086013592506060860135915060808601356001600160401b038111156123f157600080fd5b6120a888828901611f99565b60008060006040848603121561241257600080fd5b61241b84611cb9565b925060208401356001600160401b0381111561243657600080fd5b61244286828701611d32565b9497909650939450505050565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b60008251612487818460208701611df9565b9190910192915050565b6001600160a01b0385811682528416602082015260606040820181905281018290526000828460808401376000608084840101526080601f19601f850116830101905095945050505050565b600181811c908216806124f157607f821691505b60208210810361251157634e487b7160e01b600052602260045260246000fd5b50919050565b60208082526025908201527f4368696c64455243313135353a204f6e6c79207072656469636174652063616e6040820152640818d85b1b60da1b606082015260800190565b6020808252602e908201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60408201526d195c881bdc88185c1c1c9bdd995960921b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016125e8576125e86125c0565b5060010190565b80820180821115610395576103956125c0565b6c4368696c64455243313135352d60981b81526000825161262a81600d850160208701611df9565b91909101600d0192915050565b60208082526028908201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206040820152670dad2e6dac2e8c6d60c31b606082015260800190565b60208082526025908201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604082015264647265737360d81b606082015260800190565b6020808252602a908201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60408201526939103a3930b739b332b960b11b606082015260800190565b604081526000612721604083018561217f565b8281036020840152612733818561217f565b95945050505050565b60208082526023908201527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260408201526265737360e81b606082015260800190565b60208082526024908201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604082015263616e636560e01b606082015260800190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160a01b03868116825285166020820152604081018490526060810183905260a06080820181905260009061284890830184611e1d565b979650505050505050565b60006020828403121561286557600080fd5b8151611c2281611cff565b600060033d11156119995760046000803e5060005160e01c90565b600060443d10156128995790565b6040516003193d81016004833e81513d6001600160401b0381602484011181841117156128c857505050505090565b82850191508151818111156128e05750505050505090565b843d87010160208285010111156128fa5750505050505090565b61290960208286010187611ed9565b509095945050505050565b60208082526028908201527f455243313135353a204552433131353552656365697665722072656a656374656040820152676420746f6b656e7360c01b606082015260800190565b6001600160a01b0386811682528516602082015260a0604082018190526000906129889083018661217f565b828103606084015261299a818661217f565b905082810360808401526129ae8185611e1d565b98975050505050505050565b8082028115828204841417610395576103956125c0565b6000816129e0576129e06125c0565b506000190190565b601f821115612a2e57600081815260208120601f850160051c81016020861015612a0f5750805b601f850160051c820191505b8181101561119557828155600101612a1b565b505050565b81516001600160401b03811115612a4c57612a4c611ec3565b612a6081612a5a84546124dd565b846129e8565b602080601f831160018114612a955760008415612a7d5750858301515b600019600386901b1c1916600185901b178555611195565b600085815260208120601f198616915b82811015612ac457888601518255948401946001909101908401612aa5565b5085821015612ae25787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fec3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f624d6574615472616e73616374696f6e2875696e74323536206e6f6e63652c616464726573732066726f6d2c62797465732066756e6374696f6e5369676e617475726529a2646970667358221220e461f7064aa6c6c6ffa4776432fb8d1d9904257257018fc2ec1efb0abb81165064736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var ChildERC1155PredicateArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"ChildERC1155Predicate\",\n \"sourceName\": \"contracts/child/ChildERC1155Predicate.sol\",\n \"abi\": [\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"only\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"Unauthorized\",\n \"type\": \"error\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2ERC1155Deposit\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"amounts\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"L2ERC1155DepositBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2ERC1155Withdraw\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"amounts\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"L2ERC1155WithdrawBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"L2TokenMapped\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"ALLOWLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"BLOCKLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAP_TOKEN_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TOKEN_CONTRACT\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"READ_ADDRESSLIST_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"SYSTEM\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childTokenTemplate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newL2StateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newStateReceiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newRootERC1155Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"l2StateSender\",\n \"outputs\": [\n {\n \"internalType\": \"contract IStateSender\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onStateReceive\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"rootERC1155Predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"rootTokenToChildToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"stateReceiver\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC1155\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"withdraw\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC1155\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"amounts\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"withdrawBatch\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC1155\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"withdrawTo\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50612040806100206000396000f3fe608060405234801561001057600080fd5b50600436106101585760003560e01c806397e5230d116100c3578063d41f17711161007c578063d41f1771146102de578063d7c9e3ec14610305578063e0563ab11461032c578063eeb4994514610335578063f645125514610348578063f8c8765e1461036f57600080fd5b806397e5230d1461024d578063b176806514610257578063b5c5f6721461027e578063b68ad1e414610291578063b8cd3ec0146102a4578063c5ac2b1c146102b757600080fd5b806351351d531161011557806351351d53146101d357806355b01e4d146101e15780635ea5df79146101ef5780637efab4f51461020657806386937eb41461022f578063947287cf1461024457600080fd5b8063051eb2e21461015d57806305dc2e8f1461018d57806307b3e252146101a05780631bc114ba146101ae578063284017f5146101c15780633b878c22146101ca575b600080fd5b603554610170906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b603454610170906001600160a01b031681565b6101706004600360981b0181565b603354610170906001600160a01b031681565b61017061202081565b61017061101081565b6101706002600160a01b0381565b6101706004600160991b0181565b6101f861138881565b604051908152602001610184565b610170610214366004611648565b6037602052600090815260409020546001600160a01b031681565b61024261023d3660046116b7565b610382565b005b6101f861520881565b6101f8620249f081565b6101f87f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b61024261028c366004611763565b61039a565b603654610170906001600160a01b031681565b6102426102b2366004611798565b6103ab565b6101f87faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b6101f87f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b6101f87f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b61017061203081565b6102426103433660046117de565b6103bd565b6101f87f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b61024261037d366004611866565b6105dd565b6103918787878787878761073a565b50505050505050565b6103a683338484610ab9565b505050565b6103b784848484610ab9565b50505050565b6034546001600160a01b0316331461042f5760405162461bcd60e51b815260206004820152602a60248201527f4368696c64455243313135355072656469636174653a204f4e4c595f5354415460448201526922afa922a1a2a4ab22a960b11b60648201526084015b60405180910390fd5b6035546001600160a01b0384811691161461049f5760405162461bcd60e51b815260206004820152602a60248201527f4368696c64455243313135355072656469636174653a204f4e4c595f524f4f546044820152695f50524544494341544560b01b6064820152608401610426565b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f8216104ce6020600084866118c2565b6104d7916118ec565b036104f6576104f16104ec82602081866118c2565b610dce565b6103b7565b7faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d186105256020600084866118c2565b61052e916118ec565b0361053d576104f18282611039565b7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad61056c6020600084866118c2565b610575916118ec565b03610584576104f182826112a6565b60405162461bcd60e51b815260206004820152602860248201527f4368696c64455243313135355072656469636174653a20494e56414c49445f5360448201526749474e415455524560c01b6064820152608401610426565b336002600160a01b03146106215760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b6044820152606401610426565b600054610100900460ff16158080156106415750600054600160ff909116105b8061065b5750303b15801561065b575060005460ff166001145b6106be5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610426565b6000805460ff1916600117905580156106e1576000805461ff0019166101001790555b6106ed8585858561140e565b8015610733576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b8661074481611504565b6107605760405162461bcd60e51b81526004016104269061190a565b6000886001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107c4919061194d565b6001600160a01b038181166000908152603760205260409020549192508a81169116146108035760405162461bcd60e51b81526004016104269061196a565b6001600160a01b038116610819576108196119af565b306001600160a01b0316896001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610861573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610885919061194d565b6001600160a01b03161461089b5761089b6119af565b86851480156108a957508483145b6109035760405162461bcd60e51b815260206004820152602560248201527f4368696c64455243313135355072656469636174653a20494e56414c49445f4c60448201526408a9c8ea8960db1b6064820152608401610426565b604051631ac8311560e21b81526001600160a01b038a1690636b20c454906109379033908a908a908a908a906004016119f7565b6020604051808303816000875af1158015610956573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097a9190611a3b565b6109965760405162461bcd60e51b815260040161042690611a5d565b6033546035546040516001600160a01b03928316926316f198319216906109f1907f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed290869033908f908f908f908f908f908f90602001611ae8565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610a1d929190611b99565b600060405180830381600087803b158015610a3757600080fd5b505af1158015610a4b573d6000803e3d6000fd5b50505050336001600160a01b0316896001600160a01b0316826001600160a01b03167f7a10660242ca367951ff3777cdb3c2a761e3ccad204bac118501e24693f3683d8b8b8b8b8b8b604051610aa696959493929190611bc5565b60405180910390a4505050505050505050565b83610ac381611504565b610adf5760405162461bcd60e51b81526004016104269061190a565b6000856001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b43919061194d565b6001600160a01b03818116600090815260376020526040902054919250878116911614610b825760405162461bcd60e51b81526004016104269061196a565b6001600160a01b038116610b9857610b986119af565b306001600160a01b0316866001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610be0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c04919061194d565b6001600160a01b031614610c1a57610c1a6119af565b604051637a94c56560e11b81526001600160a01b0387169063f5298aca90610c4a90339088908890600401611c0e565b6020604051808303816000875af1158015610c69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c8d9190611a3b565b610ca95760405162461bcd60e51b815260040161042690611a5d565b603354603554604080517f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286960208201526001600160a01b0385811682840152336060830152898116608083015260a0820189905260c08083018990528351808403909101815260e08301938490526316f1983160e01b909352938416936316f1983193610d3b9391169160e401611b99565b600060405180830381600087803b158015610d5557600080fd5b505af1158015610d69573d6000803e3d6000fd5b50505050846001600160a01b0316866001600160a01b0316826001600160a01b03167f2ca9093e8b5356801039806c6a08003e5b7013fb8ae48f720fc90fc1c1a8bec2338888604051610dbe93929190611c0e565b60405180910390a4505050505050565b600080808080610de086880188611c2f565b6001600160a01b03808616600090815260376020526040902054959a50939850919650945092501680610e255760405162461bcd60e51b81526004016104269061196a565b610e2e81611504565b610e3a57610e3a6119af565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e9e919061194d565b9050866001600160a01b0316816001600160a01b031614610ec157610ec16119af565b6001600160a01b038116610ed757610ed76119af565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f43919061194d565b6001600160a01b031614610f5957610f596119af565b604051630ab714fb60e11b81526001600160a01b0383169063156e29f690610f8990889088908890600401611c0e565b6020604051808303816000875af1158015610fa8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fcc9190611a3b565b610fe85760405162461bcd60e51b815260040161042690611c8a565b846001600160a01b0316826001600160a01b0316886001600160a01b03167f2930d932c1cccd6add2e0e2d706ede9015db8a194405f2a3e1783703515e104f898888604051610aa693929190611c0e565b60008080808061104b86880188611da0565b6001600160a01b03808616600090815260376020526040902054959b5093995091975095509350169050806110925760405162461bcd60e51b81526004016104269061196a565b61109b81611504565b6110a7576110a76119af565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061110b919061194d565b9050866001600160a01b0316816001600160a01b03161461112e5761112e6119af565b6001600160a01b038116611144576111446119af565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa15801561118c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111b0919061194d565b6001600160a01b0316146111c6576111c66119af565b604051635712868360e01b81526001600160a01b038316906357128683906111f690889088908890600401611ee5565b6020604051808303816000875af1158015611215573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112399190611a3b565b6112555760405162461bcd60e51b815260040161042690611c8a565b856001600160a01b0316826001600160a01b0316886001600160a01b03167f17304b99f8dfa5a2b8dd5695d82f9947c2abfbc9cb64bab610b9a1a0feadb9a0888888604051610aa693929190611ee5565b6000806112b583850185611f5a565b9093509150506001600160a01b0382166112d1576112d16119af565b6001600160a01b0382811660009081526037602052604090205416156112f9576112f96119af565b6036546040516bffffffffffffffffffffffff19606085901b166020820152600091611349916001600160a01b039091169060340160405160208183030381529060405280519060200120611599565b6001600160a01b038481166000908152603760205260409081902080546001600160a01b0319169284169283179055516379ccf11760e11b81529192509063f399e22e9061139d9086908690600401611b99565b600060405180830381600087803b1580156113b757600080fd5b505af11580156113cb573d6000803e3d6000fd5b50506040516001600160a01b038085169350861691507f46bd56f98e1b14fd35691959270a6e1edf7cb8fcd489e0f9dda89e46c0d1ff0d90600090a35050505050565b6001600160a01b0384161580159061142e57506001600160a01b03831615155b801561144257506001600160a01b03821615155b801561145657506001600160a01b03811615155b6114b45760405162461bcd60e51b815260206004820152602960248201527f4368696c64455243313135355072656469636174653a204241445f494e49544960448201526820a624ad20aa24a7a760b91b6064820152608401610426565b603380546001600160a01b039586166001600160a01b0319918216179091556034805494861694821694909417909355603580549285169284169290921790915560368054919093169116179055565b6000816001600160a01b03163b60000361152057506000919050565b6040516301ffc9a760e01b8152636cdb3d1360e11b60048201526001600160a01b038316906301ffc9a790602401602060405180830381865afa925050508015611587575060408051601f3d908101601f1916820190925261158491810190611a3b565b60015b61159357506000919050565b92915050565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b0381166115935760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b6044820152606401610426565b6001600160a01b038116811461164557600080fd5b50565b60006020828403121561165a57600080fd5b813561166581611630565b9392505050565b60008083601f84011261167e57600080fd5b5081356001600160401b0381111561169557600080fd5b6020830191508360208260051b85010111156116b057600080fd5b9250929050565b60008060008060008060006080888a0312156116d257600080fd5b87356116dd81611630565b965060208801356001600160401b03808211156116f957600080fd5b6117058b838c0161166c565b909850965060408a013591508082111561171e57600080fd5b61172a8b838c0161166c565b909650945060608a013591508082111561174357600080fd5b506117508a828b0161166c565b989b979a50959850939692959293505050565b60008060006060848603121561177857600080fd5b833561178381611630565b95602085013595506040909401359392505050565b600080600080608085870312156117ae57600080fd5b84356117b981611630565b935060208501356117c981611630565b93969395505050506040820135916060013590565b600080600080606085870312156117f457600080fd5b84359350602085013561180681611630565b925060408501356001600160401b038082111561182257600080fd5b818701915087601f83011261183657600080fd5b81358181111561184557600080fd5b88602082850101111561185757600080fd5b95989497505060200194505050565b6000806000806080858703121561187c57600080fd5b843561188781611630565b9350602085013561189781611630565b925060408501356118a781611630565b915060608501356118b781611630565b939692955090935050565b600080858511156118d257600080fd5b838611156118df57600080fd5b5050820193919092039150565b8035602083101561159357600019602084900360031b1b1692915050565b60208082526023908201527f4368696c64455243313135355072656469636174653a204e4f545f434f4e54526040820152621050d560ea1b606082015260800190565b60006020828403121561195f57600080fd5b815161166581611630565b60208082526025908201527f4368696c64455243313135355072656469636174653a20554e4d41505045445f6040820152642a27a5a2a760d91b606082015260800190565b634e487b7160e01b600052600160045260246000fd5b81835260006001600160fb1b038311156119de57600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b0386168152606060208201819052600090611a1c90830186886119c5565b8281036040840152611a2f8185876119c5565b98975050505050505050565b600060208284031215611a4d57600080fd5b8151801515811461166557600080fd5b60208082526022908201527f4368696c64455243313135355072656469636174653a204255524e5f4641494c604082015261115160f21b606082015260800190565b8183526000602080850194508260005b85811015611add578135611ac281611630565b6001600160a01b031687529582019590820190600101611aaf565b509495945050505050565b8981526001600160a01b0389811660208301528816604082015260c060608201819052600090611b1b908301888a611a9f565b8281036080840152611b2e8187896119c5565b905082810360a0840152611b438185876119c5565b9c9b505050505050505050505050565b6000815180845260005b81811015611b7957602081850181015186830182015201611b5d565b506000602082860101526020601f19601f83011685010191505092915050565b6001600160a01b0383168152604060208201819052600090611bbd90830184611b53565b949350505050565b606081526000611bd960608301888a611a9f565b8281036020840152611bec8187896119c5565b90508281036040840152611c018185876119c5565b9998505050505050505050565b6001600160a01b039390931683526020830191909152604082015260600190565b600080600080600060a08688031215611c4757600080fd5b8535611c5281611630565b94506020860135611c6281611630565b93506040860135611c7281611630565b94979396509394606081013594506080013592915050565b60208082526022908201527f4368696c64455243313135355072656469636174653a204d494e545f4641494c604082015261115160f21b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715611d0a57611d0a611ccc565b604052919050565b60006001600160401b03821115611d2b57611d2b611ccc565b5060051b60200190565b600082601f830112611d4657600080fd5b81356020611d5b611d5683611d12565b611ce2565b82815260059290921b84018101918181019086841115611d7a57600080fd5b8286015b84811015611d955780358352918301918301611d7e565b509695505050505050565b60008060008060008060c08789031215611db957600080fd5b86359550602080880135611dcc81611630565b95506040880135611ddc81611630565b945060608801356001600160401b0380821115611df857600080fd5b818a0191508a601f830112611e0c57600080fd5b8135611e1a611d5682611d12565b81815260059190911b8301840190848101908d831115611e3957600080fd5b938501935b82851015611e60578435611e5181611630565b82529385019390850190611e3e565b9750505060808a0135925080831115611e7857600080fd5b611e848b848c01611d35565b945060a08a0135925080831115611e9a57600080fd5b5050611ea889828a01611d35565b9150509295509295509295565b600081518084526020808501945080840160005b83811015611add57815187529582019590820190600101611ec9565b606080825284519082018190526000906020906080840190828801845b82811015611f275781516001600160a01b031684529284019290840190600101611f02565b50505083810382850152611f3b8187611eb5565b9150508281036040840152611f508185611eb5565b9695505050505050565b600080600060608486031215611f6f57600080fd5b83359250602080850135611f8281611630565b925060408501356001600160401b0380821115611f9e57600080fd5b818701915087601f830112611fb257600080fd5b813581811115611fc457611fc4611ccc565b611fd6601f8201601f19168501611ce2565b91508082528884828501011115611fec57600080fd5b8084840185840137600084828401015250809350505050925092509256fea26469706673582212209e5ec9c7e81df1c7e5f79d00b92077b70b934e338148ee522cc77885369daf6d64736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101585760003560e01c806397e5230d116100c3578063d41f17711161007c578063d41f1771146102de578063d7c9e3ec14610305578063e0563ab11461032c578063eeb4994514610335578063f645125514610348578063f8c8765e1461036f57600080fd5b806397e5230d1461024d578063b176806514610257578063b5c5f6721461027e578063b68ad1e414610291578063b8cd3ec0146102a4578063c5ac2b1c146102b757600080fd5b806351351d531161011557806351351d53146101d357806355b01e4d146101e15780635ea5df79146101ef5780637efab4f51461020657806386937eb41461022f578063947287cf1461024457600080fd5b8063051eb2e21461015d57806305dc2e8f1461018d57806307b3e252146101a05780631bc114ba146101ae578063284017f5146101c15780633b878c22146101ca575b600080fd5b603554610170906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b603454610170906001600160a01b031681565b6101706004600360981b0181565b603354610170906001600160a01b031681565b61017061202081565b61017061101081565b6101706002600160a01b0381565b6101706004600160991b0181565b6101f861138881565b604051908152602001610184565b610170610214366004611648565b6037602052600090815260409020546001600160a01b031681565b61024261023d3660046116b7565b610382565b005b6101f861520881565b6101f8620249f081565b6101f87f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b61024261028c366004611763565b61039a565b603654610170906001600160a01b031681565b6102426102b2366004611798565b6103ab565b6101f87faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b6101f87f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b6101f87f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b61017061203081565b6102426103433660046117de565b6103bd565b6101f87f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b61024261037d366004611866565b6105dd565b6103918787878787878761073a565b50505050505050565b6103a683338484610ab9565b505050565b6103b784848484610ab9565b50505050565b6034546001600160a01b0316331461042f5760405162461bcd60e51b815260206004820152602a60248201527f4368696c64455243313135355072656469636174653a204f4e4c595f5354415460448201526922afa922a1a2a4ab22a960b11b60648201526084015b60405180910390fd5b6035546001600160a01b0384811691161461049f5760405162461bcd60e51b815260206004820152602a60248201527f4368696c64455243313135355072656469636174653a204f4e4c595f524f4f546044820152695f50524544494341544560b01b6064820152608401610426565b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f8216104ce6020600084866118c2565b6104d7916118ec565b036104f6576104f16104ec82602081866118c2565b610dce565b6103b7565b7faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d186105256020600084866118c2565b61052e916118ec565b0361053d576104f18282611039565b7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad61056c6020600084866118c2565b610575916118ec565b03610584576104f182826112a6565b60405162461bcd60e51b815260206004820152602860248201527f4368696c64455243313135355072656469636174653a20494e56414c49445f5360448201526749474e415455524560c01b6064820152608401610426565b336002600160a01b03146106215760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b6044820152606401610426565b600054610100900460ff16158080156106415750600054600160ff909116105b8061065b5750303b15801561065b575060005460ff166001145b6106be5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610426565b6000805460ff1916600117905580156106e1576000805461ff0019166101001790555b6106ed8585858561140e565b8015610733576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b8661074481611504565b6107605760405162461bcd60e51b81526004016104269061190a565b6000886001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107c4919061194d565b6001600160a01b038181166000908152603760205260409020549192508a81169116146108035760405162461bcd60e51b81526004016104269061196a565b6001600160a01b038116610819576108196119af565b306001600160a01b0316896001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610861573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610885919061194d565b6001600160a01b03161461089b5761089b6119af565b86851480156108a957508483145b6109035760405162461bcd60e51b815260206004820152602560248201527f4368696c64455243313135355072656469636174653a20494e56414c49445f4c60448201526408a9c8ea8960db1b6064820152608401610426565b604051631ac8311560e21b81526001600160a01b038a1690636b20c454906109379033908a908a908a908a906004016119f7565b6020604051808303816000875af1158015610956573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097a9190611a3b565b6109965760405162461bcd60e51b815260040161042690611a5d565b6033546035546040516001600160a01b03928316926316f198319216906109f1907f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed290869033908f908f908f908f908f908f90602001611ae8565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610a1d929190611b99565b600060405180830381600087803b158015610a3757600080fd5b505af1158015610a4b573d6000803e3d6000fd5b50505050336001600160a01b0316896001600160a01b0316826001600160a01b03167f7a10660242ca367951ff3777cdb3c2a761e3ccad204bac118501e24693f3683d8b8b8b8b8b8b604051610aa696959493929190611bc5565b60405180910390a4505050505050505050565b83610ac381611504565b610adf5760405162461bcd60e51b81526004016104269061190a565b6000856001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b43919061194d565b6001600160a01b03818116600090815260376020526040902054919250878116911614610b825760405162461bcd60e51b81526004016104269061196a565b6001600160a01b038116610b9857610b986119af565b306001600160a01b0316866001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610be0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c04919061194d565b6001600160a01b031614610c1a57610c1a6119af565b604051637a94c56560e11b81526001600160a01b0387169063f5298aca90610c4a90339088908890600401611c0e565b6020604051808303816000875af1158015610c69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c8d9190611a3b565b610ca95760405162461bcd60e51b815260040161042690611a5d565b603354603554604080517f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286960208201526001600160a01b0385811682840152336060830152898116608083015260a0820189905260c08083018990528351808403909101815260e08301938490526316f1983160e01b909352938416936316f1983193610d3b9391169160e401611b99565b600060405180830381600087803b158015610d5557600080fd5b505af1158015610d69573d6000803e3d6000fd5b50505050846001600160a01b0316866001600160a01b0316826001600160a01b03167f2ca9093e8b5356801039806c6a08003e5b7013fb8ae48f720fc90fc1c1a8bec2338888604051610dbe93929190611c0e565b60405180910390a4505050505050565b600080808080610de086880188611c2f565b6001600160a01b03808616600090815260376020526040902054959a50939850919650945092501680610e255760405162461bcd60e51b81526004016104269061196a565b610e2e81611504565b610e3a57610e3a6119af565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e9e919061194d565b9050866001600160a01b0316816001600160a01b031614610ec157610ec16119af565b6001600160a01b038116610ed757610ed76119af565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f43919061194d565b6001600160a01b031614610f5957610f596119af565b604051630ab714fb60e11b81526001600160a01b0383169063156e29f690610f8990889088908890600401611c0e565b6020604051808303816000875af1158015610fa8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fcc9190611a3b565b610fe85760405162461bcd60e51b815260040161042690611c8a565b846001600160a01b0316826001600160a01b0316886001600160a01b03167f2930d932c1cccd6add2e0e2d706ede9015db8a194405f2a3e1783703515e104f898888604051610aa693929190611c0e565b60008080808061104b86880188611da0565b6001600160a01b03808616600090815260376020526040902054959b5093995091975095509350169050806110925760405162461bcd60e51b81526004016104269061196a565b61109b81611504565b6110a7576110a76119af565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061110b919061194d565b9050866001600160a01b0316816001600160a01b03161461112e5761112e6119af565b6001600160a01b038116611144576111446119af565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa15801561118c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111b0919061194d565b6001600160a01b0316146111c6576111c66119af565b604051635712868360e01b81526001600160a01b038316906357128683906111f690889088908890600401611ee5565b6020604051808303816000875af1158015611215573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112399190611a3b565b6112555760405162461bcd60e51b815260040161042690611c8a565b856001600160a01b0316826001600160a01b0316886001600160a01b03167f17304b99f8dfa5a2b8dd5695d82f9947c2abfbc9cb64bab610b9a1a0feadb9a0888888604051610aa693929190611ee5565b6000806112b583850185611f5a565b9093509150506001600160a01b0382166112d1576112d16119af565b6001600160a01b0382811660009081526037602052604090205416156112f9576112f96119af565b6036546040516bffffffffffffffffffffffff19606085901b166020820152600091611349916001600160a01b039091169060340160405160208183030381529060405280519060200120611599565b6001600160a01b038481166000908152603760205260409081902080546001600160a01b0319169284169283179055516379ccf11760e11b81529192509063f399e22e9061139d9086908690600401611b99565b600060405180830381600087803b1580156113b757600080fd5b505af11580156113cb573d6000803e3d6000fd5b50506040516001600160a01b038085169350861691507f46bd56f98e1b14fd35691959270a6e1edf7cb8fcd489e0f9dda89e46c0d1ff0d90600090a35050505050565b6001600160a01b0384161580159061142e57506001600160a01b03831615155b801561144257506001600160a01b03821615155b801561145657506001600160a01b03811615155b6114b45760405162461bcd60e51b815260206004820152602960248201527f4368696c64455243313135355072656469636174653a204241445f494e49544960448201526820a624ad20aa24a7a760b91b6064820152608401610426565b603380546001600160a01b039586166001600160a01b0319918216179091556034805494861694821694909417909355603580549285169284169290921790915560368054919093169116179055565b6000816001600160a01b03163b60000361152057506000919050565b6040516301ffc9a760e01b8152636cdb3d1360e11b60048201526001600160a01b038316906301ffc9a790602401602060405180830381865afa925050508015611587575060408051601f3d908101601f1916820190925261158491810190611a3b565b60015b61159357506000919050565b92915050565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b0381166115935760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b6044820152606401610426565b6001600160a01b038116811461164557600080fd5b50565b60006020828403121561165a57600080fd5b813561166581611630565b9392505050565b60008083601f84011261167e57600080fd5b5081356001600160401b0381111561169557600080fd5b6020830191508360208260051b85010111156116b057600080fd5b9250929050565b60008060008060008060006080888a0312156116d257600080fd5b87356116dd81611630565b965060208801356001600160401b03808211156116f957600080fd5b6117058b838c0161166c565b909850965060408a013591508082111561171e57600080fd5b61172a8b838c0161166c565b909650945060608a013591508082111561174357600080fd5b506117508a828b0161166c565b989b979a50959850939692959293505050565b60008060006060848603121561177857600080fd5b833561178381611630565b95602085013595506040909401359392505050565b600080600080608085870312156117ae57600080fd5b84356117b981611630565b935060208501356117c981611630565b93969395505050506040820135916060013590565b600080600080606085870312156117f457600080fd5b84359350602085013561180681611630565b925060408501356001600160401b038082111561182257600080fd5b818701915087601f83011261183657600080fd5b81358181111561184557600080fd5b88602082850101111561185757600080fd5b95989497505060200194505050565b6000806000806080858703121561187c57600080fd5b843561188781611630565b9350602085013561189781611630565b925060408501356118a781611630565b915060608501356118b781611630565b939692955090935050565b600080858511156118d257600080fd5b838611156118df57600080fd5b5050820193919092039150565b8035602083101561159357600019602084900360031b1b1692915050565b60208082526023908201527f4368696c64455243313135355072656469636174653a204e4f545f434f4e54526040820152621050d560ea1b606082015260800190565b60006020828403121561195f57600080fd5b815161166581611630565b60208082526025908201527f4368696c64455243313135355072656469636174653a20554e4d41505045445f6040820152642a27a5a2a760d91b606082015260800190565b634e487b7160e01b600052600160045260246000fd5b81835260006001600160fb1b038311156119de57600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b0386168152606060208201819052600090611a1c90830186886119c5565b8281036040840152611a2f8185876119c5565b98975050505050505050565b600060208284031215611a4d57600080fd5b8151801515811461166557600080fd5b60208082526022908201527f4368696c64455243313135355072656469636174653a204255524e5f4641494c604082015261115160f21b606082015260800190565b8183526000602080850194508260005b85811015611add578135611ac281611630565b6001600160a01b031687529582019590820190600101611aaf565b509495945050505050565b8981526001600160a01b0389811660208301528816604082015260c060608201819052600090611b1b908301888a611a9f565b8281036080840152611b2e8187896119c5565b905082810360a0840152611b438185876119c5565b9c9b505050505050505050505050565b6000815180845260005b81811015611b7957602081850181015186830182015201611b5d565b506000602082860101526020601f19601f83011685010191505092915050565b6001600160a01b0383168152604060208201819052600090611bbd90830184611b53565b949350505050565b606081526000611bd960608301888a611a9f565b8281036020840152611bec8187896119c5565b90508281036040840152611c018185876119c5565b9998505050505050505050565b6001600160a01b039390931683526020830191909152604082015260600190565b600080600080600060a08688031215611c4757600080fd5b8535611c5281611630565b94506020860135611c6281611630565b93506040860135611c7281611630565b94979396509394606081013594506080013592915050565b60208082526022908201527f4368696c64455243313135355072656469636174653a204d494e545f4641494c604082015261115160f21b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715611d0a57611d0a611ccc565b604052919050565b60006001600160401b03821115611d2b57611d2b611ccc565b5060051b60200190565b600082601f830112611d4657600080fd5b81356020611d5b611d5683611d12565b611ce2565b82815260059290921b84018101918181019086841115611d7a57600080fd5b8286015b84811015611d955780358352918301918301611d7e565b509695505050505050565b60008060008060008060c08789031215611db957600080fd5b86359550602080880135611dcc81611630565b95506040880135611ddc81611630565b945060608801356001600160401b0380821115611df857600080fd5b818a0191508a601f830112611e0c57600080fd5b8135611e1a611d5682611d12565b81815260059190911b8301840190848101908d831115611e3957600080fd5b938501935b82851015611e60578435611e5181611630565b82529385019390850190611e3e565b9750505060808a0135925080831115611e7857600080fd5b611e848b848c01611d35565b945060a08a0135925080831115611e9a57600080fd5b5050611ea889828a01611d35565b9150509295509295509295565b600081518084526020808501945080840160005b83811015611add57815187529582019590820190600101611ec9565b606080825284519082018190526000906020906080840190828801845b82811015611f275781516001600160a01b031684529284019290840190600101611f02565b50505083810382850152611f3b8187611eb5565b9150508281036040840152611f508185611eb5565b9695505050505050565b600080600060608486031215611f6f57600080fd5b83359250602080850135611f8281611630565b925060408501356001600160401b0380821115611f9e57600080fd5b818701915087601f830112611fb257600080fd5b813581811115611fc457611fc4611ccc565b611fd6601f8201601f19168501611ce2565b91508082528884828501011115611fec57600080fd5b8084840185840137600084828401015250809350505050925092509256fea26469706673582212209e5ec9c7e81df1c7e5f79d00b92077b70b934e338148ee522cc77885369daf6d64736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var ChildERC1155PredicateACLArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"ChildERC1155PredicateAccessList\",\n \"sourceName\": \"contracts/child/ChildERC1155PredicateAccessList.sol\",\n \"abi\": [\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"only\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"Unauthorized\",\n \"type\": \"error\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"block\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bool\",\n \"name\": \"status\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"AllowListUsageSet\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"block\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bool\",\n \"name\": \"status\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"BlockListUsageSet\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2ERC1155Deposit\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"amounts\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"L2ERC1155DepositBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2ERC1155Withdraw\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"amounts\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"L2ERC1155WithdrawBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"L2TokenMapped\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"previousOwner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"OwnershipTransferStarted\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"previousOwner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"OwnershipTransferred\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"ALLOWLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"BLOCKLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAP_TOKEN_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TOKEN_CONTRACT\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"READ_ADDRESSLIST_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"SYSTEM\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"acceptOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childTokenTemplate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newL2StateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newStateReceiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newRootERC1155Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseAllowList\",\n \"type\": \"bool\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseBlockList\",\n \"type\": \"bool\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newL2StateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newStateReceiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newRootERC1155Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"l2StateSender\",\n \"outputs\": [\n {\n \"internalType\": \"contract IStateSender\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onStateReceive\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"owner\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"pendingOwner\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"renounceOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"rootERC1155Predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"rootTokenToChildToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseAllowList\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"setAllowList\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseBlockList\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"setBlockList\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"stateReceiver\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"transferOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC1155\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"withdraw\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC1155\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"amounts\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"withdrawBatch\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC1155\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"withdrawTo\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b506127d8806100206000396000f3fe608060405234801561001057600080fd5b50600436106101b05760003560e01c8063b1768065116100ef578063d7c9e3ec11610092578063d7c9e3ec146103a5578063d8dd1773146103cc578063e0563ab1146103df578063e30c3978146103e8578063eeb49945146103f9578063f2fde38b1461040c578063f64512551461041f578063f8c8765e1461044657600080fd5b8063b1768065146102d1578063b5c5f672146102f8578063b68ad1e41461030b578063b8cd3ec01461031e578063c1225a2014610331578063c5ac2b1c14610344578063c5e4683a1461036b578063d41f17711461037e57600080fd5b80635ea5df79116101575780635ea5df7914610247578063715018a61461025e57806379ba5097146102685780637efab4f51461027057806386937eb41461029a5780638da5cb5b146102ad578063947287cf146102be57806397e5230d146102c757600080fd5b8063051eb2e2146101b557806305dc2e8f146101e557806307b3e252146101f85780631bc114ba14610206578063284017f5146102195780633b878c221461022257806351351d531461022b57806355b01e4d14610239575b600080fd5b60fe546101c8906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b60fd546101c8906001600160a01b031681565b6101c86004600360981b0181565b60fc546101c8906001600160a01b031681565b6101c861202081565b6101c861101081565b6101c86002600160a01b0381565b6101c86004600160991b0181565b61025061138881565b6040519081526020016101dc565b610266610459565b005b61026661046d565b6101c861027e366004611c73565b610100602052600090815260409020546001600160a01b031681565b6102666102a8366004611ce2565b6104ec565b6033546001600160a01b03166101c8565b61025061520881565b610250620249f081565b6102507f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b610266610306366004611d8e565b61050c565b60ff546101c8906001600160a01b031681565b61026661032c366004611dc3565b610525565b61026661033f366004611e17565b61053f565b6102507faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b610266610379366004611e17565b61058e565b6102507f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b6102507f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b6102666103da366004611e34565b6105d5565b6101c861203081565b6065546001600160a01b03166101c8565b610266610407366004611eca565b6106f6565b61026661041a366004611c73565b610911565b6102507f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b610266610454366004611f52565b610982565b610461610a7b565b61046b6000610ad5565b565b60655433906001600160a01b031681146104e05760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084015b60405180910390fd5b6104e981610ad5565b50565b6104f4610aee565b61050387878787878787610af6565b50505050505050565b610514610aee565b61052083338484610e76565b505050565b61052d610aee565b61053984848484610e76565b50505050565b610547610a7b565b60c9805461ff0019166101008315159081029190911790915560405143907f61d574757cde41a357d030b39b2705796ccd699578037ab9a1cfd8117d82bf8690600090a350565b610596610a7b565b60c9805460ff191682151590811790915560405143907fe0a0f0fa52db091cb71c202d80420311430ce1ae2e7794149877b6720ce8bf0b90600090a350565b336002600160a01b03146105fc5760405163973d02cb60e01b81526004016104d790611fae565b600054610100900460ff161580801561061c5750600054600160ff909116105b806106365750303b158015610636575060005460ff166001145b6106525760405162461bcd60e51b81526004016104d790611fd2565b6000805460ff191660011790558015610675576000805461ff0019166101001790555b6106818888888861118c565b60c9805461ffff191685151561ff00191617610100851515021790556106a682610ad5565b80156106ec576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b60fd546001600160a01b031633146107635760405162461bcd60e51b815260206004820152602a60248201527f4368696c64455243313135355072656469636174653a204f4e4c595f5354415460448201526922afa922a1a2a4ab22a960b11b60648201526084016104d7565b60fe546001600160a01b038481169116146107d35760405162461bcd60e51b815260206004820152602a60248201527f4368696c64455243313135355072656469636174653a204f4e4c595f524f4f546044820152695f50524544494341544560b01b60648201526084016104d7565b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f821610802602060008486612020565b61080b9161204a565b0361082a576108256108208260208186612020565b611282565b610539565b7faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d18610859602060008486612020565b6108629161204a565b036108715761082582826114ee565b7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad6108a0602060008486612020565b6108a99161204a565b036108b857610825828261175c565b60405162461bcd60e51b815260206004820152602860248201527f4368696c64455243313135355072656469636174653a20494e56414c49445f5360448201526749474e415455524560c01b60648201526084016104d7565b610919610a7b565b606580546001600160a01b0383166001600160a01b0319909116811790915561094a6033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b336002600160a01b03146109a95760405163973d02cb60e01b81526004016104d790611fae565b600054610100900460ff16158080156109c95750600054600160ff909116105b806109e35750303b1580156109e3575060005460ff166001145b6109ff5760405162461bcd60e51b81526004016104d790611fd2565b6000805460ff191660011790558015610a22576000805461ff0019166101001790555b610a2e8585858561118c565b8015610a74576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b6033546001600160a01b0316331461046b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104d7565b606580546001600160a01b03191690556104e9816118c6565b61046b611918565b86610b0081611b32565b610b1c5760405162461bcd60e51b81526004016104d790612068565b6000886001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b5c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8091906120ab565b6001600160a01b03818116600090815261010060205260409020549192508a8116911614610bc05760405162461bcd60e51b81526004016104d7906120c8565b6001600160a01b038116610bd657610bd661210d565b306001600160a01b0316896001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c4291906120ab565b6001600160a01b031614610c5857610c5861210d565b8685148015610c6657508483145b610cc05760405162461bcd60e51b815260206004820152602560248201527f4368696c64455243313135355072656469636174653a20494e56414c49445f4c60448201526408a9c8ea8960db1b60648201526084016104d7565b604051631ac8311560e21b81526001600160a01b038a1690636b20c45490610cf49033908a908a908a908a90600401612155565b6020604051808303816000875af1158015610d13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d379190612199565b610d535760405162461bcd60e51b81526004016104d7906121b6565b60fc5460fe546040516001600160a01b03928316926316f19831921690610dae907f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed290869033908f908f908f908f908f908f90602001612241565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610dda9291906122fc565b600060405180830381600087803b158015610df457600080fd5b505af1158015610e08573d6000803e3d6000fd5b50505050336001600160a01b0316896001600160a01b0316826001600160a01b03167f7a10660242ca367951ff3777cdb3c2a761e3ccad204bac118501e24693f3683d8b8b8b8b8b8b604051610e6396959493929190612328565b60405180910390a4505050505050505050565b83610e8081611b32565b610e9c5760405162461bcd60e51b81526004016104d790612068565b6000856001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610edc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f0091906120ab565b6001600160a01b0381811660009081526101006020526040902054919250878116911614610f405760405162461bcd60e51b81526004016104d7906120c8565b6001600160a01b038116610f5657610f5661210d565b306001600160a01b0316866001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc291906120ab565b6001600160a01b031614610fd857610fd861210d565b604051637a94c56560e11b81526001600160a01b0387169063f5298aca9061100890339088908890600401612371565b6020604051808303816000875af1158015611027573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061104b9190612199565b6110675760405162461bcd60e51b81526004016104d7906121b6565b60fc5460fe54604080517f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286960208201526001600160a01b0385811682840152336060830152898116608083015260a0820189905260c08083018990528351808403909101815260e08301938490526316f1983160e01b909352938416936316f19831936110f99391169160e4016122fc565b600060405180830381600087803b15801561111357600080fd5b505af1158015611127573d6000803e3d6000fd5b50505050846001600160a01b0316866001600160a01b0316826001600160a01b03167f2ca9093e8b5356801039806c6a08003e5b7013fb8ae48f720fc90fc1c1a8bec233888860405161117c93929190612371565b60405180910390a4505050505050565b6001600160a01b038416158015906111ac57506001600160a01b03831615155b80156111c057506001600160a01b03821615155b80156111d457506001600160a01b03811615155b6112325760405162461bcd60e51b815260206004820152602960248201527f4368696c64455243313135355072656469636174653a204241445f494e49544960448201526820a624ad20aa24a7a760b91b60648201526084016104d7565b60fc80546001600160a01b039586166001600160a01b03199182161790915560fd80549486169482169490941790935560fe80549285169284169290921790915560ff8054919093169116179055565b60008080808061129486880188612392565b6001600160a01b0380861660009081526101006020526040902054959a509398509196509450925016806112da5760405162461bcd60e51b81526004016104d7906120c8565b6112e381611b32565b6112ef576112ef61210d565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa15801561132f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061135391906120ab565b9050866001600160a01b0316816001600160a01b0316146113765761137661210d565b6001600160a01b03811661138c5761138c61210d565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113f891906120ab565b6001600160a01b03161461140e5761140e61210d565b604051630ab714fb60e11b81526001600160a01b0383169063156e29f69061143e90889088908890600401612371565b6020604051808303816000875af115801561145d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114819190612199565b61149d5760405162461bcd60e51b81526004016104d7906123ed565b846001600160a01b0316826001600160a01b0316886001600160a01b03167f2930d932c1cccd6add2e0e2d706ede9015db8a194405f2a3e1783703515e104f898888604051610e6393929190612371565b60008080808061150086880188612503565b6001600160a01b0380861660009081526101006020526040902054959b5093995091975095509350169050806115485760405162461bcd60e51b81526004016104d7906120c8565b61155181611b32565b61155d5761155d61210d565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa15801561159d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c191906120ab565b9050866001600160a01b0316816001600160a01b0316146115e4576115e461210d565b6001600160a01b0381166115fa576115fa61210d565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015611642573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061166691906120ab565b6001600160a01b03161461167c5761167c61210d565b604051635712868360e01b81526001600160a01b038316906357128683906116ac90889088908890600401612648565b6020604051808303816000875af11580156116cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ef9190612199565b61170b5760405162461bcd60e51b81526004016104d7906123ed565b856001600160a01b0316826001600160a01b0316886001600160a01b03167f17304b99f8dfa5a2b8dd5695d82f9947c2abfbc9cb64bab610b9a1a0feadb9a0888888604051610e6393929190612648565b60008061176b838501856126bd565b9093509150506001600160a01b0382166117875761178761210d565b6001600160a01b038281166000908152610100602052604090205416156117b0576117b061210d565b60ff546040516bffffffffffffffffffffffff19606085901b166020820152600091611800916001600160a01b039091169060340160405160208183030381529060405280519060200120611bc7565b6001600160a01b03848116600090815261010060205260409081902080546001600160a01b0319169284169283179055516379ccf11760e11b81529192509063f399e22e9061185590869086906004016122fc565b600060405180830381600087803b15801561186f57600080fd5b505af1158015611883573d6000803e3d6000fd5b50506040516001600160a01b038085169350861691507f46bd56f98e1b14fd35691959270a6e1edf7cb8fcd489e0f9dda89e46c0d1ff0d90600090a35050505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60c95460ff1615611a2357604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600160991b01916113889161197a919061276d565b6000604051808303818686fa925050503d80600081146119b6576040519150601f19603f3d011682016040523d82523d6000602084013e6119bb565b606091505b50915091508180156119e057506000818060200190518101906119de9190612789565b115b611a205760405162461bcd60e51b81526020600482015260116024820152702224a9a0a62627aba2a22fa9a2a72222a960791b60448201526064016104d7565b50505b60c954610100900460ff161561046b57604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600360981b019161138891611a8a919061276d565b6000604051808303818686fa925050503d8060008114611ac6576040519150601f19603f3d011682016040523d82523d6000602084013e611acb565b606091505b5091509150818015611af1575080806020019051810190611aec9190612789565b600114155b611b2e5760405162461bcd60e51b815260206004820152600e60248201526d212627a1a5a2a22fa9a2a72222a960911b60448201526064016104d7565b5050565b6000816001600160a01b03163b600003611b4e57506000919050565b6040516301ffc9a760e01b8152636cdb3d1360e11b60048201526001600160a01b038316906301ffc9a790602401602060405180830381865afa925050508015611bb5575060408051601f3d908101601f19168201909252611bb291810190612199565b60015b611bc157506000919050565b92915050565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b038116611bc15760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b60448201526064016104d7565b6001600160a01b03811681146104e957600080fd5b600060208284031215611c8557600080fd5b8135611c9081611c5e565b9392505050565b60008083601f840112611ca957600080fd5b5081356001600160401b03811115611cc057600080fd5b6020830191508360208260051b8501011115611cdb57600080fd5b9250929050565b60008060008060008060006080888a031215611cfd57600080fd5b8735611d0881611c5e565b965060208801356001600160401b0380821115611d2457600080fd5b611d308b838c01611c97565b909850965060408a0135915080821115611d4957600080fd5b611d558b838c01611c97565b909650945060608a0135915080821115611d6e57600080fd5b50611d7b8a828b01611c97565b989b979a50959850939692959293505050565b600080600060608486031215611da357600080fd5b8335611dae81611c5e565b95602085013595506040909401359392505050565b60008060008060808587031215611dd957600080fd5b8435611de481611c5e565b93506020850135611df481611c5e565b93969395505050506040820135916060013590565b80151581146104e957600080fd5b600060208284031215611e2957600080fd5b8135611c9081611e09565b600080600080600080600060e0888a031215611e4f57600080fd5b8735611e5a81611c5e565b96506020880135611e6a81611c5e565b95506040880135611e7a81611c5e565b94506060880135611e8a81611c5e565b93506080880135611e9a81611e09565b925060a0880135611eaa81611e09565b915060c0880135611eba81611c5e565b8091505092959891949750929550565b60008060008060608587031215611ee057600080fd5b843593506020850135611ef281611c5e565b925060408501356001600160401b0380821115611f0e57600080fd5b818701915087601f830112611f2257600080fd5b813581811115611f3157600080fd5b886020828501011115611f4357600080fd5b95989497505060200194505050565b60008060008060808587031215611f6857600080fd5b8435611f7381611c5e565b93506020850135611f8381611c5e565b92506040850135611f9381611c5e565b91506060850135611fa381611c5e565b939692955090935050565b6020808252600a908201526914d654d5115350d0531360b21b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6000808585111561203057600080fd5b8386111561203d57600080fd5b5050820193919092039150565b80356020831015611bc157600019602084900360031b1b1692915050565b60208082526023908201527f4368696c64455243313135355072656469636174653a204e4f545f434f4e54526040820152621050d560ea1b606082015260800190565b6000602082840312156120bd57600080fd5b8151611c9081611c5e565b60208082526025908201527f4368696c64455243313135355072656469636174653a20554e4d41505045445f6040820152642a27a5a2a760d91b606082015260800190565b634e487b7160e01b600052600160045260246000fd5b81835260006001600160fb1b0383111561213c57600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b038616815260606020820181905260009061217a9083018688612123565b828103604084015261218d818587612123565b98975050505050505050565b6000602082840312156121ab57600080fd5b8151611c9081611e09565b60208082526022908201527f4368696c64455243313135355072656469636174653a204255524e5f4641494c604082015261115160f21b606082015260800190565b8183526000602080850194508260005b8581101561223657813561221b81611c5e565b6001600160a01b031687529582019590820190600101612208565b509495945050505050565b8981526001600160a01b0389811660208301528816604082015260c060608201819052600090612274908301888a6121f8565b8281036080840152612287818789612123565b905082810360a084015261229c818587612123565b9c9b505050505050505050505050565b60005b838110156122c75781810151838201526020016122af565b50506000910152565b600081518084526122e88160208601602086016122ac565b601f01601f19169290920160200192915050565b6001600160a01b0383168152604060208201819052600090612320908301846122d0565b949350505050565b60608152600061233c60608301888a6121f8565b828103602084015261234f818789612123565b90508281036040840152612364818587612123565b9998505050505050505050565b6001600160a01b039390931683526020830191909152604082015260600190565b600080600080600060a086880312156123aa57600080fd5b85356123b581611c5e565b945060208601356123c581611c5e565b935060408601356123d581611c5e565b94979396509394606081013594506080013592915050565b60208082526022908201527f4368696c64455243313135355072656469636174653a204d494e545f4641494c604082015261115160f21b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561246d5761246d61242f565b604052919050565b60006001600160401b0382111561248e5761248e61242f565b5060051b60200190565b600082601f8301126124a957600080fd5b813560206124be6124b983612475565b612445565b82815260059290921b840181019181810190868411156124dd57600080fd5b8286015b848110156124f857803583529183019183016124e1565b509695505050505050565b60008060008060008060c0878903121561251c57600080fd5b8635955060208088013561252f81611c5e565b9550604088013561253f81611c5e565b945060608801356001600160401b038082111561255b57600080fd5b818a0191508a601f83011261256f57600080fd5b813561257d6124b982612475565b81815260059190911b8301840190848101908d83111561259c57600080fd5b938501935b828510156125c35784356125b481611c5e565b825293850193908501906125a1565b9750505060808a01359250808311156125db57600080fd5b6125e78b848c01612498565b945060a08a01359250808311156125fd57600080fd5b505061260b89828a01612498565b9150509295509295509295565b600081518084526020808501945080840160005b838110156122365781518752958201959082019060010161262c565b606080825284519082018190526000906020906080840190828801845b8281101561268a5781516001600160a01b031684529284019290840190600101612665565b5050508381038285015261269e8187612618565b91505082810360408401526126b38185612618565b9695505050505050565b6000806000606084860312156126d257600080fd5b833592506020808501356126e581611c5e565b925060408501356001600160401b038082111561270157600080fd5b818701915087601f83011261271557600080fd5b8135818111156127275761272761242f565b612739601f8201601f19168501612445565b9150808252888482850101111561274f57600080fd5b80848401858401376000848284010152508093505050509250925092565b6000825161277f8184602087016122ac565b9190910192915050565b60006020828403121561279b57600080fd5b505191905056fea26469706673582212203a31f88332ccb328b6f5d85c4214142bbdd2dfd217a190599f91a6ebebb2eda764736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101b05760003560e01c8063b1768065116100ef578063d7c9e3ec11610092578063d7c9e3ec146103a5578063d8dd1773146103cc578063e0563ab1146103df578063e30c3978146103e8578063eeb49945146103f9578063f2fde38b1461040c578063f64512551461041f578063f8c8765e1461044657600080fd5b8063b1768065146102d1578063b5c5f672146102f8578063b68ad1e41461030b578063b8cd3ec01461031e578063c1225a2014610331578063c5ac2b1c14610344578063c5e4683a1461036b578063d41f17711461037e57600080fd5b80635ea5df79116101575780635ea5df7914610247578063715018a61461025e57806379ba5097146102685780637efab4f51461027057806386937eb41461029a5780638da5cb5b146102ad578063947287cf146102be57806397e5230d146102c757600080fd5b8063051eb2e2146101b557806305dc2e8f146101e557806307b3e252146101f85780631bc114ba14610206578063284017f5146102195780633b878c221461022257806351351d531461022b57806355b01e4d14610239575b600080fd5b60fe546101c8906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b60fd546101c8906001600160a01b031681565b6101c86004600360981b0181565b60fc546101c8906001600160a01b031681565b6101c861202081565b6101c861101081565b6101c86002600160a01b0381565b6101c86004600160991b0181565b61025061138881565b6040519081526020016101dc565b610266610459565b005b61026661046d565b6101c861027e366004611c73565b610100602052600090815260409020546001600160a01b031681565b6102666102a8366004611ce2565b6104ec565b6033546001600160a01b03166101c8565b61025061520881565b610250620249f081565b6102507f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b610266610306366004611d8e565b61050c565b60ff546101c8906001600160a01b031681565b61026661032c366004611dc3565b610525565b61026661033f366004611e17565b61053f565b6102507faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b610266610379366004611e17565b61058e565b6102507f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b6102507f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b6102666103da366004611e34565b6105d5565b6101c861203081565b6065546001600160a01b03166101c8565b610266610407366004611eca565b6106f6565b61026661041a366004611c73565b610911565b6102507f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b610266610454366004611f52565b610982565b610461610a7b565b61046b6000610ad5565b565b60655433906001600160a01b031681146104e05760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084015b60405180910390fd5b6104e981610ad5565b50565b6104f4610aee565b61050387878787878787610af6565b50505050505050565b610514610aee565b61052083338484610e76565b505050565b61052d610aee565b61053984848484610e76565b50505050565b610547610a7b565b60c9805461ff0019166101008315159081029190911790915560405143907f61d574757cde41a357d030b39b2705796ccd699578037ab9a1cfd8117d82bf8690600090a350565b610596610a7b565b60c9805460ff191682151590811790915560405143907fe0a0f0fa52db091cb71c202d80420311430ce1ae2e7794149877b6720ce8bf0b90600090a350565b336002600160a01b03146105fc5760405163973d02cb60e01b81526004016104d790611fae565b600054610100900460ff161580801561061c5750600054600160ff909116105b806106365750303b158015610636575060005460ff166001145b6106525760405162461bcd60e51b81526004016104d790611fd2565b6000805460ff191660011790558015610675576000805461ff0019166101001790555b6106818888888861118c565b60c9805461ffff191685151561ff00191617610100851515021790556106a682610ad5565b80156106ec576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b60fd546001600160a01b031633146107635760405162461bcd60e51b815260206004820152602a60248201527f4368696c64455243313135355072656469636174653a204f4e4c595f5354415460448201526922afa922a1a2a4ab22a960b11b60648201526084016104d7565b60fe546001600160a01b038481169116146107d35760405162461bcd60e51b815260206004820152602a60248201527f4368696c64455243313135355072656469636174653a204f4e4c595f524f4f546044820152695f50524544494341544560b01b60648201526084016104d7565b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f821610802602060008486612020565b61080b9161204a565b0361082a576108256108208260208186612020565b611282565b610539565b7faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d18610859602060008486612020565b6108629161204a565b036108715761082582826114ee565b7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad6108a0602060008486612020565b6108a99161204a565b036108b857610825828261175c565b60405162461bcd60e51b815260206004820152602860248201527f4368696c64455243313135355072656469636174653a20494e56414c49445f5360448201526749474e415455524560c01b60648201526084016104d7565b610919610a7b565b606580546001600160a01b0383166001600160a01b0319909116811790915561094a6033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b336002600160a01b03146109a95760405163973d02cb60e01b81526004016104d790611fae565b600054610100900460ff16158080156109c95750600054600160ff909116105b806109e35750303b1580156109e3575060005460ff166001145b6109ff5760405162461bcd60e51b81526004016104d790611fd2565b6000805460ff191660011790558015610a22576000805461ff0019166101001790555b610a2e8585858561118c565b8015610a74576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b6033546001600160a01b0316331461046b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104d7565b606580546001600160a01b03191690556104e9816118c6565b61046b611918565b86610b0081611b32565b610b1c5760405162461bcd60e51b81526004016104d790612068565b6000886001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b5c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8091906120ab565b6001600160a01b03818116600090815261010060205260409020549192508a8116911614610bc05760405162461bcd60e51b81526004016104d7906120c8565b6001600160a01b038116610bd657610bd661210d565b306001600160a01b0316896001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c4291906120ab565b6001600160a01b031614610c5857610c5861210d565b8685148015610c6657508483145b610cc05760405162461bcd60e51b815260206004820152602560248201527f4368696c64455243313135355072656469636174653a20494e56414c49445f4c60448201526408a9c8ea8960db1b60648201526084016104d7565b604051631ac8311560e21b81526001600160a01b038a1690636b20c45490610cf49033908a908a908a908a90600401612155565b6020604051808303816000875af1158015610d13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d379190612199565b610d535760405162461bcd60e51b81526004016104d7906121b6565b60fc5460fe546040516001600160a01b03928316926316f19831921690610dae907f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed290869033908f908f908f908f908f908f90602001612241565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610dda9291906122fc565b600060405180830381600087803b158015610df457600080fd5b505af1158015610e08573d6000803e3d6000fd5b50505050336001600160a01b0316896001600160a01b0316826001600160a01b03167f7a10660242ca367951ff3777cdb3c2a761e3ccad204bac118501e24693f3683d8b8b8b8b8b8b604051610e6396959493929190612328565b60405180910390a4505050505050505050565b83610e8081611b32565b610e9c5760405162461bcd60e51b81526004016104d790612068565b6000856001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610edc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f0091906120ab565b6001600160a01b0381811660009081526101006020526040902054919250878116911614610f405760405162461bcd60e51b81526004016104d7906120c8565b6001600160a01b038116610f5657610f5661210d565b306001600160a01b0316866001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc291906120ab565b6001600160a01b031614610fd857610fd861210d565b604051637a94c56560e11b81526001600160a01b0387169063f5298aca9061100890339088908890600401612371565b6020604051808303816000875af1158015611027573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061104b9190612199565b6110675760405162461bcd60e51b81526004016104d7906121b6565b60fc5460fe54604080517f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286960208201526001600160a01b0385811682840152336060830152898116608083015260a0820189905260c08083018990528351808403909101815260e08301938490526316f1983160e01b909352938416936316f19831936110f99391169160e4016122fc565b600060405180830381600087803b15801561111357600080fd5b505af1158015611127573d6000803e3d6000fd5b50505050846001600160a01b0316866001600160a01b0316826001600160a01b03167f2ca9093e8b5356801039806c6a08003e5b7013fb8ae48f720fc90fc1c1a8bec233888860405161117c93929190612371565b60405180910390a4505050505050565b6001600160a01b038416158015906111ac57506001600160a01b03831615155b80156111c057506001600160a01b03821615155b80156111d457506001600160a01b03811615155b6112325760405162461bcd60e51b815260206004820152602960248201527f4368696c64455243313135355072656469636174653a204241445f494e49544960448201526820a624ad20aa24a7a760b91b60648201526084016104d7565b60fc80546001600160a01b039586166001600160a01b03199182161790915560fd80549486169482169490941790935560fe80549285169284169290921790915560ff8054919093169116179055565b60008080808061129486880188612392565b6001600160a01b0380861660009081526101006020526040902054959a509398509196509450925016806112da5760405162461bcd60e51b81526004016104d7906120c8565b6112e381611b32565b6112ef576112ef61210d565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa15801561132f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061135391906120ab565b9050866001600160a01b0316816001600160a01b0316146113765761137661210d565b6001600160a01b03811661138c5761138c61210d565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113f891906120ab565b6001600160a01b03161461140e5761140e61210d565b604051630ab714fb60e11b81526001600160a01b0383169063156e29f69061143e90889088908890600401612371565b6020604051808303816000875af115801561145d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114819190612199565b61149d5760405162461bcd60e51b81526004016104d7906123ed565b846001600160a01b0316826001600160a01b0316886001600160a01b03167f2930d932c1cccd6add2e0e2d706ede9015db8a194405f2a3e1783703515e104f898888604051610e6393929190612371565b60008080808061150086880188612503565b6001600160a01b0380861660009081526101006020526040902054959b5093995091975095509350169050806115485760405162461bcd60e51b81526004016104d7906120c8565b61155181611b32565b61155d5761155d61210d565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa15801561159d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c191906120ab565b9050866001600160a01b0316816001600160a01b0316146115e4576115e461210d565b6001600160a01b0381166115fa576115fa61210d565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015611642573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061166691906120ab565b6001600160a01b03161461167c5761167c61210d565b604051635712868360e01b81526001600160a01b038316906357128683906116ac90889088908890600401612648565b6020604051808303816000875af11580156116cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ef9190612199565b61170b5760405162461bcd60e51b81526004016104d7906123ed565b856001600160a01b0316826001600160a01b0316886001600160a01b03167f17304b99f8dfa5a2b8dd5695d82f9947c2abfbc9cb64bab610b9a1a0feadb9a0888888604051610e6393929190612648565b60008061176b838501856126bd565b9093509150506001600160a01b0382166117875761178761210d565b6001600160a01b038281166000908152610100602052604090205416156117b0576117b061210d565b60ff546040516bffffffffffffffffffffffff19606085901b166020820152600091611800916001600160a01b039091169060340160405160208183030381529060405280519060200120611bc7565b6001600160a01b03848116600090815261010060205260409081902080546001600160a01b0319169284169283179055516379ccf11760e11b81529192509063f399e22e9061185590869086906004016122fc565b600060405180830381600087803b15801561186f57600080fd5b505af1158015611883573d6000803e3d6000fd5b50506040516001600160a01b038085169350861691507f46bd56f98e1b14fd35691959270a6e1edf7cb8fcd489e0f9dda89e46c0d1ff0d90600090a35050505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60c95460ff1615611a2357604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600160991b01916113889161197a919061276d565b6000604051808303818686fa925050503d80600081146119b6576040519150601f19603f3d011682016040523d82523d6000602084013e6119bb565b606091505b50915091508180156119e057506000818060200190518101906119de9190612789565b115b611a205760405162461bcd60e51b81526020600482015260116024820152702224a9a0a62627aba2a22fa9a2a72222a960791b60448201526064016104d7565b50505b60c954610100900460ff161561046b57604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600360981b019161138891611a8a919061276d565b6000604051808303818686fa925050503d8060008114611ac6576040519150601f19603f3d011682016040523d82523d6000602084013e611acb565b606091505b5091509150818015611af1575080806020019051810190611aec9190612789565b600114155b611b2e5760405162461bcd60e51b815260206004820152600e60248201526d212627a1a5a2a22fa9a2a72222a960911b60448201526064016104d7565b5050565b6000816001600160a01b03163b600003611b4e57506000919050565b6040516301ffc9a760e01b8152636cdb3d1360e11b60048201526001600160a01b038316906301ffc9a790602401602060405180830381865afa925050508015611bb5575060408051601f3d908101601f19168201909252611bb291810190612199565b60015b611bc157506000919050565b92915050565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b038116611bc15760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b60448201526064016104d7565b6001600160a01b03811681146104e957600080fd5b600060208284031215611c8557600080fd5b8135611c9081611c5e565b9392505050565b60008083601f840112611ca957600080fd5b5081356001600160401b03811115611cc057600080fd5b6020830191508360208260051b8501011115611cdb57600080fd5b9250929050565b60008060008060008060006080888a031215611cfd57600080fd5b8735611d0881611c5e565b965060208801356001600160401b0380821115611d2457600080fd5b611d308b838c01611c97565b909850965060408a0135915080821115611d4957600080fd5b611d558b838c01611c97565b909650945060608a0135915080821115611d6e57600080fd5b50611d7b8a828b01611c97565b989b979a50959850939692959293505050565b600080600060608486031215611da357600080fd5b8335611dae81611c5e565b95602085013595506040909401359392505050565b60008060008060808587031215611dd957600080fd5b8435611de481611c5e565b93506020850135611df481611c5e565b93969395505050506040820135916060013590565b80151581146104e957600080fd5b600060208284031215611e2957600080fd5b8135611c9081611e09565b600080600080600080600060e0888a031215611e4f57600080fd5b8735611e5a81611c5e565b96506020880135611e6a81611c5e565b95506040880135611e7a81611c5e565b94506060880135611e8a81611c5e565b93506080880135611e9a81611e09565b925060a0880135611eaa81611e09565b915060c0880135611eba81611c5e565b8091505092959891949750929550565b60008060008060608587031215611ee057600080fd5b843593506020850135611ef281611c5e565b925060408501356001600160401b0380821115611f0e57600080fd5b818701915087601f830112611f2257600080fd5b813581811115611f3157600080fd5b886020828501011115611f4357600080fd5b95989497505060200194505050565b60008060008060808587031215611f6857600080fd5b8435611f7381611c5e565b93506020850135611f8381611c5e565b92506040850135611f9381611c5e565b91506060850135611fa381611c5e565b939692955090935050565b6020808252600a908201526914d654d5115350d0531360b21b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6000808585111561203057600080fd5b8386111561203d57600080fd5b5050820193919092039150565b80356020831015611bc157600019602084900360031b1b1692915050565b60208082526023908201527f4368696c64455243313135355072656469636174653a204e4f545f434f4e54526040820152621050d560ea1b606082015260800190565b6000602082840312156120bd57600080fd5b8151611c9081611c5e565b60208082526025908201527f4368696c64455243313135355072656469636174653a20554e4d41505045445f6040820152642a27a5a2a760d91b606082015260800190565b634e487b7160e01b600052600160045260246000fd5b81835260006001600160fb1b0383111561213c57600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b038616815260606020820181905260009061217a9083018688612123565b828103604084015261218d818587612123565b98975050505050505050565b6000602082840312156121ab57600080fd5b8151611c9081611e09565b60208082526022908201527f4368696c64455243313135355072656469636174653a204255524e5f4641494c604082015261115160f21b606082015260800190565b8183526000602080850194508260005b8581101561223657813561221b81611c5e565b6001600160a01b031687529582019590820190600101612208565b509495945050505050565b8981526001600160a01b0389811660208301528816604082015260c060608201819052600090612274908301888a6121f8565b8281036080840152612287818789612123565b905082810360a084015261229c818587612123565b9c9b505050505050505050505050565b60005b838110156122c75781810151838201526020016122af565b50506000910152565b600081518084526122e88160208601602086016122ac565b601f01601f19169290920160200192915050565b6001600160a01b0383168152604060208201819052600090612320908301846122d0565b949350505050565b60608152600061233c60608301888a6121f8565b828103602084015261234f818789612123565b90508281036040840152612364818587612123565b9998505050505050505050565b6001600160a01b039390931683526020830191909152604082015260600190565b600080600080600060a086880312156123aa57600080fd5b85356123b581611c5e565b945060208601356123c581611c5e565b935060408601356123d581611c5e565b94979396509394606081013594506080013592915050565b60208082526022908201527f4368696c64455243313135355072656469636174653a204d494e545f4641494c604082015261115160f21b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561246d5761246d61242f565b604052919050565b60006001600160401b0382111561248e5761248e61242f565b5060051b60200190565b600082601f8301126124a957600080fd5b813560206124be6124b983612475565b612445565b82815260059290921b840181019181810190868411156124dd57600080fd5b8286015b848110156124f857803583529183019183016124e1565b509695505050505050565b60008060008060008060c0878903121561251c57600080fd5b8635955060208088013561252f81611c5e565b9550604088013561253f81611c5e565b945060608801356001600160401b038082111561255b57600080fd5b818a0191508a601f83011261256f57600080fd5b813561257d6124b982612475565b81815260059190911b8301840190848101908d83111561259c57600080fd5b938501935b828510156125c35784356125b481611c5e565b825293850193908501906125a1565b9750505060808a01359250808311156125db57600080fd5b6125e78b848c01612498565b945060a08a01359250808311156125fd57600080fd5b505061260b89828a01612498565b9150509295509295509295565b600081518084526020808501945080840160005b838110156122365781518752958201959082019060010161262c565b606080825284519082018190526000906020906080840190828801845b8281101561268a5781516001600160a01b031684529284019290840190600101612665565b5050508381038285015261269e8187612618565b91505082810360408401526126b38185612618565b9695505050505050565b6000806000606084860312156126d257600080fd5b833592506020808501356126e581611c5e565b925060408501356001600160401b038082111561270157600080fd5b818701915087601f83011261271557600080fd5b8135818111156127275761272761242f565b612739601f8201601f19168501612445565b9150808252888482850101111561274f57600080fd5b80848401858401376000848284010152508093505050509250925092565b6000825161277f8184602087016122ac565b9190910192915050565b60006020828403121561279b57600080fd5b505191905056fea26469706673582212203a31f88332ccb328b6f5d85c4214142bbdd2dfd217a190599f91a6ebebb2eda764736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var RootMintableERC1155PredicateArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"RootMintableERC1155Predicate\",\n \"sourceName\": \"contracts/child/RootMintableERC1155Predicate.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"depositor\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2MintableERC1155Deposit\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"depositor\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"amounts\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"L2MintableERC1155DepositBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"withdrawer\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2MintableERC1155Withdraw\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"withdrawer\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"amounts\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"L2MintableERC1155WithdrawBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"L2MintableTokenMapped\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAP_TOKEN_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childERC1155Predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childTokenTemplate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC1155MetadataURI\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"deposit\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC1155MetadataURI\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"amounts\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"depositBatch\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC1155MetadataURI\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"depositTo\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newL2StateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newStateReceiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildERC1155Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"l2StateSender\",\n \"outputs\": [\n {\n \"internalType\": \"contract IStateSender\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC1155MetadataURI\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"mapToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onERC1155BatchReceived\",\n \"outputs\": [\n {\n \"internalType\": \"bytes4\",\n \"name\": \"\",\n \"type\": \"bytes4\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onERC1155Received\",\n \"outputs\": [\n {\n \"internalType\": \"bytes4\",\n \"name\": \"\",\n \"type\": \"bytes4\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onStateReceive\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"rootTokenToChildToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"stateReceiver\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes4\",\n \"name\": \"interfaceId\",\n \"type\": \"bytes4\"\n }\n ],\n \"name\": \"supportsInterface\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50611c01806100206000396000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c8063b68ad1e4116100ad578063eeb4994511610071578063eeb49945146102fe578063f23a6e6114610311578063f4a120f714610330578063f645125514610343578063f8c8765e1461036a57600080fd5b8063b68ad1e41461023e578063bc197c8114610251578063c5ac2b1c14610289578063d41f1771146102b0578063d7c9e3ec146102d757600080fd5b80634c4c45de116100f45780634c4c45de146101a7578063654715e6146101ba5780637efab4f5146101cd578063a78e111c146101f6578063b17680651461020957600080fd5b806301ffc9a71461012657806305dc2e8f1461014e5780630efe6a8b146101795780631bc114ba1461018e575b600080fd5b610139610134366004611182565b61037d565b60405190151581526020015b60405180910390f35b600154610161906001600160a01b031681565b6040516001600160a01b039091168152602001610145565b61018c6101873660046111cb565b6103b4565b005b600054610161906201000090046001600160a01b031681565b61018c6101b536600461124b565b6103c5565b600254610161906001600160a01b031681565b6101616101db3660046112f7565b6004602052600090815260409020546001600160a01b031681565b61018c610204366004611314565b61043f565b6102307f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b604051908152602001610145565b600354610161906001600160a01b031681565b61027061025f3660046114a6565b63bc197c8160e01b95945050505050565b6040516001600160e01b03199091168152602001610145565b6102307faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b6102307f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b6102307f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b61018c61030c366004611553565b610451565b61027061031f3660046115db565b63f23a6e6160e01b95945050505050565b61016161033e3660046112f7565b610629565b6102307f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b61018c610378366004611643565b610944565b60006001600160e01b03198216630271189760e51b14806103ae57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6103c083338484610a5d565b505050565b84831480156103d357508481145b6104275760405162461bcd60e51b815260206004820152602c6024820152600080516020611bac83398151915260448201526b0ac82989288be988a9c8ea8960a31b60648201526084015b60405180910390fd5b61043687878787878787610bf3565b50505050505050565b61044b84848484610a5d565b50505050565b6001546001600160a01b031633146104c55760405162461bcd60e51b815260206004820152603160248201527f526f6f744d696e7461626c65455243313135355072656469636174653a204f4e604482015270262cafa9aa20aa22afa922a1a2a4ab22a960791b606482015260840161041e565b6002546001600160a01b0384811691161461053d5760405162461bcd60e51b815260206004820152603260248201527f526f6f744d696e7461626c65455243313135355072656469636174653a204f4e6044820152714c595f4348494c445f50524544494341544560701b606482015260840161041e565b7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286961056c60206000848661169f565b610575916116c9565b036105945761058f61058a826020818661169f565b610dd3565b61044b565b7f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed26105c360206000848661169f565b6105cc916116c9565b036105db5761058f8282610ed2565b60405162461bcd60e51b815260206004820152602f6024820152600080516020611bac83398151915260448201526e56414c49445f5349474e415455524560881b606482015260840161041e565b60006001600160a01b0382166106835760405162461bcd60e51b815260206004820152602b6024820152600080516020611bac83398151915260448201526a2b20a624a22faa27a5a2a760a91b606482015260840161041e565b6001600160a01b0382811660009081526004602052604090205416156107005760405162461bcd60e51b815260206004820152602c60248201527f526f6f744d696e7461626c65455243313135355072656469636174653a20414c60448201526b149150511657d3505414115160a21b606482015260840161041e565b6002546003546040516bffffffffffffffffffffffff19606086901b1660208201526001600160a01b03928316926107aa921690603401604051602081830303815290604052805190602001208360405160388101919091526f5af43d82803e903d91602b57fd5bf3ff60248201526014810192909252733d602d80600a3d3981f3363d3d373d3d3d363d73825260588201526037600c8201206078820152605560439091012090565b6001600160a01b03848116600081815260046020818152604080842080546001600160a01b031916968816969096179095558451908101855282815293516303a24d0760e21b8152908101919091529294509091630e89341c90602401600060405180830381865afa92505050801561084557506040513d6000823e601f3d908101601f19168201604052610842919081019061170b565b60015b1561084d5790505b600060029054906101000a90046001600160a01b03166001600160a01b03166316f19831837f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad87856040516020016108a7939291906117ad565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016108d39291906117d7565b600060405180830381600087803b1580156108ed57600080fd5b505af1158015610901573d6000803e3d6000fd5b50506040516001600160a01b038087169350871691507fb96a191bae4e25ffdff7f4136994eb0dec75d263750a07c035202c348c9515f090600090a35050919050565b600054610100900460ff16158080156109645750600054600160ff909116105b8061097e5750303b15801561097e575060005460ff166001145b6109e15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161041e565b6000805460ff191660011790558015610a04576000805461ff0019166101001790555b610a1085858585611033565b8015610a56576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b6000610a688561113b565b604051637921219560e11b81529091506001600160a01b0386169063f242432a90610a9d903390309088908890600401611803565b600060405180830381600087803b158015610ab757600080fd5b505af1158015610acb573d6000803e3d6000fd5b5050600054600254604080517f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82160208201526001600160a01b038b8116828401523360608301528a8116608083015260a082018a905260c08083018a90528351808403909101815260e08301938490526316f1983160e01b90935262010000909404841695506316f198319450610b68939092169160e4016117d7565b600060405180830381600087803b158015610b8257600080fd5b505af1158015610b96573d6000803e3d6000fd5b505060408051338152602081018790529081018590526001600160a01b03808816935084811692508816907fe6f1fb6bb1930a5d4b997d56e0a4a8cb6f3f941f0d5391f63c1f6914ee01e0b89060600160405180910390a4610a56565b6000610bfe8861113b565b905060005b84811015610caa57886001600160a01b031663f242432a3330898986818110610c2e57610c2e61183b565b90506020020135888887818110610c4757610c4761183b565b905060200201356040518563ffffffff1660e01b8152600401610c6d9493929190611803565b600060405180830381600087803b158015610c8757600080fd5b505af1158015610c9b573d6000803e3d6000fd5b50505050806001019050610c03565b506000546002546040516001600160a01b03620100009093048316926316f19831921690610d0c907faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d18908d9033908e908e908e908e908e908e906020016118cc565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610d389291906117d7565b600060405180830381600087803b158015610d5257600080fd5b505af1158015610d66573d6000803e3d6000fd5b50505050336001600160a01b0316816001600160a01b0316896001600160a01b03167fa7d9cd27143f817fe006011faf3c04351f70f75cd30e7b21405817f2f670041e8a8a8a8a8a8a604051610dc196959493929190611937565b60405180910390a45050505050505050565b600080808080610de586880188611980565b6001600160a01b03808616600090815260046020526040902054959a50939850919650945092501680610e1a57610e1a6119db565b604051637921219560e11b81526001600160a01b0387169063f242432a90610e4c903090889088908890600401611803565b600060405180830381600087803b158015610e6657600080fd5b505af1158015610e7a573d6000803e3d6000fd5b5050604080516001600160a01b0389811682526020820188905291810186905281881693508482169250908916907f52cdfbe452878311d3237a4c20a951600d8e3a4fe6691d967d33788dc12d19c690606001610dc1565b600080808080610ee4868801886119f1565b6001600160a01b03808616600090815260046020526040902054959b509399509197509550935016905080610f1b57610f1b6119db565b60005b8351811015610fe157866001600160a01b031663f242432a30878481518110610f4957610f4961183b565b6020026020010151878581518110610f6357610f6361183b565b6020026020010151878681518110610f7d57610f7d61183b565b60200260200101516040518563ffffffff1660e01b8152600401610fa49493929190611803565b600060405180830381600087803b158015610fbe57600080fd5b505af1158015610fd2573d6000803e3d6000fd5b50505050806001019050610f1e565b50846001600160a01b0316816001600160a01b0316876001600160a01b03167f52733a40a0466155541c2fc4044165dd37a3db116bc834bab2f020665e90fd20878787604051610dc193929190611b36565b6001600160a01b0384161580159061105357506001600160a01b03831615155b801561106757506001600160a01b03821615155b801561107b57506001600160a01b03811615155b6110e05760405162461bcd60e51b815260206004820152603060248201527f526f6f744d696e7461626c65455243313135355072656469636174653a20424160448201526f222fa4a724aa24a0a624ad20aa24a7a760811b606482015260840161041e565b600080546001600160a01b03958616620100000262010000600160b01b0319909116179055600180549385166001600160a01b0319948516179055600280549285169284169290921790915560038054919093169116179055565b6001600160a01b0380821660009081526004602052604090205416806111675761116482610629565b90505b6001600160a01b03811661117d5761117d6119db565b919050565b60006020828403121561119457600080fd5b81356001600160e01b0319811681146111ac57600080fd5b9392505050565b6001600160a01b03811681146111c857600080fd5b50565b6000806000606084860312156111e057600080fd5b83356111eb816111b3565b95602085013595506040909401359392505050565b60008083601f84011261121257600080fd5b5081356001600160401b0381111561122957600080fd5b6020830191508360208260051b850101111561124457600080fd5b9250929050565b60008060008060008060006080888a03121561126657600080fd5b8735611271816111b3565b965060208801356001600160401b038082111561128d57600080fd5b6112998b838c01611200565b909850965060408a01359150808211156112b257600080fd5b6112be8b838c01611200565b909650945060608a01359150808211156112d757600080fd5b506112e48a828b01611200565b989b979a50959850939692959293505050565b60006020828403121561130957600080fd5b81356111ac816111b3565b6000806000806080858703121561132a57600080fd5b8435611335816111b3565b93506020850135611345816111b3565b93969395505050506040820135916060013590565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156113985761139861135a565b604052919050565b60006001600160401b038211156113b9576113b961135a565b5060051b60200190565b600082601f8301126113d457600080fd5b813560206113e96113e4836113a0565b611370565b82815260059290921b8401810191818101908684111561140857600080fd5b8286015b84811015611423578035835291830191830161140c565b509695505050505050565b60006001600160401b038211156114475761144761135a565b50601f01601f191660200190565b600082601f83011261146657600080fd5b81356114746113e48261142e565b81815284602083860101111561148957600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a086880312156114be57600080fd5b85356114c9816111b3565b945060208601356114d9816111b3565b935060408601356001600160401b03808211156114f557600080fd5b61150189838a016113c3565b9450606088013591508082111561151757600080fd5b61152389838a016113c3565b9350608088013591508082111561153957600080fd5b5061154688828901611455565b9150509295509295909350565b6000806000806060858703121561156957600080fd5b84359350602085013561157b816111b3565b925060408501356001600160401b038082111561159757600080fd5b818701915087601f8301126115ab57600080fd5b8135818111156115ba57600080fd5b8860208285010111156115cc57600080fd5b95989497505060200194505050565b600080600080600060a086880312156115f357600080fd5b85356115fe816111b3565b9450602086013561160e816111b3565b9350604086013592506060860135915060808601356001600160401b0381111561163757600080fd5b61154688828901611455565b6000806000806080858703121561165957600080fd5b8435611664816111b3565b93506020850135611674816111b3565b92506040850135611684816111b3565b91506060850135611694816111b3565b939692955090935050565b600080858511156116af57600080fd5b838611156116bc57600080fd5b5050820193919092039150565b803560208310156103ae57600019602084900360031b1b1692915050565b60005b838110156117025781810151838201526020016116ea565b50506000910152565b60006020828403121561171d57600080fd5b81516001600160401b0381111561173357600080fd5b8201601f8101841361174457600080fd5b80516117526113e48261142e565b81815285602083850101111561176757600080fd5b6117788260208301602086016116e7565b95945050505050565b600081518084526117998160208601602086016116e7565b601f01601f19169290920160200192915050565b8381526001600160a01b038316602082015260606040820181905260009061177890830184611781565b6001600160a01b03831681526040602082018190526000906117fb90830184611781565b949350505050565b6001600160a01b0394851681529290931660208301526040820152606081019190915260a06080820181905260009082015260c00190565b634e487b7160e01b600052603260045260246000fd5b8183526000602080850194508260005b8581101561188f578135611874816111b3565b6001600160a01b031687529582019590820190600101611861565b509495945050505050565b81835260006001600160fb1b038311156118b357600080fd5b8260051b80836020870137939093016020019392505050565b8981526001600160a01b0389811660208301528816604082015260c0606082018190526000906118ff908301888a611851565b828103608084015261191281878961189a565b905082810360a084015261192781858761189a565b9c9b505050505050505050505050565b60608152600061194b60608301888a611851565b828103602084015261195e81878961189a565b9050828103604084015261197381858761189a565b9998505050505050505050565b600080600080600060a0868803121561199857600080fd5b85356119a3816111b3565b945060208601356119b3816111b3565b935060408601356119c3816111b3565b94979396509394606081013594506080013592915050565b634e487b7160e01b600052600160045260246000fd5b60008060008060008060c08789031215611a0a57600080fd5b86359550602080880135611a1d816111b3565b95506040880135611a2d816111b3565b945060608801356001600160401b0380821115611a4957600080fd5b818a0191508a601f830112611a5d57600080fd5b8135611a6b6113e4826113a0565b81815260059190911b8301840190848101908d831115611a8a57600080fd5b938501935b82851015611ab1578435611aa2816111b3565b82529385019390850190611a8f565b9750505060808a0135925080831115611ac957600080fd5b611ad58b848c016113c3565b945060a08a0135925080831115611aeb57600080fd5b5050611af989828a016113c3565b9150509295509295509295565b600081518084526020808501945080840160005b8381101561188f57815187529582019590820190600101611b1a565b606080825284519082018190526000906020906080840190828801845b82811015611b785781516001600160a01b031684529284019290840190600101611b53565b50505083810382850152611b8c8187611b06565b9150508281036040840152611ba18185611b06565b969550505050505056fe526f6f744d696e7461626c65455243313135355072656469636174653a20494ea2646970667358221220041be07610d061e0ff1ac458a256b6bf3a4db091a6a166a3ae82fa20cc5953f564736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101215760003560e01c8063b68ad1e4116100ad578063eeb4994511610071578063eeb49945146102fe578063f23a6e6114610311578063f4a120f714610330578063f645125514610343578063f8c8765e1461036a57600080fd5b8063b68ad1e41461023e578063bc197c8114610251578063c5ac2b1c14610289578063d41f1771146102b0578063d7c9e3ec146102d757600080fd5b80634c4c45de116100f45780634c4c45de146101a7578063654715e6146101ba5780637efab4f5146101cd578063a78e111c146101f6578063b17680651461020957600080fd5b806301ffc9a71461012657806305dc2e8f1461014e5780630efe6a8b146101795780631bc114ba1461018e575b600080fd5b610139610134366004611182565b61037d565b60405190151581526020015b60405180910390f35b600154610161906001600160a01b031681565b6040516001600160a01b039091168152602001610145565b61018c6101873660046111cb565b6103b4565b005b600054610161906201000090046001600160a01b031681565b61018c6101b536600461124b565b6103c5565b600254610161906001600160a01b031681565b6101616101db3660046112f7565b6004602052600090815260409020546001600160a01b031681565b61018c610204366004611314565b61043f565b6102307f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b604051908152602001610145565b600354610161906001600160a01b031681565b61027061025f3660046114a6565b63bc197c8160e01b95945050505050565b6040516001600160e01b03199091168152602001610145565b6102307faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b6102307f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b6102307f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b61018c61030c366004611553565b610451565b61027061031f3660046115db565b63f23a6e6160e01b95945050505050565b61016161033e3660046112f7565b610629565b6102307f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b61018c610378366004611643565b610944565b60006001600160e01b03198216630271189760e51b14806103ae57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6103c083338484610a5d565b505050565b84831480156103d357508481145b6104275760405162461bcd60e51b815260206004820152602c6024820152600080516020611bac83398151915260448201526b0ac82989288be988a9c8ea8960a31b60648201526084015b60405180910390fd5b61043687878787878787610bf3565b50505050505050565b61044b84848484610a5d565b50505050565b6001546001600160a01b031633146104c55760405162461bcd60e51b815260206004820152603160248201527f526f6f744d696e7461626c65455243313135355072656469636174653a204f4e604482015270262cafa9aa20aa22afa922a1a2a4ab22a960791b606482015260840161041e565b6002546001600160a01b0384811691161461053d5760405162461bcd60e51b815260206004820152603260248201527f526f6f744d696e7461626c65455243313135355072656469636174653a204f4e6044820152714c595f4348494c445f50524544494341544560701b606482015260840161041e565b7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286961056c60206000848661169f565b610575916116c9565b036105945761058f61058a826020818661169f565b610dd3565b61044b565b7f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed26105c360206000848661169f565b6105cc916116c9565b036105db5761058f8282610ed2565b60405162461bcd60e51b815260206004820152602f6024820152600080516020611bac83398151915260448201526e56414c49445f5349474e415455524560881b606482015260840161041e565b60006001600160a01b0382166106835760405162461bcd60e51b815260206004820152602b6024820152600080516020611bac83398151915260448201526a2b20a624a22faa27a5a2a760a91b606482015260840161041e565b6001600160a01b0382811660009081526004602052604090205416156107005760405162461bcd60e51b815260206004820152602c60248201527f526f6f744d696e7461626c65455243313135355072656469636174653a20414c60448201526b149150511657d3505414115160a21b606482015260840161041e565b6002546003546040516bffffffffffffffffffffffff19606086901b1660208201526001600160a01b03928316926107aa921690603401604051602081830303815290604052805190602001208360405160388101919091526f5af43d82803e903d91602b57fd5bf3ff60248201526014810192909252733d602d80600a3d3981f3363d3d373d3d3d363d73825260588201526037600c8201206078820152605560439091012090565b6001600160a01b03848116600081815260046020818152604080842080546001600160a01b031916968816969096179095558451908101855282815293516303a24d0760e21b8152908101919091529294509091630e89341c90602401600060405180830381865afa92505050801561084557506040513d6000823e601f3d908101601f19168201604052610842919081019061170b565b60015b1561084d5790505b600060029054906101000a90046001600160a01b03166001600160a01b03166316f19831837f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad87856040516020016108a7939291906117ad565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016108d39291906117d7565b600060405180830381600087803b1580156108ed57600080fd5b505af1158015610901573d6000803e3d6000fd5b50506040516001600160a01b038087169350871691507fb96a191bae4e25ffdff7f4136994eb0dec75d263750a07c035202c348c9515f090600090a35050919050565b600054610100900460ff16158080156109645750600054600160ff909116105b8061097e5750303b15801561097e575060005460ff166001145b6109e15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161041e565b6000805460ff191660011790558015610a04576000805461ff0019166101001790555b610a1085858585611033565b8015610a56576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b6000610a688561113b565b604051637921219560e11b81529091506001600160a01b0386169063f242432a90610a9d903390309088908890600401611803565b600060405180830381600087803b158015610ab757600080fd5b505af1158015610acb573d6000803e3d6000fd5b5050600054600254604080517f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82160208201526001600160a01b038b8116828401523360608301528a8116608083015260a082018a905260c08083018a90528351808403909101815260e08301938490526316f1983160e01b90935262010000909404841695506316f198319450610b68939092169160e4016117d7565b600060405180830381600087803b158015610b8257600080fd5b505af1158015610b96573d6000803e3d6000fd5b505060408051338152602081018790529081018590526001600160a01b03808816935084811692508816907fe6f1fb6bb1930a5d4b997d56e0a4a8cb6f3f941f0d5391f63c1f6914ee01e0b89060600160405180910390a4610a56565b6000610bfe8861113b565b905060005b84811015610caa57886001600160a01b031663f242432a3330898986818110610c2e57610c2e61183b565b90506020020135888887818110610c4757610c4761183b565b905060200201356040518563ffffffff1660e01b8152600401610c6d9493929190611803565b600060405180830381600087803b158015610c8757600080fd5b505af1158015610c9b573d6000803e3d6000fd5b50505050806001019050610c03565b506000546002546040516001600160a01b03620100009093048316926316f19831921690610d0c907faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d18908d9033908e908e908e908e908e908e906020016118cc565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610d389291906117d7565b600060405180830381600087803b158015610d5257600080fd5b505af1158015610d66573d6000803e3d6000fd5b50505050336001600160a01b0316816001600160a01b0316896001600160a01b03167fa7d9cd27143f817fe006011faf3c04351f70f75cd30e7b21405817f2f670041e8a8a8a8a8a8a604051610dc196959493929190611937565b60405180910390a45050505050505050565b600080808080610de586880188611980565b6001600160a01b03808616600090815260046020526040902054959a50939850919650945092501680610e1a57610e1a6119db565b604051637921219560e11b81526001600160a01b0387169063f242432a90610e4c903090889088908890600401611803565b600060405180830381600087803b158015610e6657600080fd5b505af1158015610e7a573d6000803e3d6000fd5b5050604080516001600160a01b0389811682526020820188905291810186905281881693508482169250908916907f52cdfbe452878311d3237a4c20a951600d8e3a4fe6691d967d33788dc12d19c690606001610dc1565b600080808080610ee4868801886119f1565b6001600160a01b03808616600090815260046020526040902054959b509399509197509550935016905080610f1b57610f1b6119db565b60005b8351811015610fe157866001600160a01b031663f242432a30878481518110610f4957610f4961183b565b6020026020010151878581518110610f6357610f6361183b565b6020026020010151878681518110610f7d57610f7d61183b565b60200260200101516040518563ffffffff1660e01b8152600401610fa49493929190611803565b600060405180830381600087803b158015610fbe57600080fd5b505af1158015610fd2573d6000803e3d6000fd5b50505050806001019050610f1e565b50846001600160a01b0316816001600160a01b0316876001600160a01b03167f52733a40a0466155541c2fc4044165dd37a3db116bc834bab2f020665e90fd20878787604051610dc193929190611b36565b6001600160a01b0384161580159061105357506001600160a01b03831615155b801561106757506001600160a01b03821615155b801561107b57506001600160a01b03811615155b6110e05760405162461bcd60e51b815260206004820152603060248201527f526f6f744d696e7461626c65455243313135355072656469636174653a20424160448201526f222fa4a724aa24a0a624ad20aa24a7a760811b606482015260840161041e565b600080546001600160a01b03958616620100000262010000600160b01b0319909116179055600180549385166001600160a01b0319948516179055600280549285169284169290921790915560038054919093169116179055565b6001600160a01b0380821660009081526004602052604090205416806111675761116482610629565b90505b6001600160a01b03811661117d5761117d6119db565b919050565b60006020828403121561119457600080fd5b81356001600160e01b0319811681146111ac57600080fd5b9392505050565b6001600160a01b03811681146111c857600080fd5b50565b6000806000606084860312156111e057600080fd5b83356111eb816111b3565b95602085013595506040909401359392505050565b60008083601f84011261121257600080fd5b5081356001600160401b0381111561122957600080fd5b6020830191508360208260051b850101111561124457600080fd5b9250929050565b60008060008060008060006080888a03121561126657600080fd5b8735611271816111b3565b965060208801356001600160401b038082111561128d57600080fd5b6112998b838c01611200565b909850965060408a01359150808211156112b257600080fd5b6112be8b838c01611200565b909650945060608a01359150808211156112d757600080fd5b506112e48a828b01611200565b989b979a50959850939692959293505050565b60006020828403121561130957600080fd5b81356111ac816111b3565b6000806000806080858703121561132a57600080fd5b8435611335816111b3565b93506020850135611345816111b3565b93969395505050506040820135916060013590565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156113985761139861135a565b604052919050565b60006001600160401b038211156113b9576113b961135a565b5060051b60200190565b600082601f8301126113d457600080fd5b813560206113e96113e4836113a0565b611370565b82815260059290921b8401810191818101908684111561140857600080fd5b8286015b84811015611423578035835291830191830161140c565b509695505050505050565b60006001600160401b038211156114475761144761135a565b50601f01601f191660200190565b600082601f83011261146657600080fd5b81356114746113e48261142e565b81815284602083860101111561148957600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a086880312156114be57600080fd5b85356114c9816111b3565b945060208601356114d9816111b3565b935060408601356001600160401b03808211156114f557600080fd5b61150189838a016113c3565b9450606088013591508082111561151757600080fd5b61152389838a016113c3565b9350608088013591508082111561153957600080fd5b5061154688828901611455565b9150509295509295909350565b6000806000806060858703121561156957600080fd5b84359350602085013561157b816111b3565b925060408501356001600160401b038082111561159757600080fd5b818701915087601f8301126115ab57600080fd5b8135818111156115ba57600080fd5b8860208285010111156115cc57600080fd5b95989497505060200194505050565b600080600080600060a086880312156115f357600080fd5b85356115fe816111b3565b9450602086013561160e816111b3565b9350604086013592506060860135915060808601356001600160401b0381111561163757600080fd5b61154688828901611455565b6000806000806080858703121561165957600080fd5b8435611664816111b3565b93506020850135611674816111b3565b92506040850135611684816111b3565b91506060850135611694816111b3565b939692955090935050565b600080858511156116af57600080fd5b838611156116bc57600080fd5b5050820193919092039150565b803560208310156103ae57600019602084900360031b1b1692915050565b60005b838110156117025781810151838201526020016116ea565b50506000910152565b60006020828403121561171d57600080fd5b81516001600160401b0381111561173357600080fd5b8201601f8101841361174457600080fd5b80516117526113e48261142e565b81815285602083850101111561176757600080fd5b6117788260208301602086016116e7565b95945050505050565b600081518084526117998160208601602086016116e7565b601f01601f19169290920160200192915050565b8381526001600160a01b038316602082015260606040820181905260009061177890830184611781565b6001600160a01b03831681526040602082018190526000906117fb90830184611781565b949350505050565b6001600160a01b0394851681529290931660208301526040820152606081019190915260a06080820181905260009082015260c00190565b634e487b7160e01b600052603260045260246000fd5b8183526000602080850194508260005b8581101561188f578135611874816111b3565b6001600160a01b031687529582019590820190600101611861565b509495945050505050565b81835260006001600160fb1b038311156118b357600080fd5b8260051b80836020870137939093016020019392505050565b8981526001600160a01b0389811660208301528816604082015260c0606082018190526000906118ff908301888a611851565b828103608084015261191281878961189a565b905082810360a084015261192781858761189a565b9c9b505050505050505050505050565b60608152600061194b60608301888a611851565b828103602084015261195e81878961189a565b9050828103604084015261197381858761189a565b9998505050505050505050565b600080600080600060a0868803121561199857600080fd5b85356119a3816111b3565b945060208601356119b3816111b3565b935060408601356119c3816111b3565b94979396509394606081013594506080013592915050565b634e487b7160e01b600052600160045260246000fd5b60008060008060008060c08789031215611a0a57600080fd5b86359550602080880135611a1d816111b3565b95506040880135611a2d816111b3565b945060608801356001600160401b0380821115611a4957600080fd5b818a0191508a601f830112611a5d57600080fd5b8135611a6b6113e4826113a0565b81815260059190911b8301840190848101908d831115611a8a57600080fd5b938501935b82851015611ab1578435611aa2816111b3565b82529385019390850190611a8f565b9750505060808a0135925080831115611ac957600080fd5b611ad58b848c016113c3565b945060a08a0135925080831115611aeb57600080fd5b5050611af989828a016113c3565b9150509295509295509295565b600081518084526020808501945080840160005b8381101561188f57815187529582019590820190600101611b1a565b606080825284519082018190526000906020906080840190828801845b82811015611b785781516001600160a01b031684529284019290840190600101611b53565b50505083810382850152611b8c8187611b06565b9150508281036040840152611ba18185611b06565b969550505050505056fe526f6f744d696e7461626c65455243313135355072656469636174653a20494ea2646970667358221220041be07610d061e0ff1ac458a256b6bf3a4db091a6a166a3ae82fa20cc5953f564736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var RootMintableERC1155PredicateACLArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"RootMintableERC1155PredicateAccessList\",\n \"sourceName\": \"contracts/child/RootMintableERC1155PredicateAccessList.sol\",\n \"abi\": [\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"only\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"Unauthorized\",\n \"type\": \"error\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"block\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bool\",\n \"name\": \"status\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"AllowListUsageSet\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"block\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bool\",\n \"name\": \"status\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"BlockListUsageSet\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"depositor\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2MintableERC1155Deposit\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"depositor\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"amounts\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"L2MintableERC1155DepositBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"withdrawer\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"L2MintableERC1155Withdraw\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"withdrawer\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"amounts\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"L2MintableERC1155WithdrawBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"L2MintableTokenMapped\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"previousOwner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"OwnershipTransferStarted\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"previousOwner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"OwnershipTransferred\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"ALLOWLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"BLOCKLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAP_TOKEN_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TOKEN_CONTRACT\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"READ_ADDRESSLIST_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"SYSTEM\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"acceptOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childERC1155Predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childTokenTemplate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC1155MetadataURI\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"deposit\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC1155MetadataURI\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"amounts\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"depositBatch\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC1155MetadataURI\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"depositTo\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newL2StateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newStateReceiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildERC1155Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseAllowList\",\n \"type\": \"bool\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseBlockList\",\n \"type\": \"bool\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newL2StateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newStateReceiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildERC1155Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"l2StateSender\",\n \"outputs\": [\n {\n \"internalType\": \"contract IStateSender\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC1155MetadataURI\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"mapToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onERC1155BatchReceived\",\n \"outputs\": [\n {\n \"internalType\": \"bytes4\",\n \"name\": \"\",\n \"type\": \"bytes4\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onERC1155Received\",\n \"outputs\": [\n {\n \"internalType\": \"bytes4\",\n \"name\": \"\",\n \"type\": \"bytes4\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onStateReceive\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"owner\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"pendingOwner\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"renounceOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"rootTokenToChildToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseAllowList\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"setAllowList\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"newUseBlockList\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"setBlockList\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"stateReceiver\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes4\",\n \"name\": \"interfaceId\",\n \"type\": \"bytes4\"\n }\n ],\n \"name\": \"supportsInterface\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"transferOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50612480806100206000396000f3fe608060405234801561001057600080fd5b506004361061021c5760003560e01c8063a78e111c11610125578063d8dd1773116100ad578063f23a6e611161007c578063f23a6e61146104d3578063f2fde38b146104f2578063f4a120f714610505578063f645125514610518578063f8c8765e1461053f57600080fd5b8063d8dd177314610493578063e0563ab1146104a6578063e30c3978146104af578063eeb49945146104c057600080fd5b8063c1225a20116100f4578063c1225a20146103f8578063c5ac2b1c1461040b578063c5e4683a14610432578063d41f177114610445578063d7c9e3ec1461046c57600080fd5b8063a78e111c14610373578063b176806514610386578063b68ad1e4146103ad578063bc197c81146103c057600080fd5b806355b01e4d116101a857806379ba50971161017757806379ba50971461031d5780637efab4f5146103255780638da5cb5b1461034f578063947287cf1461036057806397e5230d1461036957600080fd5b806355b01e4d146102dd5780635ea5df79146102eb578063654715e614610302578063715018a61461031557600080fd5b80631bc114ba116101ef5780631bc114ba14610297578063284017f5146102aa5780633b878c22146102b35780634c4c45de146102bc57806351351d53146102cf57600080fd5b806301ffc9a71461022157806305dc2e8f1461024957806307b3e252146102745780630efe6a8b14610282575b600080fd5b61023461022f3660046118c4565b610552565b60405190151581526020015b60405180910390f35b60fd5461025c906001600160a01b031681565b6040516001600160a01b039091168152602001610240565b61025c6004600360981b0181565b61029561029036600461190a565b610589565b005b60fc5461025c906001600160a01b031681565b61025c61202081565b61025c61101081565b6102956102ca36600461198a565b61059a565b61025c6002600160a01b0381565b61025c6004600160991b0181565b6102f461138881565b604051908152602001610240565b60fe5461025c906001600160a01b031681565b610295610614565b610295610628565b61025c610333366004611a36565b610100602052600090815260409020546001600160a01b031681565b6033546001600160a01b031661025c565b6102f461520881565b6102f4620249f081565b610295610381366004611a53565b6106a2565b6102f47f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b60ff5461025c906001600160a01b031681565b6103df6103ce366004611be5565b63bc197c8160e01b95945050505050565b6040516001600160e01b03199091168152602001610240565b610295610406366004611ca2565b6106b4565b6102f47faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b610295610440366004611ca2565b610703565b6102f47f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b6102f47f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b6102956104a1366004611cbd565b61074a565b61025c61203081565b6065546001600160a01b031661025c565b6102956104ce366004611d4f565b610888565b6103df6104e1366004611dd7565b63f23a6e6160e01b95945050505050565b610295610500366004611a36565b610a60565b61025c610513366004611a36565b610ad1565b6102f47f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b61029561054d366004611e3f565b610de1565b60006001600160e01b03198216630271189760e51b148061058357506301ffc9a760e01b6001600160e01b03198316145b92915050565b61059583338484610eb3565b505050565b84831480156105a857508481145b6105fc5760405162461bcd60e51b815260206004820152602c602482015260008051602061242b83398151915260448201526b0ac82989288be988a9c8ea8960a31b60648201526084015b60405180910390fd5b61060b8787878787878761104b565b50505050505050565b61061c611228565b6106266000611282565b565b60655433906001600160a01b031681146106965760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016105f3565b61069f81611282565b50565b6106ae84848484610eb3565b50505050565b6106bc611228565b60c9805461ff0019166101008315159081029190911790915560405143907f61d574757cde41a357d030b39b2705796ccd699578037ab9a1cfd8117d82bf8690600090a350565b61070b611228565b60c9805460ff191682151590811790915560405143907fe0a0f0fa52db091cb71c202d80420311430ce1ae2e7794149877b6720ce8bf0b90600090a350565b336002600160a01b031461078e5760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b60448201526064016105f3565b600054610100900460ff16158080156107ae5750600054600160ff909116105b806107c85750303b1580156107c8575060005460ff166001145b6107e45760405162461bcd60e51b81526004016105f390611e9b565b6000805460ff191660011790558015610807576000805461ff0019166101001790555b6108138888888861129b565b60c9805461ffff191685151561ff001916176101008515150217905561083882611282565b801561087e576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b60fd546001600160a01b031633146108fc5760405162461bcd60e51b815260206004820152603160248201527f526f6f744d696e7461626c65455243313135355072656469636174653a204f4e604482015270262cafa9aa20aa22afa922a1a2a4ab22a960791b60648201526084016105f3565b60fe546001600160a01b038481169116146109745760405162461bcd60e51b815260206004820152603260248201527f526f6f744d696e7461626c65455243313135355072656469636174653a204f4e6044820152714c595f4348494c445f50524544494341544560701b60648201526084016105f3565b7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e9828696109a3602060008486611ee9565b6109ac91611f13565b036109cb576109c66109c18260208186611ee9565b611398565b6106ae565b7f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed26109fa602060008486611ee9565b610a0391611f13565b03610a12576109c682826114a6565b60405162461bcd60e51b815260206004820152602f602482015260008051602061242b83398151915260448201526e56414c49445f5349474e415455524560881b60648201526084016105f3565b610a68611228565b606580546001600160a01b0383166001600160a01b03199091168117909155610a996033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60006001600160a01b038216610b2b5760405162461bcd60e51b815260206004820152602b602482015260008051602061242b83398151915260448201526a2b20a624a22faa27a5a2a760a91b60648201526084016105f3565b6001600160a01b03828116600090815261010060205260409020541615610ba95760405162461bcd60e51b815260206004820152602c60248201527f526f6f744d696e7461626c65455243313135355072656469636174653a20414c60448201526b149150511657d3505414115160a21b60648201526084016105f3565b60fe5460ff546040516bffffffffffffffffffffffff19606086901b1660208201526001600160a01b0392831692610c53921690603401604051602081830303815290604052805190602001208360405160388101919091526f5af43d82803e903d91602b57fd5bf3ff60248201526014810192909252733d602d80600a3d3981f3363d3d373d3d3d363d73825260588201526037600c8201206078820152605560439091012090565b6001600160a01b0384811660008181526101006020908152604080832080546001600160a01b031916958716959095179094558351908101845281815292516303a24d0760e21b815260048101919091529294509091630e89341c90602401600060405180830381865afa925050508015610cf057506040513d6000823e601f3d908101601f19168201604052610ced9190810190611f55565b60015b15610cf85790505b60fc546040516001600160a01b03909116906316f19831908490610d44907f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad9089908790602001611ff7565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610d70929190612021565b600060405180830381600087803b158015610d8a57600080fd5b505af1158015610d9e573d6000803e3d6000fd5b50506040516001600160a01b038087169350871691507fb96a191bae4e25ffdff7f4136994eb0dec75d263750a07c035202c348c9515f090600090a35050919050565b600054610100900460ff1615808015610e015750600054600160ff909116105b80610e1b5750303b158015610e1b575060005460ff166001145b610e375760405162461bcd60e51b81526004016105f390611e9b565b6000805460ff191660011790558015610e5a576000805461ff0019166101001790555b610e668585858561129b565b8015610eac576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b610ebb611608565b6000610ec685611610565b604051637921219560e11b81529091506001600160a01b0386169063f242432a90610efb90339030908890889060040161204d565b600060405180830381600087803b158015610f1557600080fd5b505af1158015610f29573d6000803e3d6000fd5b505060fc5460fe54604080517f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82160208201526001600160a01b038b8116828401523360608301528a8116608083015260a082018a905260c08083018a90528351808403909101815260e08301938490526316f1983160e01b90935293841695506316f198319450610fc0939092169160e401612021565b600060405180830381600087803b158015610fda57600080fd5b505af1158015610fee573d6000803e3d6000fd5b505060408051338152602081018790529081018590526001600160a01b03808816935084811692508816907fe6f1fb6bb1930a5d4b997d56e0a4a8cb6f3f941f0d5391f63c1f6914ee01e0b89060600160405180910390a4610eac565b611053611608565b600061105e88611610565b905060005b8481101561110a57886001600160a01b031663f242432a333089898681811061108e5761108e612085565b905060200201358888878181106110a7576110a7612085565b905060200201356040518563ffffffff1660e01b81526004016110cd949392919061204d565b600060405180830381600087803b1580156110e757600080fd5b505af11580156110fb573d6000803e3d6000fd5b50505050806001019050611063565b5060fc5460fe546040516001600160a01b03928316926316f19831921690611166907faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d18908d9033908e908e908e908e908e908e90602001612116565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401611192929190612021565b600060405180830381600087803b1580156111ac57600080fd5b505af11580156111c0573d6000803e3d6000fd5b50505050336001600160a01b0316816001600160a01b0316896001600160a01b03167fa7d9cd27143f817fe006011faf3c04351f70f75cd30e7b21405817f2f670041e8a8a8a8a8a8a60405161121b96959493929190612181565b60405180910390a461087e565b6033546001600160a01b031633146106265760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016105f3565b606580546001600160a01b031916905561069f81611658565b6001600160a01b038416158015906112bb57506001600160a01b03831615155b80156112cf57506001600160a01b03821615155b80156112e357506001600160a01b03811615155b6113485760405162461bcd60e51b815260206004820152603060248201527f526f6f744d696e7461626c65455243313135355072656469636174653a20424160448201526f222fa4a724aa24a0a624ad20aa24a7a760811b60648201526084016105f3565b60fc80546001600160a01b039586166001600160a01b03199182161790915560fd80549486169482169490941790935560fe80549285169284169290921790915560ff8054919093169116179055565b6000808080806113aa868801886121ca565b6001600160a01b0380861660009081526101006020526040902054959a509398509196509450925016806113e0576113e0612225565b604051637921219560e11b81526001600160a01b0387169063f242432a9061141290309088908890889060040161204d565b600060405180830381600087803b15801561142c57600080fd5b505af1158015611440573d6000803e3d6000fd5b5050604080516001600160a01b0389811682526020820188905291810186905281881693508482169250908916907f52cdfbe452878311d3237a4c20a951600d8e3a4fe6691d967d33788dc12d19c6906060015b60405180910390a45050505050505050565b6000808080806114b88688018861223b565b6001600160a01b0380861660009081526101006020526040902054959b5093995091975095509350169050806114f0576114f0612225565b60005b83518110156115b657866001600160a01b031663f242432a3087848151811061151e5761151e612085565b602002602001015187858151811061153857611538612085565b602002602001015187868151811061155257611552612085565b60200260200101516040518563ffffffff1660e01b8152600401611579949392919061204d565b600060405180830381600087803b15801561159357600080fd5b505af11580156115a7573d6000803e3d6000fd5b505050508060010190506114f3565b50846001600160a01b0316816001600160a01b0316876001600160a01b03167f52733a40a0466155541c2fc4044165dd37a3db116bc834bab2f020665e90fd2087878760405161149493929190612380565b6106266116aa565b6001600160a01b0380821660009081526101006020526040902054168061163d5761163a82610ad1565b90505b6001600160a01b03811661165357611653612225565b919050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60c95460ff16156117b557604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600160991b01916113889161170c91906123f5565b6000604051808303818686fa925050503d8060008114611748576040519150601f19603f3d011682016040523d82523d6000602084013e61174d565b606091505b509150915081801561177257506000818060200190518101906117709190612411565b115b6117b25760405162461bcd60e51b81526020600482015260116024820152702224a9a0a62627aba2a22fa9a2a72222a960791b60448201526064016105f3565b50505b60c954610100900460ff161561062657604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600360981b01916113889161181c91906123f5565b6000604051808303818686fa925050503d8060008114611858576040519150601f19603f3d011682016040523d82523d6000602084013e61185d565b606091505b509150915081801561188357508080602001905181019061187e9190612411565b600114155b6118c05760405162461bcd60e51b815260206004820152600e60248201526d212627a1a5a2a22fa9a2a72222a960911b60448201526064016105f3565b5050565b6000602082840312156118d657600080fd5b81356001600160e01b0319811681146118ee57600080fd5b9392505050565b6001600160a01b038116811461069f57600080fd5b60008060006060848603121561191f57600080fd5b833561192a816118f5565b95602085013595506040909401359392505050565b60008083601f84011261195157600080fd5b5081356001600160401b0381111561196857600080fd5b6020830191508360208260051b850101111561198357600080fd5b9250929050565b60008060008060008060006080888a0312156119a557600080fd5b87356119b0816118f5565b965060208801356001600160401b03808211156119cc57600080fd5b6119d88b838c0161193f565b909850965060408a01359150808211156119f157600080fd5b6119fd8b838c0161193f565b909650945060608a0135915080821115611a1657600080fd5b50611a238a828b0161193f565b989b979a50959850939692959293505050565b600060208284031215611a4857600080fd5b81356118ee816118f5565b60008060008060808587031215611a6957600080fd5b8435611a74816118f5565b93506020850135611a84816118f5565b93969395505050506040820135916060013590565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715611ad757611ad7611a99565b604052919050565b60006001600160401b03821115611af857611af8611a99565b5060051b60200190565b600082601f830112611b1357600080fd5b81356020611b28611b2383611adf565b611aaf565b82815260059290921b84018101918181019086841115611b4757600080fd5b8286015b84811015611b625780358352918301918301611b4b565b509695505050505050565b60006001600160401b03821115611b8657611b86611a99565b50601f01601f191660200190565b600082601f830112611ba557600080fd5b8135611bb3611b2382611b6d565b818152846020838601011115611bc857600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215611bfd57600080fd5b8535611c08816118f5565b94506020860135611c18816118f5565b935060408601356001600160401b0380821115611c3457600080fd5b611c4089838a01611b02565b94506060880135915080821115611c5657600080fd5b611c6289838a01611b02565b93506080880135915080821115611c7857600080fd5b50611c8588828901611b94565b9150509295509295909350565b8035801515811461165357600080fd5b600060208284031215611cb457600080fd5b6118ee82611c92565b600080600080600080600060e0888a031215611cd857600080fd5b8735611ce3816118f5565b96506020880135611cf3816118f5565b95506040880135611d03816118f5565b94506060880135611d13816118f5565b9350611d2160808901611c92565b9250611d2f60a08901611c92565b915060c0880135611d3f816118f5565b8091505092959891949750929550565b60008060008060608587031215611d6557600080fd5b843593506020850135611d77816118f5565b925060408501356001600160401b0380821115611d9357600080fd5b818701915087601f830112611da757600080fd5b813581811115611db657600080fd5b886020828501011115611dc857600080fd5b95989497505060200194505050565b600080600080600060a08688031215611def57600080fd5b8535611dfa816118f5565b94506020860135611e0a816118f5565b9350604086013592506060860135915060808601356001600160401b03811115611e3357600080fd5b611c8588828901611b94565b60008060008060808587031215611e5557600080fd5b8435611e60816118f5565b93506020850135611e70816118f5565b92506040850135611e80816118f5565b91506060850135611e90816118f5565b939692955090935050565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b60008085851115611ef957600080fd5b83861115611f0657600080fd5b5050820193919092039150565b8035602083101561058357600019602084900360031b1b1692915050565b60005b83811015611f4c578181015183820152602001611f34565b50506000910152565b600060208284031215611f6757600080fd5b81516001600160401b03811115611f7d57600080fd5b8201601f81018413611f8e57600080fd5b8051611f9c611b2382611b6d565b818152856020838501011115611fb157600080fd5b611fc2826020830160208601611f31565b95945050505050565b60008151808452611fe3816020860160208601611f31565b601f01601f19169290920160200192915050565b8381526001600160a01b0383166020820152606060408201819052600090611fc290830184611fcb565b6001600160a01b038316815260406020820181905260009061204590830184611fcb565b949350505050565b6001600160a01b0394851681529290931660208301526040820152606081019190915260a06080820181905260009082015260c00190565b634e487b7160e01b600052603260045260246000fd5b8183526000602080850194508260005b858110156120d95781356120be816118f5565b6001600160a01b0316875295820195908201906001016120ab565b509495945050505050565b81835260006001600160fb1b038311156120fd57600080fd5b8260051b80836020870137939093016020019392505050565b8981526001600160a01b0389811660208301528816604082015260c060608201819052600090612149908301888a61209b565b828103608084015261215c8187896120e4565b905082810360a08401526121718185876120e4565b9c9b505050505050505050505050565b60608152600061219560608301888a61209b565b82810360208401526121a88187896120e4565b905082810360408401526121bd8185876120e4565b9998505050505050505050565b600080600080600060a086880312156121e257600080fd5b85356121ed816118f5565b945060208601356121fd816118f5565b9350604086013561220d816118f5565b94979396509394606081013594506080013592915050565b634e487b7160e01b600052600160045260246000fd5b60008060008060008060c0878903121561225457600080fd5b86359550602080880135612267816118f5565b95506040880135612277816118f5565b945060608801356001600160401b038082111561229357600080fd5b818a0191508a601f8301126122a757600080fd5b81356122b5611b2382611adf565b81815260059190911b8301840190848101908d8311156122d457600080fd5b938501935b828510156122fb5784356122ec816118f5565b825293850193908501906122d9565b9750505060808a013592508083111561231357600080fd5b61231f8b848c01611b02565b945060a08a013592508083111561233557600080fd5b505061234389828a01611b02565b9150509295509295509295565b600081518084526020808501945080840160005b838110156120d957815187529582019590820190600101612364565b606080825284519082018190526000906020906080840190828801845b828110156123c25781516001600160a01b03168452928401929084019060010161239d565b505050838103828501526123d68187612350565b91505082810360408401526123eb8185612350565b9695505050505050565b60008251612407818460208701611f31565b9190910192915050565b60006020828403121561242357600080fd5b505191905056fe526f6f744d696e7461626c65455243313135355072656469636174653a20494ea2646970667358221220965ae0a80f2c0fef1177c03f5c9015e9cb11183a07cb364acd575c0d5b96410c64736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b506004361061021c5760003560e01c8063a78e111c11610125578063d8dd1773116100ad578063f23a6e611161007c578063f23a6e61146104d3578063f2fde38b146104f2578063f4a120f714610505578063f645125514610518578063f8c8765e1461053f57600080fd5b8063d8dd177314610493578063e0563ab1146104a6578063e30c3978146104af578063eeb49945146104c057600080fd5b8063c1225a20116100f4578063c1225a20146103f8578063c5ac2b1c1461040b578063c5e4683a14610432578063d41f177114610445578063d7c9e3ec1461046c57600080fd5b8063a78e111c14610373578063b176806514610386578063b68ad1e4146103ad578063bc197c81146103c057600080fd5b806355b01e4d116101a857806379ba50971161017757806379ba50971461031d5780637efab4f5146103255780638da5cb5b1461034f578063947287cf1461036057806397e5230d1461036957600080fd5b806355b01e4d146102dd5780635ea5df79146102eb578063654715e614610302578063715018a61461031557600080fd5b80631bc114ba116101ef5780631bc114ba14610297578063284017f5146102aa5780633b878c22146102b35780634c4c45de146102bc57806351351d53146102cf57600080fd5b806301ffc9a71461022157806305dc2e8f1461024957806307b3e252146102745780630efe6a8b14610282575b600080fd5b61023461022f3660046118c4565b610552565b60405190151581526020015b60405180910390f35b60fd5461025c906001600160a01b031681565b6040516001600160a01b039091168152602001610240565b61025c6004600360981b0181565b61029561029036600461190a565b610589565b005b60fc5461025c906001600160a01b031681565b61025c61202081565b61025c61101081565b6102956102ca36600461198a565b61059a565b61025c6002600160a01b0381565b61025c6004600160991b0181565b6102f461138881565b604051908152602001610240565b60fe5461025c906001600160a01b031681565b610295610614565b610295610628565b61025c610333366004611a36565b610100602052600090815260409020546001600160a01b031681565b6033546001600160a01b031661025c565b6102f461520881565b6102f4620249f081565b610295610381366004611a53565b6106a2565b6102f47f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b60ff5461025c906001600160a01b031681565b6103df6103ce366004611be5565b63bc197c8160e01b95945050505050565b6040516001600160e01b03199091168152602001610240565b610295610406366004611ca2565b6106b4565b6102f47faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b610295610440366004611ca2565b610703565b6102f47f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b6102f47f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b6102956104a1366004611cbd565b61074a565b61025c61203081565b6065546001600160a01b031661025c565b6102956104ce366004611d4f565b610888565b6103df6104e1366004611dd7565b63f23a6e6160e01b95945050505050565b610295610500366004611a36565b610a60565b61025c610513366004611a36565b610ad1565b6102f47f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b61029561054d366004611e3f565b610de1565b60006001600160e01b03198216630271189760e51b148061058357506301ffc9a760e01b6001600160e01b03198316145b92915050565b61059583338484610eb3565b505050565b84831480156105a857508481145b6105fc5760405162461bcd60e51b815260206004820152602c602482015260008051602061242b83398151915260448201526b0ac82989288be988a9c8ea8960a31b60648201526084015b60405180910390fd5b61060b8787878787878761104b565b50505050505050565b61061c611228565b6106266000611282565b565b60655433906001600160a01b031681146106965760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016105f3565b61069f81611282565b50565b6106ae84848484610eb3565b50505050565b6106bc611228565b60c9805461ff0019166101008315159081029190911790915560405143907f61d574757cde41a357d030b39b2705796ccd699578037ab9a1cfd8117d82bf8690600090a350565b61070b611228565b60c9805460ff191682151590811790915560405143907fe0a0f0fa52db091cb71c202d80420311430ce1ae2e7794149877b6720ce8bf0b90600090a350565b336002600160a01b031461078e5760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b60448201526064016105f3565b600054610100900460ff16158080156107ae5750600054600160ff909116105b806107c85750303b1580156107c8575060005460ff166001145b6107e45760405162461bcd60e51b81526004016105f390611e9b565b6000805460ff191660011790558015610807576000805461ff0019166101001790555b6108138888888861129b565b60c9805461ffff191685151561ff001916176101008515150217905561083882611282565b801561087e576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b60fd546001600160a01b031633146108fc5760405162461bcd60e51b815260206004820152603160248201527f526f6f744d696e7461626c65455243313135355072656469636174653a204f4e604482015270262cafa9aa20aa22afa922a1a2a4ab22a960791b60648201526084016105f3565b60fe546001600160a01b038481169116146109745760405162461bcd60e51b815260206004820152603260248201527f526f6f744d696e7461626c65455243313135355072656469636174653a204f4e6044820152714c595f4348494c445f50524544494341544560701b60648201526084016105f3565b7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e9828696109a3602060008486611ee9565b6109ac91611f13565b036109cb576109c66109c18260208186611ee9565b611398565b6106ae565b7f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed26109fa602060008486611ee9565b610a0391611f13565b03610a12576109c682826114a6565b60405162461bcd60e51b815260206004820152602f602482015260008051602061242b83398151915260448201526e56414c49445f5349474e415455524560881b60648201526084016105f3565b610a68611228565b606580546001600160a01b0383166001600160a01b03199091168117909155610a996033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60006001600160a01b038216610b2b5760405162461bcd60e51b815260206004820152602b602482015260008051602061242b83398151915260448201526a2b20a624a22faa27a5a2a760a91b60648201526084016105f3565b6001600160a01b03828116600090815261010060205260409020541615610ba95760405162461bcd60e51b815260206004820152602c60248201527f526f6f744d696e7461626c65455243313135355072656469636174653a20414c60448201526b149150511657d3505414115160a21b60648201526084016105f3565b60fe5460ff546040516bffffffffffffffffffffffff19606086901b1660208201526001600160a01b0392831692610c53921690603401604051602081830303815290604052805190602001208360405160388101919091526f5af43d82803e903d91602b57fd5bf3ff60248201526014810192909252733d602d80600a3d3981f3363d3d373d3d3d363d73825260588201526037600c8201206078820152605560439091012090565b6001600160a01b0384811660008181526101006020908152604080832080546001600160a01b031916958716959095179094558351908101845281815292516303a24d0760e21b815260048101919091529294509091630e89341c90602401600060405180830381865afa925050508015610cf057506040513d6000823e601f3d908101601f19168201604052610ced9190810190611f55565b60015b15610cf85790505b60fc546040516001600160a01b03909116906316f19831908490610d44907f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad9089908790602001611ff7565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610d70929190612021565b600060405180830381600087803b158015610d8a57600080fd5b505af1158015610d9e573d6000803e3d6000fd5b50506040516001600160a01b038087169350871691507fb96a191bae4e25ffdff7f4136994eb0dec75d263750a07c035202c348c9515f090600090a35050919050565b600054610100900460ff1615808015610e015750600054600160ff909116105b80610e1b5750303b158015610e1b575060005460ff166001145b610e375760405162461bcd60e51b81526004016105f390611e9b565b6000805460ff191660011790558015610e5a576000805461ff0019166101001790555b610e668585858561129b565b8015610eac576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b610ebb611608565b6000610ec685611610565b604051637921219560e11b81529091506001600160a01b0386169063f242432a90610efb90339030908890889060040161204d565b600060405180830381600087803b158015610f1557600080fd5b505af1158015610f29573d6000803e3d6000fd5b505060fc5460fe54604080517f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82160208201526001600160a01b038b8116828401523360608301528a8116608083015260a082018a905260c08083018a90528351808403909101815260e08301938490526316f1983160e01b90935293841695506316f198319450610fc0939092169160e401612021565b600060405180830381600087803b158015610fda57600080fd5b505af1158015610fee573d6000803e3d6000fd5b505060408051338152602081018790529081018590526001600160a01b03808816935084811692508816907fe6f1fb6bb1930a5d4b997d56e0a4a8cb6f3f941f0d5391f63c1f6914ee01e0b89060600160405180910390a4610eac565b611053611608565b600061105e88611610565b905060005b8481101561110a57886001600160a01b031663f242432a333089898681811061108e5761108e612085565b905060200201358888878181106110a7576110a7612085565b905060200201356040518563ffffffff1660e01b81526004016110cd949392919061204d565b600060405180830381600087803b1580156110e757600080fd5b505af11580156110fb573d6000803e3d6000fd5b50505050806001019050611063565b5060fc5460fe546040516001600160a01b03928316926316f19831921690611166907faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d18908d9033908e908e908e908e908e908e90602001612116565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401611192929190612021565b600060405180830381600087803b1580156111ac57600080fd5b505af11580156111c0573d6000803e3d6000fd5b50505050336001600160a01b0316816001600160a01b0316896001600160a01b03167fa7d9cd27143f817fe006011faf3c04351f70f75cd30e7b21405817f2f670041e8a8a8a8a8a8a60405161121b96959493929190612181565b60405180910390a461087e565b6033546001600160a01b031633146106265760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016105f3565b606580546001600160a01b031916905561069f81611658565b6001600160a01b038416158015906112bb57506001600160a01b03831615155b80156112cf57506001600160a01b03821615155b80156112e357506001600160a01b03811615155b6113485760405162461bcd60e51b815260206004820152603060248201527f526f6f744d696e7461626c65455243313135355072656469636174653a20424160448201526f222fa4a724aa24a0a624ad20aa24a7a760811b60648201526084016105f3565b60fc80546001600160a01b039586166001600160a01b03199182161790915560fd80549486169482169490941790935560fe80549285169284169290921790915560ff8054919093169116179055565b6000808080806113aa868801886121ca565b6001600160a01b0380861660009081526101006020526040902054959a509398509196509450925016806113e0576113e0612225565b604051637921219560e11b81526001600160a01b0387169063f242432a9061141290309088908890889060040161204d565b600060405180830381600087803b15801561142c57600080fd5b505af1158015611440573d6000803e3d6000fd5b5050604080516001600160a01b0389811682526020820188905291810186905281881693508482169250908916907f52cdfbe452878311d3237a4c20a951600d8e3a4fe6691d967d33788dc12d19c6906060015b60405180910390a45050505050505050565b6000808080806114b88688018861223b565b6001600160a01b0380861660009081526101006020526040902054959b5093995091975095509350169050806114f0576114f0612225565b60005b83518110156115b657866001600160a01b031663f242432a3087848151811061151e5761151e612085565b602002602001015187858151811061153857611538612085565b602002602001015187868151811061155257611552612085565b60200260200101516040518563ffffffff1660e01b8152600401611579949392919061204d565b600060405180830381600087803b15801561159357600080fd5b505af11580156115a7573d6000803e3d6000fd5b505050508060010190506114f3565b50846001600160a01b0316816001600160a01b0316876001600160a01b03167f52733a40a0466155541c2fc4044165dd37a3db116bc834bab2f020665e90fd2087878760405161149493929190612380565b6106266116aa565b6001600160a01b0380821660009081526101006020526040902054168061163d5761163a82610ad1565b90505b6001600160a01b03811661165357611653612225565b919050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60c95460ff16156117b557604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600160991b01916113889161170c91906123f5565b6000604051808303818686fa925050503d8060008114611748576040519150601f19603f3d011682016040523d82523d6000602084013e61174d565b606091505b509150915081801561177257506000818060200190518101906117709190612411565b115b6117b25760405162461bcd60e51b81526020600482015260116024820152702224a9a0a62627aba2a22fa9a2a72222a960791b60448201526064016105f3565b50505b60c954610100900460ff161561062657604080513360248083019190915282518083039091018152604490910182526020810180516001600160e01b031663d78bca6960e01b179052905160009182916004600360981b01916113889161181c91906123f5565b6000604051808303818686fa925050503d8060008114611858576040519150601f19603f3d011682016040523d82523d6000602084013e61185d565b606091505b509150915081801561188357508080602001905181019061187e9190612411565b600114155b6118c05760405162461bcd60e51b815260206004820152600e60248201526d212627a1a5a2a22fa9a2a72222a960911b60448201526064016105f3565b5050565b6000602082840312156118d657600080fd5b81356001600160e01b0319811681146118ee57600080fd5b9392505050565b6001600160a01b038116811461069f57600080fd5b60008060006060848603121561191f57600080fd5b833561192a816118f5565b95602085013595506040909401359392505050565b60008083601f84011261195157600080fd5b5081356001600160401b0381111561196857600080fd5b6020830191508360208260051b850101111561198357600080fd5b9250929050565b60008060008060008060006080888a0312156119a557600080fd5b87356119b0816118f5565b965060208801356001600160401b03808211156119cc57600080fd5b6119d88b838c0161193f565b909850965060408a01359150808211156119f157600080fd5b6119fd8b838c0161193f565b909650945060608a0135915080821115611a1657600080fd5b50611a238a828b0161193f565b989b979a50959850939692959293505050565b600060208284031215611a4857600080fd5b81356118ee816118f5565b60008060008060808587031215611a6957600080fd5b8435611a74816118f5565b93506020850135611a84816118f5565b93969395505050506040820135916060013590565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715611ad757611ad7611a99565b604052919050565b60006001600160401b03821115611af857611af8611a99565b5060051b60200190565b600082601f830112611b1357600080fd5b81356020611b28611b2383611adf565b611aaf565b82815260059290921b84018101918181019086841115611b4757600080fd5b8286015b84811015611b625780358352918301918301611b4b565b509695505050505050565b60006001600160401b03821115611b8657611b86611a99565b50601f01601f191660200190565b600082601f830112611ba557600080fd5b8135611bb3611b2382611b6d565b818152846020838601011115611bc857600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215611bfd57600080fd5b8535611c08816118f5565b94506020860135611c18816118f5565b935060408601356001600160401b0380821115611c3457600080fd5b611c4089838a01611b02565b94506060880135915080821115611c5657600080fd5b611c6289838a01611b02565b93506080880135915080821115611c7857600080fd5b50611c8588828901611b94565b9150509295509295909350565b8035801515811461165357600080fd5b600060208284031215611cb457600080fd5b6118ee82611c92565b600080600080600080600060e0888a031215611cd857600080fd5b8735611ce3816118f5565b96506020880135611cf3816118f5565b95506040880135611d03816118f5565b94506060880135611d13816118f5565b9350611d2160808901611c92565b9250611d2f60a08901611c92565b915060c0880135611d3f816118f5565b8091505092959891949750929550565b60008060008060608587031215611d6557600080fd5b843593506020850135611d77816118f5565b925060408501356001600160401b0380821115611d9357600080fd5b818701915087601f830112611da757600080fd5b813581811115611db657600080fd5b886020828501011115611dc857600080fd5b95989497505060200194505050565b600080600080600060a08688031215611def57600080fd5b8535611dfa816118f5565b94506020860135611e0a816118f5565b9350604086013592506060860135915060808601356001600160401b03811115611e3357600080fd5b611c8588828901611b94565b60008060008060808587031215611e5557600080fd5b8435611e60816118f5565b93506020850135611e70816118f5565b92506040850135611e80816118f5565b91506060850135611e90816118f5565b939692955090935050565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b60008085851115611ef957600080fd5b83861115611f0657600080fd5b5050820193919092039150565b8035602083101561058357600019602084900360031b1b1692915050565b60005b83811015611f4c578181015183820152602001611f34565b50506000910152565b600060208284031215611f6757600080fd5b81516001600160401b03811115611f7d57600080fd5b8201601f81018413611f8e57600080fd5b8051611f9c611b2382611b6d565b818152856020838501011115611fb157600080fd5b611fc2826020830160208601611f31565b95945050505050565b60008151808452611fe3816020860160208601611f31565b601f01601f19169290920160200192915050565b8381526001600160a01b0383166020820152606060408201819052600090611fc290830184611fcb565b6001600160a01b038316815260406020820181905260009061204590830184611fcb565b949350505050565b6001600160a01b0394851681529290931660208301526040820152606081019190915260a06080820181905260009082015260c00190565b634e487b7160e01b600052603260045260246000fd5b8183526000602080850194508260005b858110156120d95781356120be816118f5565b6001600160a01b0316875295820195908201906001016120ab565b509495945050505050565b81835260006001600160fb1b038311156120fd57600080fd5b8260051b80836020870137939093016020019392505050565b8981526001600160a01b0389811660208301528816604082015260c060608201819052600090612149908301888a61209b565b828103608084015261215c8187896120e4565b905082810360a08401526121718185876120e4565b9c9b505050505050505050505050565b60608152600061219560608301888a61209b565b82810360208401526121a88187896120e4565b905082810360408401526121bd8185876120e4565b9998505050505050505050565b600080600080600060a086880312156121e257600080fd5b85356121ed816118f5565b945060208601356121fd816118f5565b9350604086013561220d816118f5565b94979396509394606081013594506080013592915050565b634e487b7160e01b600052600160045260246000fd5b60008060008060008060c0878903121561225457600080fd5b86359550602080880135612267816118f5565b95506040880135612277816118f5565b945060608801356001600160401b038082111561229357600080fd5b818a0191508a601f8301126122a757600080fd5b81356122b5611b2382611adf565b81815260059190911b8301840190848101908d8311156122d457600080fd5b938501935b828510156122fb5784356122ec816118f5565b825293850193908501906122d9565b9750505060808a013592508083111561231357600080fd5b61231f8b848c01611b02565b945060a08a013592508083111561233557600080fd5b505061234389828a01611b02565b9150509295509295509295565b600081518084526020808501945080840160005b838110156120d957815187529582019590820190600101612364565b606080825284519082018190526000906020906080840190828801845b828110156123c25781516001600160a01b03168452928401929084019060010161239d565b505050838103828501526123d68187612350565b91505082810360408401526123eb8185612350565b9695505050505050565b60008251612407818460208701611f31565b9190910192915050565b60006020828403121561242357600080fd5b505191905056fe526f6f744d696e7461626c65455243313135355072656469636174653a20494ea2646970667358221220965ae0a80f2c0fef1177c03f5c9015e9cb11183a07cb364acd575c0d5b96410c64736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var SystemArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"System\",\n \"sourceName\": \"contracts/child/System.sol\",\n \"abi\": [\n {\n \"inputs\": [],\n \"name\": \"ALLOWLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"BLOCKLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TOKEN_CONTRACT\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"READ_ADDRESSLIST_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"SYSTEM\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b5061015a806100206000396000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c806355b01e4d1161006657806355b01e4d146100e35780635ea5df79146100f1578063947287cf1461010857806397e5230d14610111578063e0563ab11461011b57600080fd5b806307b3e25214610098578063284017f5146100c35780633b878c22146100cc57806351351d53146100d5575b600080fd5b6100a66004600360981b0181565b6040516001600160a01b0390911681526020015b60405180910390f35b6100a661202081565b6100a661101081565b6100a66002600160a01b0381565b6100a66004600160991b0181565b6100fa61138881565b6040519081526020016100ba565b6100fa61520881565b6100fa620249f081565b6100a66120308156fea2646970667358221220cdc81f82626224fb8a04246ca1d1898f8b03c160e9b2f63cd0bc4b5d0b55c3f964736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106100935760003560e01c806355b01e4d1161006657806355b01e4d146100e35780635ea5df79146100f1578063947287cf1461010857806397e5230d14610111578063e0563ab11461011b57600080fd5b806307b3e25214610098578063284017f5146100c35780633b878c22146100cc57806351351d53146100d5575b600080fd5b6100a66004600360981b0181565b6040516001600160a01b0390911681526020015b60405180910390f35b6100a661202081565b6100a661101081565b6100a66002600160a01b0381565b6100a66004600160991b0181565b6100fa61138881565b6040519081526020016100ba565b6100fa61520881565b6100fa620249f081565b6100a66120308156fea2646970667358221220cdc81f82626224fb8a04246ca1d1898f8b03c160e9b2f63cd0bc4b5d0b55c3f964736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var BLSArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"BLS\",\n \"sourceName\": \"contracts/common/BLS.sol\",\n \"abi\": [\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"domain\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"message\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"expandMsgTo96\",\n \"outputs\": [\n {\n \"internalType\": \"bytes\",\n \"name\": \"\",\n \"type\": \"bytes\"\n }\n ],\n \"stateMutability\": \"pure\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"domain\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"messages\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"hashToField\",\n \"outputs\": [\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"\",\n \"type\": \"uint256[2]\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"domain\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"message\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"hashToPoint\",\n \"outputs\": [\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"\",\n \"type\": \"uint256[2]\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"point\",\n \"type\": \"uint256[2]\"\n }\n ],\n \"name\": \"isOnCurveG1\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"_isOnCurve\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"pure\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256[4]\",\n \"name\": \"point\",\n \"type\": \"uint256[4]\"\n }\n ],\n \"name\": \"isOnCurveG2\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"_isOnCurve\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"pure\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"signature\",\n \"type\": \"uint256[2]\"\n }\n ],\n \"name\": \"isValidSignature\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"_x\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"mapToPoint\",\n \"outputs\": [\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"p\",\n \"type\": \"uint256[2]\"\n }\n ],\n \"stateMutability\": \"pure\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"signature\",\n \"type\": \"uint256[2]\"\n },\n {\n \"internalType\": \"uint256[4][]\",\n \"name\": \"pubkeys\",\n \"type\": \"uint256[4][]\"\n },\n {\n \"internalType\": \"uint256[2][]\",\n \"name\": \"messages\",\n \"type\": \"uint256[2][]\"\n }\n ],\n \"name\": \"verifyMultiple\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"checkResult\",\n \"type\": \"bool\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"callSuccess\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"signature\",\n \"type\": \"uint256[2]\"\n },\n {\n \"internalType\": \"uint256[4][]\",\n \"name\": \"pubkeys\",\n \"type\": \"uint256[4][]\"\n },\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"message\",\n \"type\": \"uint256[2]\"\n }\n ],\n \"name\": \"verifyMultipleSameMsg\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"checkResult\",\n \"type\": \"bool\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"callSuccess\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"signature\",\n \"type\": \"uint256[2]\"\n },\n {\n \"internalType\": \"uint256[4]\",\n \"name\": \"pubkey\",\n \"type\": \"uint256[4]\"\n },\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"message\",\n \"type\": \"uint256[2]\"\n }\n ],\n \"name\": \"verifySingle\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50612df8806100206000396000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c806391ec2d2b1161006657806391ec2d2b1461013b578063a850a9091461015b578063d58e77331461016e578063e242cce914610181578063ebbdac911461019457600080fd5b8063115000fe146100a3578063247dd9fb146100cb5780633e5476ce146100de5780638669026f146101085780639141376314610128575b600080fd5b6100b66100b1366004612708565b6101a7565b60405190151581526020015b60405180910390f35b6100b66100d9366004612785565b61030e565b6100f16100ec366004612841565b6103b8565b6040805192151583529015156020830152016100c2565b61011b6101163660046128ce565b61079f565b6040516100c29190612957565b6100f1610136366004612988565b6108bb565b61014e6101493660046128ce565b610d5c565b6040516100c29190612a86565b61011b6101693660046128ce565b610ff8565b61011b61017c366004612aa0565b6111d4565b6100b661018f366004612785565b6115aa565b6100f16101a2366004612ab9565b611609565b600081516020830151600080516020612d63833981519152828309600080516020612d638339815191528283098182830101600080516020612d638339815191528283840108600080516020612d638339815191528682600080516020612d6383398151915203860109935050600080516020612d638339815191528483600080516020612d63833981519152038301099150600080516020612d638339815191527f2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e584089450600080516020612d638339815191527e9713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d2830893506040870151925060608701519150600080516020612d638339815191528083600080516020612d63833981519152038508600080516020612d63833981519152848608099050600080516020612d63833981519152828460011b0994149290931491909116949350505050565b8051600090600080516020612d6383398151915211158061034157506020820151600080516020612d6383398151915211155b1561034e57506000919050565b60405163e242cce960e01b8152309063e242cce990610371908590600401612957565b602060405180830381865afa15801561038e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103b29190612b1c565b92915050565b60008083806103e25760405162461bcd60e51b81526004016103d990612b3e565b60405180910390fd5b60006103ef826001612b95565b6103fa906006612ba8565b90506000816001600160401b038111156104165761041661269a565b60405190808252806020026020018201604052801561043f578160200160208202803683370190505b50905088600060200201358160008151811061045d5761045d612b06565b602090810291909101015288600160200201358160018151811061048357610483612b06565b602002602001018181525050600080516020612d43833981519152816002815181106104b1576104b1612b06565b602002602001018181525050600080516020612d23833981519152816003815181106104df576104df612b06565b602002602001018181525050600080516020612d838339815191528160048151811061050d5761050d612b06565b602002602001018181525050600080516020612da38339815191528160058151811061053b5761053b612b06565b60200260200101818152505060005b8381101561075a57863582610560836006612ba8565b61056b906006612b95565b8151811061057b5761057b612b06565b602090810291909101015286600160200201358261059a836006612ba8565b6105a5906007612b95565b815181106105b5576105b5612b06565b6020026020010181815250508888828181106105d3576105d3612b06565b9050608002016001600481106105eb576105eb612b06565b6020020135826105fc836006612ba8565b610607906008612b95565b8151811061061757610617612b06565b60200260200101818152505088888281811061063557610635612b06565b90506080020160006004811061064d5761064d612b06565b60200201358261065e836006612ba8565b610669906009612b95565b8151811061067957610679612b06565b60200260200101818152505088888281811061069757610697612b06565b9050608002016003600481106106af576106af612b06565b6020020135826106c0836006612ba8565b6106cb90600a612b95565b815181106106db576106db612b06565b6020026020010181815250508888828181106106f9576106f9612b06565b90506080020160026004811061071157610711612b06565b602002013582610722836006612ba8565b61072d90600b612b95565b8151811061073d5761073d612b06565b60209081029190910101528061075281612bbf565b91505061054a565b50610763612640565b602081602085026020850160085afa945084610789576000809550955050505050610796565b5115159450600193505050505b94509492505050565b6107a761265e565b6040516391ec2d2b60e01b815260009030906391ec2d2b906107cf9087908790600401612bd8565b600060405180830381865afa1580156107ec573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108149190810190612bf9565b9050600080600080601885016001600160c01b0381511693506030860190506001600160c01b038151169450600080516020612d6383398151915285600080516020612d63833981519152600160c01b870908604887015160608801516001600160c01b0390811697501694509250600080516020612d6383398151915290508481600160c01b860908604080518082019091529283526020830152509695505050505050565b60008084806108dc5760405162461bcd60e51b81526004016103d990612b3e565b8084146109495760405162461bcd60e51b815260206004820152603560248201527f424c533a206e756d626572206f66207075626c6963206b65797320616e64206d604482015274195cdcd859d95cc81b5d5cdd08189948195c5d585b605a1b60648201526084016103d9565b6000610956826001612b95565b610961906006612ba8565b90506000816001600160401b0381111561097d5761097d61269a565b6040519080825280602002602001820160405280156109a6578160200160208202803683370190505b5090508960006020020135816000815181106109c4576109c4612b06565b60209081029190910101528960016020020135816001815181106109ea576109ea612b06565b602002602001018181525050600080516020612d4383398151915281600281518110610a1857610a18612b06565b602002602001018181525050600080516020612d2383398151915281600381518110610a4657610a46612b06565b602002602001018181525050600080516020612d8383398151915281600481518110610a7457610a74612b06565b602002602001018181525050600080516020612da383398151915281600581518110610aa257610aa2612b06565b60200260200101818152505060005b83811015610d1657878782818110610acb57610acb612b06565b905060400201600060028110610ae357610ae3612b06565b602002013582610af4836006612ba8565b610aff906006612b95565b81518110610b0f57610b0f612b06565b602002602001018181525050878782818110610b2d57610b2d612b06565b905060400201600160028110610b4557610b45612b06565b602002013582610b56836006612ba8565b610b61906007612b95565b81518110610b7157610b71612b06565b602002602001018181525050898982818110610b8f57610b8f612b06565b905060800201600160048110610ba757610ba7612b06565b602002013582610bb8836006612ba8565b610bc3906008612b95565b81518110610bd357610bd3612b06565b602002602001018181525050898982818110610bf157610bf1612b06565b905060800201600060048110610c0957610c09612b06565b602002013582610c1a836006612ba8565b610c25906009612b95565b81518110610c3557610c35612b06565b602002602001018181525050898982818110610c5357610c53612b06565b905060800201600360048110610c6b57610c6b612b06565b602002013582610c7c836006612ba8565b610c8790600a612b95565b81518110610c9757610c97612b06565b602002602001018181525050898982818110610cb557610cb5612b06565b905060800201600260048110610ccd57610ccd612b06565b602002013582610cde836006612ba8565b610ce990600b612b95565b81518110610cf957610cf9612b06565b602090810291909101015280610d0e81612bbf565b915050610ab1565b50610d1f612640565b602081602085026020850160085afa945084610d45576000809550955050505050610d52565b5115159450600193505050505b9550959350505050565b80516060906000610d6e826020612b95565b610d79906040612b95565b610d84906004612b95565b6001600160401b03811115610d9b57610d9b61269a565b6040519080825280601f01601f191660200182016040528015610dc5576020820181803683370190505b5060408051606080825260808201909252919250600091906020820181803683370190505090506060820160005b84811015610e0d5760208188018101518383015201610df3565b5083016000815360010160608153600101600081536001810187905260210160208153506000600283604051610e439190612c6f565b602060405180830381855afa158015610e60573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610e839190612c8b565b9050600060429450848452816020850152600160408501536041840188905260206061850153600284604051610eb99190612c6f565b602060405180830381855afa158015610ed6573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610ef99190612c8b565b905080602084015280821880602086015250600260408501536041840188905260206061850153600284604051610f309190612c6f565b602060405180830381855afa158015610f4d573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610f709190612c8b565b905080604084015280821880602086015250600360408501536041840188905260206061850153600284604051610fa79190612c6f565b602060405180830381855afa158015610fc4573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610fe79190612c8b565b606084015250909695505050505050565b61100061265e565b604051638669026f60e01b81526000903090638669026f906110289087908790600401612bd8565b6040805180830381865afa158015611044573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110689190612ca4565b805160405163d58e773360e01b81526004810191909152909150600090309063d58e7733906024016040805180830381865afa1580156110ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110d09190612ca4565b602083015160405163d58e773360e01b81526004810191909152909150600090309063d58e7733906024016040805180830381865afa158015611117573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113b9190612ca4565b905061114561267c565b825181526020808401518282015282516040808401919091529083015160608301526000908460808460066107d05a03fa9050808061118057fe5b50806111c85760405162461bcd60e51b8152602060048201526017602482015276109314ce88189b881859190818d85b1b0819985a5b1959604a1b60448201526064016103d9565b50919695505050505050565b6111dc61265e565b600080516020612d6383398151915282106112455760405162461bcd60e51b815260206004820152602360248201527f6d6170546f506f696e7446543a20696e76616c6964206669656c6420656c656d604482015262195b9d60ea1b60648201526084016103d9565b81600061125182611790565b9150506000600080516020612d638339815191528061127257611272612cf9565b8384099050600080516020612d638339815191526004820890506000600080516020612d6383398151915277b3c4d79d41a91759a9e4c7e359b6b89eaec68e62effffffd850990506000600080516020612d6383398151915283830990506112d9816117b9565b9050600080516020612d638339815191528283099150600080516020612d638339815191528183099150600080516020612d638339815191528286099150600080516020612d6383398151915261133e83600080516020612d63833981519152612d0f565b7759e26bcea0d48bacd4f263f1acdb5c4f5763473177fffffe089450600080516020612d638339815191528586099150600080516020612d638339815191528583099150600080516020612d6383398151915260038308915060006113a283611790565b909350905080156113ea57846113cd576113ca83600080516020612d63833981519152612d0f565b92505b505060408051808201909152938452602084015250909392505050565b600080516020612d638339815191526001870861141590600080516020612d63833981519152612d0f565b9550600080516020612d638339815191528687099250600080516020612d638339815191528684099250600080516020612d6383398151915260038408925061145d83611790565b9093509050801561148557846113cd576113ca83600080516020612d63833981519152612d0f565b600080516020612d638339815191528485099550600080516020612d638339815191528687099550600080516020612d638339815191528287099550600080516020612d638339815191528287099550600080516020612d63833981519152600187089550600080516020612d638339815191528687099250600080516020612d638339815191528684099250600080516020612d6383398151915260038408925061153083611790565b90935090508061158d5760405162461bcd60e51b815260206004820152602260248201527f424c533a20626164206674206d617070696e6720696d706c656d656e7461746960448201526137b760f11b60648201526084016103d9565b846113cd576113ca83600080516020612d63833981519152612d0f565b600081516020830151600080516020612d63833981519152828309600080516020612d638339815191528382099050600080516020612d63833981519152600382089050600080516020612d6383398151915282830914949350505050565b60008060006040518061018001604052808760006002811061162d5761162d612b06565b602002013581526020018760016002811061164a5761164a612b06565b60200201358152602001600080516020612d438339815191528152602001600080516020612d238339815191528152602001600080516020612d838339815191528152602001600080516020612da38339815191528152602001856000600281106116b7576116b7612b06565b60200201358152602001856001600281106116d4576116d4612b06565b60200201358152602001866001600481106116f1576116f1612b06565b602002013581526020018660006004811061170e5761170e612b06565b602002013581526020018660036004811061172b5761172b612b06565b602002013581526020018660026004811061174857611748612b06565b602002013590529050611759612640565b60006020826101808560085afa90508061177c5760008094509450505050611788565b50511515925060019150505b935093915050565b60008061179c836117c4565b915082600080516020612d63833981519152838409149050915091565b60006103b282611ef9565b6000600080516020612d638339815191528083840991508083830981838209828283098385830984848309858484098684850997508684840987858409945087898a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087838a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985050868889099750868889099750868889099750868889099750868889099750868889099750868489099750868889099750868889099750868889099750868889099750868889099750868989099750868889099750868889099750868889099750868889099750868889099750868889099750868989099750868889099750868889099750868889099750868889099750868889099750868689099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868189099750508587880996508587880996508587880996508585880996508587880996508587880996508587880996508585880996508587880996508587880996508587880996508587880996508587880996508587880996508587880996508587880996508583880996508587880996508587880996508587880996508587880996508581880996508587880996508587880996508587880996508587880996508583880996508587880996508587880996508587880996508584880996508587880996508587880996508587880996508587880996508587880996508581880996505050505050808283099392505050565b6000600080516020612d638339815191528083840991508083830981838209828283098385830984848309858484098684850997508684840987858409945087898a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087838a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985050868889099750868889099750868889099750868889099750868889099750868889099750868489099750868889099750868889099750868889099750868889099750868889099750868989099750868889099750868889099750868889099750868889099750868889099750868889099750868989099750868889099750868889099750868889099750868889099750868889099750868689099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868189099750508587880996508587880996508587880996508585880996508587880996508587880996508587880996508585880996508587880996508587880996508587880996508587880996508587880996508587880996508587880996508587880996508583880996508587880996508587880996508587880996508587880996508581880996505050838586099450838586099450838586099450838586099450838186099450508284850993508284850993508284850993508281850993508284850993508284850993508285850993508284850993508284850993508284850993508284850993508284850993508284850993508281850995945050505050565b60405180602001604052806001906020820280368337509192915050565b60405180604001604052806002906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b03811182821017156126d2576126d261269a565b60405290565b604051601f8201601f191681016001600160401b03811182821017156127005761270061269a565b604052919050565b60006080828403121561271a57600080fd5b82601f83011261272957600080fd5b604051608081018181106001600160401b038211171561274b5761274b61269a565b60405280608084018581111561276057600080fd5b845b8181101561277a578035835260209283019201612762565b509195945050505050565b60006040828403121561279757600080fd5b82601f8301126127a657600080fd5b6127ae6126b0565b8060408401858111156127c057600080fd5b845b818110156127da5780358452602093840193016127c2565b509095945050505050565b80604081018310156103b257600080fd5b60008083601f84011261280857600080fd5b5081356001600160401b0381111561281f57600080fd5b6020830191508360208260071b850101111561283a57600080fd5b9250929050565b60008060008060a0858703121561285757600080fd5b61286186866127e5565b935060408501356001600160401b0381111561287c57600080fd5b612888878288016127f6565b909450925061289c905086606087016127e5565b905092959194509250565b60006001600160401b038211156128c0576128c061269a565b50601f01601f191660200190565b600080604083850312156128e157600080fd5b8235915060208301356001600160401b038111156128fe57600080fd5b8301601f8101851361290f57600080fd5b803561292261291d826128a7565b6126d8565b81815286602083850101111561293757600080fd5b816020840160208301376000602083830101528093505050509250929050565b60408101818360005b600281101561297f578151835260209283019290910190600101612960565b50505092915050565b6000806000806000608086880312156129a057600080fd5b6129aa87876127e5565b945060408601356001600160401b03808211156129c657600080fd5b6129d289838a016127f6565b909650945060608801359150808211156129eb57600080fd5b818801915088601f8301126129ff57600080fd5b813581811115612a0e57600080fd5b8960208260061b8501011115612a2357600080fd5b9699959850939650602001949392505050565b60005b83811015612a51578181015183820152602001612a39565b50506000910152565b60008151808452612a72816020860160208601612a36565b601f01601f19169290920160200192915050565b602081526000612a996020830184612a5a565b9392505050565b600060208284031215612ab257600080fd5b5035919050565b60008060006101008486031215612acf57600080fd5b612ad985856127e5565b925060c0840185811115612aec57600080fd5b604085019250612afc86826127e5565b9150509250925092565b634e487b7160e01b600052603260045260246000fd5b600060208284031215612b2e57600080fd5b81518015158114612a9957600080fd5b60208082526021908201527f424c533a206e756d626572206f66207075626c6963206b6579206973207a65726040820152606f60f81b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b808201808211156103b2576103b2612b7f565b80820281158282048414176103b2576103b2612b7f565b600060018201612bd157612bd1612b7f565b5060010190565b828152604060208201526000612bf16040830184612a5a565b949350505050565b600060208284031215612c0b57600080fd5b81516001600160401b03811115612c2157600080fd5b8201601f81018413612c3257600080fd5b8051612c4061291d826128a7565b818152856020838501011115612c5557600080fd5b612c66826020830160208601612a36565b95945050505050565b60008251612c81818460208701612a36565b9190910192915050565b600060208284031215612c9d57600080fd5b5051919050565b600060408284031215612cb657600080fd5b82601f830112612cc557600080fd5b612ccd6126b0565b806040840185811115612cdf57600080fd5b845b818110156127da578051845260209384019301612ce1565b634e487b7160e01b600052601260045260246000fd5b818103818111156103b2576103b2612b7f56fe1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c230644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9da264697066735822122085f910855a39dd4d2f9582253d737b6f9c450d7d8e7383f636149d598d69b6ac64736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b506004361061009e5760003560e01c806391ec2d2b1161006657806391ec2d2b1461013b578063a850a9091461015b578063d58e77331461016e578063e242cce914610181578063ebbdac911461019457600080fd5b8063115000fe146100a3578063247dd9fb146100cb5780633e5476ce146100de5780638669026f146101085780639141376314610128575b600080fd5b6100b66100b1366004612708565b6101a7565b60405190151581526020015b60405180910390f35b6100b66100d9366004612785565b61030e565b6100f16100ec366004612841565b6103b8565b6040805192151583529015156020830152016100c2565b61011b6101163660046128ce565b61079f565b6040516100c29190612957565b6100f1610136366004612988565b6108bb565b61014e6101493660046128ce565b610d5c565b6040516100c29190612a86565b61011b6101693660046128ce565b610ff8565b61011b61017c366004612aa0565b6111d4565b6100b661018f366004612785565b6115aa565b6100f16101a2366004612ab9565b611609565b600081516020830151600080516020612d63833981519152828309600080516020612d638339815191528283098182830101600080516020612d638339815191528283840108600080516020612d638339815191528682600080516020612d6383398151915203860109935050600080516020612d638339815191528483600080516020612d63833981519152038301099150600080516020612d638339815191527f2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e584089450600080516020612d638339815191527e9713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d2830893506040870151925060608701519150600080516020612d638339815191528083600080516020612d63833981519152038508600080516020612d63833981519152848608099050600080516020612d63833981519152828460011b0994149290931491909116949350505050565b8051600090600080516020612d6383398151915211158061034157506020820151600080516020612d6383398151915211155b1561034e57506000919050565b60405163e242cce960e01b8152309063e242cce990610371908590600401612957565b602060405180830381865afa15801561038e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103b29190612b1c565b92915050565b60008083806103e25760405162461bcd60e51b81526004016103d990612b3e565b60405180910390fd5b60006103ef826001612b95565b6103fa906006612ba8565b90506000816001600160401b038111156104165761041661269a565b60405190808252806020026020018201604052801561043f578160200160208202803683370190505b50905088600060200201358160008151811061045d5761045d612b06565b602090810291909101015288600160200201358160018151811061048357610483612b06565b602002602001018181525050600080516020612d43833981519152816002815181106104b1576104b1612b06565b602002602001018181525050600080516020612d23833981519152816003815181106104df576104df612b06565b602002602001018181525050600080516020612d838339815191528160048151811061050d5761050d612b06565b602002602001018181525050600080516020612da38339815191528160058151811061053b5761053b612b06565b60200260200101818152505060005b8381101561075a57863582610560836006612ba8565b61056b906006612b95565b8151811061057b5761057b612b06565b602090810291909101015286600160200201358261059a836006612ba8565b6105a5906007612b95565b815181106105b5576105b5612b06565b6020026020010181815250508888828181106105d3576105d3612b06565b9050608002016001600481106105eb576105eb612b06565b6020020135826105fc836006612ba8565b610607906008612b95565b8151811061061757610617612b06565b60200260200101818152505088888281811061063557610635612b06565b90506080020160006004811061064d5761064d612b06565b60200201358261065e836006612ba8565b610669906009612b95565b8151811061067957610679612b06565b60200260200101818152505088888281811061069757610697612b06565b9050608002016003600481106106af576106af612b06565b6020020135826106c0836006612ba8565b6106cb90600a612b95565b815181106106db576106db612b06565b6020026020010181815250508888828181106106f9576106f9612b06565b90506080020160026004811061071157610711612b06565b602002013582610722836006612ba8565b61072d90600b612b95565b8151811061073d5761073d612b06565b60209081029190910101528061075281612bbf565b91505061054a565b50610763612640565b602081602085026020850160085afa945084610789576000809550955050505050610796565b5115159450600193505050505b94509492505050565b6107a761265e565b6040516391ec2d2b60e01b815260009030906391ec2d2b906107cf9087908790600401612bd8565b600060405180830381865afa1580156107ec573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108149190810190612bf9565b9050600080600080601885016001600160c01b0381511693506030860190506001600160c01b038151169450600080516020612d6383398151915285600080516020612d63833981519152600160c01b870908604887015160608801516001600160c01b0390811697501694509250600080516020612d6383398151915290508481600160c01b860908604080518082019091529283526020830152509695505050505050565b60008084806108dc5760405162461bcd60e51b81526004016103d990612b3e565b8084146109495760405162461bcd60e51b815260206004820152603560248201527f424c533a206e756d626572206f66207075626c6963206b65797320616e64206d604482015274195cdcd859d95cc81b5d5cdd08189948195c5d585b605a1b60648201526084016103d9565b6000610956826001612b95565b610961906006612ba8565b90506000816001600160401b0381111561097d5761097d61269a565b6040519080825280602002602001820160405280156109a6578160200160208202803683370190505b5090508960006020020135816000815181106109c4576109c4612b06565b60209081029190910101528960016020020135816001815181106109ea576109ea612b06565b602002602001018181525050600080516020612d4383398151915281600281518110610a1857610a18612b06565b602002602001018181525050600080516020612d2383398151915281600381518110610a4657610a46612b06565b602002602001018181525050600080516020612d8383398151915281600481518110610a7457610a74612b06565b602002602001018181525050600080516020612da383398151915281600581518110610aa257610aa2612b06565b60200260200101818152505060005b83811015610d1657878782818110610acb57610acb612b06565b905060400201600060028110610ae357610ae3612b06565b602002013582610af4836006612ba8565b610aff906006612b95565b81518110610b0f57610b0f612b06565b602002602001018181525050878782818110610b2d57610b2d612b06565b905060400201600160028110610b4557610b45612b06565b602002013582610b56836006612ba8565b610b61906007612b95565b81518110610b7157610b71612b06565b602002602001018181525050898982818110610b8f57610b8f612b06565b905060800201600160048110610ba757610ba7612b06565b602002013582610bb8836006612ba8565b610bc3906008612b95565b81518110610bd357610bd3612b06565b602002602001018181525050898982818110610bf157610bf1612b06565b905060800201600060048110610c0957610c09612b06565b602002013582610c1a836006612ba8565b610c25906009612b95565b81518110610c3557610c35612b06565b602002602001018181525050898982818110610c5357610c53612b06565b905060800201600360048110610c6b57610c6b612b06565b602002013582610c7c836006612ba8565b610c8790600a612b95565b81518110610c9757610c97612b06565b602002602001018181525050898982818110610cb557610cb5612b06565b905060800201600260048110610ccd57610ccd612b06565b602002013582610cde836006612ba8565b610ce990600b612b95565b81518110610cf957610cf9612b06565b602090810291909101015280610d0e81612bbf565b915050610ab1565b50610d1f612640565b602081602085026020850160085afa945084610d45576000809550955050505050610d52565b5115159450600193505050505b9550959350505050565b80516060906000610d6e826020612b95565b610d79906040612b95565b610d84906004612b95565b6001600160401b03811115610d9b57610d9b61269a565b6040519080825280601f01601f191660200182016040528015610dc5576020820181803683370190505b5060408051606080825260808201909252919250600091906020820181803683370190505090506060820160005b84811015610e0d5760208188018101518383015201610df3565b5083016000815360010160608153600101600081536001810187905260210160208153506000600283604051610e439190612c6f565b602060405180830381855afa158015610e60573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610e839190612c8b565b9050600060429450848452816020850152600160408501536041840188905260206061850153600284604051610eb99190612c6f565b602060405180830381855afa158015610ed6573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610ef99190612c8b565b905080602084015280821880602086015250600260408501536041840188905260206061850153600284604051610f309190612c6f565b602060405180830381855afa158015610f4d573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610f709190612c8b565b905080604084015280821880602086015250600360408501536041840188905260206061850153600284604051610fa79190612c6f565b602060405180830381855afa158015610fc4573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610fe79190612c8b565b606084015250909695505050505050565b61100061265e565b604051638669026f60e01b81526000903090638669026f906110289087908790600401612bd8565b6040805180830381865afa158015611044573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110689190612ca4565b805160405163d58e773360e01b81526004810191909152909150600090309063d58e7733906024016040805180830381865afa1580156110ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110d09190612ca4565b602083015160405163d58e773360e01b81526004810191909152909150600090309063d58e7733906024016040805180830381865afa158015611117573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113b9190612ca4565b905061114561267c565b825181526020808401518282015282516040808401919091529083015160608301526000908460808460066107d05a03fa9050808061118057fe5b50806111c85760405162461bcd60e51b8152602060048201526017602482015276109314ce88189b881859190818d85b1b0819985a5b1959604a1b60448201526064016103d9565b50919695505050505050565b6111dc61265e565b600080516020612d6383398151915282106112455760405162461bcd60e51b815260206004820152602360248201527f6d6170546f506f696e7446543a20696e76616c6964206669656c6420656c656d604482015262195b9d60ea1b60648201526084016103d9565b81600061125182611790565b9150506000600080516020612d638339815191528061127257611272612cf9565b8384099050600080516020612d638339815191526004820890506000600080516020612d6383398151915277b3c4d79d41a91759a9e4c7e359b6b89eaec68e62effffffd850990506000600080516020612d6383398151915283830990506112d9816117b9565b9050600080516020612d638339815191528283099150600080516020612d638339815191528183099150600080516020612d638339815191528286099150600080516020612d6383398151915261133e83600080516020612d63833981519152612d0f565b7759e26bcea0d48bacd4f263f1acdb5c4f5763473177fffffe089450600080516020612d638339815191528586099150600080516020612d638339815191528583099150600080516020612d6383398151915260038308915060006113a283611790565b909350905080156113ea57846113cd576113ca83600080516020612d63833981519152612d0f565b92505b505060408051808201909152938452602084015250909392505050565b600080516020612d638339815191526001870861141590600080516020612d63833981519152612d0f565b9550600080516020612d638339815191528687099250600080516020612d638339815191528684099250600080516020612d6383398151915260038408925061145d83611790565b9093509050801561148557846113cd576113ca83600080516020612d63833981519152612d0f565b600080516020612d638339815191528485099550600080516020612d638339815191528687099550600080516020612d638339815191528287099550600080516020612d638339815191528287099550600080516020612d63833981519152600187089550600080516020612d638339815191528687099250600080516020612d638339815191528684099250600080516020612d6383398151915260038408925061153083611790565b90935090508061158d5760405162461bcd60e51b815260206004820152602260248201527f424c533a20626164206674206d617070696e6720696d706c656d656e7461746960448201526137b760f11b60648201526084016103d9565b846113cd576113ca83600080516020612d63833981519152612d0f565b600081516020830151600080516020612d63833981519152828309600080516020612d638339815191528382099050600080516020612d63833981519152600382089050600080516020612d6383398151915282830914949350505050565b60008060006040518061018001604052808760006002811061162d5761162d612b06565b602002013581526020018760016002811061164a5761164a612b06565b60200201358152602001600080516020612d438339815191528152602001600080516020612d238339815191528152602001600080516020612d838339815191528152602001600080516020612da38339815191528152602001856000600281106116b7576116b7612b06565b60200201358152602001856001600281106116d4576116d4612b06565b60200201358152602001866001600481106116f1576116f1612b06565b602002013581526020018660006004811061170e5761170e612b06565b602002013581526020018660036004811061172b5761172b612b06565b602002013581526020018660026004811061174857611748612b06565b602002013590529050611759612640565b60006020826101808560085afa90508061177c5760008094509450505050611788565b50511515925060019150505b935093915050565b60008061179c836117c4565b915082600080516020612d63833981519152838409149050915091565b60006103b282611ef9565b6000600080516020612d638339815191528083840991508083830981838209828283098385830984848309858484098684850997508684840987858409945087898a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087838a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985050868889099750868889099750868889099750868889099750868889099750868889099750868489099750868889099750868889099750868889099750868889099750868889099750868989099750868889099750868889099750868889099750868889099750868889099750868889099750868989099750868889099750868889099750868889099750868889099750868889099750868689099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868189099750508587880996508587880996508587880996508585880996508587880996508587880996508587880996508585880996508587880996508587880996508587880996508587880996508587880996508587880996508587880996508587880996508583880996508587880996508587880996508587880996508587880996508581880996508587880996508587880996508587880996508587880996508583880996508587880996508587880996508587880996508584880996508587880996508587880996508587880996508587880996508587880996508581880996505050505050808283099392505050565b6000600080516020612d638339815191528083840991508083830981838209828283098385830984848309858484098684850997508684840987858409945087898a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087878a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a09985087898a09985087898a09985087898a09985087838a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087828a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087848a09985087898a09985087898a09985087898a09985087898a09985087898a09985087868a09985087898a09985087898a099850878a8a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087898a09985087818a09985050868889099750868889099750868889099750868889099750868889099750868889099750868489099750868889099750868889099750868889099750868889099750868889099750868989099750868889099750868889099750868889099750868889099750868889099750868889099750868989099750868889099750868889099750868889099750868889099750868889099750868689099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868889099750868189099750508587880996508587880996508587880996508585880996508587880996508587880996508587880996508585880996508587880996508587880996508587880996508587880996508587880996508587880996508587880996508587880996508583880996508587880996508587880996508587880996508587880996508581880996505050838586099450838586099450838586099450838586099450838186099450508284850993508284850993508284850993508281850993508284850993508284850993508285850993508284850993508284850993508284850993508284850993508284850993508284850993508281850995945050505050565b60405180602001604052806001906020820280368337509192915050565b60405180604001604052806002906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b03811182821017156126d2576126d261269a565b60405290565b604051601f8201601f191681016001600160401b03811182821017156127005761270061269a565b604052919050565b60006080828403121561271a57600080fd5b82601f83011261272957600080fd5b604051608081018181106001600160401b038211171561274b5761274b61269a565b60405280608084018581111561276057600080fd5b845b8181101561277a578035835260209283019201612762565b509195945050505050565b60006040828403121561279757600080fd5b82601f8301126127a657600080fd5b6127ae6126b0565b8060408401858111156127c057600080fd5b845b818110156127da5780358452602093840193016127c2565b509095945050505050565b80604081018310156103b257600080fd5b60008083601f84011261280857600080fd5b5081356001600160401b0381111561281f57600080fd5b6020830191508360208260071b850101111561283a57600080fd5b9250929050565b60008060008060a0858703121561285757600080fd5b61286186866127e5565b935060408501356001600160401b0381111561287c57600080fd5b612888878288016127f6565b909450925061289c905086606087016127e5565b905092959194509250565b60006001600160401b038211156128c0576128c061269a565b50601f01601f191660200190565b600080604083850312156128e157600080fd5b8235915060208301356001600160401b038111156128fe57600080fd5b8301601f8101851361290f57600080fd5b803561292261291d826128a7565b6126d8565b81815286602083850101111561293757600080fd5b816020840160208301376000602083830101528093505050509250929050565b60408101818360005b600281101561297f578151835260209283019290910190600101612960565b50505092915050565b6000806000806000608086880312156129a057600080fd5b6129aa87876127e5565b945060408601356001600160401b03808211156129c657600080fd5b6129d289838a016127f6565b909650945060608801359150808211156129eb57600080fd5b818801915088601f8301126129ff57600080fd5b813581811115612a0e57600080fd5b8960208260061b8501011115612a2357600080fd5b9699959850939650602001949392505050565b60005b83811015612a51578181015183820152602001612a39565b50506000910152565b60008151808452612a72816020860160208601612a36565b601f01601f19169290920160200192915050565b602081526000612a996020830184612a5a565b9392505050565b600060208284031215612ab257600080fd5b5035919050565b60008060006101008486031215612acf57600080fd5b612ad985856127e5565b925060c0840185811115612aec57600080fd5b604085019250612afc86826127e5565b9150509250925092565b634e487b7160e01b600052603260045260246000fd5b600060208284031215612b2e57600080fd5b81518015158114612a9957600080fd5b60208082526021908201527f424c533a206e756d626572206f66207075626c6963206b6579206973207a65726040820152606f60f81b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b808201808211156103b2576103b2612b7f565b80820281158282048414176103b2576103b2612b7f565b600060018201612bd157612bd1612b7f565b5060010190565b828152604060208201526000612bf16040830184612a5a565b949350505050565b600060208284031215612c0b57600080fd5b81516001600160401b03811115612c2157600080fd5b8201601f81018413612c3257600080fd5b8051612c4061291d826128a7565b818152856020838501011115612c5557600080fd5b612c66826020830160208601612a36565b95945050505050565b60008251612c81818460208701612a36565b9190910192915050565b600060208284031215612c9d57600080fd5b5051919050565b600060408284031215612cb657600080fd5b82601f830112612cc557600080fd5b612ccd6126b0565b806040840185811115612cdf57600080fd5b845b818110156127da578051845260209384019301612ce1565b634e487b7160e01b600052601260045260246000fd5b818103818111156103b2576103b2612b7f56fe1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c230644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9da264697066735822122085f910855a39dd4d2f9582253d737b6f9c450d7d8e7383f636149d598d69b6ac64736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var BN256G2Artifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"BN256G2\",\n \"sourceName\": \"contracts/common/BN256G2.sol\",\n \"abi\": [\n {\n \"inputs\": [],\n \"name\": \"G2_NEG_X_IM\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"G2_NEG_X_RE\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"G2_NEG_Y_IM\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"G2_NEG_Y_RE\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt1xx\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt1xy\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt1yx\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt1yy\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt2xx\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt2xy\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt2yx\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt2yy\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"ecTwistAdd\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"s\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt1xx\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt1xy\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt1yx\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"pt1yy\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"ecTwistMul\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"getFieldModulus\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"pure\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50610dfd806100206000396000f3fe608060405234801561001057600080fd5b506004361061006d5760003560e01c80635120675214610072578063779d890d146100ac578063783bde80146100c05780639b0c399a146100e7578063ad50f9c11461010e578063cbe96a5014610135578063defbcdee14610168575b600080fd5b6100997f1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d81565b6040519081526020015b60405180910390f35b600080516020610da8833981519152610099565b6100997f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c281565b6100997f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed81565b6100997f275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec81565b610148610143366004610c8c565b61017b565b6040805194855260208501939093529183015260608201526080016100a3565b610148610176366004610ce1565b61031a565b60008080808b15801561018c57508a155b8015610196575089155b80156101a0575088155b1561020a57871580156101b1575086155b80156101bb575085155b80156101c5575084155b6101fa576101d5888888886103b1565b6101fa5760405162461bcd60e51b81526004016101f190610d1c565b60405180910390fd5b508692508591508490508361030b565b87158015610216575086155b8015610220575085155b801561022a575084155b156102675761023b8c8c8c8c6103b1565b6102575760405162461bcd60e51b81526004016101f190610d1c565b508a92508991508890508761030b565b6102738c8c8c8c6103b1565b61028f5760405162461bcd60e51b81526004016101f190610d1c565b61029b888888886103b1565b6102b75760405162461bcd60e51b81526004016101f190610d1c565b60006102d18d8d8d8d600160008f8f8f8f60016000610466565b90506103018160005b602090810291909101519083015160408401516060850151608086015160a08701516106f1565b9450945094509450505b98509850985098945050505050565b600080808060018815801561032d575087155b8015610337575086155b8015610341575085155b15610355575060019750879550600061037d565b610361898989896103b1565b61037d5760405162461bcd60e51b81526004016101f190610d1c565b600061038f8b8b8b8b8b87600061075c565b905061039c8160006102da565b929e919d509b50909950975050505050505050565b60008060008060006103c5878789896107df565b90945092506103d6898981816107df565b90925090506103e782828b8b6107df565b90925090506103f884848484610850565b909450925061044884847f2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e57e9713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d2610850565b909450925083158015610459575082155b9998505050505050505050565b61046e610c50565b8815801561047a575087155b156104bc578686868686868660005b60a089019290925260808801929092526060870192909252604086019290925260208581019390935290910201526106e1565b821580156104c8575081155b156104db578c8c8c8c8c8c866000610489565b6104e785858b8b6107df565b90955093506104f88b8b85856107df565b6060830152604082015261050e87878b8b6107df565b909750955061051f8d8d85856107df565b60a0830152608082018190528714801561053c575060a081015186145b15610581576040810151851480156105575750606081015184145b156105725761056a8d8d8d8d8d8d610892565b866000610489565b60016000818180808681610489565b61058d898985856107df565b90935091506105ad858583600260200201518460035b6020020151610850565b909d509b506105c887878360045b60200201518460056105a3565b909b5099506105d98b8b81816107df565b90995097506105fa89898360045b60200201518460055b60200201516107df565b909550935061060b89898d8d6107df565b909950975061061c898985856107df565b60a083015260808201526106328d8d81816107df565b9097509550610643878785856107df565b909750955061065487878b8b610850565b909750955061066585856002610ada565b909350915061067687878585610850565b90975095506106878b8b89896107df565b6020830152815261069a85858989610850565b909b5099506106ab8d8d8d8d6107df565b909b5099506106c5898983600260200201518460036105f0565b909d509b506106d68b8b8f8f610850565b606083015260408201525b9c9b505050505050505050505050565b600080600080600080610702610c6e565b61070c8989610b0d565b909350915061071d8d8d85856107df565b602083015281526107308b8b85856107df565b60608301819052604083018290528251602090930151929f929e50909c509a5098505050505050505050565b610764610c50565b87156107d45760018816156107a5578051602082015160408301516060840151608085015160a08601516107a29594939291908d8d8d8d8d8d610466565b90505b6107b3878787878787610892565b949b509299509097509550935091506107cd600289610d5e565b9750610764565b979650505050505050565b60008061081d600080516020610da8833981519152858809600080516020610da8833981519152858809600080516020610da8833981519152610b98565b600080516020610da883398151915280868809600080516020610da8833981519152868a09089150915094509492505050565b60008061086c8685600080516020610da8833981519152610b98565b6108858685600080516020610da8833981519152610b98565b9150915094509492505050565b6000806000806000806108a3610c50565b6108af8d8d6003610ada565b602083018190528183526108c591908f8f6107df565b602083015281526108d88b8b8b8b6107df565b90995097506108e98d8d8d8d6107df565b606083015260408201819052610909908260035b60200201518b8b6107df565b60608301526040820152805161092c908260015b602002015183518460016105f0565b6040830151919e509c5061094a908260035b60200201516008610ada565b60a083015260808201526109618d8d8360046105bb565b909d509b50610972898981816107df565b60a083015260808201526040810151606082015161099291906004610ada565b60608301819052604083018290526109ac91908f8f610850565b6060830152604082018190526109c49082600361091d565b606083015260408201526109da8b8b6008610ada565b602083018190528183526109f091908d8d6107df565b60208301819052818352610a0791908360046105e7565b602083015280825260408201516060830151610a25928460016105a3565b60608301526040820152610a3b8d8d6002610ada565b6020830152808252610a4f908260016108fd565b60208301528152610a6389898360046105e7565b60a083015260808201819052610a7b9082600561093e565b826004602002018360056020020191909152528060006020020151816001602002015182600260200201518360036020020151846004602002015185600560200201519650965096509650965096505096509650965096509650969050565b600080600080516020610da8833981519152838609600080516020610da883398151915284860991509150935093915050565b60008080610b4e600080516020610da883398151915280878809600080516020610da883398151915287880908600080516020610da8833981519152610bbc565b9050600080516020610da8833981519152818609600080516020610da8833981519152828609610b8c90600080516020610da8833981519152610d80565b92509250509250929050565b60008180610ba857610ba8610d48565b610bb28484610d80565b8508949350505050565b60008060405160208152602080820152602060408201528460608201526002840360808201528360a082015260208160c08360056107d05a03fa90519250905080610c495760405162461bcd60e51b815260206004820152601a60248201527f6572726f722077697468206d6f64756c617220696e766572736500000000000060448201526064016101f1565b5092915050565b6040518060c001604052806006906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b600080600080600080600080610100898b031215610ca957600080fd5b505086359860208801359850604088013597606081013597506080810135965060a0810135955060c0810135945060e0013592509050565b600080600080600060a08688031215610cf957600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b602080825260129082015271706f696e74206e6f7420696e20637572766560701b604082015260600190565b634e487b7160e01b600052601260045260246000fd5b600082610d7b57634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115610da157634e487b7160e01b600052601160045260246000fd5b9291505056fe30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47a264697066735822122024dcb3a9296b82f91b23679c198173b7089b6e2bf33b84c731f25089bfd8b7e964736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b506004361061006d5760003560e01c80635120675214610072578063779d890d146100ac578063783bde80146100c05780639b0c399a146100e7578063ad50f9c11461010e578063cbe96a5014610135578063defbcdee14610168575b600080fd5b6100997f1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d81565b6040519081526020015b60405180910390f35b600080516020610da8833981519152610099565b6100997f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c281565b6100997f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed81565b6100997f275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec81565b610148610143366004610c8c565b61017b565b6040805194855260208501939093529183015260608201526080016100a3565b610148610176366004610ce1565b61031a565b60008080808b15801561018c57508a155b8015610196575089155b80156101a0575088155b1561020a57871580156101b1575086155b80156101bb575085155b80156101c5575084155b6101fa576101d5888888886103b1565b6101fa5760405162461bcd60e51b81526004016101f190610d1c565b60405180910390fd5b508692508591508490508361030b565b87158015610216575086155b8015610220575085155b801561022a575084155b156102675761023b8c8c8c8c6103b1565b6102575760405162461bcd60e51b81526004016101f190610d1c565b508a92508991508890508761030b565b6102738c8c8c8c6103b1565b61028f5760405162461bcd60e51b81526004016101f190610d1c565b61029b888888886103b1565b6102b75760405162461bcd60e51b81526004016101f190610d1c565b60006102d18d8d8d8d600160008f8f8f8f60016000610466565b90506103018160005b602090810291909101519083015160408401516060850151608086015160a08701516106f1565b9450945094509450505b98509850985098945050505050565b600080808060018815801561032d575087155b8015610337575086155b8015610341575085155b15610355575060019750879550600061037d565b610361898989896103b1565b61037d5760405162461bcd60e51b81526004016101f190610d1c565b600061038f8b8b8b8b8b87600061075c565b905061039c8160006102da565b929e919d509b50909950975050505050505050565b60008060008060006103c5878789896107df565b90945092506103d6898981816107df565b90925090506103e782828b8b6107df565b90925090506103f884848484610850565b909450925061044884847f2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e57e9713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d2610850565b909450925083158015610459575082155b9998505050505050505050565b61046e610c50565b8815801561047a575087155b156104bc578686868686868660005b60a089019290925260808801929092526060870192909252604086019290925260208581019390935290910201526106e1565b821580156104c8575081155b156104db578c8c8c8c8c8c866000610489565b6104e785858b8b6107df565b90955093506104f88b8b85856107df565b6060830152604082015261050e87878b8b6107df565b909750955061051f8d8d85856107df565b60a0830152608082018190528714801561053c575060a081015186145b15610581576040810151851480156105575750606081015184145b156105725761056a8d8d8d8d8d8d610892565b866000610489565b60016000818180808681610489565b61058d898985856107df565b90935091506105ad858583600260200201518460035b6020020151610850565b909d509b506105c887878360045b60200201518460056105a3565b909b5099506105d98b8b81816107df565b90995097506105fa89898360045b60200201518460055b60200201516107df565b909550935061060b89898d8d6107df565b909950975061061c898985856107df565b60a083015260808201526106328d8d81816107df565b9097509550610643878785856107df565b909750955061065487878b8b610850565b909750955061066585856002610ada565b909350915061067687878585610850565b90975095506106878b8b89896107df565b6020830152815261069a85858989610850565b909b5099506106ab8d8d8d8d6107df565b909b5099506106c5898983600260200201518460036105f0565b909d509b506106d68b8b8f8f610850565b606083015260408201525b9c9b505050505050505050505050565b600080600080600080610702610c6e565b61070c8989610b0d565b909350915061071d8d8d85856107df565b602083015281526107308b8b85856107df565b60608301819052604083018290528251602090930151929f929e50909c509a5098505050505050505050565b610764610c50565b87156107d45760018816156107a5578051602082015160408301516060840151608085015160a08601516107a29594939291908d8d8d8d8d8d610466565b90505b6107b3878787878787610892565b949b509299509097509550935091506107cd600289610d5e565b9750610764565b979650505050505050565b60008061081d600080516020610da8833981519152858809600080516020610da8833981519152858809600080516020610da8833981519152610b98565b600080516020610da883398151915280868809600080516020610da8833981519152868a09089150915094509492505050565b60008061086c8685600080516020610da8833981519152610b98565b6108858685600080516020610da8833981519152610b98565b9150915094509492505050565b6000806000806000806108a3610c50565b6108af8d8d6003610ada565b602083018190528183526108c591908f8f6107df565b602083015281526108d88b8b8b8b6107df565b90995097506108e98d8d8d8d6107df565b606083015260408201819052610909908260035b60200201518b8b6107df565b60608301526040820152805161092c908260015b602002015183518460016105f0565b6040830151919e509c5061094a908260035b60200201516008610ada565b60a083015260808201526109618d8d8360046105bb565b909d509b50610972898981816107df565b60a083015260808201526040810151606082015161099291906004610ada565b60608301819052604083018290526109ac91908f8f610850565b6060830152604082018190526109c49082600361091d565b606083015260408201526109da8b8b6008610ada565b602083018190528183526109f091908d8d6107df565b60208301819052818352610a0791908360046105e7565b602083015280825260408201516060830151610a25928460016105a3565b60608301526040820152610a3b8d8d6002610ada565b6020830152808252610a4f908260016108fd565b60208301528152610a6389898360046105e7565b60a083015260808201819052610a7b9082600561093e565b826004602002018360056020020191909152528060006020020151816001602002015182600260200201518360036020020151846004602002015185600560200201519650965096509650965096505096509650965096509650969050565b600080600080516020610da8833981519152838609600080516020610da883398151915284860991509150935093915050565b60008080610b4e600080516020610da883398151915280878809600080516020610da883398151915287880908600080516020610da8833981519152610bbc565b9050600080516020610da8833981519152818609600080516020610da8833981519152828609610b8c90600080516020610da8833981519152610d80565b92509250509250929050565b60008180610ba857610ba8610d48565b610bb28484610d80565b8508949350505050565b60008060405160208152602080820152602060408201528460608201526002840360808201528360a082015260208160c08360056107d05a03fa90519250905080610c495760405162461bcd60e51b815260206004820152601a60248201527f6572726f722077697468206d6f64756c617220696e766572736500000000000060448201526064016101f1565b5092915050565b6040518060c001604052806006906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b600080600080600080600080610100898b031215610ca957600080fd5b505086359860208801359850604088013597606081013597506080810135965060a0810135955060c0810135945060e0013592509050565b600080600080600060a08688031215610cf957600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b602080825260129082015271706f696e74206e6f7420696e20637572766560701b604082015260600190565b634e487b7160e01b600052601260045260246000fd5b600082610d7b57634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115610da157634e487b7160e01b600052601160045260246000fd5b9291505056fe30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47a264697066735822122024dcb3a9296b82f91b23679c198173b7089b6e2bf33b84c731f25089bfd8b7e964736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var MerkleArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"Merkle\",\n \"sourceName\": \"contracts/common/Merkle.sol\",\n \"abi\": [],\n \"bytecode\": \"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220eeab68a149534820e1fc8be8e5a499f3c286d335c0406923df5f8dbafe7db56b64736f6c63430008130033\",\n \"deployedBytecode\": \"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220eeab68a149534820e1fc8be8e5a499f3c286d335c0406923df5f8dbafe7db56b64736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var CheckpointManagerArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"CheckpointManager\",\n \"sourceName\": \"contracts/root/CheckpointManager.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"DOMAIN\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"bls\",\n \"outputs\": [\n {\n \"internalType\": \"contract IBLS\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"bn256G2\",\n \"outputs\": [\n {\n \"internalType\": \"contract IBN256G2\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"chainId\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"checkpointBlockNumbers\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"checkpoints\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"epoch\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockNumber\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"eventRoot\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"currentCheckpointBlockNumber\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"currentEpoch\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"currentValidatorSet\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"_address\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"votingPower\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"currentValidatorSetHash\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"currentValidatorSetLength\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockNumber\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"getCheckpointBlock\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockNumber\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"leaf\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"leafIndex\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32[]\",\n \"name\": \"proof\",\n \"type\": \"bytes32[]\"\n }\n ],\n \"name\": \"getEventMembershipByBlockNumber\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"epoch\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"leaf\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"leafIndex\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32[]\",\n \"name\": \"proof\",\n \"type\": \"bytes32[]\"\n }\n ],\n \"name\": \"getEventMembershipByEpoch\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockNumber\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"getEventRootByBlock\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IBLS\",\n \"name\": \"newBls\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"contract IBN256G2\",\n \"name\": \"newBn256G2\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"chainId_\",\n \"type\": \"uint256\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"address\",\n \"name\": \"_address\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256[4]\",\n \"name\": \"blsKey\",\n \"type\": \"uint256[4]\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"votingPower\",\n \"type\": \"uint256\"\n }\n ],\n \"internalType\": \"struct ICheckpointManager.Validator[]\",\n \"name\": \"newValidatorSet\",\n \"type\": \"tuple[]\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"components\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"blockHash\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockRound\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"currentValidatorSetHash\",\n \"type\": \"bytes32\"\n }\n ],\n \"internalType\": \"struct ICheckpointManager.CheckpointMetadata\",\n \"name\": \"checkpointMetadata\",\n \"type\": \"tuple\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"epoch\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockNumber\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"eventRoot\",\n \"type\": \"bytes32\"\n }\n ],\n \"internalType\": \"struct ICheckpointManager.Checkpoint\",\n \"name\": \"checkpoint\",\n \"type\": \"tuple\"\n },\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"signature\",\n \"type\": \"uint256[2]\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"address\",\n \"name\": \"_address\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256[4]\",\n \"name\": \"blsKey\",\n \"type\": \"uint256[4]\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"votingPower\",\n \"type\": \"uint256\"\n }\n ],\n \"internalType\": \"struct ICheckpointManager.Validator[]\",\n \"name\": \"newValidatorSet\",\n \"type\": \"tuple[]\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"bitmap\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"submit\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"totalVotingPower\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b506116f2806100206000396000f3fe608060405234801561001057600080fd5b50600436106101165760003560e01c806376671808116100a2578063babd4ee411610071578063babd4ee4146102c8578063d4c8e3e8146102db578063e416d677146102ee578063e9193d2b146102f7578063f896f1a51461030a57600080fd5b8063766718081461024157806395b0b0271461024a5780639a8a059214610275578063b8a242521461027e57600080fd5b806361a02208116100e957806361a022081461019b578063671b3793146101be5780636969a25c146101c7578063729e7c6e1461021957806373cb1a111461022c57600080fd5b80631d1d4f261461011b57806322fd1818146101375780633569ed931461016157806352a9674b14610174575b600080fd5b61012460035481565b6040519081526020015b60405180910390f35b61014a610145366004610fdb565b610313565b60408051921515835260208301919091520161012e565b61012461016f366004610fdb565b610364565b6101247fbee7fa562a38908559e4a988e62d6c08b84ef05f2ebd5d2bb2b855dc19d19fe281565b6101ae6101a9366004610ff4565b610398565b604051901515815260200161012e565b61012460055481565b6101fa6101d5366004610fdb565b600960205260009081526040902080546005909101546001600160a01b039091169082565b604080516001600160a01b03909316835260208301919091520161012e565b6101ae610227366004610ff4565b610410565b61023f61023a3660046110e8565b610469565b005b61012460025481565b60065461025d906001600160a01b031681565b6040516001600160a01b03909116815260200161012e565b61012460015481565b6102ad61028c366004610fdb565b60086020526000908152604090208054600182015460029092015490919083565b6040805193845260208401929092529082015260600161012e565b61023f6102d6366004611173565b6105bb565b60075461025d906001600160a01b031681565b61012460045481565b610124610305366004610fdb565b610820565b610124600b5481565b60008080610322600a85610841565b600a54909150810361033a5750600093849350915050565b6001600a828154811061034f5761034f61124c565b90600052602060002001549250925050915091565b6000600881610374600a85610841565b61037f906001611278565b8152602001908152602001600020600201549050919050565b6000806103a487610364565b9050806103f85760405162461bcd60e51b815260206004820152601e60248201527f4e4f5f4556454e545f524f4f545f464f525f424c4f434b5f4e554d424552000060448201526064015b60405180910390fd5b61040586868387876108f0565b979650505050505050565b600085815260086020526040812060020154806103f85760405162461bcd60e51b815260206004820152601760248201527609c9ebe8aac8a9ca8bea49e9ea8be8c9ea4be8aa09e869604b1b60448201526064016103ef565b600054610100900460ff16158080156104895750600054600160ff909116105b806104a35750303b1580156104a3575060005460ff166001145b6105065760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016103ef565b6000805460ff191660011790558015610529576000805461ff0019166101001790555b6001849055600680546001600160a01b038089166001600160a01b0319928316179092556007805492881692909116919091179055600382905561056d8383610a45565b80156105b3576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b8660400135600b54146106105760405162461bcd60e51b815260206004820152601a60248201527f494e56414c49445f56414c494441544f525f5345545f4841534800000000000060448201526064016103ef565b6000600154876020013589600001358a602001358a600001358b604001358d604001358b8b60405160200161064692919061128b565b604051602081830303815290604052805190602001206040516020016106739897969594939291906112ee565b60408051601f198184030181528282528051602091820120908301520160408051601f198184030181529082905260065463a850a90960e01b835290925061073f916001600160a01b039091169063a850a909906106f7907fbee7fa562a38908559e4a988e62d6c08b84ef05f2ebd5d2bb2b855dc19d19fe2908690600401611324565b6040805180830381865afa158015610713573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610737919061137a565b878585610b4b565b60025461074c8189610e55565b8735600081815260086020908152604091829020838155908b01356001820155908a01356002909101558110156107cf57600a8054600181018255600091825260208a01357fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a890910155600280549091906107c690611408565b90915550610803565b600a805460208a013591906107e690600190611421565b815481106107f6576107f661124c565b6000918252602090912001555b60208801356004556108158686610a45565b505050505050505050565b600a818154811061083057600080fd5b600091825260209091200154905081565b81546000908103610854575060006108ea565b82546000905b808210156108a157600061086e8383610f32565b6000878152602090209091508590820154111561088d5780915061089b565b610898816001611278565b92505b5061085a565b6000821180156108cd5750836108ca866108bc600186611421565b600091825260209091200190565b54145b156108e6576108dd600183611421565b925050506108ea565b5090505b92915050565b6000816108fe816002611518565b86106109415760405162461bcd60e51b81526020600482015260126024820152710929cac82989288be988a828cbe929c888ab60731b60448201526064016103ef565b8661097d5760405162461bcd60e51b815260206004820152600c60248201526b24a72b20a624a22fa622a0a360a11b60448201526064016103ef565b8660005b82811015610a3757600086868381811061099d5761099d61124c565b9050602002013590506002896109b3919061153a565b6000036109eb576040805160208101859052908101829052606001604051602081830303815290604052805190602001209250610a18565b60408051602081018390529081018490526060016040516020818303038152906040528051906020012092505b610a2360028a61154e565b98505080610a3090611408565b9050610981565b509094149695505050505050565b60038190556040518190610a5f908490839060200161128b565b60408051601f198184030181529190528051602090910120600b556000805b82811015610b42576000858583818110610a9a57610a9a61124c565b905060c0020160a00135905060008111610aea5760405162461bcd60e51b8152602060048201526011602482015270564f54494e475f504f5745525f5a45524f60781b60448201526064016103ef565b610af48184611278565b9250858583818110610b0857610b0861124c565b905060c00201600960008481526020019081526020016000208181610b2d9190611579565b9050505080610b3b90611408565b9050610a7e565b50600555505050565b600354610b56610fbd565b6000805b83811015610cda57610b6d868683610f54565b15610cd25781600003610bc1576000818152600960205260409081902081516080810190925260010160048282826020028201915b815481526020019060010190808311610ba25750505050509250610cb3565b60008181526009602052604080822081516080810190925260010160048282826020028201915b815481526020019060010190808311610be857505060075488516020808b01516040808d01516060808f01518b51958c0151848d0151928d01519451630cbe96a560e41b81529c9d506001600160a01b039098169b63cbe96a509b50610c5f9a5096985093969195939493919290916004016112ee565b608060405180830381865afa158015610c7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca091906115d8565b6060880152604087015260208601528452505b600081815260096020526040902060050154610ccf9083611278565b91505b600101610b5a565b5080600003610d1d5760405162461bcd60e51b815260206004820152600f60248201526e4249544d41505f49535f454d50545960881b60448201526064016103ef565b60036005546002610d2e9190611562565b610d38919061154e565b8111610d825760405162461bcd60e51b815260206004820152601960248201527824a729aaa32324a1a4a2a72a2fab27aa24a723afa827aba2a960391b60448201526064016103ef565b60065460405163ebbdac9160e01b815260009182916001600160a01b039091169063ebbdac9190610dbb908b9088908e9060040161160e565b6040805180830381865afa158015610dd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dfb9190611689565b91509150818015610e095750805b6108155760405162461bcd60e51b815260206004820152601d60248201527f5349474e41545552455f564552494649434154494f4e5f4641494c454400000060448201526064016103ef565b600082815260086020908152604091829020825160608101845281548082526001830154938201939093526002909101549281019290925282351480610ea757508051610ea3906001611278565b8235145b610ee35760405162461bcd60e51b815260206004820152600d60248201526c0929cac82989288be8aa09e869609b1b60448201526064016103ef565b8060200151826020013511610f2d5760405162461bcd60e51b815260206004820152601060248201526f115354151657d0d21150d2d413d2539560821b60448201526064016103ef565b505050565b6000610f41600284841861154e565b610f4d90848416611278565b9392505050565b600080610f6260088461154e565b90506000610f7160088561153a565b9050848210610f8557600092505050610f4d565b6000600160ff83161b878785818110610fa057610fa061124c565b9050013560f81c60f81b60f81c60ff161611925050509392505050565b60405180608001604052806004906020820280368337509192915050565b600060208284031215610fed57600080fd5b5035919050565b60008060008060006080868803121561100c57600080fd5b853594506020860135935060408601359250606086013567ffffffffffffffff8082111561103957600080fd5b818801915088601f83011261104d57600080fd5b81358181111561105c57600080fd5b8960208260051b850101111561107157600080fd5b9699959850939650602001949392505050565b6001600160a01b038116811461109957600080fd5b50565b60008083601f8401126110ae57600080fd5b50813567ffffffffffffffff8111156110c657600080fd5b60208301915083602060c0830285010111156110e157600080fd5b9250929050565b60008060008060006080868803121561110057600080fd5b853561110b81611084565b9450602086013561111b81611084565b935060408601359250606086013567ffffffffffffffff81111561113e57600080fd5b61114a8882890161109c565b969995985093965092949392505050565b60006060828403121561116d57600080fd5b50919050565b6000806000806000806000610140888a03121561118f57600080fd5b611199898961115b565b96506111a88960608a0161115b565b95506101008801898111156111bc57600080fd5b60c0890195503567ffffffffffffffff808211156111d957600080fd5b6111e58b838c0161109c565b90965094506101208a01359150808211156111ff57600080fd5b818a0191508a601f83011261121357600080fd5b81358181111561122257600080fd5b8b602082850101111561123457600080fd5b60208301945080935050505092959891949750929550565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b808201808211156108ea576108ea611262565b60208082528181018390526000908460408401835b868110156112e35782356112b381611084565b6001600160a01b0316825260808385018584013760a0838101359083015260c092830192909101906001016112a0565b509695505050505050565b978852602088019690965260408701949094526060860192909252608085015260a084015260c083015260e08201526101000190565b82815260006020604081840152835180604085015260005b818110156113585785810183015185820160600152820161133c565b506000606082860101526060601f19601f830116850101925050509392505050565b60006040828403121561138c57600080fd5b82601f83011261139b57600080fd5b6040516040810181811067ffffffffffffffff821117156113cc57634e487b7160e01b600052604160045260246000fd5b80604052508060408401858111156113e357600080fd5b845b818110156113fd5780518352602092830192016113e5565b509195945050505050565b60006001820161141a5761141a611262565b5060010190565b818103818111156108ea576108ea611262565b600181815b8085111561146f57816000190482111561145557611455611262565b8085161561146257918102915b93841c9390800290611439565b509250929050565b600082611486575060016108ea565b81611493575060006108ea565b81600181146114a957600281146114b3576114cf565b60019150506108ea565b60ff8411156114c4576114c4611262565b50506001821b6108ea565b5060208310610133831016604e8410600b84101617156114f2575081810a6108ea565b6114fc8383611434565b806000190482111561151057611510611262565b029392505050565b6000610f4d8383611477565b634e487b7160e01b600052601260045260246000fd5b60008261154957611549611524565b500690565b60008261155d5761155d611524565b500490565b80820281158282048414176108ea576108ea611262565b813561158481611084565b81546001600160a01b0319166001600160a01b0391909116178155602082810160005b60048110156115c7578135600182860181019190915591830191016115a7565b50505060a082013560058201555050565b600080600080608085870312156115ee57600080fd5b505082516020840151604085015160609095015191969095509092509050565b61010081016040858337604082018460005b600481101561163f578151835260209283019290910190600101611620565b50505060c082018360005b600281101561166957815183526020928301929091019060010161164a565b505050949350505050565b8051801515811461168457600080fd5b919050565b6000806040838503121561169c57600080fd5b6116a583611674565b91506116b360208401611674565b9050925092905056fea2646970667358221220d095a39e3b93e017f00f9714cc6e9b2280742361a1a5f6c69775bcc0c3c154e964736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101165760003560e01c806376671808116100a2578063babd4ee411610071578063babd4ee4146102c8578063d4c8e3e8146102db578063e416d677146102ee578063e9193d2b146102f7578063f896f1a51461030a57600080fd5b8063766718081461024157806395b0b0271461024a5780639a8a059214610275578063b8a242521461027e57600080fd5b806361a02208116100e957806361a022081461019b578063671b3793146101be5780636969a25c146101c7578063729e7c6e1461021957806373cb1a111461022c57600080fd5b80631d1d4f261461011b57806322fd1818146101375780633569ed931461016157806352a9674b14610174575b600080fd5b61012460035481565b6040519081526020015b60405180910390f35b61014a610145366004610fdb565b610313565b60408051921515835260208301919091520161012e565b61012461016f366004610fdb565b610364565b6101247fbee7fa562a38908559e4a988e62d6c08b84ef05f2ebd5d2bb2b855dc19d19fe281565b6101ae6101a9366004610ff4565b610398565b604051901515815260200161012e565b61012460055481565b6101fa6101d5366004610fdb565b600960205260009081526040902080546005909101546001600160a01b039091169082565b604080516001600160a01b03909316835260208301919091520161012e565b6101ae610227366004610ff4565b610410565b61023f61023a3660046110e8565b610469565b005b61012460025481565b60065461025d906001600160a01b031681565b6040516001600160a01b03909116815260200161012e565b61012460015481565b6102ad61028c366004610fdb565b60086020526000908152604090208054600182015460029092015490919083565b6040805193845260208401929092529082015260600161012e565b61023f6102d6366004611173565b6105bb565b60075461025d906001600160a01b031681565b61012460045481565b610124610305366004610fdb565b610820565b610124600b5481565b60008080610322600a85610841565b600a54909150810361033a5750600093849350915050565b6001600a828154811061034f5761034f61124c565b90600052602060002001549250925050915091565b6000600881610374600a85610841565b61037f906001611278565b8152602001908152602001600020600201549050919050565b6000806103a487610364565b9050806103f85760405162461bcd60e51b815260206004820152601e60248201527f4e4f5f4556454e545f524f4f545f464f525f424c4f434b5f4e554d424552000060448201526064015b60405180910390fd5b61040586868387876108f0565b979650505050505050565b600085815260086020526040812060020154806103f85760405162461bcd60e51b815260206004820152601760248201527609c9ebe8aac8a9ca8bea49e9ea8be8c9ea4be8aa09e869604b1b60448201526064016103ef565b600054610100900460ff16158080156104895750600054600160ff909116105b806104a35750303b1580156104a3575060005460ff166001145b6105065760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016103ef565b6000805460ff191660011790558015610529576000805461ff0019166101001790555b6001849055600680546001600160a01b038089166001600160a01b0319928316179092556007805492881692909116919091179055600382905561056d8383610a45565b80156105b3576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b8660400135600b54146106105760405162461bcd60e51b815260206004820152601a60248201527f494e56414c49445f56414c494441544f525f5345545f4841534800000000000060448201526064016103ef565b6000600154876020013589600001358a602001358a600001358b604001358d604001358b8b60405160200161064692919061128b565b604051602081830303815290604052805190602001206040516020016106739897969594939291906112ee565b60408051601f198184030181528282528051602091820120908301520160408051601f198184030181529082905260065463a850a90960e01b835290925061073f916001600160a01b039091169063a850a909906106f7907fbee7fa562a38908559e4a988e62d6c08b84ef05f2ebd5d2bb2b855dc19d19fe2908690600401611324565b6040805180830381865afa158015610713573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610737919061137a565b878585610b4b565b60025461074c8189610e55565b8735600081815260086020908152604091829020838155908b01356001820155908a01356002909101558110156107cf57600a8054600181018255600091825260208a01357fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a890910155600280549091906107c690611408565b90915550610803565b600a805460208a013591906107e690600190611421565b815481106107f6576107f661124c565b6000918252602090912001555b60208801356004556108158686610a45565b505050505050505050565b600a818154811061083057600080fd5b600091825260209091200154905081565b81546000908103610854575060006108ea565b82546000905b808210156108a157600061086e8383610f32565b6000878152602090209091508590820154111561088d5780915061089b565b610898816001611278565b92505b5061085a565b6000821180156108cd5750836108ca866108bc600186611421565b600091825260209091200190565b54145b156108e6576108dd600183611421565b925050506108ea565b5090505b92915050565b6000816108fe816002611518565b86106109415760405162461bcd60e51b81526020600482015260126024820152710929cac82989288be988a828cbe929c888ab60731b60448201526064016103ef565b8661097d5760405162461bcd60e51b815260206004820152600c60248201526b24a72b20a624a22fa622a0a360a11b60448201526064016103ef565b8660005b82811015610a3757600086868381811061099d5761099d61124c565b9050602002013590506002896109b3919061153a565b6000036109eb576040805160208101859052908101829052606001604051602081830303815290604052805190602001209250610a18565b60408051602081018390529081018490526060016040516020818303038152906040528051906020012092505b610a2360028a61154e565b98505080610a3090611408565b9050610981565b509094149695505050505050565b60038190556040518190610a5f908490839060200161128b565b60408051601f198184030181529190528051602090910120600b556000805b82811015610b42576000858583818110610a9a57610a9a61124c565b905060c0020160a00135905060008111610aea5760405162461bcd60e51b8152602060048201526011602482015270564f54494e475f504f5745525f5a45524f60781b60448201526064016103ef565b610af48184611278565b9250858583818110610b0857610b0861124c565b905060c00201600960008481526020019081526020016000208181610b2d9190611579565b9050505080610b3b90611408565b9050610a7e565b50600555505050565b600354610b56610fbd565b6000805b83811015610cda57610b6d868683610f54565b15610cd25781600003610bc1576000818152600960205260409081902081516080810190925260010160048282826020028201915b815481526020019060010190808311610ba25750505050509250610cb3565b60008181526009602052604080822081516080810190925260010160048282826020028201915b815481526020019060010190808311610be857505060075488516020808b01516040808d01516060808f01518b51958c0151848d0151928d01519451630cbe96a560e41b81529c9d506001600160a01b039098169b63cbe96a509b50610c5f9a5096985093969195939493919290916004016112ee565b608060405180830381865afa158015610c7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca091906115d8565b6060880152604087015260208601528452505b600081815260096020526040902060050154610ccf9083611278565b91505b600101610b5a565b5080600003610d1d5760405162461bcd60e51b815260206004820152600f60248201526e4249544d41505f49535f454d50545960881b60448201526064016103ef565b60036005546002610d2e9190611562565b610d38919061154e565b8111610d825760405162461bcd60e51b815260206004820152601960248201527824a729aaa32324a1a4a2a72a2fab27aa24a723afa827aba2a960391b60448201526064016103ef565b60065460405163ebbdac9160e01b815260009182916001600160a01b039091169063ebbdac9190610dbb908b9088908e9060040161160e565b6040805180830381865afa158015610dd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dfb9190611689565b91509150818015610e095750805b6108155760405162461bcd60e51b815260206004820152601d60248201527f5349474e41545552455f564552494649434154494f4e5f4641494c454400000060448201526064016103ef565b600082815260086020908152604091829020825160608101845281548082526001830154938201939093526002909101549281019290925282351480610ea757508051610ea3906001611278565b8235145b610ee35760405162461bcd60e51b815260206004820152600d60248201526c0929cac82989288be8aa09e869609b1b60448201526064016103ef565b8060200151826020013511610f2d5760405162461bcd60e51b815260206004820152601060248201526f115354151657d0d21150d2d413d2539560821b60448201526064016103ef565b505050565b6000610f41600284841861154e565b610f4d90848416611278565b9392505050565b600080610f6260088461154e565b90506000610f7160088561153a565b9050848210610f8557600092505050610f4d565b6000600160ff83161b878785818110610fa057610fa061124c565b9050013560f81c60f81b60f81c60ff161611925050509392505050565b60405180608001604052806004906020820280368337509192915050565b600060208284031215610fed57600080fd5b5035919050565b60008060008060006080868803121561100c57600080fd5b853594506020860135935060408601359250606086013567ffffffffffffffff8082111561103957600080fd5b818801915088601f83011261104d57600080fd5b81358181111561105c57600080fd5b8960208260051b850101111561107157600080fd5b9699959850939650602001949392505050565b6001600160a01b038116811461109957600080fd5b50565b60008083601f8401126110ae57600080fd5b50813567ffffffffffffffff8111156110c657600080fd5b60208301915083602060c0830285010111156110e157600080fd5b9250929050565b60008060008060006080868803121561110057600080fd5b853561110b81611084565b9450602086013561111b81611084565b935060408601359250606086013567ffffffffffffffff81111561113e57600080fd5b61114a8882890161109c565b969995985093965092949392505050565b60006060828403121561116d57600080fd5b50919050565b6000806000806000806000610140888a03121561118f57600080fd5b611199898961115b565b96506111a88960608a0161115b565b95506101008801898111156111bc57600080fd5b60c0890195503567ffffffffffffffff808211156111d957600080fd5b6111e58b838c0161109c565b90965094506101208a01359150808211156111ff57600080fd5b818a0191508a601f83011261121357600080fd5b81358181111561122257600080fd5b8b602082850101111561123457600080fd5b60208301945080935050505092959891949750929550565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b808201808211156108ea576108ea611262565b60208082528181018390526000908460408401835b868110156112e35782356112b381611084565b6001600160a01b0316825260808385018584013760a0838101359083015260c092830192909101906001016112a0565b509695505050505050565b978852602088019690965260408701949094526060860192909252608085015260a084015260c083015260e08201526101000190565b82815260006020604081840152835180604085015260005b818110156113585785810183015185820160600152820161133c565b506000606082860101526060601f19601f830116850101925050509392505050565b60006040828403121561138c57600080fd5b82601f83011261139b57600080fd5b6040516040810181811067ffffffffffffffff821117156113cc57634e487b7160e01b600052604160045260246000fd5b80604052508060408401858111156113e357600080fd5b845b818110156113fd5780518352602092830192016113e5565b509195945050505050565b60006001820161141a5761141a611262565b5060010190565b818103818111156108ea576108ea611262565b600181815b8085111561146f57816000190482111561145557611455611262565b8085161561146257918102915b93841c9390800290611439565b509250929050565b600082611486575060016108ea565b81611493575060006108ea565b81600181146114a957600281146114b3576114cf565b60019150506108ea565b60ff8411156114c4576114c4611262565b50506001821b6108ea565b5060208310610133831016604e8410600b84101617156114f2575081810a6108ea565b6114fc8383611434565b806000190482111561151057611510611262565b029392505050565b6000610f4d8383611477565b634e487b7160e01b600052601260045260246000fd5b60008261154957611549611524565b500690565b60008261155d5761155d611524565b500490565b80820281158282048414176108ea576108ea611262565b813561158481611084565b81546001600160a01b0319166001600160a01b0391909116178155602082810160005b60048110156115c7578135600182860181019190915591830191016115a7565b50505060a082013560058201555050565b600080600080608085870312156115ee57600080fd5b505082516020840151604085015160609095015191969095509092509050565b61010081016040858337604082018460005b600481101561163f578151835260209283019290910190600101611620565b50505060c082018360005b600281101561166957815183526020928301929091019060010161164a565b505050949350505050565b8051801515811461168457600080fd5b919050565b6000806040838503121561169c57600080fd5b6116a583611674565b91506116b360208401611674565b9050925092905056fea2646970667358221220d095a39e3b93e017f00f9714cc6e9b2280742361a1a5f6c69775bcc0c3c154e964736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var ExitHelperArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"ExitHelper\",\n \"sourceName\": \"contracts/root/ExitHelper.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bool\",\n \"name\": \"success\",\n \"type\": \"bool\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bytes\",\n \"name\": \"returnData\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"ExitProcessed\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [\n {\n \"components\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockNumber\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"leafIndex\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"unhashedLeaf\",\n \"type\": \"bytes\"\n },\n {\n \"internalType\": \"bytes32[]\",\n \"name\": \"proof\",\n \"type\": \"bytes32[]\"\n }\n ],\n \"internalType\": \"struct IExitHelper.BatchExitInput[]\",\n \"name\": \"inputs\",\n \"type\": \"tuple[]\"\n }\n ],\n \"name\": \"batchExit\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"checkpointManager\",\n \"outputs\": [\n {\n \"internalType\": \"contract ICheckpointManager\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"blockNumber\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"leafIndex\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"unhashedLeaf\",\n \"type\": \"bytes\"\n },\n {\n \"internalType\": \"bytes32[]\",\n \"name\": \"proof\",\n \"type\": \"bytes32[]\"\n }\n ],\n \"name\": \"exit\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract ICheckpointManager\",\n \"name\": \"newCheckpointManager\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"processedExits\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50610b62806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c806350607b351461005c578063aa209cc314610071578063bd88ea7914610084578063c0857ba0146100bc578063c4d66de8146100e7575b600080fd5b61006f61006a3660046106c9565b6100fa565b005b61006f61007f36600461070b565b610200565b6100a76100923660046107bc565b60016020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6002546100cf906001600160a01b031681565b6040516001600160a01b0390911681526020016100b3565b61006f6100f53660046107ed565b610240565b6002546001600160a01b031661012b5760405162461bcd60e51b815260040161012290610811565b60405180910390fd5b8060005b818110156101fa576101f284848381811061014c5761014c610848565b905060200281019061015e919061085e565b3585858481811061017157610171610848565b9050602002810190610183919061085e565b6020013586868581811061019957610199610848565b90506020028101906101ab919061085e565b6101b990604081019061087e565b8888878181106101cb576101cb610848565b90506020028101906101dd919061085e565b6101eb9060608101906108c5565b60016103d2565b60010161012f565b50505050565b6002546001600160a01b03166102285760405162461bcd60e51b815260040161012290610811565b61023886868686868660006103d2565b505050505050565b600054610100900460ff16158080156102605750600054600160ff909116105b8061027a5750303b15801561027a575060005460ff166001145b6102dd5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610122565b6000805460ff191660011790558015610300576000805461ff0019166101001790555b6001600160a01b0382161580159061032157506001600160a01b0382163b15155b61036d5760405162461bcd60e51b815260206004820152601b60248201527f4578697448656c7065723a20494e56414c49445f4144445245535300000000006044820152606401610122565b600280546001600160a01b0319166001600160a01b03841617905580156103ce576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b60008080806103e3888a018a610925565b935093509350935084156104165760008481526001602052604090205460ff16156104115750505050610674565b610480565b60008481526001602052604090205460ff16156104805760405162461bcd60e51b815260206004820152602260248201527f4578697448656c7065723a20455849545f414c52454144595f50524f43455353604482015261115160f21b6064820152608401610122565b6002546040516001600160a01b03909116906361a02208908d906104a7908d908d90610a05565b6040519081900381206001600160e01b031960e085901b1682526104d492918f908d908d90600401610a15565b602060405180830381865afa1580156104f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105159190610a62565b61055d5760405162461bcd60e51b815260206004820152601960248201527822bc34ba2432b63832b91d1024a72b20a624a22fa82927a7a360391b6044820152606401610122565b6000848152600160208190526040808320805460ff19169092179091555181906001600160a01b0385169061059a90889088908790602401610ad4565b60408051601f198184030181529181526020820180516001600160e01b031663f43cda8b60e01b179052516105cf9190610b07565b6000604051808303816000865af19150503d806000811461060c576040519150601f19603f3d011682016040523d82523d6000602084013e610611565b606091505b509150915081610632576000868152600160205260409020805460ff191690555b811515867f8bbfa0c9bee3785c03700d2a909592286efb83fc7e7002be5764424b9842f7ec836040516106659190610b19565b60405180910390a35050505050505b50505050505050565b60008083601f84011261068f57600080fd5b50813567ffffffffffffffff8111156106a757600080fd5b6020830191508360208260051b85010111156106c257600080fd5b9250929050565b600080602083850312156106dc57600080fd5b823567ffffffffffffffff8111156106f357600080fd5b6106ff8582860161067d565b90969095509350505050565b6000806000806000806080878903121561072457600080fd5b8635955060208701359450604087013567ffffffffffffffff8082111561074a57600080fd5b818901915089601f83011261075e57600080fd5b81358181111561076d57600080fd5b8a602082850101111561077f57600080fd5b60208301965080955050606089013591508082111561079d57600080fd5b506107aa89828a0161067d565b979a9699509497509295939492505050565b6000602082840312156107ce57600080fd5b5035919050565b6001600160a01b03811681146107ea57600080fd5b50565b6000602082840312156107ff57600080fd5b813561080a816107d5565b9392505050565b6020808252601b908201527f4578697448656c7065723a204e4f545f494e495449414c495a45440000000000604082015260600190565b634e487b7160e01b600052603260045260246000fd5b60008235607e1983360301811261087457600080fd5b9190910192915050565b6000808335601e1984360301811261089557600080fd5b83018035915067ffffffffffffffff8211156108b057600080fd5b6020019150368190038213156106c257600080fd5b6000808335601e198436030181126108dc57600080fd5b83018035915067ffffffffffffffff8211156108f757600080fd5b6020019150600581901b36038213156106c257600080fd5b634e487b7160e01b600052604160045260246000fd5b6000806000806080858703121561093b57600080fd5b84359350602085013561094d816107d5565b9250604085013561095d816107d5565b9150606085013567ffffffffffffffff8082111561097a57600080fd5b818701915087601f83011261098e57600080fd5b8135818111156109a0576109a061090f565b604051601f8201601f19908116603f011681019083821181831017156109c8576109c861090f565b816040528281528a60208487010111156109e157600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b8183823760009101908152919050565b85815284602082015283604082015260806060820152816080820152600060018060fb1b03831115610a4657600080fd5b8260051b808560a08501379190910160a0019695505050505050565b600060208284031215610a7457600080fd5b8151801515811461080a57600080fd5b60005b83811015610a9f578181015183820152602001610a87565b50506000910152565b60008151808452610ac0816020860160208601610a84565b601f01601f19169290920160200192915050565b8381526001600160a01b0383166020820152606060408201819052600090610afe90830184610aa8565b95945050505050565b60008251610874818460208701610a84565b60208152600061080a6020830184610aa856fea2646970667358221220110b70554f8d1ab0b9a239e02f7c81f25da1730583ae343da1033e8e7157258a64736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106100575760003560e01c806350607b351461005c578063aa209cc314610071578063bd88ea7914610084578063c0857ba0146100bc578063c4d66de8146100e7575b600080fd5b61006f61006a3660046106c9565b6100fa565b005b61006f61007f36600461070b565b610200565b6100a76100923660046107bc565b60016020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6002546100cf906001600160a01b031681565b6040516001600160a01b0390911681526020016100b3565b61006f6100f53660046107ed565b610240565b6002546001600160a01b031661012b5760405162461bcd60e51b815260040161012290610811565b60405180910390fd5b8060005b818110156101fa576101f284848381811061014c5761014c610848565b905060200281019061015e919061085e565b3585858481811061017157610171610848565b9050602002810190610183919061085e565b6020013586868581811061019957610199610848565b90506020028101906101ab919061085e565b6101b990604081019061087e565b8888878181106101cb576101cb610848565b90506020028101906101dd919061085e565b6101eb9060608101906108c5565b60016103d2565b60010161012f565b50505050565b6002546001600160a01b03166102285760405162461bcd60e51b815260040161012290610811565b61023886868686868660006103d2565b505050505050565b600054610100900460ff16158080156102605750600054600160ff909116105b8061027a5750303b15801561027a575060005460ff166001145b6102dd5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610122565b6000805460ff191660011790558015610300576000805461ff0019166101001790555b6001600160a01b0382161580159061032157506001600160a01b0382163b15155b61036d5760405162461bcd60e51b815260206004820152601b60248201527f4578697448656c7065723a20494e56414c49445f4144445245535300000000006044820152606401610122565b600280546001600160a01b0319166001600160a01b03841617905580156103ce576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b60008080806103e3888a018a610925565b935093509350935084156104165760008481526001602052604090205460ff16156104115750505050610674565b610480565b60008481526001602052604090205460ff16156104805760405162461bcd60e51b815260206004820152602260248201527f4578697448656c7065723a20455849545f414c52454144595f50524f43455353604482015261115160f21b6064820152608401610122565b6002546040516001600160a01b03909116906361a02208908d906104a7908d908d90610a05565b6040519081900381206001600160e01b031960e085901b1682526104d492918f908d908d90600401610a15565b602060405180830381865afa1580156104f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105159190610a62565b61055d5760405162461bcd60e51b815260206004820152601960248201527822bc34ba2432b63832b91d1024a72b20a624a22fa82927a7a360391b6044820152606401610122565b6000848152600160208190526040808320805460ff19169092179091555181906001600160a01b0385169061059a90889088908790602401610ad4565b60408051601f198184030181529181526020820180516001600160e01b031663f43cda8b60e01b179052516105cf9190610b07565b6000604051808303816000865af19150503d806000811461060c576040519150601f19603f3d011682016040523d82523d6000602084013e610611565b606091505b509150915081610632576000868152600160205260409020805460ff191690555b811515867f8bbfa0c9bee3785c03700d2a909592286efb83fc7e7002be5764424b9842f7ec836040516106659190610b19565b60405180910390a35050505050505b50505050505050565b60008083601f84011261068f57600080fd5b50813567ffffffffffffffff8111156106a757600080fd5b6020830191508360208260051b85010111156106c257600080fd5b9250929050565b600080602083850312156106dc57600080fd5b823567ffffffffffffffff8111156106f357600080fd5b6106ff8582860161067d565b90969095509350505050565b6000806000806000806080878903121561072457600080fd5b8635955060208701359450604087013567ffffffffffffffff8082111561074a57600080fd5b818901915089601f83011261075e57600080fd5b81358181111561076d57600080fd5b8a602082850101111561077f57600080fd5b60208301965080955050606089013591508082111561079d57600080fd5b506107aa89828a0161067d565b979a9699509497509295939492505050565b6000602082840312156107ce57600080fd5b5035919050565b6001600160a01b03811681146107ea57600080fd5b50565b6000602082840312156107ff57600080fd5b813561080a816107d5565b9392505050565b6020808252601b908201527f4578697448656c7065723a204e4f545f494e495449414c495a45440000000000604082015260600190565b634e487b7160e01b600052603260045260246000fd5b60008235607e1983360301811261087457600080fd5b9190910192915050565b6000808335601e1984360301811261089557600080fd5b83018035915067ffffffffffffffff8211156108b057600080fd5b6020019150368190038213156106c257600080fd5b6000808335601e198436030181126108dc57600080fd5b83018035915067ffffffffffffffff8211156108f757600080fd5b6020019150600581901b36038213156106c257600080fd5b634e487b7160e01b600052604160045260246000fd5b6000806000806080858703121561093b57600080fd5b84359350602085013561094d816107d5565b9250604085013561095d816107d5565b9150606085013567ffffffffffffffff8082111561097a57600080fd5b818701915087601f83011261098e57600080fd5b8135818111156109a0576109a061090f565b604051601f8201601f19908116603f011681019083821181831017156109c8576109c861090f565b816040528281528a60208487010111156109e157600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b8183823760009101908152919050565b85815284602082015283604082015260806060820152816080820152600060018060fb1b03831115610a4657600080fd5b8260051b808560a08501379190910160a0019695505050505050565b600060208284031215610a7457600080fd5b8151801515811461080a57600080fd5b60005b83811015610a9f578181015183820152602001610a87565b50506000910152565b60008151808452610ac0816020860160208601610a84565b601f01601f19169290920160200192915050565b8381526001600160a01b0383166020820152606060408201819052600090610afe90830184610aa8565b95945050505050565b60008251610874818460208701610a84565b60208152600061080a6020830184610aa856fea2646970667358221220110b70554f8d1ab0b9a239e02f7c81f25da1730583ae343da1033e8e7157258a64736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var StateSenderArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"StateSender\",\n \"sourceName\": \"contracts/root/StateSender.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"StateSynced\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAX_LENGTH\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"counter\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"syncState\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50610297806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806316f198311461004657806361bc221a1461005b578063a6f9885c14610076575b600080fd5b61005961005436600461017a565b61007f565b005b61006460005481565b60405190815260200160405180910390f35b61006461080081565b6001600160a01b0383166100cd5760405162461bcd60e51b815260206004820152601060248201526f24a72b20a624a22fa922a1a2a4ab22a960811b60448201526064015b60405180910390fd5b6108008111156101145760405162461bcd60e51b815260206004820152601260248201527108ab0868a8a88a6be9a82b0be988a9c8ea8960731b60448201526064016100c4565b826001600160a01b0316336001600160a01b031660008081546101369061020b565b9190508190557fd1d7f6609674cc5871fdb4b0bcd4f0a214118411de9e38983866514f22659165858560405161016d929190610232565b60405180910390a4505050565b60008060006040848603121561018f57600080fd5b83356001600160a01b03811681146101a657600080fd5b9250602084013567ffffffffffffffff808211156101c357600080fd5b818601915086601f8301126101d757600080fd5b8135818111156101e657600080fd5b8760208285010111156101f857600080fd5b6020830194508093505050509250925092565b60006001820161022b57634e487b7160e01b600052601160045260246000fd5b5060010190565b60208152816020820152818360408301376000818301604090810191909152601f909201601f1916010191905056fea264697066735822122031b7ec2bc87f0234fe89e0f741bc18f51baa2be5cc844033ea10f35e4b86094c64736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106100415760003560e01c806316f198311461004657806361bc221a1461005b578063a6f9885c14610076575b600080fd5b61005961005436600461017a565b61007f565b005b61006460005481565b60405190815260200160405180910390f35b61006461080081565b6001600160a01b0383166100cd5760405162461bcd60e51b815260206004820152601060248201526f24a72b20a624a22fa922a1a2a4ab22a960811b60448201526064015b60405180910390fd5b6108008111156101145760405162461bcd60e51b815260206004820152601260248201527108ab0868a8a88a6be9a82b0be988a9c8ea8960731b60448201526064016100c4565b826001600160a01b0316336001600160a01b031660008081546101369061020b565b9190508190557fd1d7f6609674cc5871fdb4b0bcd4f0a214118411de9e38983866514f22659165858560405161016d929190610232565b60405180910390a4505050565b60008060006040848603121561018f57600080fd5b83356001600160a01b03811681146101a657600080fd5b9250602084013567ffffffffffffffff808211156101c357600080fd5b818601915086601f8301126101d757600080fd5b8135818111156101e657600080fd5b8760208285010111156101f857600080fd5b6020830194508093505050509250925092565b60006001820161022b57634e487b7160e01b600052601160045260246000fd5b5060010190565b60208152816020820152818360408301376000818301604090810191909152601f909201601f1916010191905056fea264697066735822122031b7ec2bc87f0234fe89e0f741bc18f51baa2be5cc844033ea10f35e4b86094c64736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var MockERC20Artifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"MockERC20\",\n \"sourceName\": \"contracts/mocks/MockERC20.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Approval\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"Paused\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bytes32\",\n \"name\": \"previousAdminRole\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bytes32\",\n \"name\": \"newAdminRole\",\n \"type\": \"bytes32\"\n }\n ],\n \"name\": \"RoleAdminChanged\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"RoleGranted\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"RoleRevoked\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Transfer\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"Unpaused\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEFAULT_ADMIN_ROLE\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MINTER_ROLE\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"PAUSER_ROLE\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"allowance\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"approve\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"balanceOf\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"burn\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"burnFrom\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"decimals\",\n \"outputs\": [\n {\n \"internalType\": \"uint8\",\n \"name\": \"\",\n \"type\": \"uint8\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"subtractedValue\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"decreaseAllowance\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n }\n ],\n \"name\": \"getRoleAdmin\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"index\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"getRoleMember\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n }\n ],\n \"name\": \"getRoleMemberCount\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"grantRole\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"hasRole\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"addedValue\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"increaseAllowance\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"mint\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"name\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"pause\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"paused\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"renounceRole\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"revokeRole\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes4\",\n \"name\": \"interfaceId\",\n \"type\": \"bytes4\"\n }\n ],\n \"name\": \"supportsInterface\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"symbol\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"totalSupply\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transfer\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transferFrom\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"unpause\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x60806040523480156200001157600080fd5b50604080518082018252600480825263151154d560e21b60208084018290528451808601909552918452908301529081816005620000508382620002ca565b5060066200005f8282620002ca565b50506007805460ff191690555062000079600033620000d9565b620000a57f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a633620000d9565b620000d17f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a33620000d9565b505062000396565b620000e58282620000e9565b5050565b620000f5828262000114565b60008281526001602052604090206200010f9082620001b4565b505050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16620000e5576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620001703390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000620001cb836001600160a01b038416620001d4565b90505b92915050565b60008181526001830160205260408120546200021d57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155620001ce565b506000620001ce565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200025157607f821691505b6020821081036200027257634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200010f57600081815260208120601f850160051c81016020861015620002a15750805b601f850160051c820191505b81811015620002c257828155600101620002ad565b505050505050565b81516001600160401b03811115620002e657620002e662000226565b620002fe81620002f784546200023c565b8462000278565b602080601f8311600181146200033657600084156200031d5750858301515b600019600386901b1c1916600185901b178555620002c2565b600085815260208120601f198616915b82811015620003675788860151825594840194600190910190840162000346565b5085821015620003865787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6117fa80620003a66000396000f3fe608060405234801561001057600080fd5b50600436106101845760003560e01c806370a08231116100d9578063a457c2d711610087578063a457c2d714610336578063a9059cbb14610349578063ca15c8731461035c578063d53913931461036f578063d547741f14610396578063dd62ed3e146103a9578063e63ab1e9146103bc57600080fd5b806370a08231146102a457806379cc6790146102cd5780638456cb59146102e05780639010d07c146102e857806391d148541461031357806395d89b4114610326578063a217fddf1461032e57600080fd5b8063313ce56711610136578063313ce5671461023657806336568abe1461024557806339509351146102585780633f4ba83a1461026b57806340c10f191461027357806342966c68146102865780635c975abb1461029957600080fd5b806301ffc9a71461018957806306fdde03146101b1578063095ea7b3146101c657806318160ddd146101d957806323b872dd146101eb578063248a9ca3146101fe5780632f2ff15d14610221575b600080fd5b61019c610197366004611460565b6103d1565b60405190151581526020015b60405180910390f35b6101b96103fc565b6040516101a891906114ae565b61019c6101d43660046114fd565b61048e565b6004545b6040519081526020016101a8565b61019c6101f9366004611527565b6104a6565b6101dd61020c366004611563565b60009081526020819052604090206001015490565b61023461022f36600461157c565b6104ca565b005b604051601281526020016101a8565b61023461025336600461157c565b6104f4565b61019c6102663660046114fd565b610577565b610234610599565b6102346102813660046114fd565b610617565b610234610294366004611563565b6106a4565b60075460ff1661019c565b6101dd6102b23660046115a8565b6001600160a01b031660009081526002602052604090205490565b6102346102db3660046114fd565b6106b1565b6102346106c6565b6102fb6102f63660046115c3565b610740565b6040516001600160a01b0390911681526020016101a8565b61019c61032136600461157c565b61075f565b6101b9610788565b6101dd600081565b61019c6103443660046114fd565b610797565b61019c6103573660046114fd565b610812565b6101dd61036a366004611563565b610820565b6101dd7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b6102346103a436600461157c565b610837565b6101dd6103b73660046115e5565b61085c565b6101dd60008051602061178583398151915281565b60006001600160e01b03198216635a05180f60e01b14806103f657506103f682610887565b92915050565b60606005805461040b9061160f565b80601f01602080910402602001604051908101604052809291908181526020018280546104379061160f565b80156104845780601f1061045957610100808354040283529160200191610484565b820191906000526020600020905b81548152906001019060200180831161046757829003601f168201915b5050505050905090565b60003361049c8185856108bc565b5060019392505050565b6000336104b48582856109e0565b6104bf858585610a5a565b506001949350505050565b6000828152602081905260409020600101546104e581610bfe565b6104ef8383610c08565b505050565b6001600160a01b03811633146105695760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b6105738282610c2a565b5050565b60003361049c81858561058a838361085c565b610594919061165f565b6108bc565b6105b16000805160206117858339815191523361075f565b61060d5760405162461bcd60e51b8152602060048201526039602482015260008051602061176583398151915260448201527876652070617573657220726f6c6520746f20756e706175736560381b6064820152608401610560565b610615610c4c565b565b6106417f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a63361075f565b61069a5760405162461bcd60e51b815260206004820152603660248201526000805160206117658339815191526044820152751d99481b5a5b9d195c881c9bdb19481d1bc81b5a5b9d60521b6064820152608401610560565b6105738282610c9e565b6106ae3382610d59565b50565b6106bc8233836109e0565b6105738282610d59565b6106de6000805160206117858339815191523361075f565b6107385760405162461bcd60e51b8152602060048201526037602482015260008051602061176583398151915260448201527676652070617573657220726f6c6520746f20706175736560481b6064820152608401610560565b610615610e87565b60008281526001602052604081206107589083610ec4565b9392505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60606006805461040b9061160f565b600033816107a5828661085c565b9050838110156108055760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610560565b6104bf82868684036108bc565b60003361049c818585610a5a565b60008181526001602052604081206103f690610ed0565b60008281526020819052604090206001015461085281610bfe565b6104ef8383610c2a565b6001600160a01b03918216600090815260036020908152604080832093909416825291909152205490565b60006001600160e01b03198216637965db0b60e01b14806103f657506301ffc9a760e01b6001600160e01b03198316146103f6565b6001600160a01b03831661091e5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610560565b6001600160a01b03821661097f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610560565b6001600160a01b0383811660008181526003602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60006109ec848461085c565b90506000198114610a545781811015610a475760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610560565b610a5484848484036108bc565b50505050565b6001600160a01b038316610abe5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610560565b6001600160a01b038216610b205760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610560565b610b2b838383610eda565b6001600160a01b03831660009081526002602052604090205481811015610ba35760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610560565b6001600160a01b0380851660008181526002602052604080822086860390559286168082529083902080548601905591516000805160206117a583398151915290610bf19086815260200190565b60405180910390a3610a54565b6106ae8133610ee5565b610c128282610f3e565b60008281526001602052604090206104ef9082610fc2565b610c348282610fd7565b60008281526001602052604090206104ef908261103c565b610c54611051565b6007805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6001600160a01b038216610cf45760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610560565b610d0060008383610eda565b8060046000828254610d12919061165f565b90915550506001600160a01b0382166000818152600260209081526040808320805486019055518481526000805160206117a5833981519152910160405180910390a35050565b6001600160a01b038216610db95760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610560565b610dc582600083610eda565b6001600160a01b03821660009081526002602052604090205481811015610e395760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610560565b6001600160a01b03831660008181526002602090815260408083208686039055600480548790039055518581529192916000805160206117a5833981519152910160405180910390a3505050565b610e8f61109a565b6007805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610c813390565b600061075883836110e0565b60006103f6825490565b6104ef83838361110a565b610eef828261075f565b61057357610efc81611170565b610f07836020611182565b604051602001610f18929190611672565b60408051601f198184030181529082905262461bcd60e51b8252610560916004016114ae565b610f48828261075f565b610573576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055610f7e3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000610758836001600160a01b03841661131e565b610fe1828261075f565b15610573576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000610758836001600160a01b03841661136d565b60075460ff166106155760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610560565b60075460ff16156106155760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610560565b60008260000182815481106110f7576110f76116e1565b9060005260206000200154905092915050565b60075460ff16156104ef5760405162461bcd60e51b815260206004820152602a60248201527f45524332305061757361626c653a20746f6b656e207472616e736665722077686044820152691a5b19481c185d5cd95960b21b6064820152608401610560565b60606103f66001600160a01b03831660145b606060006111918360026116f7565b61119c90600261165f565b67ffffffffffffffff8111156111b4576111b461170e565b6040519080825280601f01601f1916602001820160405280156111de576020820181803683370190505b509050600360fc1b816000815181106111f9576111f96116e1565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110611228576112286116e1565b60200101906001600160f81b031916908160001a905350600061124c8460026116f7565b61125790600161165f565b90505b60018111156112cf576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061128b5761128b6116e1565b1a60f81b8282815181106112a1576112a16116e1565b60200101906001600160f81b031916908160001a90535060049490941c936112c881611724565b905061125a565b5083156107585760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610560565b6000818152600183016020526040812054611365575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556103f6565b5060006103f6565b6000818152600183016020526040812054801561145657600061139160018361173b565b85549091506000906113a59060019061173b565b905081811461140a5760008660000182815481106113c5576113c56116e1565b90600052602060002001549050808760000184815481106113e8576113e86116e1565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061141b5761141b61174e565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506103f6565b60009150506103f6565b60006020828403121561147257600080fd5b81356001600160e01b03198116811461075857600080fd5b60005b838110156114a557818101518382015260200161148d565b50506000910152565b60208152600082518060208401526114cd81604085016020870161148a565b601f01601f19169190910160400192915050565b80356001600160a01b03811681146114f857600080fd5b919050565b6000806040838503121561151057600080fd5b611519836114e1565b946020939093013593505050565b60008060006060848603121561153c57600080fd5b611545846114e1565b9250611553602085016114e1565b9150604084013590509250925092565b60006020828403121561157557600080fd5b5035919050565b6000806040838503121561158f57600080fd5b8235915061159f602084016114e1565b90509250929050565b6000602082840312156115ba57600080fd5b610758826114e1565b600080604083850312156115d657600080fd5b50508035926020909101359150565b600080604083850312156115f857600080fd5b611601836114e1565b915061159f602084016114e1565b600181811c9082168061162357607f821691505b60208210810361164357634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156103f6576103f6611649565b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b8152600083516116a481601785016020880161148a565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516116d581602884016020880161148a565b01602801949350505050565b634e487b7160e01b600052603260045260246000fd5b80820281158282048414176103f6576103f6611649565b634e487b7160e01b600052604160045260246000fd5b60008161173357611733611649565b506000190190565b818103818111156103f6576103f6611649565b634e487b7160e01b600052603160045260246000fdfe45524332305072657365744d696e7465725061757365723a206d75737420686165d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862addf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220d5a22b9391b8f37e5b49e43cc1eabfcea8be6d7b5aa0a84dc5daa1b7a05730f364736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101845760003560e01c806370a08231116100d9578063a457c2d711610087578063a457c2d714610336578063a9059cbb14610349578063ca15c8731461035c578063d53913931461036f578063d547741f14610396578063dd62ed3e146103a9578063e63ab1e9146103bc57600080fd5b806370a08231146102a457806379cc6790146102cd5780638456cb59146102e05780639010d07c146102e857806391d148541461031357806395d89b4114610326578063a217fddf1461032e57600080fd5b8063313ce56711610136578063313ce5671461023657806336568abe1461024557806339509351146102585780633f4ba83a1461026b57806340c10f191461027357806342966c68146102865780635c975abb1461029957600080fd5b806301ffc9a71461018957806306fdde03146101b1578063095ea7b3146101c657806318160ddd146101d957806323b872dd146101eb578063248a9ca3146101fe5780632f2ff15d14610221575b600080fd5b61019c610197366004611460565b6103d1565b60405190151581526020015b60405180910390f35b6101b96103fc565b6040516101a891906114ae565b61019c6101d43660046114fd565b61048e565b6004545b6040519081526020016101a8565b61019c6101f9366004611527565b6104a6565b6101dd61020c366004611563565b60009081526020819052604090206001015490565b61023461022f36600461157c565b6104ca565b005b604051601281526020016101a8565b61023461025336600461157c565b6104f4565b61019c6102663660046114fd565b610577565b610234610599565b6102346102813660046114fd565b610617565b610234610294366004611563565b6106a4565b60075460ff1661019c565b6101dd6102b23660046115a8565b6001600160a01b031660009081526002602052604090205490565b6102346102db3660046114fd565b6106b1565b6102346106c6565b6102fb6102f63660046115c3565b610740565b6040516001600160a01b0390911681526020016101a8565b61019c61032136600461157c565b61075f565b6101b9610788565b6101dd600081565b61019c6103443660046114fd565b610797565b61019c6103573660046114fd565b610812565b6101dd61036a366004611563565b610820565b6101dd7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b6102346103a436600461157c565b610837565b6101dd6103b73660046115e5565b61085c565b6101dd60008051602061178583398151915281565b60006001600160e01b03198216635a05180f60e01b14806103f657506103f682610887565b92915050565b60606005805461040b9061160f565b80601f01602080910402602001604051908101604052809291908181526020018280546104379061160f565b80156104845780601f1061045957610100808354040283529160200191610484565b820191906000526020600020905b81548152906001019060200180831161046757829003601f168201915b5050505050905090565b60003361049c8185856108bc565b5060019392505050565b6000336104b48582856109e0565b6104bf858585610a5a565b506001949350505050565b6000828152602081905260409020600101546104e581610bfe565b6104ef8383610c08565b505050565b6001600160a01b03811633146105695760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b6105738282610c2a565b5050565b60003361049c81858561058a838361085c565b610594919061165f565b6108bc565b6105b16000805160206117858339815191523361075f565b61060d5760405162461bcd60e51b8152602060048201526039602482015260008051602061176583398151915260448201527876652070617573657220726f6c6520746f20756e706175736560381b6064820152608401610560565b610615610c4c565b565b6106417f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a63361075f565b61069a5760405162461bcd60e51b815260206004820152603660248201526000805160206117658339815191526044820152751d99481b5a5b9d195c881c9bdb19481d1bc81b5a5b9d60521b6064820152608401610560565b6105738282610c9e565b6106ae3382610d59565b50565b6106bc8233836109e0565b6105738282610d59565b6106de6000805160206117858339815191523361075f565b6107385760405162461bcd60e51b8152602060048201526037602482015260008051602061176583398151915260448201527676652070617573657220726f6c6520746f20706175736560481b6064820152608401610560565b610615610e87565b60008281526001602052604081206107589083610ec4565b9392505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60606006805461040b9061160f565b600033816107a5828661085c565b9050838110156108055760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610560565b6104bf82868684036108bc565b60003361049c818585610a5a565b60008181526001602052604081206103f690610ed0565b60008281526020819052604090206001015461085281610bfe565b6104ef8383610c2a565b6001600160a01b03918216600090815260036020908152604080832093909416825291909152205490565b60006001600160e01b03198216637965db0b60e01b14806103f657506301ffc9a760e01b6001600160e01b03198316146103f6565b6001600160a01b03831661091e5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610560565b6001600160a01b03821661097f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610560565b6001600160a01b0383811660008181526003602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60006109ec848461085c565b90506000198114610a545781811015610a475760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610560565b610a5484848484036108bc565b50505050565b6001600160a01b038316610abe5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610560565b6001600160a01b038216610b205760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610560565b610b2b838383610eda565b6001600160a01b03831660009081526002602052604090205481811015610ba35760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610560565b6001600160a01b0380851660008181526002602052604080822086860390559286168082529083902080548601905591516000805160206117a583398151915290610bf19086815260200190565b60405180910390a3610a54565b6106ae8133610ee5565b610c128282610f3e565b60008281526001602052604090206104ef9082610fc2565b610c348282610fd7565b60008281526001602052604090206104ef908261103c565b610c54611051565b6007805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6001600160a01b038216610cf45760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610560565b610d0060008383610eda565b8060046000828254610d12919061165f565b90915550506001600160a01b0382166000818152600260209081526040808320805486019055518481526000805160206117a5833981519152910160405180910390a35050565b6001600160a01b038216610db95760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610560565b610dc582600083610eda565b6001600160a01b03821660009081526002602052604090205481811015610e395760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610560565b6001600160a01b03831660008181526002602090815260408083208686039055600480548790039055518581529192916000805160206117a5833981519152910160405180910390a3505050565b610e8f61109a565b6007805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610c813390565b600061075883836110e0565b60006103f6825490565b6104ef83838361110a565b610eef828261075f565b61057357610efc81611170565b610f07836020611182565b604051602001610f18929190611672565b60408051601f198184030181529082905262461bcd60e51b8252610560916004016114ae565b610f48828261075f565b610573576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055610f7e3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000610758836001600160a01b03841661131e565b610fe1828261075f565b15610573576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000610758836001600160a01b03841661136d565b60075460ff166106155760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610560565b60075460ff16156106155760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610560565b60008260000182815481106110f7576110f76116e1565b9060005260206000200154905092915050565b60075460ff16156104ef5760405162461bcd60e51b815260206004820152602a60248201527f45524332305061757361626c653a20746f6b656e207472616e736665722077686044820152691a5b19481c185d5cd95960b21b6064820152608401610560565b60606103f66001600160a01b03831660145b606060006111918360026116f7565b61119c90600261165f565b67ffffffffffffffff8111156111b4576111b461170e565b6040519080825280601f01601f1916602001820160405280156111de576020820181803683370190505b509050600360fc1b816000815181106111f9576111f96116e1565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110611228576112286116e1565b60200101906001600160f81b031916908160001a905350600061124c8460026116f7565b61125790600161165f565b90505b60018111156112cf576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061128b5761128b6116e1565b1a60f81b8282815181106112a1576112a16116e1565b60200101906001600160f81b031916908160001a90535060049490941c936112c881611724565b905061125a565b5083156107585760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610560565b6000818152600183016020526040812054611365575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556103f6565b5060006103f6565b6000818152600183016020526040812054801561145657600061139160018361173b565b85549091506000906113a59060019061173b565b905081811461140a5760008660000182815481106113c5576113c56116e1565b90600052602060002001549050808760000184815481106113e8576113e86116e1565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061141b5761141b61174e565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506103f6565b60009150506103f6565b60006020828403121561147257600080fd5b81356001600160e01b03198116811461075857600080fd5b60005b838110156114a557818101518382015260200161148d565b50506000910152565b60208152600082518060208401526114cd81604085016020870161148a565b601f01601f19169190910160400192915050565b80356001600160a01b03811681146114f857600080fd5b919050565b6000806040838503121561151057600080fd5b611519836114e1565b946020939093013593505050565b60008060006060848603121561153c57600080fd5b611545846114e1565b9250611553602085016114e1565b9150604084013590509250925092565b60006020828403121561157557600080fd5b5035919050565b6000806040838503121561158f57600080fd5b8235915061159f602084016114e1565b90509250929050565b6000602082840312156115ba57600080fd5b610758826114e1565b600080604083850312156115d657600080fd5b50508035926020909101359150565b600080604083850312156115f857600080fd5b611601836114e1565b915061159f602084016114e1565b600181811c9082168061162357607f821691505b60208210810361164357634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156103f6576103f6611649565b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b8152600083516116a481601785016020880161148a565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516116d581602884016020880161148a565b01602801949350505050565b634e487b7160e01b600052603260045260246000fd5b80820281158282048414176103f6576103f6611649565b634e487b7160e01b600052604160045260246000fd5b60008161173357611733611649565b506000190190565b818103818111156103f6576103f6611649565b634e487b7160e01b600052603160045260246000fdfe45524332305072657365744d696e7465725061757365723a206d75737420686165d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862addf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220d5a22b9391b8f37e5b49e43cc1eabfcea8be6d7b5aa0a84dc5daa1b7a05730f364736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var RootERC20PredicateArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"RootERC20Predicate\",\n \"sourceName\": \"contracts/root/RootERC20Predicate.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"depositor\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"ERC20Deposit\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"withdrawer\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"ERC20Withdraw\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"TokenMapped\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAP_TOKEN_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childERC20Predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childTokenTemplate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC20Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"deposit\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC20Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"depositTo\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"exitHelper\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newStateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newExitHelper\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildERC20Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"nativeTokenRootAddress\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC20Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"mapToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onL2StateReceive\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"rootTokenToChildToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"stateSender\",\n \"outputs\": [\n {\n \"internalType\": \"contract IStateSender\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b506113c7806100206000396000f3fe608060405234801561001057600080fd5b50600436106100bf5760003560e01c8063cb10f94c1161007c578063cb10f94c1461018d578063d41f1771146101a6578063d57184e4146101cd578063f213159c146101e0578063f43cda8b146101f3578063f4a120f714610206578063f64512551461021957600080fd5b80631459457a146100c457806347e7ef24146100d95780637efab4f5146100ec57806395c7041c14610132578063b176806514610145578063b68ad1e41461017a575b600080fd5b6100d76100d2366004610f4b565b610240565b005b6100d76100e7366004610fbc565b6104ae565b6101156100fa366004610fe8565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b600154610115906001600160a01b031681565b61016c7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b604051908152602001610129565b600354610115906001600160a01b031681565b600054610115906201000090046001600160a01b031681565b61016c7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b600254610115906001600160a01b031681565b6100d76101ee36600461100c565b6104bd565b6100d761020136600461104d565b6104cd565b610115610214366004610fe8565b610654565b61016c7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b600054610100900460ff16158080156102605750600054600160ff909116105b8061027a5750303b15801561027a575060005460ff166001145b6102e25760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610305576000805461ff0019166101001790555b6001600160a01b0386161580159061032557506001600160a01b03851615155b801561033957506001600160a01b03841615155b801561034d57506001600160a01b03831615155b6103a85760405162461bcd60e51b815260206004820152602660248201527f526f6f7445524332305072656469636174653a204241445f494e495449414c496044820152652d20aa24a7a760d11b60648201526084016102d9565b6000805462010000600160b01b031916620100006001600160a01b038981169190910291909117909155600180546001600160a01b03199081168884161790915560028054821687841617905560038054909116858316179055821615610460576001600160a01b03821660008181526004602052604080822080546001600160a01b03191661101090811790915590519092917f85920d35e6c72f6b2affffa04298b0cecfeba86e4a9f407df661f1cb8ab5e61791a35b80156104a6576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b6104b9823383610a15565b5050565b6104c8838383610a15565b505050565b6001546001600160a01b031633146105335760405162461bcd60e51b8152602060048201526024808201527f526f6f7445524332305072656469636174653a204f4e4c595f455849545f4845604482015263262822a960e11b60648201526084016102d9565b6002546001600160a01b038481169116146105a15760405162461bcd60e51b815260206004820152602860248201527f526f6f7445524332305072656469636174653a204f4e4c595f4348494c445f50604482015267524544494341544560c01b60648201526084016102d9565b7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e9828696105d06020600084866110d6565b6105d991611100565b036105f8576105f36105ee82602081866110d6565b610b8c565b61064e565b60405162461bcd60e51b815260206004820152602560248201527f526f6f7445524332305072656469636174653a20494e56414c49445f5349474e604482015264415455524560d81b60648201526084016102d9565b50505050565b60006001600160a01b0382166106b65760405162461bcd60e51b815260206004820152602160248201527f526f6f7445524332305072656469636174653a20494e56414c49445f544f4b456044820152602760f91b60648201526084016102d9565b6001600160a01b0382811660009081526004602052604090205416156107295760405162461bcd60e51b815260206004820152602260248201527f526f6f7445524332305072656469636174653a20414c52454144595f4d415050604482015261115160f21b60648201526084016102d9565b6002546003546040516bffffffffffffffffffffffff19606086901b1660208201526001600160a01b03928316926000926107d792911690603401604051602081830303815290604052805190602001208460405160388101919091526f5af43d82803e903d91602b57fd5bf3ff60248201526014810192909252733d602d80600a3d3981f3363d3d373d3d3d363d73825260588201526037600c8201206078820152605560439091012090565b6001600160a01b03858116600081815260046020819052604080832080546001600160a01b031916878716179055825481516306fdde0360e01b81529151969750620100009004909416946316f198319488947f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad948c9491936306fdde039380840193908290030181865afa158015610874573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261089c9190810190611159565b896001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156108da573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109029190810190611159565b8a6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610940573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096491906111fb565b60405160200161097895949392919061124a565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016109a492919061129c565b600060405180830381600087803b1580156109be57600080fd5b505af11580156109d2573d6000803e3d6000fd5b50506040516001600160a01b038085169350871691507f85920d35e6c72f6b2affffa04298b0cecfeba86e4a9f407df661f1cb8ab5e61790600090a39392505050565b6001600160a01b038084166000908152600460205260409020541680610a4157610a3e84610654565b90505b6001600160a01b038116610a5757610a576112c0565b610a6c6001600160a01b038516333085610c44565b600054600254604080517f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82160208201526001600160a01b0388811682840152336060830152878116608083015260a08083018890528351808403909101815260c08301938490526316f1983160e01b909352620100009094048416936316f1983193610afd9391169160c40161129c565b600060405180830381600087803b158015610b1757600080fd5b505af1158015610b2b573d6000803e3d6000fd5b50505050826001600160a01b0316816001600160a01b0316856001600160a01b03167f8be9001bb612c7123a1861dc0d9d94e683261f6cbbd7c7438b708975bc4908a33386604051610b7e9291906112d6565b60405180910390a450505050565b6000808080610b9d858701876112ef565b6001600160a01b0380851660009081526004602052604090205494985092965090945092501680610bd057610bd06112c0565b610be46001600160a01b0386168484610caf565b826001600160a01b0316816001600160a01b0316866001600160a01b03167f9c4f744b2e971d7058a9d8f43977e0e17bf7d57a48659f0e18541b7ee3d022e48786604051610c339291906112d6565b60405180910390a450505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261064e9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610cce565b6104c88363a9059cbb60e01b8484604051602401610c789291906112d6565b6000610d23826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610da39092919063ffffffff16565b9050805160001480610d44575080806020019051810190610d449190611340565b6104c85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016102d9565b6060610db28484600085610dba565b949350505050565b606082471015610e1b5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016102d9565b600080866001600160a01b03168587604051610e379190611362565b60006040518083038185875af1925050503d8060008114610e74576040519150601f19603f3d011682016040523d82523d6000602084013e610e79565b606091505b5091509150610e8a87838387610e95565b979650505050505050565b60608315610f04578251600003610efd576001600160a01b0385163b610efd5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102d9565b5081610db2565b610db28383815115610f195781518083602001fd5b8060405162461bcd60e51b81526004016102d9919061137e565b6001600160a01b0381168114610f4857600080fd5b50565b600080600080600060a08688031215610f6357600080fd5b8535610f6e81610f33565b94506020860135610f7e81610f33565b93506040860135610f8e81610f33565b92506060860135610f9e81610f33565b91506080860135610fae81610f33565b809150509295509295909350565b60008060408385031215610fcf57600080fd5b8235610fda81610f33565b946020939093013593505050565b600060208284031215610ffa57600080fd5b813561100581610f33565b9392505050565b60008060006060848603121561102157600080fd5b833561102c81610f33565b9250602084013561103c81610f33565b929592945050506040919091013590565b6000806000806060858703121561106357600080fd5b84359350602085013561107581610f33565b9250604085013567ffffffffffffffff8082111561109257600080fd5b818701915087601f8301126110a657600080fd5b8135818111156110b557600080fd5b8860208285010111156110c757600080fd5b95989497505060200194505050565b600080858511156110e657600080fd5b838611156110f357600080fd5b5050820193919092039150565b8035602083101561111957600019602084900360031b1b165b92915050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015611150578181015183820152602001611138565b50506000910152565b60006020828403121561116b57600080fd5b815167ffffffffffffffff8082111561118357600080fd5b818401915084601f83011261119757600080fd5b8151818111156111a9576111a961111f565b604051601f8201601f19908116603f011681019083821181831017156111d1576111d161111f565b816040528281528760208487010111156111ea57600080fd5b610e8a836020830160208801611135565b60006020828403121561120d57600080fd5b815160ff8116811461100557600080fd5b60008151808452611236816020860160208601611135565b601f01601f19169290920160200192915050565b8581526001600160a01b038516602082015260a0604082018190526000906112749083018661121e565b8281036060840152611286818661121e565b91505060ff831660808301529695505050505050565b6001600160a01b0383168152604060208201819052600090610db29083018461121e565b634e487b7160e01b600052600160045260246000fd5b6001600160a01b03929092168252602082015260400190565b6000806000806080858703121561130557600080fd5b843561131081610f33565b9350602085013561132081610f33565b9250604085013561133081610f33565b9396929550929360600135925050565b60006020828403121561135257600080fd5b8151801515811461100557600080fd5b60008251611374818460208701611135565b9190910192915050565b602081526000611005602083018461121e56fea26469706673582212208273d626c27034ddec9bc7a16685788a61724d2c7c1fc56e7299933565b205fa64736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106100bf5760003560e01c8063cb10f94c1161007c578063cb10f94c1461018d578063d41f1771146101a6578063d57184e4146101cd578063f213159c146101e0578063f43cda8b146101f3578063f4a120f714610206578063f64512551461021957600080fd5b80631459457a146100c457806347e7ef24146100d95780637efab4f5146100ec57806395c7041c14610132578063b176806514610145578063b68ad1e41461017a575b600080fd5b6100d76100d2366004610f4b565b610240565b005b6100d76100e7366004610fbc565b6104ae565b6101156100fa366004610fe8565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b600154610115906001600160a01b031681565b61016c7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b604051908152602001610129565b600354610115906001600160a01b031681565b600054610115906201000090046001600160a01b031681565b61016c7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b600254610115906001600160a01b031681565b6100d76101ee36600461100c565b6104bd565b6100d761020136600461104d565b6104cd565b610115610214366004610fe8565b610654565b61016c7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b600054610100900460ff16158080156102605750600054600160ff909116105b8061027a5750303b15801561027a575060005460ff166001145b6102e25760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610305576000805461ff0019166101001790555b6001600160a01b0386161580159061032557506001600160a01b03851615155b801561033957506001600160a01b03841615155b801561034d57506001600160a01b03831615155b6103a85760405162461bcd60e51b815260206004820152602660248201527f526f6f7445524332305072656469636174653a204241445f494e495449414c496044820152652d20aa24a7a760d11b60648201526084016102d9565b6000805462010000600160b01b031916620100006001600160a01b038981169190910291909117909155600180546001600160a01b03199081168884161790915560028054821687841617905560038054909116858316179055821615610460576001600160a01b03821660008181526004602052604080822080546001600160a01b03191661101090811790915590519092917f85920d35e6c72f6b2affffa04298b0cecfeba86e4a9f407df661f1cb8ab5e61791a35b80156104a6576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b6104b9823383610a15565b5050565b6104c8838383610a15565b505050565b6001546001600160a01b031633146105335760405162461bcd60e51b8152602060048201526024808201527f526f6f7445524332305072656469636174653a204f4e4c595f455849545f4845604482015263262822a960e11b60648201526084016102d9565b6002546001600160a01b038481169116146105a15760405162461bcd60e51b815260206004820152602860248201527f526f6f7445524332305072656469636174653a204f4e4c595f4348494c445f50604482015267524544494341544560c01b60648201526084016102d9565b7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e9828696105d06020600084866110d6565b6105d991611100565b036105f8576105f36105ee82602081866110d6565b610b8c565b61064e565b60405162461bcd60e51b815260206004820152602560248201527f526f6f7445524332305072656469636174653a20494e56414c49445f5349474e604482015264415455524560d81b60648201526084016102d9565b50505050565b60006001600160a01b0382166106b65760405162461bcd60e51b815260206004820152602160248201527f526f6f7445524332305072656469636174653a20494e56414c49445f544f4b456044820152602760f91b60648201526084016102d9565b6001600160a01b0382811660009081526004602052604090205416156107295760405162461bcd60e51b815260206004820152602260248201527f526f6f7445524332305072656469636174653a20414c52454144595f4d415050604482015261115160f21b60648201526084016102d9565b6002546003546040516bffffffffffffffffffffffff19606086901b1660208201526001600160a01b03928316926000926107d792911690603401604051602081830303815290604052805190602001208460405160388101919091526f5af43d82803e903d91602b57fd5bf3ff60248201526014810192909252733d602d80600a3d3981f3363d3d373d3d3d363d73825260588201526037600c8201206078820152605560439091012090565b6001600160a01b03858116600081815260046020819052604080832080546001600160a01b031916878716179055825481516306fdde0360e01b81529151969750620100009004909416946316f198319488947f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad948c9491936306fdde039380840193908290030181865afa158015610874573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261089c9190810190611159565b896001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156108da573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109029190810190611159565b8a6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610940573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096491906111fb565b60405160200161097895949392919061124a565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016109a492919061129c565b600060405180830381600087803b1580156109be57600080fd5b505af11580156109d2573d6000803e3d6000fd5b50506040516001600160a01b038085169350871691507f85920d35e6c72f6b2affffa04298b0cecfeba86e4a9f407df661f1cb8ab5e61790600090a39392505050565b6001600160a01b038084166000908152600460205260409020541680610a4157610a3e84610654565b90505b6001600160a01b038116610a5757610a576112c0565b610a6c6001600160a01b038516333085610c44565b600054600254604080517f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82160208201526001600160a01b0388811682840152336060830152878116608083015260a08083018890528351808403909101815260c08301938490526316f1983160e01b909352620100009094048416936316f1983193610afd9391169160c40161129c565b600060405180830381600087803b158015610b1757600080fd5b505af1158015610b2b573d6000803e3d6000fd5b50505050826001600160a01b0316816001600160a01b0316856001600160a01b03167f8be9001bb612c7123a1861dc0d9d94e683261f6cbbd7c7438b708975bc4908a33386604051610b7e9291906112d6565b60405180910390a450505050565b6000808080610b9d858701876112ef565b6001600160a01b0380851660009081526004602052604090205494985092965090945092501680610bd057610bd06112c0565b610be46001600160a01b0386168484610caf565b826001600160a01b0316816001600160a01b0316866001600160a01b03167f9c4f744b2e971d7058a9d8f43977e0e17bf7d57a48659f0e18541b7ee3d022e48786604051610c339291906112d6565b60405180910390a450505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261064e9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610cce565b6104c88363a9059cbb60e01b8484604051602401610c789291906112d6565b6000610d23826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610da39092919063ffffffff16565b9050805160001480610d44575080806020019051810190610d449190611340565b6104c85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016102d9565b6060610db28484600085610dba565b949350505050565b606082471015610e1b5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016102d9565b600080866001600160a01b03168587604051610e379190611362565b60006040518083038185875af1925050503d8060008114610e74576040519150601f19603f3d011682016040523d82523d6000602084013e610e79565b606091505b5091509150610e8a87838387610e95565b979650505050505050565b60608315610f04578251600003610efd576001600160a01b0385163b610efd5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102d9565b5081610db2565b610db28383815115610f195781518083602001fd5b8060405162461bcd60e51b81526004016102d9919061137e565b6001600160a01b0381168114610f4857600080fd5b50565b600080600080600060a08688031215610f6357600080fd5b8535610f6e81610f33565b94506020860135610f7e81610f33565b93506040860135610f8e81610f33565b92506060860135610f9e81610f33565b91506080860135610fae81610f33565b809150509295509295909350565b60008060408385031215610fcf57600080fd5b8235610fda81610f33565b946020939093013593505050565b600060208284031215610ffa57600080fd5b813561100581610f33565b9392505050565b60008060006060848603121561102157600080fd5b833561102c81610f33565b9250602084013561103c81610f33565b929592945050506040919091013590565b6000806000806060858703121561106357600080fd5b84359350602085013561107581610f33565b9250604085013567ffffffffffffffff8082111561109257600080fd5b818701915087601f8301126110a657600080fd5b8135818111156110b557600080fd5b8860208285010111156110c757600080fd5b95989497505060200194505050565b600080858511156110e657600080fd5b838611156110f357600080fd5b5050820193919092039150565b8035602083101561111957600019602084900360031b1b165b92915050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015611150578181015183820152602001611138565b50506000910152565b60006020828403121561116b57600080fd5b815167ffffffffffffffff8082111561118357600080fd5b818401915084601f83011261119757600080fd5b8151818111156111a9576111a961111f565b604051601f8201601f19908116603f011681019083821181831017156111d1576111d161111f565b816040528281528760208487010111156111ea57600080fd5b610e8a836020830160208801611135565b60006020828403121561120d57600080fd5b815160ff8116811461100557600080fd5b60008151808452611236816020860160208601611135565b601f01601f19169290920160200192915050565b8581526001600160a01b038516602082015260a0604082018190526000906112749083018661121e565b8281036060840152611286818661121e565b91505060ff831660808301529695505050505050565b6001600160a01b0383168152604060208201819052600090610db29083018461121e565b634e487b7160e01b600052600160045260246000fd5b6001600160a01b03929092168252602082015260400190565b6000806000806080858703121561130557600080fd5b843561131081610f33565b9350602085013561132081610f33565b9250604085013561133081610f33565b9396929550929360600135925050565b60006020828403121561135257600080fd5b8151801515811461100557600080fd5b60008251611374818460208701611135565b9190910192915050565b602081526000611005602083018461121e56fea26469706673582212208273d626c27034ddec9bc7a16685788a61724d2c7c1fc56e7299933565b205fa64736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var ChildMintableERC20PredicateArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"ChildMintableERC20Predicate\",\n \"sourceName\": \"contracts/root/ChildMintableERC20Predicate.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"MintableERC20Deposit\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"MintableERC20Withdraw\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"MintableTokenMapped\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAP_TOKEN_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childTokenTemplate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"exitHelper\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newStateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newExitHelper\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newRootERC20Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onL2StateReceive\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"rootERC20Predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"rootTokenToChildToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"stateSender\",\n \"outputs\": [\n {\n \"internalType\": \"contract IStateSender\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC20\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"withdraw\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC20\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"withdrawTo\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b506113c8806100206000396000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c8063cb10f94c11610071578063cb10f94c14610182578063d41f17711461019b578063f3fef3a3146101c2578063f43cda8b146101d5578063f6451255146101e8578063f8c8765e1461020f57600080fd5b806371cf93b7146100b95780637efab4f5146100e957806395c7041c14610112578063b176806514610125578063b68ad1e41461015a578063c3b35a7e1461016d575b600080fd5b6002546100cc906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6100cc6100f7366004610ecf565b6004602052600090815260409020546001600160a01b031681565b6001546100cc906001600160a01b031681565b61014c7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b6040519081526020016100e0565b6003546100cc906001600160a01b031681565b61018061017b366004610ef3565b610222565b005b6000546100cc906201000090046001600160a01b031681565b61014c7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b6101806101d0366004610f34565b610232565b6101806101e3366004610f60565b610241565b61014c7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b61018061021d366004610fe9565b610432565b61022d83838361054b565b505050565b61023d82338361054b565b5050565b6001546001600160a01b031633146102b95760405162461bcd60e51b815260206004820152603060248201527f4368696c644d696e7461626c6545524332305072656469636174653a204f4e4c60448201526f2cafa9aa20aa22afa922a1a2a4ab22a960811b60648201526084015b60405180910390fd5b6002546001600160a01b0384811691161461032f5760405162461bcd60e51b815260206004820152603060248201527f4368696c644d696e7461626c6545524332305072656469636174653a204f4e4c60448201526f595f524f4f545f50524544494341544560801b60648201526084016102b0565b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82161035e602060008486611045565b6103679161106f565b036103865761038161037c8260208186611045565b6108e0565b61042c565b7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad6103b5602060008486611045565b6103be9161106f565b036103cd576103818282610b9c565b60405162461bcd60e51b815260206004820152602e60248201527f4368696c644d696e7461626c6545524332305072656469636174653a20494e5660448201526d414c49445f5349474e415455524560901b60648201526084016102b0565b50505050565b600054610100900460ff16158080156104525750600054600160ff909116105b8061046c5750303b15801561046c575060005460ff166001145b6104cf5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016102b0565b6000805460ff1916600117905580156104f2576000805461ff0019166101001790555b6104fe85858585610d13565b8015610544576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b826001600160a01b03163b6000036105b75760405162461bcd60e51b815260206004820152602960248201527f4368696c644d696e7461626c6545524332305072656469636174653a204e4f5460448201526817d0d3d395149050d560ba1b60648201526084016102b0565b6000836001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061b919061108d565b6001600160a01b0381811660009081526004602052604090205491925085811691161461065a5760405162461bcd60e51b81526004016102b0906110aa565b6001600160a01b038116610670576106706110f5565b306001600160a01b0316846001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106dc919061108d565b6001600160a01b0316146106f2576106f26110f5565b604051632770a7eb60e21b81526001600160a01b03851690639dc29fac90610720903390869060040161110b565b6020604051808303816000875af115801561073f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107639190611124565b6107c05760405162461bcd60e51b815260206004820152602860248201527f4368696c644d696e7461626c6545524332305072656469636174653a204255526044820152671397d1905253115160c21b60648201526084016102b0565b600054600254604080517f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286960208201526001600160a01b0385811682840152336060830152878116608083015260a08083018890528351808403909101815260c08301938490526316f1983160e01b909352620100009094048416936316f19831936108519391169160c40161118c565b600060405180830381600087803b15801561086b57600080fd5b505af115801561087f573d6000803e3d6000fd5b50505050826001600160a01b0316846001600160a01b0316826001600160a01b03167f1da92ba31d15f9af529a2efe7acebc6c0a4ac8e9cd86a84f199a474e505d77a633866040516108d292919061110b565b60405180910390a450505050565b60008080806108f1858701876111b8565b6001600160a01b03808516600090815260046020526040902054949850929650909450925016806109345760405162461bcd60e51b81526004016102b0906110aa565b806001600160a01b03163b60000361094e5761094e6110f5565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa15801561098e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109b2919061108d565b9050856001600160a01b0316816001600160a01b0316146109d5576109d56110f5565b6001600160a01b0381166109eb576109eb6110f5565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a57919061108d565b6001600160a01b031614610a6d57610a6d6110f5565b6040516340c10f1960e01b81526001600160a01b038316906340c10f1990610a9b908790879060040161110b565b6020604051808303816000875af1158015610aba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ade9190611124565b610b3b5760405162461bcd60e51b815260206004820152602860248201527f4368696c644d696e7461626c6545524332305072656469636174653a204d494e6044820152671517d1905253115160c21b60648201526084016102b0565b836001600160a01b0316826001600160a01b0316876001600160a01b03167fcf47ccd68b2113d6309d8d504a67c10963dc0bfbf2416e4726a316511cca27b58887604051610b8a92919061110b565b60405180910390a45050505050505050565b6000808080610bad858701876112ac565b92975090955093509150506001600160a01b038416610bce57610bce6110f5565b6001600160a01b038481166000908152600460205260409020541615610bf657610bf66110f5565b6003546040516bffffffffffffffffffffffff19606087901b166020820152600091610c46916001600160a01b039091169060340160405160208183030381529060405280519060200120610e1a565b6001600160a01b0386811660009081526004602081905260409182902080546001600160a01b03191693851693841790559051637b69774360e11b8152929350909163f6d2ee8691610ca091899189918991899101611347565b600060405180830381600087803b158015610cba57600080fd5b505af1158015610cce573d6000803e3d6000fd5b50506040516001600160a01b038085169350881691507f0a1eaf9aa124c3f84c9dd77f7016af0f16f67639abb913af1697387db01f5ca590600090a350505050505050565b6001600160a01b03841615801590610d3357506001600160a01b03831615155b8015610d4757506001600160a01b03821615155b8015610d5b57506001600160a01b03811615155b610dbf5760405162461bcd60e51b815260206004820152602f60248201527f4368696c644d696e7461626c6545524332305072656469636174653a2042414460448201526e2fa4a724aa24a0a624ad20aa24a7a760891b60648201526084016102b0565b600080546001600160a01b03958616620100000262010000600160b01b0319909116179055600180549385166001600160a01b0319948516179055600280549285169284169290921790915560038054919093169116179055565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b038116610eb15760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b60448201526064016102b0565b92915050565b6001600160a01b0381168114610ecc57600080fd5b50565b600060208284031215610ee157600080fd5b8135610eec81610eb7565b9392505050565b600080600060608486031215610f0857600080fd5b8335610f1381610eb7565b92506020840135610f2381610eb7565b929592945050506040919091013590565b60008060408385031215610f4757600080fd5b8235610f5281610eb7565b946020939093013593505050565b60008060008060608587031215610f7657600080fd5b843593506020850135610f8881610eb7565b9250604085013567ffffffffffffffff80821115610fa557600080fd5b818701915087601f830112610fb957600080fd5b813581811115610fc857600080fd5b886020828501011115610fda57600080fd5b95989497505060200194505050565b60008060008060808587031215610fff57600080fd5b843561100a81610eb7565b9350602085013561101a81610eb7565b9250604085013561102a81610eb7565b9150606085013561103a81610eb7565b939692955090935050565b6000808585111561105557600080fd5b8386111561106257600080fd5b5050820193919092039150565b80356020831015610eb157600019602084900360031b1b1692915050565b60006020828403121561109f57600080fd5b8151610eec81610eb7565b6020808252602b908201527f4368696c644d696e7461626c6545524332305072656469636174653a20554e4d60408201526a20a82822a22faa27a5a2a760a91b606082015260800190565b634e487b7160e01b600052600160045260246000fd5b6001600160a01b03929092168252602082015260400190565b60006020828403121561113657600080fd5b81518015158114610eec57600080fd5b6000815180845260005b8181101561116c57602081850181015186830182015201611150565b506000602082860101526020601f19601f83011685010191505092915050565b6001600160a01b03831681526040602082018190526000906111b090830184611146565b949350505050565b600080600080608085870312156111ce57600080fd5b84356111d981610eb7565b935060208501356111e981610eb7565b925060408501356111f981610eb7565b9396929550929360600135925050565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261123057600080fd5b813567ffffffffffffffff8082111561124b5761124b611209565b604051601f8301601f19908116603f0116810190828211818310171561127357611273611209565b8160405283815286602085880101111561128c57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060a086880312156112c457600080fd5b8535945060208601356112d681610eb7565b9350604086013567ffffffffffffffff808211156112f357600080fd5b6112ff89838a0161121f565b9450606088013591508082111561131557600080fd5b506113228882890161121f565b925050608086013560ff8116811461133957600080fd5b809150509295509295909350565b6001600160a01b038516815260806020820181905260009061136b90830186611146565b828103604084015261137d8186611146565b91505060ff831660608301529594505050505056fea2646970667358221220984c3094e8562bd0956d9fdc403002d008ee01ac2423018d1e0c059931ee689764736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106100b45760003560e01c8063cb10f94c11610071578063cb10f94c14610182578063d41f17711461019b578063f3fef3a3146101c2578063f43cda8b146101d5578063f6451255146101e8578063f8c8765e1461020f57600080fd5b806371cf93b7146100b95780637efab4f5146100e957806395c7041c14610112578063b176806514610125578063b68ad1e41461015a578063c3b35a7e1461016d575b600080fd5b6002546100cc906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6100cc6100f7366004610ecf565b6004602052600090815260409020546001600160a01b031681565b6001546100cc906001600160a01b031681565b61014c7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b6040519081526020016100e0565b6003546100cc906001600160a01b031681565b61018061017b366004610ef3565b610222565b005b6000546100cc906201000090046001600160a01b031681565b61014c7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b6101806101d0366004610f34565b610232565b6101806101e3366004610f60565b610241565b61014c7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b61018061021d366004610fe9565b610432565b61022d83838361054b565b505050565b61023d82338361054b565b5050565b6001546001600160a01b031633146102b95760405162461bcd60e51b815260206004820152603060248201527f4368696c644d696e7461626c6545524332305072656469636174653a204f4e4c60448201526f2cafa9aa20aa22afa922a1a2a4ab22a960811b60648201526084015b60405180910390fd5b6002546001600160a01b0384811691161461032f5760405162461bcd60e51b815260206004820152603060248201527f4368696c644d696e7461626c6545524332305072656469636174653a204f4e4c60448201526f595f524f4f545f50524544494341544560801b60648201526084016102b0565b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82161035e602060008486611045565b6103679161106f565b036103865761038161037c8260208186611045565b6108e0565b61042c565b7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad6103b5602060008486611045565b6103be9161106f565b036103cd576103818282610b9c565b60405162461bcd60e51b815260206004820152602e60248201527f4368696c644d696e7461626c6545524332305072656469636174653a20494e5660448201526d414c49445f5349474e415455524560901b60648201526084016102b0565b50505050565b600054610100900460ff16158080156104525750600054600160ff909116105b8061046c5750303b15801561046c575060005460ff166001145b6104cf5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016102b0565b6000805460ff1916600117905580156104f2576000805461ff0019166101001790555b6104fe85858585610d13565b8015610544576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b826001600160a01b03163b6000036105b75760405162461bcd60e51b815260206004820152602960248201527f4368696c644d696e7461626c6545524332305072656469636174653a204e4f5460448201526817d0d3d395149050d560ba1b60648201526084016102b0565b6000836001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061b919061108d565b6001600160a01b0381811660009081526004602052604090205491925085811691161461065a5760405162461bcd60e51b81526004016102b0906110aa565b6001600160a01b038116610670576106706110f5565b306001600160a01b0316846001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106dc919061108d565b6001600160a01b0316146106f2576106f26110f5565b604051632770a7eb60e21b81526001600160a01b03851690639dc29fac90610720903390869060040161110b565b6020604051808303816000875af115801561073f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107639190611124565b6107c05760405162461bcd60e51b815260206004820152602860248201527f4368696c644d696e7461626c6545524332305072656469636174653a204255526044820152671397d1905253115160c21b60648201526084016102b0565b600054600254604080517f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286960208201526001600160a01b0385811682840152336060830152878116608083015260a08083018890528351808403909101815260c08301938490526316f1983160e01b909352620100009094048416936316f19831936108519391169160c40161118c565b600060405180830381600087803b15801561086b57600080fd5b505af115801561087f573d6000803e3d6000fd5b50505050826001600160a01b0316846001600160a01b0316826001600160a01b03167f1da92ba31d15f9af529a2efe7acebc6c0a4ac8e9cd86a84f199a474e505d77a633866040516108d292919061110b565b60405180910390a450505050565b60008080806108f1858701876111b8565b6001600160a01b03808516600090815260046020526040902054949850929650909450925016806109345760405162461bcd60e51b81526004016102b0906110aa565b806001600160a01b03163b60000361094e5761094e6110f5565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa15801561098e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109b2919061108d565b9050856001600160a01b0316816001600160a01b0316146109d5576109d56110f5565b6001600160a01b0381166109eb576109eb6110f5565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a57919061108d565b6001600160a01b031614610a6d57610a6d6110f5565b6040516340c10f1960e01b81526001600160a01b038316906340c10f1990610a9b908790879060040161110b565b6020604051808303816000875af1158015610aba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ade9190611124565b610b3b5760405162461bcd60e51b815260206004820152602860248201527f4368696c644d696e7461626c6545524332305072656469636174653a204d494e6044820152671517d1905253115160c21b60648201526084016102b0565b836001600160a01b0316826001600160a01b0316876001600160a01b03167fcf47ccd68b2113d6309d8d504a67c10963dc0bfbf2416e4726a316511cca27b58887604051610b8a92919061110b565b60405180910390a45050505050505050565b6000808080610bad858701876112ac565b92975090955093509150506001600160a01b038416610bce57610bce6110f5565b6001600160a01b038481166000908152600460205260409020541615610bf657610bf66110f5565b6003546040516bffffffffffffffffffffffff19606087901b166020820152600091610c46916001600160a01b039091169060340160405160208183030381529060405280519060200120610e1a565b6001600160a01b0386811660009081526004602081905260409182902080546001600160a01b03191693851693841790559051637b69774360e11b8152929350909163f6d2ee8691610ca091899189918991899101611347565b600060405180830381600087803b158015610cba57600080fd5b505af1158015610cce573d6000803e3d6000fd5b50506040516001600160a01b038085169350881691507f0a1eaf9aa124c3f84c9dd77f7016af0f16f67639abb913af1697387db01f5ca590600090a350505050505050565b6001600160a01b03841615801590610d3357506001600160a01b03831615155b8015610d4757506001600160a01b03821615155b8015610d5b57506001600160a01b03811615155b610dbf5760405162461bcd60e51b815260206004820152602f60248201527f4368696c644d696e7461626c6545524332305072656469636174653a2042414460448201526e2fa4a724aa24a0a624ad20aa24a7a760891b60648201526084016102b0565b600080546001600160a01b03958616620100000262010000600160b01b0319909116179055600180549385166001600160a01b0319948516179055600280549285169284169290921790915560038054919093169116179055565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b038116610eb15760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b60448201526064016102b0565b92915050565b6001600160a01b0381168114610ecc57600080fd5b50565b600060208284031215610ee157600080fd5b8135610eec81610eb7565b9392505050565b600080600060608486031215610f0857600080fd5b8335610f1381610eb7565b92506020840135610f2381610eb7565b929592945050506040919091013590565b60008060408385031215610f4757600080fd5b8235610f5281610eb7565b946020939093013593505050565b60008060008060608587031215610f7657600080fd5b843593506020850135610f8881610eb7565b9250604085013567ffffffffffffffff80821115610fa557600080fd5b818701915087601f830112610fb957600080fd5b813581811115610fc857600080fd5b886020828501011115610fda57600080fd5b95989497505060200194505050565b60008060008060808587031215610fff57600080fd5b843561100a81610eb7565b9350602085013561101a81610eb7565b9250604085013561102a81610eb7565b9150606085013561103a81610eb7565b939692955090935050565b6000808585111561105557600080fd5b8386111561106257600080fd5b5050820193919092039150565b80356020831015610eb157600019602084900360031b1b1692915050565b60006020828403121561109f57600080fd5b8151610eec81610eb7565b6020808252602b908201527f4368696c644d696e7461626c6545524332305072656469636174653a20554e4d60408201526a20a82822a22faa27a5a2a760a91b606082015260800190565b634e487b7160e01b600052600160045260246000fd5b6001600160a01b03929092168252602082015260400190565b60006020828403121561113657600080fd5b81518015158114610eec57600080fd5b6000815180845260005b8181101561116c57602081850181015186830182015201611150565b506000602082860101526020601f19601f83011685010191505092915050565b6001600160a01b03831681526040602082018190526000906111b090830184611146565b949350505050565b600080600080608085870312156111ce57600080fd5b84356111d981610eb7565b935060208501356111e981610eb7565b925060408501356111f981610eb7565b9396929550929360600135925050565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261123057600080fd5b813567ffffffffffffffff8082111561124b5761124b611209565b604051601f8301601f19908116603f0116810190828211818310171561127357611273611209565b8160405283815286602085880101111561128c57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060a086880312156112c457600080fd5b8535945060208601356112d681610eb7565b9350604086013567ffffffffffffffff808211156112f357600080fd5b6112ff89838a0161121f565b9450606088013591508082111561131557600080fd5b506113228882890161121f565b925050608086013560ff8116811461133957600080fd5b809150509295509295909350565b6001600160a01b038516815260806020820181905260009061136b90830186611146565b828103604084015261137d8186611146565b91505060ff831660608301529594505050505056fea2646970667358221220984c3094e8562bd0956d9fdc403002d008ee01ac2423018d1e0c059931ee689764736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var MockERC721Artifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"MockERC721\",\n \"sourceName\": \"contracts/mocks/MockERC721.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"approved\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Approval\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"operator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bool\",\n \"name\": \"approved\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"ApprovalForAll\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"Paused\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bytes32\",\n \"name\": \"previousAdminRole\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bytes32\",\n \"name\": \"newAdminRole\",\n \"type\": \"bytes32\"\n }\n ],\n \"name\": \"RoleAdminChanged\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"RoleGranted\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"RoleRevoked\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Transfer\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"Unpaused\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEFAULT_ADMIN_ROLE\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MINTER_ROLE\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"PAUSER_ROLE\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"approve\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"balanceOf\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"burn\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"getApproved\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n }\n ],\n \"name\": \"getRoleAdmin\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"index\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"getRoleMember\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n }\n ],\n \"name\": \"getRoleMemberCount\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"grantRole\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"hasRole\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"operator\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"isApprovedForAll\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"mint\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"name\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"ownerOf\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"pause\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"paused\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"renounceRole\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"revokeRole\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"safeTransferFrom\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"safeTransferFrom\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"operator\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"approved\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"setApprovalForAll\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes4\",\n \"name\": \"interfaceId\",\n \"type\": \"bytes4\"\n }\n ],\n \"name\": \"supportsInterface\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"symbol\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"index\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"tokenByIndex\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"index\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"tokenOfOwnerByIndex\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"tokenURI\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"totalSupply\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transferFrom\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"unpause\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x60806040523480156200001157600080fd5b5060405180604001604052806004815260200163151154d560e21b81525060405180604001604052806004815260200163151154d560e21b815250604051806040016040528060058152602001646c6f72656d60d81b815250828281600290816200007d919062000307565b5060036200008c828262000307565b5050600c805460ff1916905550600e620000a7828262000307565b50620000b560003362000116565b620000e17f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a63362000116565b6200010d7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a3362000116565b505050620003d3565b62000122828262000126565b5050565b62000132828262000151565b60008281526001602052604090206200014c9082620001f1565b505050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1662000122576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620001ad3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600062000208836001600160a01b03841662000211565b90505b92915050565b60008181526001830160205260408120546200025a575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200020b565b5060006200020b565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200028e57607f821691505b602082108103620002af57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200014c57600081815260208120601f850160051c81016020861015620002de5750805b601f850160051c820191505b81811015620002ff57828155600101620002ea565b505050505050565b81516001600160401b0381111562000323576200032362000263565b6200033b8162000334845462000279565b84620002b5565b602080601f8311600181146200037357600084156200035a5750858301515b600019600386901b1c1916600185901b178555620002ff565b600085815260208120601f198616915b82811015620003a45788860151825594840194600190910190840162000383565b5085821015620003c35787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b61244180620003e36000396000f3fe608060405234801561001057600080fd5b50600436106101a55760003560e01c80636352211e116100ef578063a22cb46511610092578063a22cb4651461036b578063b88d4fde1461037e578063c87b56dd14610391578063ca15c873146103a4578063d5391393146103b7578063d547741f146103de578063e63ab1e9146103f1578063e985e9c51461040657600080fd5b80636352211e146102f45780636a6278421461030757806370a082311461031a5780638456cb591461032d5780639010d07c1461033557806391d148541461034857806395d89b411461035b578063a217fddf1461036357600080fd5b80632f2ff15d116101575780632f2ff15d1461026f5780632f745c591461028257806336568abe146102955780633f4ba83a146102a857806342842e0e146102b057806342966c68146102c35780634f6ccce7146102d65780635c975abb146102e957600080fd5b806301ffc9a7146101aa57806306fdde03146101d2578063081812fc146101e7578063095ea7b31461021257806318160ddd1461022757806323b872dd14610239578063248a9ca31461024c575b600080fd5b6101bd6101b8366004611dba565b610419565b60405190151581526020015b60405180910390f35b6101da61042a565b6040516101c99190611e27565b6101fa6101f5366004611e3a565b6104bc565b6040516001600160a01b0390911681526020016101c9565b610225610220366004611e6f565b6104e3565b005b600a545b6040519081526020016101c9565b610225610247366004611e99565b6105fd565b61022b61025a366004611e3a565b60009081526020819052604090206001015490565b61022561027d366004611ed5565b61062f565b61022b610290366004611e6f565b610654565b6102256102a3366004611ed5565b6106ea565b610225610768565b6102256102be366004611e99565b6107ec565b6102256102d1366004611e3a565b610807565b61022b6102e4366004611e3a565b610838565b600c5460ff166101bd565b6101fa610302366004611e3a565b6108cb565b610225610315366004611f01565b610900565b61022b610328366004611f01565b6109aa565b610225610a30565b6101fa610343366004611f1c565b610ab0565b6101bd610356366004611ed5565b610acf565b6101da610af8565b61022b600081565b610225610379366004611f3e565b610b07565b61022561038c366004611f90565b610b12565b6101da61039f366004611e3a565b610b4a565b61022b6103b2366004611e3a565b610bb0565b61022b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b6102256103ec366004611ed5565b610bc7565b61022b6000805160206123ac83398151915281565b6101bd61041436600461206c565b610bec565b600061042482610c1a565b92915050565b60606002805461043990612096565b80601f016020809104026020016040519081016040528092919081815260200182805461046590612096565b80156104b25780601f10610487576101008083540402835291602001916104b2565b820191906000526020600020905b81548152906001019060200180831161049557829003601f168201915b5050505050905090565b60006104c782610c3f565b506000908152600660205260409020546001600160a01b031690565b60006104ee826108cb565b9050806001600160a01b0316836001600160a01b0316036105605760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b038216148061057c575061057c8133610bec565b6105ee5760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152608401610557565b6105f88383610c64565b505050565b610608335b82610cd2565b6106245760405162461bcd60e51b8152600401610557906120d0565b6105f8838383610d31565b60008281526020819052604090206001015461064a81610e90565b6105f88383610e9a565b600061065f836109aa565b82106106c15760405162461bcd60e51b815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201526a74206f6620626f756e647360a81b6064820152608401610557565b506001600160a01b03919091166000908152600860209081526040808320938352929052205490565b6001600160a01b038116331461075a5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610557565b6107648282610ebc565b5050565b6107806000805160206123ac83398151915233610acf565b6107e2576040805162461bcd60e51b81526020600482015260248101919091526000805160206123ec83398151915260448201527f6d75737420686176652070617573657220726f6c6520746f20756e70617573656064820152608401610557565b6107ea610ede565b565b6105f883838360405180602001604052806000815250610b12565b61081033610602565b61082c5760405162461bcd60e51b8152600401610557906120d0565b61083581610f30565b50565b6000610843600a5490565b82106108a65760405162461bcd60e51b815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201526b7574206f6620626f756e647360a01b6064820152608401610557565b600a82815481106108b9576108b961211d565b90600052602060002001549050919050565b6000818152600460205260408120546001600160a01b0316806104245760405162461bcd60e51b815260040161055790612133565b61092a7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a633610acf565b61098a5760405162461bcd60e51b815260206004820152603d60248201526000805160206123ec83398151915260448201527f6d7573742068617665206d696e74657220726f6c6520746f206d696e740000006064820152608401610557565b61099c81610997600d5490565b610fc1565b610835600d80546001019055565b60006001600160a01b038216610a145760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608401610557565b506001600160a01b031660009081526005602052604090205490565b610a486000805160206123ac83398151915233610acf565b610aa85760405162461bcd60e51b815260206004820152603e60248201526000805160206123ec83398151915260448201527f6d75737420686176652070617573657220726f6c6520746f20706175736500006064820152608401610557565b6107ea6110ca565b6000828152600160205260408120610ac89083611107565b9392505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60606003805461043990612096565b610764338383611113565b610b1c3383610cd2565b610b385760405162461bcd60e51b8152600401610557906120d0565b610b44848484846111dd565b50505050565b6060610b5582610c3f565b6000610b5f611210565b90506000815111610b7f5760405180602001604052806000815250610ac8565b80610b898461121f565b604051602001610b9a929190612165565b6040516020818303038152906040529392505050565b6000818152600160205260408120610424906112b2565b600082815260208190526040902060010154610be281610e90565b6105f88383610ebc565b6001600160a01b03918216600090815260076020908152604080832093909416825291909152205460ff1690565b60006001600160e01b0319821663780e9d6360e01b14806104245750610424826112bc565b610c48816112fc565b6108355760405162461bcd60e51b815260040161055790612133565b600081815260066020526040902080546001600160a01b0319166001600160a01b0384169081179091558190610c99826108cb565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b600080610cde836108cb565b9050806001600160a01b0316846001600160a01b03161480610d055750610d058185610bec565b80610d295750836001600160a01b0316610d1e846104bc565b6001600160a01b0316145b949350505050565b826001600160a01b0316610d44826108cb565b6001600160a01b031614610d6a5760405162461bcd60e51b815260040161055790612194565b6001600160a01b038216610dcc5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610557565b610dd98383836001611319565b826001600160a01b0316610dec826108cb565b6001600160a01b031614610e125760405162461bcd60e51b815260040161055790612194565b600081815260066020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260058552838620805460001901905590871680865283862080546001019055868652600490945282852080549092168417909155905184936000805160206123cc83398151915291a4505050565b6108358133611325565b610ea4828261137e565b60008281526001602052604090206105f89082611402565b610ec68282611417565b60008281526001602052604090206105f8908261147c565b610ee6611491565b600c805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000610f3b826108cb565b9050610f4b816000846001611319565b610f54826108cb565b600083815260066020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526005845282852080546000190190558785526004909352818420805490911690555192935084926000805160206123cc833981519152908390a45050565b6001600160a01b0382166110175760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610557565b611020816112fc565b1561103d5760405162461bcd60e51b8152600401610557906121d9565b61104b600083836001611319565b611054816112fc565b156110715760405162461bcd60e51b8152600401610557906121d9565b6001600160a01b038216600081815260056020908152604080832080546001019055848352600490915280822080546001600160a01b0319168417905551839291906000805160206123cc833981519152908290a45050565b6110d26114da565b600c805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610f133390565b6000610ac88383611520565b816001600160a01b0316836001600160a01b0316036111705760405162461bcd60e51b815260206004820152601960248201527822a9219b99189d1030b8383937bb32903a379031b0b63632b960391b6044820152606401610557565b6001600160a01b03838116600081815260076020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6111e8848484610d31565b6111f48484848461154a565b610b445760405162461bcd60e51b815260040161055790612210565b6060600e805461043990612096565b6060600061122c8361164b565b600101905060008167ffffffffffffffff81111561124c5761124c611f7a565b6040519080825280601f01601f191660200182016040528015611276576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461128057509392505050565b6000610424825490565b60006001600160e01b031982166380ac58cd60e01b14806112ed57506001600160e01b03198216635b5e139f60e01b145b80610424575061042482611723565b6000908152600460205260409020546001600160a01b0316151590565b610b4484848484611748565b61132f8282610acf565b6107645761133c816117bb565b6113478360206117cd565b604051602001611358929190612262565b60408051601f198184030181529082905262461bcd60e51b825261055791600401611e27565b6113888282610acf565b610764576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556113be3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000610ac8836001600160a01b038416611969565b6114218282610acf565b15610764576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000610ac8836001600160a01b0384166119b8565b600c5460ff166107ea5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610557565b600c5460ff16156107ea5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610557565b60008260000182815481106115375761153761211d565b9060005260206000200154905092915050565b60006001600160a01b0384163b1561164057604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061158e9033908990889088906004016122d1565b6020604051808303816000875af19250505080156115c9575060408051601f3d908101601f191682019092526115c69181019061230e565b60015b611626573d8080156115f7576040519150601f19603f3d011682016040523d82523d6000602084013e6115fc565b606091505b50805160000361161e5760405162461bcd60e51b815260040161055790612210565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050610d29565b506001949350505050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061168a5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106116b6576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106116d457662386f26fc10000830492506010015b6305f5e10083106116ec576305f5e100830492506008015b612710831061170057612710830492506004015b60648310611712576064830492506002015b600a83106104245760010192915050565b60006001600160e01b03198216635a05180f60e01b1480610424575061042482611aab565b61175484848484611ae0565b600c5460ff1615610b445760405162461bcd60e51b815260206004820152602b60248201527f4552433732315061757361626c653a20746f6b656e207472616e73666572207760448201526a1a1a5b19481c185d5cd95960aa1b6064820152608401610557565b60606104246001600160a01b03831660145b606060006117dc836002612341565b6117e7906002612358565b67ffffffffffffffff8111156117ff576117ff611f7a565b6040519080825280601f01601f191660200182016040528015611829576020820181803683370190505b509050600360fc1b816000815181106118445761184461211d565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106118735761187361211d565b60200101906001600160f81b031916908160001a9053506000611897846002612341565b6118a2906001612358565b90505b600181111561191a576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106118d6576118d661211d565b1a60f81b8282815181106118ec576118ec61211d565b60200101906001600160f81b031916908160001a90535060049490941c936119138161236b565b90506118a5565b508315610ac85760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610557565b60008181526001830160205260408120546119b057508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610424565b506000610424565b60008181526001830160205260408120548015611aa15760006119dc600183612382565b85549091506000906119f090600190612382565b9050818114611a55576000866000018281548110611a1057611a1061211d565b9060005260206000200154905080876000018481548110611a3357611a3361211d565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080611a6657611a66612395565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610424565b6000915050610424565b60006001600160e01b03198216637965db0b60e01b148061042457506301ffc9a760e01b6001600160e01b0319831614610424565b6001811115611b4f5760405162461bcd60e51b815260206004820152603560248201527f455243373231456e756d657261626c653a20636f6e7365637574697665207472604482015274185b9cd9995c9cc81b9bdd081cdd5c1c1bdc9d1959605a1b6064820152608401610557565b816001600160a01b038516611bab57611ba681600a80546000838152600b60205260408120829055600182018355919091527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a80155565b611bce565b836001600160a01b0316856001600160a01b031614611bce57611bce8582611c14565b6001600160a01b038416611bea57611be581611cb1565b611c0d565b846001600160a01b0316846001600160a01b031614611c0d57611c0d8482611d60565b5050505050565b60006001611c21846109aa565b611c2b9190612382565b600083815260096020526040902054909150808214611c7e576001600160a01b03841660009081526008602090815260408083208584528252808320548484528184208190558352600990915290208190555b5060009182526009602090815260408084208490556001600160a01b039094168352600881528383209183525290812055565b600a54600090611cc390600190612382565b6000838152600b6020526040812054600a8054939450909284908110611ceb57611ceb61211d565b9060005260206000200154905080600a8381548110611d0c57611d0c61211d565b6000918252602080832090910192909255828152600b9091526040808220849055858252812055600a805480611d4457611d44612395565b6001900381819060005260206000200160009055905550505050565b6000611d6b836109aa565b6001600160a01b039093166000908152600860209081526040808320868452825280832085905593825260099052919091209190915550565b6001600160e01b03198116811461083557600080fd5b600060208284031215611dcc57600080fd5b8135610ac881611da4565b60005b83811015611df2578181015183820152602001611dda565b50506000910152565b60008151808452611e13816020860160208601611dd7565b601f01601f19169290920160200192915050565b602081526000610ac86020830184611dfb565b600060208284031215611e4c57600080fd5b5035919050565b80356001600160a01b0381168114611e6a57600080fd5b919050565b60008060408385031215611e8257600080fd5b611e8b83611e53565b946020939093013593505050565b600080600060608486031215611eae57600080fd5b611eb784611e53565b9250611ec560208501611e53565b9150604084013590509250925092565b60008060408385031215611ee857600080fd5b82359150611ef860208401611e53565b90509250929050565b600060208284031215611f1357600080fd5b610ac882611e53565b60008060408385031215611f2f57600080fd5b50508035926020909101359150565b60008060408385031215611f5157600080fd5b611f5a83611e53565b915060208301358015158114611f6f57600080fd5b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b60008060008060808587031215611fa657600080fd5b611faf85611e53565b9350611fbd60208601611e53565b925060408501359150606085013567ffffffffffffffff80821115611fe157600080fd5b818701915087601f830112611ff557600080fd5b81358181111561200757612007611f7a565b604051601f8201601f19908116603f0116810190838211818310171561202f5761202f611f7a565b816040528281528a602084870101111561204857600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b6000806040838503121561207f57600080fd5b61208883611e53565b9150611ef860208401611e53565b600181811c908216806120aa57607f821691505b6020821081036120ca57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b602080825260189082015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604082015260600190565b60008351612177818460208801611dd7565b83519083019061218b818360208801611dd7565b01949350505050565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b6020808252601c908201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604082015260600190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b815260008351612294816017850160208801611dd7565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516122c5816028840160208801611dd7565b01602801949350505050565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061230490830184611dfb565b9695505050505050565b60006020828403121561232057600080fd5b8151610ac881611da4565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176104245761042461232b565b808201808211156104245761042461232b565b60008161237a5761237a61232b565b506000190190565b818103818111156104245761042461232b565b634e487b7160e01b600052603160045260246000fdfe65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862addf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef4552433732315072657365744d696e7465725061757365724175746f49643a20a2646970667358221220f586c29d0cbd3e2cee9bd99a648a34864226f46f9a05471902f3728b4f230c2864736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101a55760003560e01c80636352211e116100ef578063a22cb46511610092578063a22cb4651461036b578063b88d4fde1461037e578063c87b56dd14610391578063ca15c873146103a4578063d5391393146103b7578063d547741f146103de578063e63ab1e9146103f1578063e985e9c51461040657600080fd5b80636352211e146102f45780636a6278421461030757806370a082311461031a5780638456cb591461032d5780639010d07c1461033557806391d148541461034857806395d89b411461035b578063a217fddf1461036357600080fd5b80632f2ff15d116101575780632f2ff15d1461026f5780632f745c591461028257806336568abe146102955780633f4ba83a146102a857806342842e0e146102b057806342966c68146102c35780634f6ccce7146102d65780635c975abb146102e957600080fd5b806301ffc9a7146101aa57806306fdde03146101d2578063081812fc146101e7578063095ea7b31461021257806318160ddd1461022757806323b872dd14610239578063248a9ca31461024c575b600080fd5b6101bd6101b8366004611dba565b610419565b60405190151581526020015b60405180910390f35b6101da61042a565b6040516101c99190611e27565b6101fa6101f5366004611e3a565b6104bc565b6040516001600160a01b0390911681526020016101c9565b610225610220366004611e6f565b6104e3565b005b600a545b6040519081526020016101c9565b610225610247366004611e99565b6105fd565b61022b61025a366004611e3a565b60009081526020819052604090206001015490565b61022561027d366004611ed5565b61062f565b61022b610290366004611e6f565b610654565b6102256102a3366004611ed5565b6106ea565b610225610768565b6102256102be366004611e99565b6107ec565b6102256102d1366004611e3a565b610807565b61022b6102e4366004611e3a565b610838565b600c5460ff166101bd565b6101fa610302366004611e3a565b6108cb565b610225610315366004611f01565b610900565b61022b610328366004611f01565b6109aa565b610225610a30565b6101fa610343366004611f1c565b610ab0565b6101bd610356366004611ed5565b610acf565b6101da610af8565b61022b600081565b610225610379366004611f3e565b610b07565b61022561038c366004611f90565b610b12565b6101da61039f366004611e3a565b610b4a565b61022b6103b2366004611e3a565b610bb0565b61022b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b6102256103ec366004611ed5565b610bc7565b61022b6000805160206123ac83398151915281565b6101bd61041436600461206c565b610bec565b600061042482610c1a565b92915050565b60606002805461043990612096565b80601f016020809104026020016040519081016040528092919081815260200182805461046590612096565b80156104b25780601f10610487576101008083540402835291602001916104b2565b820191906000526020600020905b81548152906001019060200180831161049557829003601f168201915b5050505050905090565b60006104c782610c3f565b506000908152600660205260409020546001600160a01b031690565b60006104ee826108cb565b9050806001600160a01b0316836001600160a01b0316036105605760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b038216148061057c575061057c8133610bec565b6105ee5760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152608401610557565b6105f88383610c64565b505050565b610608335b82610cd2565b6106245760405162461bcd60e51b8152600401610557906120d0565b6105f8838383610d31565b60008281526020819052604090206001015461064a81610e90565b6105f88383610e9a565b600061065f836109aa565b82106106c15760405162461bcd60e51b815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201526a74206f6620626f756e647360a81b6064820152608401610557565b506001600160a01b03919091166000908152600860209081526040808320938352929052205490565b6001600160a01b038116331461075a5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610557565b6107648282610ebc565b5050565b6107806000805160206123ac83398151915233610acf565b6107e2576040805162461bcd60e51b81526020600482015260248101919091526000805160206123ec83398151915260448201527f6d75737420686176652070617573657220726f6c6520746f20756e70617573656064820152608401610557565b6107ea610ede565b565b6105f883838360405180602001604052806000815250610b12565b61081033610602565b61082c5760405162461bcd60e51b8152600401610557906120d0565b61083581610f30565b50565b6000610843600a5490565b82106108a65760405162461bcd60e51b815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201526b7574206f6620626f756e647360a01b6064820152608401610557565b600a82815481106108b9576108b961211d565b90600052602060002001549050919050565b6000818152600460205260408120546001600160a01b0316806104245760405162461bcd60e51b815260040161055790612133565b61092a7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a633610acf565b61098a5760405162461bcd60e51b815260206004820152603d60248201526000805160206123ec83398151915260448201527f6d7573742068617665206d696e74657220726f6c6520746f206d696e740000006064820152608401610557565b61099c81610997600d5490565b610fc1565b610835600d80546001019055565b60006001600160a01b038216610a145760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608401610557565b506001600160a01b031660009081526005602052604090205490565b610a486000805160206123ac83398151915233610acf565b610aa85760405162461bcd60e51b815260206004820152603e60248201526000805160206123ec83398151915260448201527f6d75737420686176652070617573657220726f6c6520746f20706175736500006064820152608401610557565b6107ea6110ca565b6000828152600160205260408120610ac89083611107565b9392505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60606003805461043990612096565b610764338383611113565b610b1c3383610cd2565b610b385760405162461bcd60e51b8152600401610557906120d0565b610b44848484846111dd565b50505050565b6060610b5582610c3f565b6000610b5f611210565b90506000815111610b7f5760405180602001604052806000815250610ac8565b80610b898461121f565b604051602001610b9a929190612165565b6040516020818303038152906040529392505050565b6000818152600160205260408120610424906112b2565b600082815260208190526040902060010154610be281610e90565b6105f88383610ebc565b6001600160a01b03918216600090815260076020908152604080832093909416825291909152205460ff1690565b60006001600160e01b0319821663780e9d6360e01b14806104245750610424826112bc565b610c48816112fc565b6108355760405162461bcd60e51b815260040161055790612133565b600081815260066020526040902080546001600160a01b0319166001600160a01b0384169081179091558190610c99826108cb565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b600080610cde836108cb565b9050806001600160a01b0316846001600160a01b03161480610d055750610d058185610bec565b80610d295750836001600160a01b0316610d1e846104bc565b6001600160a01b0316145b949350505050565b826001600160a01b0316610d44826108cb565b6001600160a01b031614610d6a5760405162461bcd60e51b815260040161055790612194565b6001600160a01b038216610dcc5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610557565b610dd98383836001611319565b826001600160a01b0316610dec826108cb565b6001600160a01b031614610e125760405162461bcd60e51b815260040161055790612194565b600081815260066020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260058552838620805460001901905590871680865283862080546001019055868652600490945282852080549092168417909155905184936000805160206123cc83398151915291a4505050565b6108358133611325565b610ea4828261137e565b60008281526001602052604090206105f89082611402565b610ec68282611417565b60008281526001602052604090206105f8908261147c565b610ee6611491565b600c805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000610f3b826108cb565b9050610f4b816000846001611319565b610f54826108cb565b600083815260066020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526005845282852080546000190190558785526004909352818420805490911690555192935084926000805160206123cc833981519152908390a45050565b6001600160a01b0382166110175760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610557565b611020816112fc565b1561103d5760405162461bcd60e51b8152600401610557906121d9565b61104b600083836001611319565b611054816112fc565b156110715760405162461bcd60e51b8152600401610557906121d9565b6001600160a01b038216600081815260056020908152604080832080546001019055848352600490915280822080546001600160a01b0319168417905551839291906000805160206123cc833981519152908290a45050565b6110d26114da565b600c805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610f133390565b6000610ac88383611520565b816001600160a01b0316836001600160a01b0316036111705760405162461bcd60e51b815260206004820152601960248201527822a9219b99189d1030b8383937bb32903a379031b0b63632b960391b6044820152606401610557565b6001600160a01b03838116600081815260076020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6111e8848484610d31565b6111f48484848461154a565b610b445760405162461bcd60e51b815260040161055790612210565b6060600e805461043990612096565b6060600061122c8361164b565b600101905060008167ffffffffffffffff81111561124c5761124c611f7a565b6040519080825280601f01601f191660200182016040528015611276576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461128057509392505050565b6000610424825490565b60006001600160e01b031982166380ac58cd60e01b14806112ed57506001600160e01b03198216635b5e139f60e01b145b80610424575061042482611723565b6000908152600460205260409020546001600160a01b0316151590565b610b4484848484611748565b61132f8282610acf565b6107645761133c816117bb565b6113478360206117cd565b604051602001611358929190612262565b60408051601f198184030181529082905262461bcd60e51b825261055791600401611e27565b6113888282610acf565b610764576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556113be3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000610ac8836001600160a01b038416611969565b6114218282610acf565b15610764576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000610ac8836001600160a01b0384166119b8565b600c5460ff166107ea5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610557565b600c5460ff16156107ea5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610557565b60008260000182815481106115375761153761211d565b9060005260206000200154905092915050565b60006001600160a01b0384163b1561164057604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061158e9033908990889088906004016122d1565b6020604051808303816000875af19250505080156115c9575060408051601f3d908101601f191682019092526115c69181019061230e565b60015b611626573d8080156115f7576040519150601f19603f3d011682016040523d82523d6000602084013e6115fc565b606091505b50805160000361161e5760405162461bcd60e51b815260040161055790612210565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050610d29565b506001949350505050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061168a5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106116b6576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106116d457662386f26fc10000830492506010015b6305f5e10083106116ec576305f5e100830492506008015b612710831061170057612710830492506004015b60648310611712576064830492506002015b600a83106104245760010192915050565b60006001600160e01b03198216635a05180f60e01b1480610424575061042482611aab565b61175484848484611ae0565b600c5460ff1615610b445760405162461bcd60e51b815260206004820152602b60248201527f4552433732315061757361626c653a20746f6b656e207472616e73666572207760448201526a1a1a5b19481c185d5cd95960aa1b6064820152608401610557565b60606104246001600160a01b03831660145b606060006117dc836002612341565b6117e7906002612358565b67ffffffffffffffff8111156117ff576117ff611f7a565b6040519080825280601f01601f191660200182016040528015611829576020820181803683370190505b509050600360fc1b816000815181106118445761184461211d565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106118735761187361211d565b60200101906001600160f81b031916908160001a9053506000611897846002612341565b6118a2906001612358565b90505b600181111561191a576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106118d6576118d661211d565b1a60f81b8282815181106118ec576118ec61211d565b60200101906001600160f81b031916908160001a90535060049490941c936119138161236b565b90506118a5565b508315610ac85760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610557565b60008181526001830160205260408120546119b057508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610424565b506000610424565b60008181526001830160205260408120548015611aa15760006119dc600183612382565b85549091506000906119f090600190612382565b9050818114611a55576000866000018281548110611a1057611a1061211d565b9060005260206000200154905080876000018481548110611a3357611a3361211d565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080611a6657611a66612395565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610424565b6000915050610424565b60006001600160e01b03198216637965db0b60e01b148061042457506301ffc9a760e01b6001600160e01b0319831614610424565b6001811115611b4f5760405162461bcd60e51b815260206004820152603560248201527f455243373231456e756d657261626c653a20636f6e7365637574697665207472604482015274185b9cd9995c9cc81b9bdd081cdd5c1c1bdc9d1959605a1b6064820152608401610557565b816001600160a01b038516611bab57611ba681600a80546000838152600b60205260408120829055600182018355919091527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a80155565b611bce565b836001600160a01b0316856001600160a01b031614611bce57611bce8582611c14565b6001600160a01b038416611bea57611be581611cb1565b611c0d565b846001600160a01b0316846001600160a01b031614611c0d57611c0d8482611d60565b5050505050565b60006001611c21846109aa565b611c2b9190612382565b600083815260096020526040902054909150808214611c7e576001600160a01b03841660009081526008602090815260408083208584528252808320548484528184208190558352600990915290208190555b5060009182526009602090815260408084208490556001600160a01b039094168352600881528383209183525290812055565b600a54600090611cc390600190612382565b6000838152600b6020526040812054600a8054939450909284908110611ceb57611ceb61211d565b9060005260206000200154905080600a8381548110611d0c57611d0c61211d565b6000918252602080832090910192909255828152600b9091526040808220849055858252812055600a805480611d4457611d44612395565b6001900381819060005260206000200160009055905550505050565b6000611d6b836109aa565b6001600160a01b039093166000908152600860209081526040808320868452825280832085905593825260099052919091209190915550565b6001600160e01b03198116811461083557600080fd5b600060208284031215611dcc57600080fd5b8135610ac881611da4565b60005b83811015611df2578181015183820152602001611dda565b50506000910152565b60008151808452611e13816020860160208601611dd7565b601f01601f19169290920160200192915050565b602081526000610ac86020830184611dfb565b600060208284031215611e4c57600080fd5b5035919050565b80356001600160a01b0381168114611e6a57600080fd5b919050565b60008060408385031215611e8257600080fd5b611e8b83611e53565b946020939093013593505050565b600080600060608486031215611eae57600080fd5b611eb784611e53565b9250611ec560208501611e53565b9150604084013590509250925092565b60008060408385031215611ee857600080fd5b82359150611ef860208401611e53565b90509250929050565b600060208284031215611f1357600080fd5b610ac882611e53565b60008060408385031215611f2f57600080fd5b50508035926020909101359150565b60008060408385031215611f5157600080fd5b611f5a83611e53565b915060208301358015158114611f6f57600080fd5b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b60008060008060808587031215611fa657600080fd5b611faf85611e53565b9350611fbd60208601611e53565b925060408501359150606085013567ffffffffffffffff80821115611fe157600080fd5b818701915087601f830112611ff557600080fd5b81358181111561200757612007611f7a565b604051601f8201601f19908116603f0116810190838211818310171561202f5761202f611f7a565b816040528281528a602084870101111561204857600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b6000806040838503121561207f57600080fd5b61208883611e53565b9150611ef860208401611e53565b600181811c908216806120aa57607f821691505b6020821081036120ca57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b602080825260189082015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604082015260600190565b60008351612177818460208801611dd7565b83519083019061218b818360208801611dd7565b01949350505050565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b6020808252601c908201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604082015260600190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b815260008351612294816017850160208801611dd7565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516122c5816028840160208801611dd7565b01602801949350505050565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061230490830184611dfb565b9695505050505050565b60006020828403121561232057600080fd5b8151610ac881611da4565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176104245761042461232b565b808201808211156104245761042461232b565b60008161237a5761237a61232b565b506000190190565b818103818111156104245761042461232b565b634e487b7160e01b600052603160045260246000fdfe65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862addf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef4552433732315072657365744d696e7465725061757365724175746f49643a20a2646970667358221220f586c29d0cbd3e2cee9bd99a648a34864226f46f9a05471902f3728b4f230c2864736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var RootERC721PredicateArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"RootERC721Predicate\",\n \"sourceName\": \"contracts/root/RootERC721Predicate.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"depositor\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"ERC721Deposit\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"depositor\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"ERC721DepositBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"withdrawer\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"ERC721Withdraw\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"withdrawer\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"ERC721WithdrawBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"TokenMapped\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAP_TOKEN_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childERC721Predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childTokenTemplate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC721Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"deposit\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC721Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"depositBatch\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC721Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"depositTo\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"exitHelper\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newStateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newExitHelper\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildERC721Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC721Metadata\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"mapToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onERC721Received\",\n \"outputs\": [\n {\n \"internalType\": \"bytes4\",\n \"name\": \"\",\n \"type\": \"bytes4\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onL2StateReceive\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"rootTokenToChildToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"stateSender\",\n \"outputs\": [\n {\n \"internalType\": \"contract IStateSender\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b5061196b806100206000396000f3fe608060405234801561001057600080fd5b50600436106100fb5760003560e01c8063cb10f94c116100a2578063f43cda8b11610071578063f43cda8b146102a1578063f4a120f7146102b4578063f6451255146102c7578063f8c8765e146102ee578063ff6f870c1461030157600080fd5b8063cb10f94c14610227578063d41f177114610240578063d7c9e3ec14610267578063f213159c1461028e57600080fd5b8063150b7a021461010057806347e7ef241461013c5780634fdca69d146101515780637efab4f51461017c57806395c7041c146101a5578063b1768065146101b8578063b68ad1e4146101ed578063c5ac2b1c14610200575b600080fd5b61011e61010e36600461112d565b630a85bd0160e11b949350505050565b6040516001600160e01b031990911681526020015b60405180910390f35b61014f61014a3660046111db565b610314565b005b600254610164906001600160a01b031681565b6040516001600160a01b039091168152602001610133565b61016461018a366004611207565b6004602052600090815260409020546001600160a01b031681565b600154610164906001600160a01b031681565b6101df7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b604051908152602001610133565b600354610164906001600160a01b031681565b6101df7faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b600054610164906201000090046001600160a01b031681565b6101df7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b6101df7f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b61014f61029c36600461122b565b610323565b61014f6102af36600461126c565b610333565b6101646102c2366004611207565b61050a565b6101df7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b61014f6102fc3660046112f4565b61086a565b61014f61030f36600461139b565b610a78565b61031f823383610ae0565b5050565b61032e838383610ae0565b505050565b6001546001600160a01b031633146103a05760405162461bcd60e51b815260206004820152602560248201527f526f6f744552433732315072656469636174653a204f4e4c595f455849545f4860448201526422a62822a960d91b60648201526084015b60405180910390fd5b6002546001600160a01b0384811691161461040f5760405162461bcd60e51b815260206004820152602960248201527f526f6f744552433732315072656469636174653a204f4e4c595f4348494c445f60448201526850524544494341544560b81b6064820152608401610397565b7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286961043e60206000848661141d565b61044791611447565b036104665761046161045c826020818661141d565b610c66565b610504565b7f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed261049560206000848661141d565b61049e91611447565b036104ad576104618282610d64565b60405162461bcd60e51b815260206004820152602660248201527f526f6f744552433732315072656469636174653a20494e56414c49445f5349476044820152654e415455524560d01b6064820152608401610397565b50505050565b60006001600160a01b03821661056d5760405162461bcd60e51b815260206004820152602260248201527f526f6f744552433732315072656469636174653a20494e56414c49445f544f4b60448201526122a760f11b6064820152608401610397565b6001600160a01b0382811660009081526004602052604090205416156105e15760405162461bcd60e51b815260206004820152602360248201527f526f6f744552433732315072656469636174653a20414c52454144595f4d415060448201526214115160ea1b6064820152608401610397565b6002546003546040516bffffffffffffffffffffffff19606086901b1660208201526001600160a01b039283169260009261068f92911690603401604051602081830303815290604052805190602001208460405160388101919091526f5af43d82803e903d91602b57fd5bf3ff60248201526014810192909252733d602d80600a3d3981f3363d3d373d3d3d363d73825260588201526037600c8201206078820152605560439091012090565b6001600160a01b03858116600081815260046020819052604080832080546001600160a01b031916878716179055825481516306fdde0360e01b81529151969750620100009004909416946316f198319488947f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad948c9491936306fdde039380840193908290030181865afa15801561072c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610754919081019061148a565b896001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610792573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107ba919081019061148a565b6040516020016107cd949392919061152c565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016107f9929190611573565b600060405180830381600087803b15801561081357600080fd5b505af1158015610827573d6000803e3d6000fd5b50506040516001600160a01b038085169350871691507f85920d35e6c72f6b2affffa04298b0cecfeba86e4a9f407df661f1cb8ab5e61790600090a39392505050565b600054610100900460ff161580801561088a5750600054600160ff909116105b806108a45750303b1580156108a4575060005460ff166001145b6109075760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610397565b6000805460ff19166001179055801561092a576000805461ff0019166101001790555b6001600160a01b0385161580159061094a57506001600160a01b03841615155b801561095e57506001600160a01b03831615155b801561097257506001600160a01b03821615155b6109ce5760405162461bcd60e51b815260206004820152602760248201527f526f6f744552433732315072656469636174653a204241445f494e495449414c60448201526624ad20aa24a7a760c91b6064820152608401610397565b6000805462010000600160b01b031916620100006001600160a01b038881169190910291909117909155600180546001600160a01b031990811687841617909155600280548216868416179055600380549091169184169190911790558015610a71576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b828114610ad35760405162461bcd60e51b815260206004820152602360248201527f526f6f744552433732315072656469636174653a20494e56414c49445f4c454e60448201526208ea8960eb1b6064820152608401610397565b610a718585858585610ea5565b6000610aeb84611061565b604051632142170760e11b81529091506001600160a01b038516906342842e0e90610b1e9033903090879060040161159f565b600060405180830381600087803b158015610b3857600080fd5b505af1158015610b4c573d6000803e3d6000fd5b5050600054600254604080517f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82160208201526001600160a01b038a811682840152336060830152898116608083015260a08083018a90528351808403909101815260c08301938490526316f1983160e01b90935262010000909404841695506316f198319450610be2939092169160c401611573565b600060405180830381600087803b158015610bfc57600080fd5b505af1158015610c10573d6000803e3d6000fd5b505060408051338152602081018690526001600160a01b03808816945085811693508816917f40e242710be14b7d61d3b93e9d56b40df89cc4dbad8bb88da38c8e0c23809ba7910160405180910390a450505050565b6000808080610c77858701876115c3565b6001600160a01b0380851660009081526004602052604090205494985092965090945092501680610caa57610caa611614565b604051632142170760e11b81526001600160a01b038616906342842e0e90610cda9030908790879060040161159f565b600060405180830381600087803b158015610cf457600080fd5b505af1158015610d08573d6000803e3d6000fd5b5050604080516001600160a01b03888116825260208201879052808816945085811693508916917f8194f168e6e9e449d05a46936e071a710c0f22634eaadeb5b85a86540123931991015b60405180910390a450505050505050565b6000808080610d75858701876116b3565b6001600160a01b03808516600090815260046020526040902054949950929750909550935016905080610daa57610daa611614565b60005b8251811015610e5557856001600160a01b03166342842e0e30868481518110610dd857610dd86117a5565b6020026020010151868581518110610df257610df26117a5565b60200260200101516040518463ffffffff1660e01b8152600401610e189392919061159f565b600060405180830381600087803b158015610e3257600080fd5b505af1158015610e46573d6000803e3d6000fd5b50505050806001019050610dad565b50836001600160a01b0316816001600160a01b0316866001600160a01b03167f1b7b9713fdef5dfadf92f6d6e998eb1fc4763cee62a194a095d76349f7dce20c8686604051610d539291906117bb565b6000610eb086611061565b905060005b82811015610f4257866001600160a01b03166342842e0e3330878786818110610ee057610ee06117a5565b905060200201356040518463ffffffff1660e01b8152600401610f059392919061159f565b600060405180830381600087803b158015610f1f57600080fd5b505af1158015610f33573d6000803e3d6000fd5b50505050806001019050610eb5565b506000546002546040516001600160a01b03620100009093048316926316f19831921690610fa0907faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d18908b9033908c908c908c908c906020016118ba565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610fcc929190611573565b600060405180830381600087803b158015610fe657600080fd5b505af1158015610ffa573d6000803e3d6000fd5b50505050336001600160a01b0316816001600160a01b0316876001600160a01b03167f02c575a943105cda454293b7ac636c87c94ff1bfcfac968aa5423e6b9b312ee988888888604051611051949392919061190e565b60405180910390a4505050505050565b6001600160a01b03808216600090815260046020526040902054168061108d5761108a8261050a565b90505b6001600160a01b0381166110a3576110a3611614565b919050565b6001600160a01b03811681146110bd57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156110fe576110fe6110c0565b604052919050565b60006001600160401b0382111561111f5761111f6110c0565b50601f01601f191660200190565b6000806000806080858703121561114357600080fd5b843561114e816110a8565b9350602085013561115e816110a8565b92506040850135915060608501356001600160401b0381111561118057600080fd5b8501601f8101871361119157600080fd5b80356111a461119f82611106565b6110d6565b8181528860208385010111156111b957600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b600080604083850312156111ee57600080fd5b82356111f9816110a8565b946020939093013593505050565b60006020828403121561121957600080fd5b8135611224816110a8565b9392505050565b60008060006060848603121561124057600080fd5b833561124b816110a8565b9250602084013561125b816110a8565b929592945050506040919091013590565b6000806000806060858703121561128257600080fd5b843593506020850135611294816110a8565b925060408501356001600160401b03808211156112b057600080fd5b818701915087601f8301126112c457600080fd5b8135818111156112d357600080fd5b8860208285010111156112e557600080fd5b95989497505060200194505050565b6000806000806080858703121561130a57600080fd5b8435611315816110a8565b93506020850135611325816110a8565b92506040850135611335816110a8565b91506060850135611345816110a8565b939692955090935050565b60008083601f84011261136257600080fd5b5081356001600160401b0381111561137957600080fd5b6020830191508360208260051b850101111561139457600080fd5b9250929050565b6000806000806000606086880312156113b357600080fd5b85356113be816110a8565b945060208601356001600160401b03808211156113da57600080fd5b6113e689838a01611350565b909650945060408801359150808211156113ff57600080fd5b5061140c88828901611350565b969995985093965092949392505050565b6000808585111561142d57600080fd5b8386111561143a57600080fd5b5050820193919092039150565b8035602083101561146057600019602084900360031b1b165b92915050565b60005b83811015611481578181015183820152602001611469565b50506000910152565b60006020828403121561149c57600080fd5b81516001600160401b038111156114b257600080fd5b8201601f810184136114c357600080fd5b80516114d161119f82611106565b8181528560208385010111156114e657600080fd5b6114f7826020830160208601611466565b95945050505050565b60008151808452611518816020860160208601611466565b601f01601f19169290920160200192915050565b8481526001600160a01b038416602082015260806040820181905260009061155690830185611500565b82810360608401526115688185611500565b979650505050505050565b6001600160a01b038316815260406020820181905260009061159790830184611500565b949350505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b600080600080608085870312156115d957600080fd5b84356115e4816110a8565b935060208501356115f4816110a8565b92506040850135611604816110a8565b9396929550929360600135925050565b634e487b7160e01b600052600160045260246000fd5b60006001600160401b03821115611643576116436110c0565b5060051b60200190565b600082601f83011261165e57600080fd5b8135602061166e61119f8361162a565b82815260059290921b8401810191818101908684111561168d57600080fd5b8286015b848110156116a85780358352918301918301611691565b509695505050505050565b600080600080600060a086880312156116cb57600080fd5b853594506020808701356116de816110a8565b945060408701356116ee816110a8565b935060608701356001600160401b038082111561170a57600080fd5b818901915089601f83011261171e57600080fd5b813561172c61119f8261162a565b81815260059190911b8301840190848101908c83111561174b57600080fd5b938501935b82851015611772578435611763816110a8565b82529385019390850190611750565b96505050608089013592508083111561178a57600080fd5b50506117988882890161164d565b9150509295509295909350565b634e487b7160e01b600052603260045260246000fd5b604080825283519082018190526000906020906060840190828701845b828110156117fd5781516001600160a01b0316845292840192908401906001016117d8565b5050508381038285015284518082528583019183019060005b8181101561183257835183529284019291840191600101611816565b5090979650505050505050565b8183526000602080850194508260005b8581101561187d578135611862816110a8565b6001600160a01b03168752958201959082019060010161184f565b509495945050505050565b81835260006001600160fb1b038311156118a157600080fd5b8260051b80836020870137939093016020019392505050565b8781526001600160a01b0387811660208301528616604082015260a0606082018190526000906118ed908301868861183f565b8281036080840152611900818587611888565b9a9950505050505050505050565b60408152600061192260408301868861183f565b828103602084015261156881858761188856fea2646970667358221220bfd1948d5c4cd21e4982d8b20eeb9cb5a362f336cd5a6789511e6ae9d664a37e64736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106100fb5760003560e01c8063cb10f94c116100a2578063f43cda8b11610071578063f43cda8b146102a1578063f4a120f7146102b4578063f6451255146102c7578063f8c8765e146102ee578063ff6f870c1461030157600080fd5b8063cb10f94c14610227578063d41f177114610240578063d7c9e3ec14610267578063f213159c1461028e57600080fd5b8063150b7a021461010057806347e7ef241461013c5780634fdca69d146101515780637efab4f51461017c57806395c7041c146101a5578063b1768065146101b8578063b68ad1e4146101ed578063c5ac2b1c14610200575b600080fd5b61011e61010e36600461112d565b630a85bd0160e11b949350505050565b6040516001600160e01b031990911681526020015b60405180910390f35b61014f61014a3660046111db565b610314565b005b600254610164906001600160a01b031681565b6040516001600160a01b039091168152602001610133565b61016461018a366004611207565b6004602052600090815260409020546001600160a01b031681565b600154610164906001600160a01b031681565b6101df7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b604051908152602001610133565b600354610164906001600160a01b031681565b6101df7faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b600054610164906201000090046001600160a01b031681565b6101df7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b6101df7f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b61014f61029c36600461122b565b610323565b61014f6102af36600461126c565b610333565b6101646102c2366004611207565b61050a565b6101df7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b61014f6102fc3660046112f4565b61086a565b61014f61030f36600461139b565b610a78565b61031f823383610ae0565b5050565b61032e838383610ae0565b505050565b6001546001600160a01b031633146103a05760405162461bcd60e51b815260206004820152602560248201527f526f6f744552433732315072656469636174653a204f4e4c595f455849545f4860448201526422a62822a960d91b60648201526084015b60405180910390fd5b6002546001600160a01b0384811691161461040f5760405162461bcd60e51b815260206004820152602960248201527f526f6f744552433732315072656469636174653a204f4e4c595f4348494c445f60448201526850524544494341544560b81b6064820152608401610397565b7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286961043e60206000848661141d565b61044791611447565b036104665761046161045c826020818661141d565b610c66565b610504565b7f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed261049560206000848661141d565b61049e91611447565b036104ad576104618282610d64565b60405162461bcd60e51b815260206004820152602660248201527f526f6f744552433732315072656469636174653a20494e56414c49445f5349476044820152654e415455524560d01b6064820152608401610397565b50505050565b60006001600160a01b03821661056d5760405162461bcd60e51b815260206004820152602260248201527f526f6f744552433732315072656469636174653a20494e56414c49445f544f4b60448201526122a760f11b6064820152608401610397565b6001600160a01b0382811660009081526004602052604090205416156105e15760405162461bcd60e51b815260206004820152602360248201527f526f6f744552433732315072656469636174653a20414c52454144595f4d415060448201526214115160ea1b6064820152608401610397565b6002546003546040516bffffffffffffffffffffffff19606086901b1660208201526001600160a01b039283169260009261068f92911690603401604051602081830303815290604052805190602001208460405160388101919091526f5af43d82803e903d91602b57fd5bf3ff60248201526014810192909252733d602d80600a3d3981f3363d3d373d3d3d363d73825260588201526037600c8201206078820152605560439091012090565b6001600160a01b03858116600081815260046020819052604080832080546001600160a01b031916878716179055825481516306fdde0360e01b81529151969750620100009004909416946316f198319488947f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad948c9491936306fdde039380840193908290030181865afa15801561072c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610754919081019061148a565b896001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610792573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107ba919081019061148a565b6040516020016107cd949392919061152c565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016107f9929190611573565b600060405180830381600087803b15801561081357600080fd5b505af1158015610827573d6000803e3d6000fd5b50506040516001600160a01b038085169350871691507f85920d35e6c72f6b2affffa04298b0cecfeba86e4a9f407df661f1cb8ab5e61790600090a39392505050565b600054610100900460ff161580801561088a5750600054600160ff909116105b806108a45750303b1580156108a4575060005460ff166001145b6109075760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610397565b6000805460ff19166001179055801561092a576000805461ff0019166101001790555b6001600160a01b0385161580159061094a57506001600160a01b03841615155b801561095e57506001600160a01b03831615155b801561097257506001600160a01b03821615155b6109ce5760405162461bcd60e51b815260206004820152602760248201527f526f6f744552433732315072656469636174653a204241445f494e495449414c60448201526624ad20aa24a7a760c91b6064820152608401610397565b6000805462010000600160b01b031916620100006001600160a01b038881169190910291909117909155600180546001600160a01b031990811687841617909155600280548216868416179055600380549091169184169190911790558015610a71576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b828114610ad35760405162461bcd60e51b815260206004820152602360248201527f526f6f744552433732315072656469636174653a20494e56414c49445f4c454e60448201526208ea8960eb1b6064820152608401610397565b610a718585858585610ea5565b6000610aeb84611061565b604051632142170760e11b81529091506001600160a01b038516906342842e0e90610b1e9033903090879060040161159f565b600060405180830381600087803b158015610b3857600080fd5b505af1158015610b4c573d6000803e3d6000fd5b5050600054600254604080517f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82160208201526001600160a01b038a811682840152336060830152898116608083015260a08083018a90528351808403909101815260c08301938490526316f1983160e01b90935262010000909404841695506316f198319450610be2939092169160c401611573565b600060405180830381600087803b158015610bfc57600080fd5b505af1158015610c10573d6000803e3d6000fd5b505060408051338152602081018690526001600160a01b03808816945085811693508816917f40e242710be14b7d61d3b93e9d56b40df89cc4dbad8bb88da38c8e0c23809ba7910160405180910390a450505050565b6000808080610c77858701876115c3565b6001600160a01b0380851660009081526004602052604090205494985092965090945092501680610caa57610caa611614565b604051632142170760e11b81526001600160a01b038616906342842e0e90610cda9030908790879060040161159f565b600060405180830381600087803b158015610cf457600080fd5b505af1158015610d08573d6000803e3d6000fd5b5050604080516001600160a01b03888116825260208201879052808816945085811693508916917f8194f168e6e9e449d05a46936e071a710c0f22634eaadeb5b85a86540123931991015b60405180910390a450505050505050565b6000808080610d75858701876116b3565b6001600160a01b03808516600090815260046020526040902054949950929750909550935016905080610daa57610daa611614565b60005b8251811015610e5557856001600160a01b03166342842e0e30868481518110610dd857610dd86117a5565b6020026020010151868581518110610df257610df26117a5565b60200260200101516040518463ffffffff1660e01b8152600401610e189392919061159f565b600060405180830381600087803b158015610e3257600080fd5b505af1158015610e46573d6000803e3d6000fd5b50505050806001019050610dad565b50836001600160a01b0316816001600160a01b0316866001600160a01b03167f1b7b9713fdef5dfadf92f6d6e998eb1fc4763cee62a194a095d76349f7dce20c8686604051610d539291906117bb565b6000610eb086611061565b905060005b82811015610f4257866001600160a01b03166342842e0e3330878786818110610ee057610ee06117a5565b905060200201356040518463ffffffff1660e01b8152600401610f059392919061159f565b600060405180830381600087803b158015610f1f57600080fd5b505af1158015610f33573d6000803e3d6000fd5b50505050806001019050610eb5565b506000546002546040516001600160a01b03620100009093048316926316f19831921690610fa0907faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d18908b9033908c908c908c908c906020016118ba565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610fcc929190611573565b600060405180830381600087803b158015610fe657600080fd5b505af1158015610ffa573d6000803e3d6000fd5b50505050336001600160a01b0316816001600160a01b0316876001600160a01b03167f02c575a943105cda454293b7ac636c87c94ff1bfcfac968aa5423e6b9b312ee988888888604051611051949392919061190e565b60405180910390a4505050505050565b6001600160a01b03808216600090815260046020526040902054168061108d5761108a8261050a565b90505b6001600160a01b0381166110a3576110a3611614565b919050565b6001600160a01b03811681146110bd57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156110fe576110fe6110c0565b604052919050565b60006001600160401b0382111561111f5761111f6110c0565b50601f01601f191660200190565b6000806000806080858703121561114357600080fd5b843561114e816110a8565b9350602085013561115e816110a8565b92506040850135915060608501356001600160401b0381111561118057600080fd5b8501601f8101871361119157600080fd5b80356111a461119f82611106565b6110d6565b8181528860208385010111156111b957600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b600080604083850312156111ee57600080fd5b82356111f9816110a8565b946020939093013593505050565b60006020828403121561121957600080fd5b8135611224816110a8565b9392505050565b60008060006060848603121561124057600080fd5b833561124b816110a8565b9250602084013561125b816110a8565b929592945050506040919091013590565b6000806000806060858703121561128257600080fd5b843593506020850135611294816110a8565b925060408501356001600160401b03808211156112b057600080fd5b818701915087601f8301126112c457600080fd5b8135818111156112d357600080fd5b8860208285010111156112e557600080fd5b95989497505060200194505050565b6000806000806080858703121561130a57600080fd5b8435611315816110a8565b93506020850135611325816110a8565b92506040850135611335816110a8565b91506060850135611345816110a8565b939692955090935050565b60008083601f84011261136257600080fd5b5081356001600160401b0381111561137957600080fd5b6020830191508360208260051b850101111561139457600080fd5b9250929050565b6000806000806000606086880312156113b357600080fd5b85356113be816110a8565b945060208601356001600160401b03808211156113da57600080fd5b6113e689838a01611350565b909650945060408801359150808211156113ff57600080fd5b5061140c88828901611350565b969995985093965092949392505050565b6000808585111561142d57600080fd5b8386111561143a57600080fd5b5050820193919092039150565b8035602083101561146057600019602084900360031b1b165b92915050565b60005b83811015611481578181015183820152602001611469565b50506000910152565b60006020828403121561149c57600080fd5b81516001600160401b038111156114b257600080fd5b8201601f810184136114c357600080fd5b80516114d161119f82611106565b8181528560208385010111156114e657600080fd5b6114f7826020830160208601611466565b95945050505050565b60008151808452611518816020860160208601611466565b601f01601f19169290920160200192915050565b8481526001600160a01b038416602082015260806040820181905260009061155690830185611500565b82810360608401526115688185611500565b979650505050505050565b6001600160a01b038316815260406020820181905260009061159790830184611500565b949350505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b600080600080608085870312156115d957600080fd5b84356115e4816110a8565b935060208501356115f4816110a8565b92506040850135611604816110a8565b9396929550929360600135925050565b634e487b7160e01b600052600160045260246000fd5b60006001600160401b03821115611643576116436110c0565b5060051b60200190565b600082601f83011261165e57600080fd5b8135602061166e61119f8361162a565b82815260059290921b8401810191818101908684111561168d57600080fd5b8286015b848110156116a85780358352918301918301611691565b509695505050505050565b600080600080600060a086880312156116cb57600080fd5b853594506020808701356116de816110a8565b945060408701356116ee816110a8565b935060608701356001600160401b038082111561170a57600080fd5b818901915089601f83011261171e57600080fd5b813561172c61119f8261162a565b81815260059190911b8301840190848101908c83111561174b57600080fd5b938501935b82851015611772578435611763816110a8565b82529385019390850190611750565b96505050608089013592508083111561178a57600080fd5b50506117988882890161164d565b9150509295509295909350565b634e487b7160e01b600052603260045260246000fd5b604080825283519082018190526000906020906060840190828701845b828110156117fd5781516001600160a01b0316845292840192908401906001016117d8565b5050508381038285015284518082528583019183019060005b8181101561183257835183529284019291840191600101611816565b5090979650505050505050565b8183526000602080850194508260005b8581101561187d578135611862816110a8565b6001600160a01b03168752958201959082019060010161184f565b509495945050505050565b81835260006001600160fb1b038311156118a157600080fd5b8260051b80836020870137939093016020019392505050565b8781526001600160a01b0387811660208301528616604082015260a0606082018190526000906118ed908301868861183f565b8281036080840152611900818587611888565b9a9950505050505050505050565b60408152600061192260408301868861183f565b828103602084015261156881858761188856fea2646970667358221220bfd1948d5c4cd21e4982d8b20eeb9cb5a362f336cd5a6789511e6ae9d664a37e64736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var ChildMintableERC721PredicateArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"ChildMintableERC721Predicate\",\n \"sourceName\": \"contracts/root/ChildMintableERC721Predicate.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"MintableERC721Deposit\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"MintableERC721DepositBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"MintableERC721Withdraw\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"MintableERC721WithdrawBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"MintableTokenMapped\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAP_TOKEN_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childTokenTemplate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"exitHelper\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newStateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newExitHelper\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newRootERC721Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onL2StateReceive\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"rootERC721Predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"rootTokenToChildToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"stateSender\",\n \"outputs\": [\n {\n \"internalType\": \"contract IStateSender\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC721\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"withdraw\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC721\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"withdrawBatch\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC721\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"withdrawTo\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50611f01806100206000396000f3fe608060405234801561001057600080fd5b50600436106100d55760003560e01c8063cb10f94c11610087578063cb10f94c146101ca578063d41f1771146101e3578063d7c9e3ec1461020a578063f3fef3a314610231578063f43cda8b14610244578063f645125514610257578063f691325c1461027e578063f8c8765e1461029157600080fd5b80636f33e695146100da5780637efab4f5146100ef57806395c7041c14610135578063b176806514610148578063b68ad1e41461017d578063c3b35a7e14610190578063c5ac2b1c146101a3575b600080fd5b6100ed6100e836600461158c565b6102a4565b005b6101186100fd36600461160e565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b600154610118906001600160a01b031681565b61016f7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b60405190815260200161012c565b600354610118906001600160a01b031681565b6100ed61019e366004611632565b6102b8565b61016f7faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b600054610118906201000090046001600160a01b031681565b61016f7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b61016f7f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b6100ed61023f366004611673565b6102c8565b6100ed61025236600461169f565b6102d7565b61016f7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b600254610118906001600160a01b031681565b6100ed61029f366004611727565b61050f565b6102b18585858585610627565b5050505050565b6102c383838361099a565b505050565b6102d382338361099a565b5050565b6001546001600160a01b0316331461034d5760405162461bcd60e51b815260206004820152602e60248201527f4368696c644d696e7461626c654552433732315072656469636174653a204f4e60448201526d262cafa2ac24aa2fa422a62822a960911b60648201526084015b60405180910390fd5b6002546001600160a01b038481169116146103c45760405162461bcd60e51b815260206004820152603160248201527f4368696c644d696e7461626c654552433732315072656469636174653a204f4e6044820152704c595f524f4f545f50524544494341544560781b6064820152608401610344565b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f8216103f3602060008486611783565b6103fc916117ad565b0361041b576104166104118260208186611783565b610ca9565b610509565b7faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1861044a602060008486611783565b610453916117ad565b03610462576104168282610f1f565b7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad610491602060008486611783565b61049a916117ad565b036104a9576104168282611185565b60405162461bcd60e51b815260206004820152602f60248201527f4368696c644d696e7461626c654552433732315072656469636174653a20494e60448201526e56414c49445f5349474e415455524560881b6064820152608401610344565b50505050565b600054610100900460ff161580801561052f5750600054600160ff909116105b806105495750303b158015610549575060005460ff166001145b6105ac5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610344565b6000805460ff1916600117905580156105cf576000805461ff0019166101001790555b6105db858585856112f5565b80156102b1576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050565b84610631816113fd565b61064d5760405162461bcd60e51b8152600401610344906117cb565b6000866001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa15801561068d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106b19190611815565b6001600160a01b038181166000908152600460205260409020549192508881169116146106f05760405162461bcd60e51b815260040161034490611832565b6001600160a01b0381166107065761070661187e565b306001600160a01b0316876001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa15801561074e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107729190611815565b6001600160a01b0316146107885761078861187e565b8483146107ec5760405162461bcd60e51b815260206004820152602c60248201527f4368696c644d696e7461626c654552433732315072656469636174653a20494e60448201526b0ac82989288be988a9c8ea8960a31b6064820152608401610344565b60405163b2dc5dc360e01b81526001600160a01b0388169063b2dc5dc39061081c903390889088906004016118c6565b6020604051808303816000875af115801561083b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085f91906118f4565b61087b5760405162461bcd60e51b815260040161034490611916565b6000546002546040516001600160a01b03620100009093048316926316f198319216906108d8907f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed290869033908d908d908d908d906020016119a8565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610904929190611a42565b600060405180830381600087803b15801561091e57600080fd5b505af1158015610932573d6000803e3d6000fd5b50505050336001600160a01b0316876001600160a01b0316826001600160a01b03167f5faed28924bb6c5b0d3eea1cc028b4814f49c39eac622b81ef17035d794ac774898989896040516109899493929190611a6e565b60405180910390a450505050505050565b826109a4816113fd565b6109c05760405162461bcd60e51b8152600401610344906117cb565b6000846001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a249190611815565b6001600160a01b03818116600090815260046020526040902054919250868116911614610a635760405162461bcd60e51b815260040161034490611832565b6001600160a01b038116610a7957610a7961187e565b306001600160a01b0316856001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ac1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae59190611815565b6001600160a01b031614610afb57610afb61187e565b604051632770a7eb60e21b81526001600160a01b03861690639dc29fac90610b299033908790600401611aa0565b6020604051808303816000875af1158015610b48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b6c91906118f4565b610b885760405162461bcd60e51b815260040161034490611916565b600054600254604080517f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286960208201526001600160a01b0385811682840152336060830152888116608083015260a08083018990528351808403909101815260c08301938490526316f1983160e01b909352620100009094048416936316f1983193610c199391169160c401611a42565b600060405180830381600087803b158015610c3357600080fd5b505af1158015610c47573d6000803e3d6000fd5b50505050836001600160a01b0316856001600160a01b0316826001600160a01b03167f85b3d9b3b871daf1d10c7ba1016854e371ab931adef5569172f0289515a9a6de3387604051610c9a929190611aa0565b60405180910390a45050505050565b6000808080610cba85870187611ab9565b6001600160a01b0380851660009081526004602052604090205494985092965090945092501680610cfd5760405162461bcd60e51b815260040161034490611832565b610d06816113fd565b610d1257610d1261187e565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d769190611815565b9050856001600160a01b0316816001600160a01b031614610d9957610d9961187e565b6001600160a01b038116610daf57610daf61187e565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610df7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e1b9190611815565b6001600160a01b031614610e3157610e3161187e565b6040516340c10f1960e01b81526001600160a01b038316906340c10f1990610e5f9087908790600401611aa0565b6020604051808303816000875af1158015610e7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea291906118f4565b610ebe5760405162461bcd60e51b815260040161034490611b0a565b836001600160a01b0316826001600160a01b0316876001600160a01b03167fb26f02b79335e4b2c506d9e5ae02e042b464a7556419bbc42522fc92833aff528887604051610f0d929190611aa0565b60405180910390a45050505050505050565b6000808080610f3085870187611c27565b6001600160a01b03808516600090815260046020526040902054949950929750909550935016905080610f755760405162461bcd60e51b815260040161034490611832565b610f7e816113fd565b610f8a57610f8a61187e565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fee9190611815565b9050856001600160a01b0316816001600160a01b0316146110115761101161187e565b6001600160a01b0381166110275761102761187e565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa15801561106f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110939190611815565b6001600160a01b0316146110a9576110a961187e565b604051637c88e3d960e01b81526001600160a01b03831690637c88e3d9906110d79087908790600401611d19565b6020604051808303816000875af11580156110f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061111a91906118f4565b6111365760405162461bcd60e51b815260040161034490611b0a565b846001600160a01b0316826001600160a01b0316876001600160a01b03167f7f51e520a281df2deae2754a9232b5a78c8cfeae79568668a0a97a116e1401b88787604051610f0d929190611d19565b6000808061119584860186611e0c565b91955093509150506001600160a01b0383166111b3576111b361187e565b6001600160a01b0383811660009081526004602052604090205416156111db576111db61187e565b6003546040516bffffffffffffffffffffffff19606086901b16602082015260009161122b916001600160a01b039091169060340160405160208183030381529060405280519060200120611492565b6001600160a01b0385811660009081526004602081905260409182902080546001600160a01b03191693851693841790559051639065714760e01b815292935090916390657147916112839188918891889101611e8b565b600060405180830381600087803b15801561129d57600080fd5b505af11580156112b1573d6000803e3d6000fd5b50506040516001600160a01b038085169350871691507f0a1eaf9aa124c3f84c9dd77f7016af0f16f67639abb913af1697387db01f5ca590600090a3505050505050565b6001600160a01b0384161580159061131557506001600160a01b03831615155b801561132957506001600160a01b03821615155b801561133d57506001600160a01b03811615155b6113a25760405162461bcd60e51b815260206004820152603060248201527f4368696c644d696e7461626c654552433732315072656469636174653a20424160448201526f222fa4a724aa24a0a624ad20aa24a7a760811b6064820152608401610344565b600080546001600160a01b03958616620100000262010000600160b01b0319909116179055600180549385166001600160a01b0319948516179055600280549285169284169290921790915560038054919093169116179055565b6000816001600160a01b03163b60000361141957506000919050565b6040516301ffc9a760e01b81526380ac58cd60e01b60048201526001600160a01b038316906301ffc9a790602401602060405180830381865afa925050508015611480575060408051601f3d908101601f1916820190925261147d918101906118f4565b60015b61148c57506000919050565b92915050565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b03811661148c5760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b6044820152606401610344565b6001600160a01b038116811461153e57600080fd5b50565b60008083601f84011261155357600080fd5b5081356001600160401b0381111561156a57600080fd5b6020830191508360208260051b850101111561158557600080fd5b9250929050565b6000806000806000606086880312156115a457600080fd5b85356115af81611529565b945060208601356001600160401b03808211156115cb57600080fd5b6115d789838a01611541565b909650945060408801359150808211156115f057600080fd5b506115fd88828901611541565b969995985093965092949392505050565b60006020828403121561162057600080fd5b813561162b81611529565b9392505050565b60008060006060848603121561164757600080fd5b833561165281611529565b9250602084013561166281611529565b929592945050506040919091013590565b6000806040838503121561168657600080fd5b823561169181611529565b946020939093013593505050565b600080600080606085870312156116b557600080fd5b8435935060208501356116c781611529565b925060408501356001600160401b03808211156116e357600080fd5b818701915087601f8301126116f757600080fd5b81358181111561170657600080fd5b88602082850101111561171857600080fd5b95989497505060200194505050565b6000806000806080858703121561173d57600080fd5b843561174881611529565b9350602085013561175881611529565b9250604085013561176881611529565b9150606085013561177881611529565b939692955090935050565b6000808585111561179357600080fd5b838611156117a057600080fd5b5050820193919092039150565b8035602083101561148c57600019602084900360031b1b1692915050565b6020808252602a908201527f4368696c644d696e7461626c654552433732315072656469636174653a204e4f6040820152691517d0d3d395149050d560b21b606082015260800190565b60006020828403121561182757600080fd5b815161162b81611529565b6020808252602c908201527f4368696c644d696e7461626c654552433732315072656469636174653a20554e60408201526b26a0a82822a22faa27a5a2a760a11b606082015260800190565b634e487b7160e01b600052600160045260246000fd5b81835260006001600160fb1b038311156118ad57600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b03841681526040602082018190526000906118eb9083018486611894565b95945050505050565b60006020828403121561190657600080fd5b8151801515811461162b57600080fd5b60208082526029908201527f4368696c644d696e7461626c654552433732315072656469636174653a204255604082015268149397d1905253115160ba1b606082015260800190565b8183526000602080850194508260005b8581101561199d57813561198281611529565b6001600160a01b03168752958201959082019060010161196f565b509495945050505050565b8781526001600160a01b0387811660208301528616604082015260a0606082018190526000906119db908301868861195f565b82810360808401526119ee818587611894565b9a9950505050505050505050565b6000815180845260005b81811015611a2257602081850181015186830182015201611a06565b506000602082860101526020601f19601f83011685010191505092915050565b6001600160a01b0383168152604060208201819052600090611a66908301846119fc565b949350505050565b604081526000611a8260408301868861195f565b8281036020840152611a95818587611894565b979650505050505050565b6001600160a01b03929092168252602082015260400190565b60008060008060808587031215611acf57600080fd5b8435611ada81611529565b93506020850135611aea81611529565b92506040850135611afa81611529565b9396929550929360600135925050565b60208082526029908201527f4368696c644d696e7461626c654552433732315072656469636174653a204d49604082015268139517d1905253115160ba1b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715611b9157611b91611b53565b604052919050565b60006001600160401b03821115611bb257611bb2611b53565b5060051b60200190565b600082601f830112611bcd57600080fd5b81356020611be2611bdd83611b99565b611b69565b82815260059290921b84018101918181019086841115611c0157600080fd5b8286015b84811015611c1c5780358352918301918301611c05565b509695505050505050565b600080600080600060a08688031215611c3f57600080fd5b85359450602080870135611c5281611529565b94506040870135611c6281611529565b935060608701356001600160401b0380821115611c7e57600080fd5b818901915089601f830112611c9257600080fd5b8135611ca0611bdd82611b99565b81815260059190911b8301840190848101908c831115611cbf57600080fd5b938501935b82851015611ce6578435611cd781611529565b82529385019390850190611cc4565b965050506080890135925080831115611cfe57600080fd5b5050611d0c88828901611bbc565b9150509295509295909350565b604080825283519082018190526000906020906060840190828701845b82811015611d5b5781516001600160a01b031684529284019290840190600101611d36565b5050508381038285015284518082528583019183019060005b81811015611d9057835183529284019291840191600101611d74565b5090979650505050505050565b600082601f830112611dae57600080fd5b81356001600160401b03811115611dc757611dc7611b53565b611dda601f8201601f1916602001611b69565b818152846020838601011115611def57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215611e2257600080fd5b843593506020850135611e3481611529565b925060408501356001600160401b0380821115611e5057600080fd5b611e5c88838901611d9d565b93506060870135915080821115611e7257600080fd5b50611e7f87828801611d9d565b91505092959194509250565b6001600160a01b0384168152606060208201819052600090611eaf908301856119fc565b8281036040840152611ec181856119fc565b969550505050505056fea2646970667358221220c8b583610f0e8aefa292fd059d42937fb210322169349afab2ad08a7f054e61d64736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106100d55760003560e01c8063cb10f94c11610087578063cb10f94c146101ca578063d41f1771146101e3578063d7c9e3ec1461020a578063f3fef3a314610231578063f43cda8b14610244578063f645125514610257578063f691325c1461027e578063f8c8765e1461029157600080fd5b80636f33e695146100da5780637efab4f5146100ef57806395c7041c14610135578063b176806514610148578063b68ad1e41461017d578063c3b35a7e14610190578063c5ac2b1c146101a3575b600080fd5b6100ed6100e836600461158c565b6102a4565b005b6101186100fd36600461160e565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b600154610118906001600160a01b031681565b61016f7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b60405190815260200161012c565b600354610118906001600160a01b031681565b6100ed61019e366004611632565b6102b8565b61016f7faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b600054610118906201000090046001600160a01b031681565b61016f7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b61016f7f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b6100ed61023f366004611673565b6102c8565b6100ed61025236600461169f565b6102d7565b61016f7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b600254610118906001600160a01b031681565b6100ed61029f366004611727565b61050f565b6102b18585858585610627565b5050505050565b6102c383838361099a565b505050565b6102d382338361099a565b5050565b6001546001600160a01b0316331461034d5760405162461bcd60e51b815260206004820152602e60248201527f4368696c644d696e7461626c654552433732315072656469636174653a204f4e60448201526d262cafa2ac24aa2fa422a62822a960911b60648201526084015b60405180910390fd5b6002546001600160a01b038481169116146103c45760405162461bcd60e51b815260206004820152603160248201527f4368696c644d696e7461626c654552433732315072656469636174653a204f4e6044820152704c595f524f4f545f50524544494341544560781b6064820152608401610344565b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f8216103f3602060008486611783565b6103fc916117ad565b0361041b576104166104118260208186611783565b610ca9565b610509565b7faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1861044a602060008486611783565b610453916117ad565b03610462576104168282610f1f565b7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad610491602060008486611783565b61049a916117ad565b036104a9576104168282611185565b60405162461bcd60e51b815260206004820152602f60248201527f4368696c644d696e7461626c654552433732315072656469636174653a20494e60448201526e56414c49445f5349474e415455524560881b6064820152608401610344565b50505050565b600054610100900460ff161580801561052f5750600054600160ff909116105b806105495750303b158015610549575060005460ff166001145b6105ac5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610344565b6000805460ff1916600117905580156105cf576000805461ff0019166101001790555b6105db858585856112f5565b80156102b1576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050565b84610631816113fd565b61064d5760405162461bcd60e51b8152600401610344906117cb565b6000866001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa15801561068d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106b19190611815565b6001600160a01b038181166000908152600460205260409020549192508881169116146106f05760405162461bcd60e51b815260040161034490611832565b6001600160a01b0381166107065761070661187e565b306001600160a01b0316876001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa15801561074e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107729190611815565b6001600160a01b0316146107885761078861187e565b8483146107ec5760405162461bcd60e51b815260206004820152602c60248201527f4368696c644d696e7461626c654552433732315072656469636174653a20494e60448201526b0ac82989288be988a9c8ea8960a31b6064820152608401610344565b60405163b2dc5dc360e01b81526001600160a01b0388169063b2dc5dc39061081c903390889088906004016118c6565b6020604051808303816000875af115801561083b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085f91906118f4565b61087b5760405162461bcd60e51b815260040161034490611916565b6000546002546040516001600160a01b03620100009093048316926316f198319216906108d8907f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed290869033908d908d908d908d906020016119a8565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610904929190611a42565b600060405180830381600087803b15801561091e57600080fd5b505af1158015610932573d6000803e3d6000fd5b50505050336001600160a01b0316876001600160a01b0316826001600160a01b03167f5faed28924bb6c5b0d3eea1cc028b4814f49c39eac622b81ef17035d794ac774898989896040516109899493929190611a6e565b60405180910390a450505050505050565b826109a4816113fd565b6109c05760405162461bcd60e51b8152600401610344906117cb565b6000846001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a249190611815565b6001600160a01b03818116600090815260046020526040902054919250868116911614610a635760405162461bcd60e51b815260040161034490611832565b6001600160a01b038116610a7957610a7961187e565b306001600160a01b0316856001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ac1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae59190611815565b6001600160a01b031614610afb57610afb61187e565b604051632770a7eb60e21b81526001600160a01b03861690639dc29fac90610b299033908790600401611aa0565b6020604051808303816000875af1158015610b48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b6c91906118f4565b610b885760405162461bcd60e51b815260040161034490611916565b600054600254604080517f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286960208201526001600160a01b0385811682840152336060830152888116608083015260a08083018990528351808403909101815260c08301938490526316f1983160e01b909352620100009094048416936316f1983193610c199391169160c401611a42565b600060405180830381600087803b158015610c3357600080fd5b505af1158015610c47573d6000803e3d6000fd5b50505050836001600160a01b0316856001600160a01b0316826001600160a01b03167f85b3d9b3b871daf1d10c7ba1016854e371ab931adef5569172f0289515a9a6de3387604051610c9a929190611aa0565b60405180910390a45050505050565b6000808080610cba85870187611ab9565b6001600160a01b0380851660009081526004602052604090205494985092965090945092501680610cfd5760405162461bcd60e51b815260040161034490611832565b610d06816113fd565b610d1257610d1261187e565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d769190611815565b9050856001600160a01b0316816001600160a01b031614610d9957610d9961187e565b6001600160a01b038116610daf57610daf61187e565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610df7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e1b9190611815565b6001600160a01b031614610e3157610e3161187e565b6040516340c10f1960e01b81526001600160a01b038316906340c10f1990610e5f9087908790600401611aa0565b6020604051808303816000875af1158015610e7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea291906118f4565b610ebe5760405162461bcd60e51b815260040161034490611b0a565b836001600160a01b0316826001600160a01b0316876001600160a01b03167fb26f02b79335e4b2c506d9e5ae02e042b464a7556419bbc42522fc92833aff528887604051610f0d929190611aa0565b60405180910390a45050505050505050565b6000808080610f3085870187611c27565b6001600160a01b03808516600090815260046020526040902054949950929750909550935016905080610f755760405162461bcd60e51b815260040161034490611832565b610f7e816113fd565b610f8a57610f8a61187e565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fee9190611815565b9050856001600160a01b0316816001600160a01b0316146110115761101161187e565b6001600160a01b0381166110275761102761187e565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa15801561106f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110939190611815565b6001600160a01b0316146110a9576110a961187e565b604051637c88e3d960e01b81526001600160a01b03831690637c88e3d9906110d79087908790600401611d19565b6020604051808303816000875af11580156110f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061111a91906118f4565b6111365760405162461bcd60e51b815260040161034490611b0a565b846001600160a01b0316826001600160a01b0316876001600160a01b03167f7f51e520a281df2deae2754a9232b5a78c8cfeae79568668a0a97a116e1401b88787604051610f0d929190611d19565b6000808061119584860186611e0c565b91955093509150506001600160a01b0383166111b3576111b361187e565b6001600160a01b0383811660009081526004602052604090205416156111db576111db61187e565b6003546040516bffffffffffffffffffffffff19606086901b16602082015260009161122b916001600160a01b039091169060340160405160208183030381529060405280519060200120611492565b6001600160a01b0385811660009081526004602081905260409182902080546001600160a01b03191693851693841790559051639065714760e01b815292935090916390657147916112839188918891889101611e8b565b600060405180830381600087803b15801561129d57600080fd5b505af11580156112b1573d6000803e3d6000fd5b50506040516001600160a01b038085169350871691507f0a1eaf9aa124c3f84c9dd77f7016af0f16f67639abb913af1697387db01f5ca590600090a3505050505050565b6001600160a01b0384161580159061131557506001600160a01b03831615155b801561132957506001600160a01b03821615155b801561133d57506001600160a01b03811615155b6113a25760405162461bcd60e51b815260206004820152603060248201527f4368696c644d696e7461626c654552433732315072656469636174653a20424160448201526f222fa4a724aa24a0a624ad20aa24a7a760811b6064820152608401610344565b600080546001600160a01b03958616620100000262010000600160b01b0319909116179055600180549385166001600160a01b0319948516179055600280549285169284169290921790915560038054919093169116179055565b6000816001600160a01b03163b60000361141957506000919050565b6040516301ffc9a760e01b81526380ac58cd60e01b60048201526001600160a01b038316906301ffc9a790602401602060405180830381865afa925050508015611480575060408051601f3d908101601f1916820190925261147d918101906118f4565b60015b61148c57506000919050565b92915050565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b03811661148c5760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b6044820152606401610344565b6001600160a01b038116811461153e57600080fd5b50565b60008083601f84011261155357600080fd5b5081356001600160401b0381111561156a57600080fd5b6020830191508360208260051b850101111561158557600080fd5b9250929050565b6000806000806000606086880312156115a457600080fd5b85356115af81611529565b945060208601356001600160401b03808211156115cb57600080fd5b6115d789838a01611541565b909650945060408801359150808211156115f057600080fd5b506115fd88828901611541565b969995985093965092949392505050565b60006020828403121561162057600080fd5b813561162b81611529565b9392505050565b60008060006060848603121561164757600080fd5b833561165281611529565b9250602084013561166281611529565b929592945050506040919091013590565b6000806040838503121561168657600080fd5b823561169181611529565b946020939093013593505050565b600080600080606085870312156116b557600080fd5b8435935060208501356116c781611529565b925060408501356001600160401b03808211156116e357600080fd5b818701915087601f8301126116f757600080fd5b81358181111561170657600080fd5b88602082850101111561171857600080fd5b95989497505060200194505050565b6000806000806080858703121561173d57600080fd5b843561174881611529565b9350602085013561175881611529565b9250604085013561176881611529565b9150606085013561177881611529565b939692955090935050565b6000808585111561179357600080fd5b838611156117a057600080fd5b5050820193919092039150565b8035602083101561148c57600019602084900360031b1b1692915050565b6020808252602a908201527f4368696c644d696e7461626c654552433732315072656469636174653a204e4f6040820152691517d0d3d395149050d560b21b606082015260800190565b60006020828403121561182757600080fd5b815161162b81611529565b6020808252602c908201527f4368696c644d696e7461626c654552433732315072656469636174653a20554e60408201526b26a0a82822a22faa27a5a2a760a11b606082015260800190565b634e487b7160e01b600052600160045260246000fd5b81835260006001600160fb1b038311156118ad57600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b03841681526040602082018190526000906118eb9083018486611894565b95945050505050565b60006020828403121561190657600080fd5b8151801515811461162b57600080fd5b60208082526029908201527f4368696c644d696e7461626c654552433732315072656469636174653a204255604082015268149397d1905253115160ba1b606082015260800190565b8183526000602080850194508260005b8581101561199d57813561198281611529565b6001600160a01b03168752958201959082019060010161196f565b509495945050505050565b8781526001600160a01b0387811660208301528616604082015260a0606082018190526000906119db908301868861195f565b82810360808401526119ee818587611894565b9a9950505050505050505050565b6000815180845260005b81811015611a2257602081850181015186830182015201611a06565b506000602082860101526020601f19601f83011685010191505092915050565b6001600160a01b0383168152604060208201819052600090611a66908301846119fc565b949350505050565b604081526000611a8260408301868861195f565b8281036020840152611a95818587611894565b979650505050505050565b6001600160a01b03929092168252602082015260400190565b60008060008060808587031215611acf57600080fd5b8435611ada81611529565b93506020850135611aea81611529565b92506040850135611afa81611529565b9396929550929360600135925050565b60208082526029908201527f4368696c644d696e7461626c654552433732315072656469636174653a204d49604082015268139517d1905253115160ba1b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715611b9157611b91611b53565b604052919050565b60006001600160401b03821115611bb257611bb2611b53565b5060051b60200190565b600082601f830112611bcd57600080fd5b81356020611be2611bdd83611b99565b611b69565b82815260059290921b84018101918181019086841115611c0157600080fd5b8286015b84811015611c1c5780358352918301918301611c05565b509695505050505050565b600080600080600060a08688031215611c3f57600080fd5b85359450602080870135611c5281611529565b94506040870135611c6281611529565b935060608701356001600160401b0380821115611c7e57600080fd5b818901915089601f830112611c9257600080fd5b8135611ca0611bdd82611b99565b81815260059190911b8301840190848101908c831115611cbf57600080fd5b938501935b82851015611ce6578435611cd781611529565b82529385019390850190611cc4565b965050506080890135925080831115611cfe57600080fd5b5050611d0c88828901611bbc565b9150509295509295909350565b604080825283519082018190526000906020906060840190828701845b82811015611d5b5781516001600160a01b031684529284019290840190600101611d36565b5050508381038285015284518082528583019183019060005b81811015611d9057835183529284019291840191600101611d74565b5090979650505050505050565b600082601f830112611dae57600080fd5b81356001600160401b03811115611dc757611dc7611b53565b611dda601f8201601f1916602001611b69565b818152846020838601011115611def57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215611e2257600080fd5b843593506020850135611e3481611529565b925060408501356001600160401b0380821115611e5057600080fd5b611e5c88838901611d9d565b93506060870135915080821115611e7257600080fd5b50611e7f87828801611d9d565b91505092959194509250565b6001600160a01b0384168152606060208201819052600090611eaf908301856119fc565b8281036040840152611ec181856119fc565b969550505050505056fea2646970667358221220c8b583610f0e8aefa292fd059d42937fb210322169349afab2ad08a7f054e61d64736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var MockERC1155Artifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"MockERC1155\",\n \"sourceName\": \"contracts/mocks/MockERC1155.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"operator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bool\",\n \"name\": \"approved\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"ApprovalForAll\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"Paused\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bytes32\",\n \"name\": \"previousAdminRole\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bytes32\",\n \"name\": \"newAdminRole\",\n \"type\": \"bytes32\"\n }\n ],\n \"name\": \"RoleAdminChanged\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"RoleGranted\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"RoleRevoked\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"operator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"ids\",\n \"type\": \"uint256[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"values\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"TransferBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"operator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"TransferSingle\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"string\",\n \"name\": \"value\",\n \"type\": \"string\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"URI\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"Unpaused\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEFAULT_ADMIN_ROLE\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MINTER_ROLE\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"PAUSER_ROLE\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"balanceOf\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address[]\",\n \"name\": \"accounts\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"ids\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"balanceOfBatch\",\n \"outputs\": [\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"\",\n \"type\": \"uint256[]\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"burn\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"ids\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"values\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"burnBatch\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n }\n ],\n \"name\": \"getRoleAdmin\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"index\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"getRoleMember\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n }\n ],\n \"name\": \"getRoleMemberCount\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"grantRole\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"hasRole\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"operator\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"isApprovedForAll\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"mint\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"ids\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"amounts\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"mintBatch\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"pause\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"paused\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"renounceRole\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"role\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"revokeRole\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"ids\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"amounts\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"safeBatchTransferFrom\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"safeTransferFrom\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"operator\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"approved\",\n \"type\": \"bool\"\n }\n ],\n \"name\": \"setApprovalForAll\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes4\",\n \"name\": \"interfaceId\",\n \"type\": \"bytes4\"\n }\n ],\n \"name\": \"supportsInterface\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"unpause\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"uri\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x60806040523480156200001157600080fd5b506040805180820190915260058152646c6f72656d60d81b6020820152806200003a81620000b1565b506005805460ff1916905562000052600033620000c3565b6200007e7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a633620000c3565b620000aa7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a33620000c3565b5062000376565b6004620000bf8282620002aa565b5050565b620000bf8282620000d58282620000f4565b6000828152600160205260409020620000ef908262000194565b505050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16620000bf576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620001503390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000620001ab836001600160a01b038416620001b4565b90505b92915050565b6000818152600183016020526040812054620001fd57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155620001ae565b506000620001ae565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200023157607f821691505b6020821081036200025257634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620000ef57600081815260208120601f850160051c81016020861015620002815750805b601f850160051c820191505b81811015620002a2578281556001016200028d565b505050505050565b81516001600160401b03811115620002c657620002c662000206565b620002de81620002d784546200021c565b8462000258565b602080601f831160018114620003165760008415620002fd5750858301515b600019600386901b1c1916600185901b178555620002a2565b600085815260208120601f198616915b82811015620003475788860151825594840194600190910190840162000326565b5085821015620003665787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6128a080620003866000396000f3fe608060405234801561001057600080fd5b50600436106101625760003560e01c8063731133e9116100ce578063ca15c87311610087578063ca15c873146102fb578063d53913931461030e578063d547741f14610323578063e63ab1e914610336578063e985e9c51461034b578063f242432a14610387578063f5298aca1461039a57600080fd5b8063731133e9146102875780638456cb591461029a5780639010d07c146102a257806391d14854146102cd578063a217fddf146102e0578063a22cb465146102e857600080fd5b80632f2ff15d116101205780632f2ff15d1461021b57806336568abe1461022e5780633f4ba83a146102415780634e1273f4146102495780635c975abb146102695780636b20c4541461027457600080fd5b8062fdd58e1461016757806301ffc9a71461018d5780630e89341c146101b05780631f7fdffa146101d0578063248a9ca3146101e55780632eb2c2d614610208575b600080fd5b61017a610175366004611bd7565b6103ad565b6040519081526020015b60405180910390f35b6101a061019b366004611c17565b610448565b6040519015158152602001610184565b6101c36101be366004611c34565b610453565b6040516101849190611c9d565b6101e36101de366004611df9565b6104e7565b005b61017a6101f3366004611c34565b60009081526020819052604090206001015490565b6101e3610216366004611e91565b61052d565b6101e3610229366004611f3a565b610579565b6101e361023c366004611f3a565b6105a3565b6101e3610621565b61025c610257366004611f66565b6106a3565b604051610184919061206b565b60055460ff166101a0565b6101e361028236600461207e565b6107cc565b6101e36102953660046120f1565b61080f565b6101e361084f565b6102b56102b0366004612145565b6108cb565b6040516001600160a01b039091168152602001610184565b6101a06102db366004611f3a565b6108ea565b61017a600081565b6101e36102f6366004612167565b610913565b61017a610309366004611c34565b61091e565b61017a60008051602061284b83398151915281565b6101e3610331366004611f3a565b610935565b61017a60008051602061282b83398151915281565b6101a06103593660046121a3565b6001600160a01b03918216600090815260036020908152604080832093909416825291909152205460ff1690565b6101e36103953660046121cd565b61095a565b6101e36103a8366004612231565b61099f565b60006001600160a01b03831661041d5760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201526930b634b21037bbb732b960b11b60648201526084015b60405180910390fd5b5060008181526002602090815260408083206001600160a01b03861684529091529020545b92915050565b6000610442826109e2565b60606004805461046290612264565b80601f016020809104026020016040519081016040528092919081815260200182805461048e90612264565b80156104db5780601f106104b0576101008083540402835291602001916104db565b820191906000526020600020905b8154815290600101906020018083116104be57829003601f168201915b50505050509050919050565b6104ff60008051602061284b833981519152336108ea565b61051b5760405162461bcd60e51b81526004016104149061229e565b61052784848484610a22565b50505050565b6001600160a01b03851633148061054957506105498533610359565b6105655760405162461bcd60e51b8152600401610414906122e4565b6105728585858585610b6b565b5050505050565b60008281526020819052604090206001015461059481610d06565b61059e8383610d13565b505050565b6001600160a01b03811633146106135760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610414565b61061d8282610d35565b5050565b61063960008051602061282b833981519152336108ea565b6106995760405162461bcd60e51b815260206004820152603b60248201526000805160206127eb83398151915260448201527f686176652070617573657220726f6c6520746f20756e706175736500000000006064820152608401610414565b6106a1610d57565b565b606081518351146107085760405162461bcd60e51b815260206004820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e677468604482015268040dad2e6dac2e8c6d60bb1b6064820152608401610414565b600083516001600160401b0381111561072357610723611cb0565b60405190808252806020026020018201604052801561074c578160200160208202803683370190505b50905060005b84518110156107c45761079785828151811061077057610770612332565b602002602001015185838151811061078a5761078a612332565b60200260200101516103ad565b8282815181106107a9576107a9612332565b60209081029190910101526107bd8161235e565b9050610752565b509392505050565b6001600160a01b0383163314806107e857506107e88333610359565b6108045760405162461bcd60e51b8152600401610414906122e4565b61059e838383610da9565b61082760008051602061284b833981519152336108ea565b6108435760405162461bcd60e51b81526004016104149061229e565b61052784848484610f36565b61086760008051602061282b833981519152336108ea565b6108c35760405162461bcd60e51b815260206004820152603960248201526000805160206127eb833981519152604482015278686176652070617573657220726f6c6520746f20706175736560381b6064820152608401610414565b6106a161100f565b60008281526001602052604081206108e3908361104c565b9392505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b61061d338383611058565b600081815260016020526040812061044290611138565b60008281526020819052604090206001015461095081610d06565b61059e8383610d35565b6001600160a01b03851633148061097657506109768533610359565b6109925760405162461bcd60e51b8152600401610414906122e4565b6105728585858585611142565b6001600160a01b0383163314806109bb57506109bb8333610359565b6109d75760405162461bcd60e51b8152600401610414906122e4565b61059e83838361126c565b60006001600160e01b03198216636cdb3d1360e11b1480610a1357506001600160e01b031982166303a24d0760e21b145b80610442575061044282611376565b6001600160a01b038416610a485760405162461bcd60e51b815260040161041490612377565b8151835114610a695760405162461bcd60e51b8152600401610414906123b8565b33610a798160008787878761139b565b60005b8451811015610b1557838181518110610a9757610a97612332565b602002602001015160026000878481518110610ab557610ab5612332565b602002602001015181526020019081526020016000206000886001600160a01b03166001600160a01b031681526020019081526020016000206000828254610afd9190612400565b90915550819050610b0d8161235e565b915050610a7c565b50846001600160a01b031660006001600160a01b0316826001600160a01b03166000805160206127cb8339815191528787604051610b54929190612413565b60405180910390a4610572816000878787876113a9565b8151835114610b8c5760405162461bcd60e51b8152600401610414906123b8565b6001600160a01b038416610bb25760405162461bcd60e51b815260040161041490612441565b33610bc181878787878761139b565b60005b8451811015610caa576000858281518110610be157610be1612332565b602002602001015190506000858381518110610bff57610bff612332565b60209081029190910181015160008481526002835260408082206001600160a01b038e168352909352919091205490915081811015610c505760405162461bcd60e51b815260040161041490612486565b60008381526002602090815260408083206001600160a01b038e8116855292528083208585039055908b16825281208054849290610c8f908490612400565b9250508190555050505080610ca39061235e565b9050610bc4565b50846001600160a01b0316866001600160a01b0316826001600160a01b03166000805160206127cb8339815191528787604051610ce8929190612413565b60405180910390a4610cfe8187878787876113a9565b505050505050565b610d108133611504565b50565b610d1d828261155d565b600082815260016020526040902061059e90826115e1565b610d3f82826115f6565b600082815260016020526040902061059e908261165b565b610d5f611670565b6005805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6001600160a01b038316610dcf5760405162461bcd60e51b8152600401610414906124d0565b8051825114610df05760405162461bcd60e51b8152600401610414906123b8565b6000339050610e138185600086866040518060200160405280600081525061139b565b60005b8351811015610edb576000848281518110610e3357610e33612332565b602002602001015190506000848381518110610e5157610e51612332565b60209081029190910181015160008481526002835260408082206001600160a01b038c168352909352919091205490915081811015610ea25760405162461bcd60e51b815260040161041490612513565b60009283526002602090815260408085206001600160a01b038b1686529091529092209103905580610ed38161235e565b915050610e16565b5060006001600160a01b0316846001600160a01b0316826001600160a01b03166000805160206127cb8339815191528686604051610f1a929190612413565b60405180910390a4604080516020810190915260009052610527565b6001600160a01b038416610f5c5760405162461bcd60e51b815260040161041490612377565b336000610f68856116b9565b90506000610f75856116b9565b9050610f868360008985858961139b565b60008681526002602090815260408083206001600160a01b038b16845290915281208054879290610fb8908490612400565b909155505060408051878152602081018790526001600160a01b03808a16926000929187169160008051602061280b833981519152910160405180910390a461100683600089898989611704565b50505050505050565b6110176117bf565b6005805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610d8c3390565b60006108e38383611805565b816001600160a01b0316836001600160a01b0316036110cb5760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b6064820152608401610414565b6001600160a01b03838116600081815260036020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6000610442825490565b6001600160a01b0384166111685760405162461bcd60e51b815260040161041490612441565b336000611174856116b9565b90506000611181856116b9565b905061119183898985858961139b565b60008681526002602090815260408083206001600160a01b038c168452909152902054858110156111d45760405162461bcd60e51b815260040161041490612486565b60008781526002602090815260408083206001600160a01b038d8116855292528083208985039055908a16825281208054889290611213908490612400565b909155505060408051888152602081018890526001600160a01b03808b16928c8216929188169160008051602061280b833981519152910160405180910390a4611261848a8a8a8a8a611704565b505050505050505050565b6001600160a01b0383166112925760405162461bcd60e51b8152600401610414906124d0565b33600061129e846116b9565b905060006112ab846116b9565b90506112cb8387600085856040518060200160405280600081525061139b565b60008581526002602090815260408083206001600160a01b038a1684529091529020548481101561130e5760405162461bcd60e51b815260040161041490612513565b60008681526002602090815260408083206001600160a01b038b81168086529184528285208a8703905582518b81529384018a905290929088169160008051602061280b833981519152910160405180910390a4604080516020810190915260009052611006565b60006001600160e01b03198216635a05180f60e01b148061044257506104428261182f565b610cfe868686868686611864565b6001600160a01b0384163b15610cfe5760405163bc197c8160e01b81526001600160a01b0385169063bc197c81906113ed9089908990889088908890600401612557565b6020604051808303816000875af1925050508015611428575060408051601f3d908101601f19168201909252611425918101906125b5565b60015b6114d4576114346125d2565b806308c379a00361146d57506114486125ee565b80611453575061146f565b8060405162461bcd60e51b81526004016104149190611c9d565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e2d455243313135356044820152732932b1b2b4bb32b91034b6b83632b6b2b73a32b960611b6064820152608401610414565b6001600160e01b0319811663bc197c8160e01b146110065760405162461bcd60e51b815260040161041490612677565b61150e82826108ea565b61061d5761151b816118cc565b6115268360206118de565b6040516020016115379291906126bf565b60408051601f198184030181529082905262461bcd60e51b825261041491600401611c9d565b61156782826108ea565b61061d576000828152602081815260408083206001600160a01b03851684529091529020805460ff1916600117905561159d3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60006108e3836001600160a01b038416611a79565b61160082826108ea565b1561061d576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60006108e3836001600160a01b038416611ac8565b60055460ff166106a15760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610414565b604080516001808252818301909252606091600091906020808301908036833701905050905082816000815181106116f3576116f3612332565b602090810291909101015292915050565b6001600160a01b0384163b15610cfe5760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e6190611748908990899088908890889060040161272e565b6020604051808303816000875af1925050508015611783575060408051601f3d908101601f19168201909252611780918101906125b5565b60015b61178f576114346125d2565b6001600160e01b0319811663f23a6e6160e01b146110065760405162461bcd60e51b815260040161041490612677565b60055460ff16156106a15760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610414565b600082600001828154811061181c5761181c612332565b9060005260206000200154905092915050565b60006001600160e01b03198216637965db0b60e01b148061044257506301ffc9a760e01b6001600160e01b0319831614610442565b60055460ff1615610cfe5760405162461bcd60e51b815260206004820152602c60248201527f455243313135355061757361626c653a20746f6b656e207472616e736665722060448201526b1dda1a5b19481c185d5cd95960a21b6064820152608401610414565b60606104426001600160a01b03831660145b606060006118ed836002612773565b6118f8906002612400565b6001600160401b0381111561190f5761190f611cb0565b6040519080825280601f01601f191660200182016040528015611939576020820181803683370190505b509050600360fc1b8160008151811061195457611954612332565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061198357611983612332565b60200101906001600160f81b031916908160001a90535060006119a7846002612773565b6119b2906001612400565b90505b6001811115611a2a576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106119e6576119e6612332565b1a60f81b8282815181106119fc576119fc612332565b60200101906001600160f81b031916908160001a90535060049490941c93611a238161278a565b90506119b5565b5083156108e35760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610414565b6000818152600183016020526040812054611ac057508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610442565b506000610442565b60008181526001830160205260408120548015611bb1576000611aec6001836127a1565b8554909150600090611b00906001906127a1565b9050818114611b65576000866000018281548110611b2057611b20612332565b9060005260206000200154905080876000018481548110611b4357611b43612332565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080611b7657611b766127b4565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610442565b6000915050610442565b80356001600160a01b0381168114611bd257600080fd5b919050565b60008060408385031215611bea57600080fd5b611bf383611bbb565b946020939093013593505050565b6001600160e01b031981168114610d1057600080fd5b600060208284031215611c2957600080fd5b81356108e381611c01565b600060208284031215611c4657600080fd5b5035919050565b60005b83811015611c68578181015183820152602001611c50565b50506000910152565b60008151808452611c89816020860160208601611c4d565b601f01601f19169290920160200192915050565b6020815260006108e36020830184611c71565b634e487b7160e01b600052604160045260246000fd5b601f8201601f191681016001600160401b0381118282101715611ceb57611ceb611cb0565b6040525050565b60006001600160401b03821115611d0b57611d0b611cb0565b5060051b60200190565b600082601f830112611d2657600080fd5b81356020611d3382611cf2565b604051611d408282611cc6565b83815260059390931b8501820192828101915086841115611d6057600080fd5b8286015b84811015611d7b5780358352918301918301611d64565b509695505050505050565b600082601f830112611d9757600080fd5b81356001600160401b03811115611db057611db0611cb0565b604051611dc7601f8301601f191660200182611cc6565b818152846020838601011115611ddc57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215611e0f57600080fd5b611e1885611bbb565b935060208501356001600160401b0380821115611e3457600080fd5b611e4088838901611d15565b94506040870135915080821115611e5657600080fd5b611e6288838901611d15565b93506060870135915080821115611e7857600080fd5b50611e8587828801611d86565b91505092959194509250565b600080600080600060a08688031215611ea957600080fd5b611eb286611bbb565b9450611ec060208701611bbb565b935060408601356001600160401b0380821115611edc57600080fd5b611ee889838a01611d15565b94506060880135915080821115611efe57600080fd5b611f0a89838a01611d15565b93506080880135915080821115611f2057600080fd5b50611f2d88828901611d86565b9150509295509295909350565b60008060408385031215611f4d57600080fd5b82359150611f5d60208401611bbb565b90509250929050565b60008060408385031215611f7957600080fd5b82356001600160401b0380821115611f9057600080fd5b818501915085601f830112611fa457600080fd5b81356020611fb182611cf2565b604051611fbe8282611cc6565b83815260059390931b8501820192828101915089841115611fde57600080fd5b948201945b8386101561200357611ff486611bbb565b82529482019490820190611fe3565b9650508601359250508082111561201957600080fd5b5061202685828601611d15565b9150509250929050565b600081518084526020808501945080840160005b8381101561206057815187529582019590820190600101612044565b509495945050505050565b6020815260006108e36020830184612030565b60008060006060848603121561209357600080fd5b61209c84611bbb565b925060208401356001600160401b03808211156120b857600080fd5b6120c487838801611d15565b935060408601359150808211156120da57600080fd5b506120e786828701611d15565b9150509250925092565b6000806000806080858703121561210757600080fd5b61211085611bbb565b9350602085013592506040850135915060608501356001600160401b0381111561213957600080fd5b611e8587828801611d86565b6000806040838503121561215857600080fd5b50508035926020909101359150565b6000806040838503121561217a57600080fd5b61218383611bbb565b91506020830135801515811461219857600080fd5b809150509250929050565b600080604083850312156121b657600080fd5b6121bf83611bbb565b9150611f5d60208401611bbb565b600080600080600060a086880312156121e557600080fd5b6121ee86611bbb565b94506121fc60208701611bbb565b9350604086013592506060860135915060808601356001600160401b0381111561222557600080fd5b611f2d88828901611d86565b60008060006060848603121561224657600080fd5b61224f84611bbb565b95602085013595506040909401359392505050565b600181811c9082168061227857607f821691505b60208210810361229857634e487b7160e01b600052602260045260246000fd5b50919050565b60208082526038908201526000805160206127eb8339815191526040820152771a185d99481b5a5b9d195c881c9bdb19481d1bc81b5a5b9d60421b606082015260800190565b6020808252602e908201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60408201526d195c881bdc88185c1c1c9bdd995960921b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001820161237057612370612348565b5060010190565b60208082526021908201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736040820152607360f81b606082015260800190565b60208082526028908201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206040820152670dad2e6dac2e8c6d60c31b606082015260800190565b8082018082111561044257610442612348565b6040815260006124266040830185612030565b82810360208401526124388185612030565b95945050505050565b60208082526025908201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604082015264647265737360d81b606082015260800190565b6020808252602a908201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60408201526939103a3930b739b332b960b11b606082015260800190565b60208082526023908201527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260408201526265737360e81b606082015260800190565b60208082526024908201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604082015263616e636560e01b606082015260800190565b6001600160a01b0386811682528516602082015260a06040820181905260009061258390830186612030565b82810360608401526125958186612030565b905082810360808401526125a98185611c71565b98975050505050505050565b6000602082840312156125c757600080fd5b81516108e381611c01565b600060033d11156125eb5760046000803e5060005160e01c5b90565b600060443d10156125fc5790565b6040516003193d81016004833e81513d6001600160401b03816024840111818411171561262b57505050505090565b82850191508151818111156126435750505050505090565b843d870101602082850101111561265d5750505050505090565b61266c60208286010187611cc6565b509095945050505050565b60208082526028908201527f455243313135353a204552433131353552656365697665722072656a656374656040820152676420746f6b656e7360c01b606082015260800190565b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b8152600083516126f1816017850160208801611c4d565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351612722816028840160208801611c4d565b01602801949350505050565b6001600160a01b03868116825285166020820152604081018490526060810183905260a06080820181905260009061276890830184611c71565b979650505050505050565b808202811582820484141761044257610442612348565b60008161279957612799612348565b506000190190565b8181038181111561044257610442612348565b634e487b7160e01b600052603160045260246000fdfe4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb455243313135355072657365744d696e7465725061757365723a206d75737420c3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6265d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6a2646970667358221220294efe154e549198ff0c6b7ab7e9846223d9e8fe7ae7de1938f6eb7d0f5e66a664736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101625760003560e01c8063731133e9116100ce578063ca15c87311610087578063ca15c873146102fb578063d53913931461030e578063d547741f14610323578063e63ab1e914610336578063e985e9c51461034b578063f242432a14610387578063f5298aca1461039a57600080fd5b8063731133e9146102875780638456cb591461029a5780639010d07c146102a257806391d14854146102cd578063a217fddf146102e0578063a22cb465146102e857600080fd5b80632f2ff15d116101205780632f2ff15d1461021b57806336568abe1461022e5780633f4ba83a146102415780634e1273f4146102495780635c975abb146102695780636b20c4541461027457600080fd5b8062fdd58e1461016757806301ffc9a71461018d5780630e89341c146101b05780631f7fdffa146101d0578063248a9ca3146101e55780632eb2c2d614610208575b600080fd5b61017a610175366004611bd7565b6103ad565b6040519081526020015b60405180910390f35b6101a061019b366004611c17565b610448565b6040519015158152602001610184565b6101c36101be366004611c34565b610453565b6040516101849190611c9d565b6101e36101de366004611df9565b6104e7565b005b61017a6101f3366004611c34565b60009081526020819052604090206001015490565b6101e3610216366004611e91565b61052d565b6101e3610229366004611f3a565b610579565b6101e361023c366004611f3a565b6105a3565b6101e3610621565b61025c610257366004611f66565b6106a3565b604051610184919061206b565b60055460ff166101a0565b6101e361028236600461207e565b6107cc565b6101e36102953660046120f1565b61080f565b6101e361084f565b6102b56102b0366004612145565b6108cb565b6040516001600160a01b039091168152602001610184565b6101a06102db366004611f3a565b6108ea565b61017a600081565b6101e36102f6366004612167565b610913565b61017a610309366004611c34565b61091e565b61017a60008051602061284b83398151915281565b6101e3610331366004611f3a565b610935565b61017a60008051602061282b83398151915281565b6101a06103593660046121a3565b6001600160a01b03918216600090815260036020908152604080832093909416825291909152205460ff1690565b6101e36103953660046121cd565b61095a565b6101e36103a8366004612231565b61099f565b60006001600160a01b03831661041d5760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201526930b634b21037bbb732b960b11b60648201526084015b60405180910390fd5b5060008181526002602090815260408083206001600160a01b03861684529091529020545b92915050565b6000610442826109e2565b60606004805461046290612264565b80601f016020809104026020016040519081016040528092919081815260200182805461048e90612264565b80156104db5780601f106104b0576101008083540402835291602001916104db565b820191906000526020600020905b8154815290600101906020018083116104be57829003601f168201915b50505050509050919050565b6104ff60008051602061284b833981519152336108ea565b61051b5760405162461bcd60e51b81526004016104149061229e565b61052784848484610a22565b50505050565b6001600160a01b03851633148061054957506105498533610359565b6105655760405162461bcd60e51b8152600401610414906122e4565b6105728585858585610b6b565b5050505050565b60008281526020819052604090206001015461059481610d06565b61059e8383610d13565b505050565b6001600160a01b03811633146106135760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610414565b61061d8282610d35565b5050565b61063960008051602061282b833981519152336108ea565b6106995760405162461bcd60e51b815260206004820152603b60248201526000805160206127eb83398151915260448201527f686176652070617573657220726f6c6520746f20756e706175736500000000006064820152608401610414565b6106a1610d57565b565b606081518351146107085760405162461bcd60e51b815260206004820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e677468604482015268040dad2e6dac2e8c6d60bb1b6064820152608401610414565b600083516001600160401b0381111561072357610723611cb0565b60405190808252806020026020018201604052801561074c578160200160208202803683370190505b50905060005b84518110156107c45761079785828151811061077057610770612332565b602002602001015185838151811061078a5761078a612332565b60200260200101516103ad565b8282815181106107a9576107a9612332565b60209081029190910101526107bd8161235e565b9050610752565b509392505050565b6001600160a01b0383163314806107e857506107e88333610359565b6108045760405162461bcd60e51b8152600401610414906122e4565b61059e838383610da9565b61082760008051602061284b833981519152336108ea565b6108435760405162461bcd60e51b81526004016104149061229e565b61052784848484610f36565b61086760008051602061282b833981519152336108ea565b6108c35760405162461bcd60e51b815260206004820152603960248201526000805160206127eb833981519152604482015278686176652070617573657220726f6c6520746f20706175736560381b6064820152608401610414565b6106a161100f565b60008281526001602052604081206108e3908361104c565b9392505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b61061d338383611058565b600081815260016020526040812061044290611138565b60008281526020819052604090206001015461095081610d06565b61059e8383610d35565b6001600160a01b03851633148061097657506109768533610359565b6109925760405162461bcd60e51b8152600401610414906122e4565b6105728585858585611142565b6001600160a01b0383163314806109bb57506109bb8333610359565b6109d75760405162461bcd60e51b8152600401610414906122e4565b61059e83838361126c565b60006001600160e01b03198216636cdb3d1360e11b1480610a1357506001600160e01b031982166303a24d0760e21b145b80610442575061044282611376565b6001600160a01b038416610a485760405162461bcd60e51b815260040161041490612377565b8151835114610a695760405162461bcd60e51b8152600401610414906123b8565b33610a798160008787878761139b565b60005b8451811015610b1557838181518110610a9757610a97612332565b602002602001015160026000878481518110610ab557610ab5612332565b602002602001015181526020019081526020016000206000886001600160a01b03166001600160a01b031681526020019081526020016000206000828254610afd9190612400565b90915550819050610b0d8161235e565b915050610a7c565b50846001600160a01b031660006001600160a01b0316826001600160a01b03166000805160206127cb8339815191528787604051610b54929190612413565b60405180910390a4610572816000878787876113a9565b8151835114610b8c5760405162461bcd60e51b8152600401610414906123b8565b6001600160a01b038416610bb25760405162461bcd60e51b815260040161041490612441565b33610bc181878787878761139b565b60005b8451811015610caa576000858281518110610be157610be1612332565b602002602001015190506000858381518110610bff57610bff612332565b60209081029190910181015160008481526002835260408082206001600160a01b038e168352909352919091205490915081811015610c505760405162461bcd60e51b815260040161041490612486565b60008381526002602090815260408083206001600160a01b038e8116855292528083208585039055908b16825281208054849290610c8f908490612400565b9250508190555050505080610ca39061235e565b9050610bc4565b50846001600160a01b0316866001600160a01b0316826001600160a01b03166000805160206127cb8339815191528787604051610ce8929190612413565b60405180910390a4610cfe8187878787876113a9565b505050505050565b610d108133611504565b50565b610d1d828261155d565b600082815260016020526040902061059e90826115e1565b610d3f82826115f6565b600082815260016020526040902061059e908261165b565b610d5f611670565b6005805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6001600160a01b038316610dcf5760405162461bcd60e51b8152600401610414906124d0565b8051825114610df05760405162461bcd60e51b8152600401610414906123b8565b6000339050610e138185600086866040518060200160405280600081525061139b565b60005b8351811015610edb576000848281518110610e3357610e33612332565b602002602001015190506000848381518110610e5157610e51612332565b60209081029190910181015160008481526002835260408082206001600160a01b038c168352909352919091205490915081811015610ea25760405162461bcd60e51b815260040161041490612513565b60009283526002602090815260408085206001600160a01b038b1686529091529092209103905580610ed38161235e565b915050610e16565b5060006001600160a01b0316846001600160a01b0316826001600160a01b03166000805160206127cb8339815191528686604051610f1a929190612413565b60405180910390a4604080516020810190915260009052610527565b6001600160a01b038416610f5c5760405162461bcd60e51b815260040161041490612377565b336000610f68856116b9565b90506000610f75856116b9565b9050610f868360008985858961139b565b60008681526002602090815260408083206001600160a01b038b16845290915281208054879290610fb8908490612400565b909155505060408051878152602081018790526001600160a01b03808a16926000929187169160008051602061280b833981519152910160405180910390a461100683600089898989611704565b50505050505050565b6110176117bf565b6005805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610d8c3390565b60006108e38383611805565b816001600160a01b0316836001600160a01b0316036110cb5760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b6064820152608401610414565b6001600160a01b03838116600081815260036020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6000610442825490565b6001600160a01b0384166111685760405162461bcd60e51b815260040161041490612441565b336000611174856116b9565b90506000611181856116b9565b905061119183898985858961139b565b60008681526002602090815260408083206001600160a01b038c168452909152902054858110156111d45760405162461bcd60e51b815260040161041490612486565b60008781526002602090815260408083206001600160a01b038d8116855292528083208985039055908a16825281208054889290611213908490612400565b909155505060408051888152602081018890526001600160a01b03808b16928c8216929188169160008051602061280b833981519152910160405180910390a4611261848a8a8a8a8a611704565b505050505050505050565b6001600160a01b0383166112925760405162461bcd60e51b8152600401610414906124d0565b33600061129e846116b9565b905060006112ab846116b9565b90506112cb8387600085856040518060200160405280600081525061139b565b60008581526002602090815260408083206001600160a01b038a1684529091529020548481101561130e5760405162461bcd60e51b815260040161041490612513565b60008681526002602090815260408083206001600160a01b038b81168086529184528285208a8703905582518b81529384018a905290929088169160008051602061280b833981519152910160405180910390a4604080516020810190915260009052611006565b60006001600160e01b03198216635a05180f60e01b148061044257506104428261182f565b610cfe868686868686611864565b6001600160a01b0384163b15610cfe5760405163bc197c8160e01b81526001600160a01b0385169063bc197c81906113ed9089908990889088908890600401612557565b6020604051808303816000875af1925050508015611428575060408051601f3d908101601f19168201909252611425918101906125b5565b60015b6114d4576114346125d2565b806308c379a00361146d57506114486125ee565b80611453575061146f565b8060405162461bcd60e51b81526004016104149190611c9d565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e2d455243313135356044820152732932b1b2b4bb32b91034b6b83632b6b2b73a32b960611b6064820152608401610414565b6001600160e01b0319811663bc197c8160e01b146110065760405162461bcd60e51b815260040161041490612677565b61150e82826108ea565b61061d5761151b816118cc565b6115268360206118de565b6040516020016115379291906126bf565b60408051601f198184030181529082905262461bcd60e51b825261041491600401611c9d565b61156782826108ea565b61061d576000828152602081815260408083206001600160a01b03851684529091529020805460ff1916600117905561159d3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60006108e3836001600160a01b038416611a79565b61160082826108ea565b1561061d576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60006108e3836001600160a01b038416611ac8565b60055460ff166106a15760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610414565b604080516001808252818301909252606091600091906020808301908036833701905050905082816000815181106116f3576116f3612332565b602090810291909101015292915050565b6001600160a01b0384163b15610cfe5760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e6190611748908990899088908890889060040161272e565b6020604051808303816000875af1925050508015611783575060408051601f3d908101601f19168201909252611780918101906125b5565b60015b61178f576114346125d2565b6001600160e01b0319811663f23a6e6160e01b146110065760405162461bcd60e51b815260040161041490612677565b60055460ff16156106a15760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610414565b600082600001828154811061181c5761181c612332565b9060005260206000200154905092915050565b60006001600160e01b03198216637965db0b60e01b148061044257506301ffc9a760e01b6001600160e01b0319831614610442565b60055460ff1615610cfe5760405162461bcd60e51b815260206004820152602c60248201527f455243313135355061757361626c653a20746f6b656e207472616e736665722060448201526b1dda1a5b19481c185d5cd95960a21b6064820152608401610414565b60606104426001600160a01b03831660145b606060006118ed836002612773565b6118f8906002612400565b6001600160401b0381111561190f5761190f611cb0565b6040519080825280601f01601f191660200182016040528015611939576020820181803683370190505b509050600360fc1b8160008151811061195457611954612332565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061198357611983612332565b60200101906001600160f81b031916908160001a90535060006119a7846002612773565b6119b2906001612400565b90505b6001811115611a2a576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106119e6576119e6612332565b1a60f81b8282815181106119fc576119fc612332565b60200101906001600160f81b031916908160001a90535060049490941c93611a238161278a565b90506119b5565b5083156108e35760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610414565b6000818152600183016020526040812054611ac057508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610442565b506000610442565b60008181526001830160205260408120548015611bb1576000611aec6001836127a1565b8554909150600090611b00906001906127a1565b9050818114611b65576000866000018281548110611b2057611b20612332565b9060005260206000200154905080876000018481548110611b4357611b43612332565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080611b7657611b766127b4565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610442565b6000915050610442565b80356001600160a01b0381168114611bd257600080fd5b919050565b60008060408385031215611bea57600080fd5b611bf383611bbb565b946020939093013593505050565b6001600160e01b031981168114610d1057600080fd5b600060208284031215611c2957600080fd5b81356108e381611c01565b600060208284031215611c4657600080fd5b5035919050565b60005b83811015611c68578181015183820152602001611c50565b50506000910152565b60008151808452611c89816020860160208601611c4d565b601f01601f19169290920160200192915050565b6020815260006108e36020830184611c71565b634e487b7160e01b600052604160045260246000fd5b601f8201601f191681016001600160401b0381118282101715611ceb57611ceb611cb0565b6040525050565b60006001600160401b03821115611d0b57611d0b611cb0565b5060051b60200190565b600082601f830112611d2657600080fd5b81356020611d3382611cf2565b604051611d408282611cc6565b83815260059390931b8501820192828101915086841115611d6057600080fd5b8286015b84811015611d7b5780358352918301918301611d64565b509695505050505050565b600082601f830112611d9757600080fd5b81356001600160401b03811115611db057611db0611cb0565b604051611dc7601f8301601f191660200182611cc6565b818152846020838601011115611ddc57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215611e0f57600080fd5b611e1885611bbb565b935060208501356001600160401b0380821115611e3457600080fd5b611e4088838901611d15565b94506040870135915080821115611e5657600080fd5b611e6288838901611d15565b93506060870135915080821115611e7857600080fd5b50611e8587828801611d86565b91505092959194509250565b600080600080600060a08688031215611ea957600080fd5b611eb286611bbb565b9450611ec060208701611bbb565b935060408601356001600160401b0380821115611edc57600080fd5b611ee889838a01611d15565b94506060880135915080821115611efe57600080fd5b611f0a89838a01611d15565b93506080880135915080821115611f2057600080fd5b50611f2d88828901611d86565b9150509295509295909350565b60008060408385031215611f4d57600080fd5b82359150611f5d60208401611bbb565b90509250929050565b60008060408385031215611f7957600080fd5b82356001600160401b0380821115611f9057600080fd5b818501915085601f830112611fa457600080fd5b81356020611fb182611cf2565b604051611fbe8282611cc6565b83815260059390931b8501820192828101915089841115611fde57600080fd5b948201945b8386101561200357611ff486611bbb565b82529482019490820190611fe3565b9650508601359250508082111561201957600080fd5b5061202685828601611d15565b9150509250929050565b600081518084526020808501945080840160005b8381101561206057815187529582019590820190600101612044565b509495945050505050565b6020815260006108e36020830184612030565b60008060006060848603121561209357600080fd5b61209c84611bbb565b925060208401356001600160401b03808211156120b857600080fd5b6120c487838801611d15565b935060408601359150808211156120da57600080fd5b506120e786828701611d15565b9150509250925092565b6000806000806080858703121561210757600080fd5b61211085611bbb565b9350602085013592506040850135915060608501356001600160401b0381111561213957600080fd5b611e8587828801611d86565b6000806040838503121561215857600080fd5b50508035926020909101359150565b6000806040838503121561217a57600080fd5b61218383611bbb565b91506020830135801515811461219857600080fd5b809150509250929050565b600080604083850312156121b657600080fd5b6121bf83611bbb565b9150611f5d60208401611bbb565b600080600080600060a086880312156121e557600080fd5b6121ee86611bbb565b94506121fc60208701611bbb565b9350604086013592506060860135915060808601356001600160401b0381111561222557600080fd5b611f2d88828901611d86565b60008060006060848603121561224657600080fd5b61224f84611bbb565b95602085013595506040909401359392505050565b600181811c9082168061227857607f821691505b60208210810361229857634e487b7160e01b600052602260045260246000fd5b50919050565b60208082526038908201526000805160206127eb8339815191526040820152771a185d99481b5a5b9d195c881c9bdb19481d1bc81b5a5b9d60421b606082015260800190565b6020808252602e908201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60408201526d195c881bdc88185c1c1c9bdd995960921b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001820161237057612370612348565b5060010190565b60208082526021908201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736040820152607360f81b606082015260800190565b60208082526028908201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206040820152670dad2e6dac2e8c6d60c31b606082015260800190565b8082018082111561044257610442612348565b6040815260006124266040830185612030565b82810360208401526124388185612030565b95945050505050565b60208082526025908201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604082015264647265737360d81b606082015260800190565b6020808252602a908201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60408201526939103a3930b739b332b960b11b606082015260800190565b60208082526023908201527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260408201526265737360e81b606082015260800190565b60208082526024908201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604082015263616e636560e01b606082015260800190565b6001600160a01b0386811682528516602082015260a06040820181905260009061258390830186612030565b82810360608401526125958186612030565b905082810360808401526125a98185611c71565b98975050505050505050565b6000602082840312156125c757600080fd5b81516108e381611c01565b600060033d11156125eb5760046000803e5060005160e01c5b90565b600060443d10156125fc5790565b6040516003193d81016004833e81513d6001600160401b03816024840111818411171561262b57505050505090565b82850191508151818111156126435750505050505090565b843d870101602082850101111561265d5750505050505090565b61266c60208286010187611cc6565b509095945050505050565b60208082526028908201527f455243313135353a204552433131353552656365697665722072656a656374656040820152676420746f6b656e7360c01b606082015260800190565b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b8152600083516126f1816017850160208801611c4d565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351612722816028840160208801611c4d565b01602801949350505050565b6001600160a01b03868116825285166020820152604081018490526060810183905260a06080820181905260009061276890830184611c71565b979650505050505050565b808202811582820484141761044257610442612348565b60008161279957612799612348565b506000190190565b8181038181111561044257610442612348565b634e487b7160e01b600052603160045260246000fdfe4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb455243313135355072657365744d696e7465725061757365723a206d75737420c3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6265d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6a2646970667358221220294efe154e549198ff0c6b7ab7e9846223d9e8fe7ae7de1938f6eb7d0f5e66a664736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var RootERC1155PredicateArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"RootERC1155Predicate\",\n \"sourceName\": \"contracts/root/RootERC1155Predicate.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"depositor\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"ERC1155Deposit\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"depositor\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"amounts\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"ERC1155DepositBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"withdrawer\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"ERC1155Withdraw\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"withdrawer\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"amounts\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"ERC1155WithdrawBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"TokenMapped\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAP_TOKEN_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childERC1155Predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childTokenTemplate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC1155MetadataURI\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"deposit\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC1155MetadataURI\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"amounts\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"depositBatch\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC1155MetadataURI\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"depositTo\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"exitHelper\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newStateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newExitHelper\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildERC1155Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IERC1155MetadataURI\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"mapToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onERC1155BatchReceived\",\n \"outputs\": [\n {\n \"internalType\": \"bytes4\",\n \"name\": \"\",\n \"type\": \"bytes4\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onERC1155Received\",\n \"outputs\": [\n {\n \"internalType\": \"bytes4\",\n \"name\": \"\",\n \"type\": \"bytes4\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onL2StateReceive\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"rootTokenToChildToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"stateSender\",\n \"outputs\": [\n {\n \"internalType\": \"contract IStateSender\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes4\",\n \"name\": \"interfaceId\",\n \"type\": \"bytes4\"\n }\n ],\n \"name\": \"supportsInterface\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50611bd2806100206000396000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c8063bc197c81116100ad578063f23a6e6111610071578063f23a6e61146102fe578063f43cda8b1461031d578063f4a120f714610330578063f645125514610343578063f8c8765e1461036a57600080fd5b8063bc197c8114610238578063c5ac2b1c14610270578063cb10f94c14610297578063d41f1771146102b0578063d7c9e3ec146102d757600080fd5b80637efab4f5116100f45780637efab4f5146101a157806395c7041c146101ca578063a78e111c146101dd578063b1768065146101f0578063b68ad1e41461022557600080fd5b806301ffc9a7146101265780630efe6a8b1461014e5780634c4c45de14610163578063654715e614610176575b600080fd5b610139610134366004611173565b61037d565b60405190151581526020015b60405180910390f35b61016161015c3660046111bc565b6103b4565b005b61016161017136600461123c565b6103c5565b600254610189906001600160a01b031681565b6040516001600160a01b039091168152602001610145565b6101896101af3660046112e8565b6004602052600090815260409020546001600160a01b031681565b600154610189906001600160a01b031681565b6101616101eb366004611305565b610448565b6102177f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b604051908152602001610145565b600354610189906001600160a01b031681565b610257610246366004611497565b63bc197c8160e01b95945050505050565b6040516001600160e01b03199091168152602001610145565b6102177faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b600054610189906201000090046001600160a01b031681565b6102177f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b6102177f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b61025761030c366004611544565b63f23a6e6160e01b95945050505050565b61016161032b3660046115ac565b61045a565b61018961033e3660046112e8565b610629565b6102177f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b610161610378366004611634565b610945565b60006001600160e01b03198216630271189760e51b14806103ae57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6103c083338484610b54565b505050565b84831480156103d357508481145b6104305760405162461bcd60e51b8152602060048201526024808201527f526f6f74455243313135355072656469636174653a20494e56414c49445f4c4560448201526309c8ea8960e31b60648201526084015b60405180910390fd5b61043f87878787878787610cec565b50505050505050565b61045484848484610b54565b50505050565b6001546001600160a01b031633146104c35760405162461bcd60e51b815260206004820152602660248201527f526f6f74455243313135355072656469636174653a204f4e4c595f455849545f6044820152652422a62822a960d11b6064820152608401610427565b6002546001600160a01b038481169116146105335760405162461bcd60e51b815260206004820152602a60248201527f526f6f74455243313135355072656469636174653a204f4e4c595f4348494c446044820152695f50524544494341544560b01b6064820152608401610427565b7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e982869610562602060008486611690565b61056b916116ba565b0361058a576105856105808260208186611690565b610ecc565b610454565b7f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed26105b9602060008486611690565b6105c2916116ba565b036105d1576105858282610fcb565b60405162461bcd60e51b815260206004820152602760248201527f526f6f74455243313135355072656469636174653a20494e56414c49445f5349604482015266474e415455524560c81b6064820152608401610427565b60006001600160a01b03821661068d5760405162461bcd60e51b815260206004820152602360248201527f526f6f74455243313135355072656469636174653a20494e56414c49445f544f60448201526225a2a760e91b6064820152608401610427565b6001600160a01b0382811660009081526004602052604090205416156107015760405162461bcd60e51b8152602060048201526024808201527f526f6f74455243313135355072656469636174653a20414c52454144595f4d416044820152631414115160e21b6064820152608401610427565b6002546003546040516bffffffffffffffffffffffff19606086901b1660208201526001600160a01b03928316926107ab921690603401604051602081830303815290604052805190602001208360405160388101919091526f5af43d82803e903d91602b57fd5bf3ff60248201526014810192909252733d602d80600a3d3981f3363d3d373d3d3d363d73825260588201526037600c8201206078820152605560439091012090565b6001600160a01b03848116600081815260046020818152604080842080546001600160a01b031916968816969096179095558451908101855282815293516303a24d0760e21b8152908101919091529294509091630e89341c90602401600060405180830381865afa92505050801561084657506040513d6000823e601f3d908101601f1916820160405261084391908101906116fc565b60015b1561084e5790505b600060029054906101000a90046001600160a01b03166001600160a01b03166316f19831837f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad87856040516020016108a89392919061179e565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016108d49291906117c8565b600060405180830381600087803b1580156108ee57600080fd5b505af1158015610902573d6000803e3d6000fd5b50506040516001600160a01b038087169350871691507f85920d35e6c72f6b2affffa04298b0cecfeba86e4a9f407df661f1cb8ab5e61790600090a35050919050565b600054610100900460ff16158080156109655750600054600160ff909116105b8061097f5750303b15801561097f575060005460ff166001145b6109e25760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610427565b6000805460ff191660011790558015610a05576000805461ff0019166101001790555b6001600160a01b03851615801590610a2557506001600160a01b03841615155b8015610a3957506001600160a01b03831615155b8015610a4d57506001600160a01b03821615155b610aaa5760405162461bcd60e51b815260206004820152602860248201527f526f6f74455243313135355072656469636174653a204241445f494e495449416044820152672624ad20aa24a7a760c11b6064820152608401610427565b6000805462010000600160b01b031916620100006001600160a01b038881169190910291909117909155600180546001600160a01b031990811687841617909155600280548216868416179055600380549091169184169190911790558015610b4d576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b6000610b5f8561112c565b604051637921219560e11b81529091506001600160a01b0386169063f242432a90610b949033903090889088906004016117f4565b600060405180830381600087803b158015610bae57600080fd5b505af1158015610bc2573d6000803e3d6000fd5b5050600054600254604080517f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82160208201526001600160a01b038b8116828401523360608301528a8116608083015260a082018a905260c08083018a90528351808403909101815260e08301938490526316f1983160e01b90935262010000909404841695506316f198319450610c5f939092169160e4016117c8565b600060405180830381600087803b158015610c7957600080fd5b505af1158015610c8d573d6000803e3d6000fd5b505060408051338152602081018790529081018590526001600160a01b03808816935084811692508816907fbcbdf0c69f975f2a4085544938b054f02e77e87cbd055146d388c0be7120e04f9060600160405180910390a45050505050565b6000610cf78861112c565b905060005b84811015610da357886001600160a01b031663f242432a3330898986818110610d2757610d2761182c565b90506020020135888887818110610d4057610d4061182c565b905060200201356040518563ffffffff1660e01b8152600401610d6694939291906117f4565b600060405180830381600087803b158015610d8057600080fd5b505af1158015610d94573d6000803e3d6000fd5b50505050806001019050610cfc565b506000546002546040516001600160a01b03620100009093048316926316f19831921690610e05907faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d18908d9033908e908e908e908e908e908e906020016118bd565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610e319291906117c8565b600060405180830381600087803b158015610e4b57600080fd5b505af1158015610e5f573d6000803e3d6000fd5b50505050336001600160a01b0316816001600160a01b0316896001600160a01b03167f7e8ab6f25cb177d65db49b7a2197bb2a7df5757434857d411e2523b332a913e68a8a8a8a8a8a604051610eba96959493929190611928565b60405180910390a45050505050505050565b600080808080610ede86880188611971565b6001600160a01b03808616600090815260046020526040902054959a50939850919650945092501680610f1357610f136119cc565b604051637921219560e11b81526001600160a01b0387169063f242432a90610f459030908890889088906004016117f4565b600060405180830381600087803b158015610f5f57600080fd5b505af1158015610f73573d6000803e3d6000fd5b5050604080516001600160a01b0389811682526020820188905291810186905281881693508482169250908916907fc42752949ca07109e6f25adcde4a9407be23e084b1d32ca2bce8aa55bf3dd62590606001610eba565b600080808080610fdd868801886119e2565b6001600160a01b03808616600090815260046020526040902054959b509399509197509550935016905080611014576110146119cc565b60005b83518110156110da57866001600160a01b031663f242432a308784815181106110425761104261182c565b602002602001015187858151811061105c5761105c61182c565b60200260200101518786815181106110765761107661182c565b60200260200101516040518563ffffffff1660e01b815260040161109d94939291906117f4565b600060405180830381600087803b1580156110b757600080fd5b505af11580156110cb573d6000803e3d6000fd5b50505050806001019050611017565b50846001600160a01b0316816001600160a01b0316876001600160a01b03167fce612e98b81c726375e7c2395409e74ee0a29b22f7641ea5a8ce8508616448c0878787604051610eba93929190611b27565b6001600160a01b0380821660009081526004602052604090205416806111585761115582610629565b90505b6001600160a01b03811661116e5761116e6119cc565b919050565b60006020828403121561118557600080fd5b81356001600160e01b03198116811461119d57600080fd5b9392505050565b6001600160a01b03811681146111b957600080fd5b50565b6000806000606084860312156111d157600080fd5b83356111dc816111a4565b95602085013595506040909401359392505050565b60008083601f84011261120357600080fd5b5081356001600160401b0381111561121a57600080fd5b6020830191508360208260051b850101111561123557600080fd5b9250929050565b60008060008060008060006080888a03121561125757600080fd5b8735611262816111a4565b965060208801356001600160401b038082111561127e57600080fd5b61128a8b838c016111f1565b909850965060408a01359150808211156112a357600080fd5b6112af8b838c016111f1565b909650945060608a01359150808211156112c857600080fd5b506112d58a828b016111f1565b989b979a50959850939692959293505050565b6000602082840312156112fa57600080fd5b813561119d816111a4565b6000806000806080858703121561131b57600080fd5b8435611326816111a4565b93506020850135611336816111a4565b93969395505050506040820135916060013590565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156113895761138961134b565b604052919050565b60006001600160401b038211156113aa576113aa61134b565b5060051b60200190565b600082601f8301126113c557600080fd5b813560206113da6113d583611391565b611361565b82815260059290921b840181019181810190868411156113f957600080fd5b8286015b8481101561141457803583529183019183016113fd565b509695505050505050565b60006001600160401b038211156114385761143861134b565b50601f01601f191660200190565b600082601f83011261145757600080fd5b81356114656113d58261141f565b81815284602083860101111561147a57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a086880312156114af57600080fd5b85356114ba816111a4565b945060208601356114ca816111a4565b935060408601356001600160401b03808211156114e657600080fd5b6114f289838a016113b4565b9450606088013591508082111561150857600080fd5b61151489838a016113b4565b9350608088013591508082111561152a57600080fd5b5061153788828901611446565b9150509295509295909350565b600080600080600060a0868803121561155c57600080fd5b8535611567816111a4565b94506020860135611577816111a4565b9350604086013592506060860135915060808601356001600160401b038111156115a057600080fd5b61153788828901611446565b600080600080606085870312156115c257600080fd5b8435935060208501356115d4816111a4565b925060408501356001600160401b03808211156115f057600080fd5b818701915087601f83011261160457600080fd5b81358181111561161357600080fd5b88602082850101111561162557600080fd5b95989497505060200194505050565b6000806000806080858703121561164a57600080fd5b8435611655816111a4565b93506020850135611665816111a4565b92506040850135611675816111a4565b91506060850135611685816111a4565b939692955090935050565b600080858511156116a057600080fd5b838611156116ad57600080fd5b5050820193919092039150565b803560208310156103ae57600019602084900360031b1b1692915050565b60005b838110156116f35781810151838201526020016116db565b50506000910152565b60006020828403121561170e57600080fd5b81516001600160401b0381111561172457600080fd5b8201601f8101841361173557600080fd5b80516117436113d58261141f565b81815285602083850101111561175857600080fd5b6117698260208301602086016116d8565b95945050505050565b6000815180845261178a8160208601602086016116d8565b601f01601f19169290920160200192915050565b8381526001600160a01b038316602082015260606040820181905260009061176990830184611772565b6001600160a01b03831681526040602082018190526000906117ec90830184611772565b949350505050565b6001600160a01b0394851681529290931660208301526040820152606081019190915260a06080820181905260009082015260c00190565b634e487b7160e01b600052603260045260246000fd5b8183526000602080850194508260005b85811015611880578135611865816111a4565b6001600160a01b031687529582019590820190600101611852565b509495945050505050565b81835260006001600160fb1b038311156118a457600080fd5b8260051b80836020870137939093016020019392505050565b8981526001600160a01b0389811660208301528816604082015260c0606082018190526000906118f0908301888a611842565b828103608084015261190381878961188b565b905082810360a084015261191881858761188b565b9c9b505050505050505050505050565b60608152600061193c60608301888a611842565b828103602084015261194f81878961188b565b9050828103604084015261196481858761188b565b9998505050505050505050565b600080600080600060a0868803121561198957600080fd5b8535611994816111a4565b945060208601356119a4816111a4565b935060408601356119b4816111a4565b94979396509394606081013594506080013592915050565b634e487b7160e01b600052600160045260246000fd5b60008060008060008060c087890312156119fb57600080fd5b86359550602080880135611a0e816111a4565b95506040880135611a1e816111a4565b945060608801356001600160401b0380821115611a3a57600080fd5b818a0191508a601f830112611a4e57600080fd5b8135611a5c6113d582611391565b81815260059190911b8301840190848101908d831115611a7b57600080fd5b938501935b82851015611aa2578435611a93816111a4565b82529385019390850190611a80565b9750505060808a0135925080831115611aba57600080fd5b611ac68b848c016113b4565b945060a08a0135925080831115611adc57600080fd5b5050611aea89828a016113b4565b9150509295509295509295565b600081518084526020808501945080840160005b8381101561188057815187529582019590820190600101611b0b565b606080825284519082018190526000906020906080840190828801845b82811015611b695781516001600160a01b031684529284019290840190600101611b44565b50505083810382850152611b7d8187611af7565b9150508281036040840152611b928185611af7565b969550505050505056fea264697066735822122005fb54218b08fc0f9fa24d9c92ec93ef996fd7628635e6083aa645b236dbb08864736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101215760003560e01c8063bc197c81116100ad578063f23a6e6111610071578063f23a6e61146102fe578063f43cda8b1461031d578063f4a120f714610330578063f645125514610343578063f8c8765e1461036a57600080fd5b8063bc197c8114610238578063c5ac2b1c14610270578063cb10f94c14610297578063d41f1771146102b0578063d7c9e3ec146102d757600080fd5b80637efab4f5116100f45780637efab4f5146101a157806395c7041c146101ca578063a78e111c146101dd578063b1768065146101f0578063b68ad1e41461022557600080fd5b806301ffc9a7146101265780630efe6a8b1461014e5780634c4c45de14610163578063654715e614610176575b600080fd5b610139610134366004611173565b61037d565b60405190151581526020015b60405180910390f35b61016161015c3660046111bc565b6103b4565b005b61016161017136600461123c565b6103c5565b600254610189906001600160a01b031681565b6040516001600160a01b039091168152602001610145565b6101896101af3660046112e8565b6004602052600090815260409020546001600160a01b031681565b600154610189906001600160a01b031681565b6101616101eb366004611305565b610448565b6102177f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b604051908152602001610145565b600354610189906001600160a01b031681565b610257610246366004611497565b63bc197c8160e01b95945050505050565b6040516001600160e01b03199091168152602001610145565b6102177faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b600054610189906201000090046001600160a01b031681565b6102177f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b6102177f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b61025761030c366004611544565b63f23a6e6160e01b95945050505050565b61016161032b3660046115ac565b61045a565b61018961033e3660046112e8565b610629565b6102177f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b610161610378366004611634565b610945565b60006001600160e01b03198216630271189760e51b14806103ae57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6103c083338484610b54565b505050565b84831480156103d357508481145b6104305760405162461bcd60e51b8152602060048201526024808201527f526f6f74455243313135355072656469636174653a20494e56414c49445f4c4560448201526309c8ea8960e31b60648201526084015b60405180910390fd5b61043f87878787878787610cec565b50505050505050565b61045484848484610b54565b50505050565b6001546001600160a01b031633146104c35760405162461bcd60e51b815260206004820152602660248201527f526f6f74455243313135355072656469636174653a204f4e4c595f455849545f6044820152652422a62822a960d11b6064820152608401610427565b6002546001600160a01b038481169116146105335760405162461bcd60e51b815260206004820152602a60248201527f526f6f74455243313135355072656469636174653a204f4e4c595f4348494c446044820152695f50524544494341544560b01b6064820152608401610427565b7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e982869610562602060008486611690565b61056b916116ba565b0361058a576105856105808260208186611690565b610ecc565b610454565b7f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed26105b9602060008486611690565b6105c2916116ba565b036105d1576105858282610fcb565b60405162461bcd60e51b815260206004820152602760248201527f526f6f74455243313135355072656469636174653a20494e56414c49445f5349604482015266474e415455524560c81b6064820152608401610427565b60006001600160a01b03821661068d5760405162461bcd60e51b815260206004820152602360248201527f526f6f74455243313135355072656469636174653a20494e56414c49445f544f60448201526225a2a760e91b6064820152608401610427565b6001600160a01b0382811660009081526004602052604090205416156107015760405162461bcd60e51b8152602060048201526024808201527f526f6f74455243313135355072656469636174653a20414c52454144595f4d416044820152631414115160e21b6064820152608401610427565b6002546003546040516bffffffffffffffffffffffff19606086901b1660208201526001600160a01b03928316926107ab921690603401604051602081830303815290604052805190602001208360405160388101919091526f5af43d82803e903d91602b57fd5bf3ff60248201526014810192909252733d602d80600a3d3981f3363d3d373d3d3d363d73825260588201526037600c8201206078820152605560439091012090565b6001600160a01b03848116600081815260046020818152604080842080546001600160a01b031916968816969096179095558451908101855282815293516303a24d0760e21b8152908101919091529294509091630e89341c90602401600060405180830381865afa92505050801561084657506040513d6000823e601f3d908101601f1916820160405261084391908101906116fc565b60015b1561084e5790505b600060029054906101000a90046001600160a01b03166001600160a01b03166316f19831837f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad87856040516020016108a89392919061179e565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016108d49291906117c8565b600060405180830381600087803b1580156108ee57600080fd5b505af1158015610902573d6000803e3d6000fd5b50506040516001600160a01b038087169350871691507f85920d35e6c72f6b2affffa04298b0cecfeba86e4a9f407df661f1cb8ab5e61790600090a35050919050565b600054610100900460ff16158080156109655750600054600160ff909116105b8061097f5750303b15801561097f575060005460ff166001145b6109e25760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610427565b6000805460ff191660011790558015610a05576000805461ff0019166101001790555b6001600160a01b03851615801590610a2557506001600160a01b03841615155b8015610a3957506001600160a01b03831615155b8015610a4d57506001600160a01b03821615155b610aaa5760405162461bcd60e51b815260206004820152602860248201527f526f6f74455243313135355072656469636174653a204241445f494e495449416044820152672624ad20aa24a7a760c11b6064820152608401610427565b6000805462010000600160b01b031916620100006001600160a01b038881169190910291909117909155600180546001600160a01b031990811687841617909155600280548216868416179055600380549091169184169190911790558015610b4d576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b6000610b5f8561112c565b604051637921219560e11b81529091506001600160a01b0386169063f242432a90610b949033903090889088906004016117f4565b600060405180830381600087803b158015610bae57600080fd5b505af1158015610bc2573d6000803e3d6000fd5b5050600054600254604080517f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82160208201526001600160a01b038b8116828401523360608301528a8116608083015260a082018a905260c08083018a90528351808403909101815260e08301938490526316f1983160e01b90935262010000909404841695506316f198319450610c5f939092169160e4016117c8565b600060405180830381600087803b158015610c7957600080fd5b505af1158015610c8d573d6000803e3d6000fd5b505060408051338152602081018790529081018590526001600160a01b03808816935084811692508816907fbcbdf0c69f975f2a4085544938b054f02e77e87cbd055146d388c0be7120e04f9060600160405180910390a45050505050565b6000610cf78861112c565b905060005b84811015610da357886001600160a01b031663f242432a3330898986818110610d2757610d2761182c565b90506020020135888887818110610d4057610d4061182c565b905060200201356040518563ffffffff1660e01b8152600401610d6694939291906117f4565b600060405180830381600087803b158015610d8057600080fd5b505af1158015610d94573d6000803e3d6000fd5b50505050806001019050610cfc565b506000546002546040516001600160a01b03620100009093048316926316f19831921690610e05907faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d18908d9033908e908e908e908e908e908e906020016118bd565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610e319291906117c8565b600060405180830381600087803b158015610e4b57600080fd5b505af1158015610e5f573d6000803e3d6000fd5b50505050336001600160a01b0316816001600160a01b0316896001600160a01b03167f7e8ab6f25cb177d65db49b7a2197bb2a7df5757434857d411e2523b332a913e68a8a8a8a8a8a604051610eba96959493929190611928565b60405180910390a45050505050505050565b600080808080610ede86880188611971565b6001600160a01b03808616600090815260046020526040902054959a50939850919650945092501680610f1357610f136119cc565b604051637921219560e11b81526001600160a01b0387169063f242432a90610f459030908890889088906004016117f4565b600060405180830381600087803b158015610f5f57600080fd5b505af1158015610f73573d6000803e3d6000fd5b5050604080516001600160a01b0389811682526020820188905291810186905281881693508482169250908916907fc42752949ca07109e6f25adcde4a9407be23e084b1d32ca2bce8aa55bf3dd62590606001610eba565b600080808080610fdd868801886119e2565b6001600160a01b03808616600090815260046020526040902054959b509399509197509550935016905080611014576110146119cc565b60005b83518110156110da57866001600160a01b031663f242432a308784815181106110425761104261182c565b602002602001015187858151811061105c5761105c61182c565b60200260200101518786815181106110765761107661182c565b60200260200101516040518563ffffffff1660e01b815260040161109d94939291906117f4565b600060405180830381600087803b1580156110b757600080fd5b505af11580156110cb573d6000803e3d6000fd5b50505050806001019050611017565b50846001600160a01b0316816001600160a01b0316876001600160a01b03167fce612e98b81c726375e7c2395409e74ee0a29b22f7641ea5a8ce8508616448c0878787604051610eba93929190611b27565b6001600160a01b0380821660009081526004602052604090205416806111585761115582610629565b90505b6001600160a01b03811661116e5761116e6119cc565b919050565b60006020828403121561118557600080fd5b81356001600160e01b03198116811461119d57600080fd5b9392505050565b6001600160a01b03811681146111b957600080fd5b50565b6000806000606084860312156111d157600080fd5b83356111dc816111a4565b95602085013595506040909401359392505050565b60008083601f84011261120357600080fd5b5081356001600160401b0381111561121a57600080fd5b6020830191508360208260051b850101111561123557600080fd5b9250929050565b60008060008060008060006080888a03121561125757600080fd5b8735611262816111a4565b965060208801356001600160401b038082111561127e57600080fd5b61128a8b838c016111f1565b909850965060408a01359150808211156112a357600080fd5b6112af8b838c016111f1565b909650945060608a01359150808211156112c857600080fd5b506112d58a828b016111f1565b989b979a50959850939692959293505050565b6000602082840312156112fa57600080fd5b813561119d816111a4565b6000806000806080858703121561131b57600080fd5b8435611326816111a4565b93506020850135611336816111a4565b93969395505050506040820135916060013590565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156113895761138961134b565b604052919050565b60006001600160401b038211156113aa576113aa61134b565b5060051b60200190565b600082601f8301126113c557600080fd5b813560206113da6113d583611391565b611361565b82815260059290921b840181019181810190868411156113f957600080fd5b8286015b8481101561141457803583529183019183016113fd565b509695505050505050565b60006001600160401b038211156114385761143861134b565b50601f01601f191660200190565b600082601f83011261145757600080fd5b81356114656113d58261141f565b81815284602083860101111561147a57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a086880312156114af57600080fd5b85356114ba816111a4565b945060208601356114ca816111a4565b935060408601356001600160401b03808211156114e657600080fd5b6114f289838a016113b4565b9450606088013591508082111561150857600080fd5b61151489838a016113b4565b9350608088013591508082111561152a57600080fd5b5061153788828901611446565b9150509295509295909350565b600080600080600060a0868803121561155c57600080fd5b8535611567816111a4565b94506020860135611577816111a4565b9350604086013592506060860135915060808601356001600160401b038111156115a057600080fd5b61153788828901611446565b600080600080606085870312156115c257600080fd5b8435935060208501356115d4816111a4565b925060408501356001600160401b03808211156115f057600080fd5b818701915087601f83011261160457600080fd5b81358181111561161357600080fd5b88602082850101111561162557600080fd5b95989497505060200194505050565b6000806000806080858703121561164a57600080fd5b8435611655816111a4565b93506020850135611665816111a4565b92506040850135611675816111a4565b91506060850135611685816111a4565b939692955090935050565b600080858511156116a057600080fd5b838611156116ad57600080fd5b5050820193919092039150565b803560208310156103ae57600019602084900360031b1b1692915050565b60005b838110156116f35781810151838201526020016116db565b50506000910152565b60006020828403121561170e57600080fd5b81516001600160401b0381111561172457600080fd5b8201601f8101841361173557600080fd5b80516117436113d58261141f565b81815285602083850101111561175857600080fd5b6117698260208301602086016116d8565b95945050505050565b6000815180845261178a8160208601602086016116d8565b601f01601f19169290920160200192915050565b8381526001600160a01b038316602082015260606040820181905260009061176990830184611772565b6001600160a01b03831681526040602082018190526000906117ec90830184611772565b949350505050565b6001600160a01b0394851681529290931660208301526040820152606081019190915260a06080820181905260009082015260c00190565b634e487b7160e01b600052603260045260246000fd5b8183526000602080850194508260005b85811015611880578135611865816111a4565b6001600160a01b031687529582019590820190600101611852565b509495945050505050565b81835260006001600160fb1b038311156118a457600080fd5b8260051b80836020870137939093016020019392505050565b8981526001600160a01b0389811660208301528816604082015260c0606082018190526000906118f0908301888a611842565b828103608084015261190381878961188b565b905082810360a084015261191881858761188b565b9c9b505050505050505050505050565b60608152600061193c60608301888a611842565b828103602084015261194f81878961188b565b9050828103604084015261196481858761188b565b9998505050505050505050565b600080600080600060a0868803121561198957600080fd5b8535611994816111a4565b945060208601356119a4816111a4565b935060408601356119b4816111a4565b94979396509394606081013594506080013592915050565b634e487b7160e01b600052600160045260246000fd5b60008060008060008060c087890312156119fb57600080fd5b86359550602080880135611a0e816111a4565b95506040880135611a1e816111a4565b945060608801356001600160401b0380821115611a3a57600080fd5b818a0191508a601f830112611a4e57600080fd5b8135611a5c6113d582611391565b81815260059190911b8301840190848101908d831115611a7b57600080fd5b938501935b82851015611aa2578435611a93816111a4565b82529385019390850190611a80565b9750505060808a0135925080831115611aba57600080fd5b611ac68b848c016113b4565b945060a08a0135925080831115611adc57600080fd5b5050611aea89828a016113b4565b9150509295509295509295565b600081518084526020808501945080840160005b8381101561188057815187529582019590820190600101611b0b565b606080825284519082018190526000906020906080840190828801845b82811015611b695781516001600160a01b031684529284019290840190600101611b44565b50505083810382850152611b7d8187611af7565b9150508281036040840152611b928185611af7565b969550505050505056fea264697066735822122005fb54218b08fc0f9fa24d9c92ec93ef996fd7628635e6083aa645b236dbb08864736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var ChildMintableERC1155PredicateArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"ChildMintableERC1155Predicate\",\n \"sourceName\": \"contracts/root/ChildMintableERC1155Predicate.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"MintableERC1155Deposit\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"amounts\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"MintableERC1155DepositBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"MintableERC1155Withdraw\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"amounts\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"MintableERC1155WithdrawBatch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"rootToken\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"MintableTokenMapped\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"DEPOSIT_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"MAP_TOKEN_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_BATCH_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAW_SIG\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childTokenTemplate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"exitHelper\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newStateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newExitHelper\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newRootERC1155Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildTokenTemplate\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onL2StateReceive\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"rootERC1155Predicate\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"rootTokenToChildToken\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"stateSender\",\n \"outputs\": [\n {\n \"internalType\": \"contract IStateSender\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC1155\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"withdraw\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC1155\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address[]\",\n \"name\": \"receivers\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"tokenIds\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"amounts\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"withdrawBatch\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC1155\",\n \"name\": \"childToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"receiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"tokenId\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"withdrawTo\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50611f7c806100206000396000f3fe608060405234801561001057600080fd5b50600436106100d55760003560e01c8063b8cd3ec011610087578063b8cd3ec0146101b6578063c5ac2b1c146101c9578063cb10f94c146101f0578063d41f177114610209578063d7c9e3ec14610230578063f43cda8b14610257578063f64512551461026a578063f8c8765e1461029157600080fd5b8063051eb2e2146100da5780637efab4f51461010a57806386937eb41461013357806395c7041c14610148578063b17680651461015b578063b5c5f67214610190578063b68ad1e4146101a3575b600080fd5b6002546100ed906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6100ed610118366004611564565b6004602052600090815260409020546001600160a01b031681565b6101466101413660046115d3565b6102a4565b005b6001546100ed906001600160a01b031681565b6101827f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b604051908152602001610101565b61014661019e36600461167f565b6102bc565b6003546100ed906001600160a01b031681565b6101466101c43660046116b4565b6102cd565b6101827faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b6000546100ed906201000090046001600160a01b031681565b6101827f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b6101827f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b6101466102653660046116fa565b6102df565b6101827f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b61014661029f366004611782565b610514565b6102b38787878787878761062d565b50505050505050565b6102c8833384846109ba565b505050565b6102d9848484846109ba565b50505050565b6001546001600160a01b031633146103565760405162461bcd60e51b815260206004820152602f60248201527f4368696c644d696e7461626c65455243313135355072656469636174653a204f60448201526e27262cafa2ac24aa2fa422a62822a960891b60648201526084015b60405180910390fd5b6002546001600160a01b038481169116146103ce5760405162461bcd60e51b815260206004820152603260248201527f4368696c644d696e7461626c65455243313135355072656469636174653a204f6044820152714e4c595f524f4f545f50524544494341544560701b606482015260840161034d565b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f8216103fd6020600084866117de565b61040691611808565b036104255761042061041b82602081866117de565b610cd5565b6102d9565b7faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d186104546020600084866117de565b61045d91611808565b0361046c576104208282610f40565b7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad61049b6020600084866117de565b6104a491611808565b036104b35761042082826111ad565b60405162461bcd60e51b815260206004820152603060248201527f4368696c644d696e7461626c65455243313135355072656469636174653a204960448201526f4e56414c49445f5349474e415455524560801b606482015260840161034d565b600054610100900460ff16158080156105345750600054600160ff909116105b8061054e5750303b15801561054e575060005460ff166001145b6105b15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161034d565b6000805460ff1916600117905580156105d4576000805461ff0019166101001790555b6105e085858585611317565b8015610626576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b8661063781611420565b6106535760405162461bcd60e51b815260040161034d90611826565b6000886001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610693573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106b79190611871565b6001600160a01b038181166000908152600460205260409020549192508a81169116146106f65760405162461bcd60e51b815260040161034d9061188e565b6001600160a01b03811661070c5761070c6118db565b306001600160a01b0316896001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610754573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107789190611871565b6001600160a01b03161461078e5761078e6118db565b868514801561079c57508483145b6107fe5760405162461bcd60e51b815260206004820152602d60248201527f4368696c644d696e7461626c65455243313135355072656469636174653a204960448201526c09cac82989288be988a9c8ea89609b1b606482015260840161034d565b604051631ac8311560e21b81526001600160a01b038a1690636b20c454906108329033908a908a908a908a90600401611923565b6020604051808303816000875af1158015610851573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108759190611967565b6108915760405162461bcd60e51b815260040161034d90611989565b6000546002546040516001600160a01b03620100009093048316926316f198319216906108f2907f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed290869033908f908f908f908f908f908f90602001611a1c565b6040516020818303038152906040526040518363ffffffff1660e01b815260040161091e929190611acd565b600060405180830381600087803b15801561093857600080fd5b505af115801561094c573d6000803e3d6000fd5b50505050336001600160a01b0316896001600160a01b0316826001600160a01b03167fdd47868997765508c515e1f8ca079846dafbdfd8f98f6e76bca0891810b9f9d18b8b8b8b8b8b6040516109a796959493929190611af9565b60405180910390a4505050505050505050565b836109c481611420565b6109e05760405162461bcd60e51b815260040161034d90611826565b6000856001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a449190611871565b6001600160a01b03818116600090815260046020526040902054919250878116911614610a835760405162461bcd60e51b815260040161034d9061188e565b6001600160a01b038116610a9957610a996118db565b306001600160a01b0316866001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ae1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b059190611871565b6001600160a01b031614610b1b57610b1b6118db565b604051637a94c56560e11b81526001600160a01b0387169063f5298aca90610b4b90339088908890600401611b42565b6020604051808303816000875af1158015610b6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8e9190611967565b610baa5760405162461bcd60e51b815260040161034d90611989565b600054600254604080517f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286960208201526001600160a01b0385811682840152336060830152898116608083015260a0820189905260c08083018990528351808403909101815260e08301938490526316f1983160e01b909352620100009094048416936316f1983193610c429391169160e401611acd565b600060405180830381600087803b158015610c5c57600080fd5b505af1158015610c70573d6000803e3d6000fd5b50505050846001600160a01b0316866001600160a01b0316826001600160a01b03167fda58d73e08ba3c7767de904e68d208be8291494a9faaf70a6d4f736d24ec1f0f338888604051610cc593929190611b42565b60405180910390a4505050505050565b600080808080610ce786880188611b63565b6001600160a01b03808616600090815260046020526040902054959a50939850919650945092501680610d2c5760405162461bcd60e51b815260040161034d9061188e565b610d3581611420565b610d4157610d416118db565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da59190611871565b9050866001600160a01b0316816001600160a01b031614610dc857610dc86118db565b6001600160a01b038116610dde57610dde6118db565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e4a9190611871565b6001600160a01b031614610e6057610e606118db565b604051630ab714fb60e11b81526001600160a01b0383169063156e29f690610e9090889088908890600401611b42565b6020604051808303816000875af1158015610eaf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ed39190611967565b610eef5760405162461bcd60e51b815260040161034d90611bbe565b846001600160a01b0316826001600160a01b0316886001600160a01b03167f76a4cd47013e7e58abe817eedbb692d1614d71080b527412ebfb3f91a085a6de8988886040516109a793929190611b42565b600080808080610f5286880188611cdc565b6001600160a01b03808616600090815260046020526040902054959b509399509197509550935016905080610f995760405162461bcd60e51b815260040161034d9061188e565b610fa281611420565b610fae57610fae6118db565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110129190611871565b9050866001600160a01b0316816001600160a01b031614611035576110356118db565b6001600160a01b03811661104b5761104b6118db565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015611093573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b79190611871565b6001600160a01b0316146110cd576110cd6118db565b604051635712868360e01b81526001600160a01b038316906357128683906110fd90889088908890600401611e21565b6020604051808303816000875af115801561111c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111409190611967565b61115c5760405162461bcd60e51b815260040161034d90611bbe565b856001600160a01b0316826001600160a01b0316886001600160a01b03167fc244cac13e0edc863dc5a2c3bd2b935f605b2ed225fb052eaef869bc24b76fde8888886040516109a793929190611e21565b6000806111bc83850185611e96565b9093509150506001600160a01b0382166111d8576111d86118db565b6001600160a01b038281166000908152600460205260409020541615611200576112006118db565b6003546040516bffffffffffffffffffffffff19606085901b166020820152600091611250916001600160a01b0390911690603401604051602081830303815290604052805190602001206114b5565b6001600160a01b0384811660009081526004602081905260409182902080546001600160a01b031916938516938417905590516379ccf11760e11b8152929350909163f399e22e916112a6918791879101611acd565b600060405180830381600087803b1580156112c057600080fd5b505af11580156112d4573d6000803e3d6000fd5b50506040516001600160a01b038085169350861691507f0a1eaf9aa124c3f84c9dd77f7016af0f16f67639abb913af1697387db01f5ca590600090a35050505050565b6001600160a01b0384161580159061133757506001600160a01b03831615155b801561134b57506001600160a01b03821615155b801561135f57506001600160a01b03811615155b6113c55760405162461bcd60e51b815260206004820152603160248201527f4368696c644d696e7461626c65455243313135355072656469636174653a204260448201527020a22fa4a724aa24a0a624ad20aa24a7a760791b606482015260840161034d565b600080546001600160a01b03958616620100000262010000600160b01b0319909116179055600180549385166001600160a01b0319948516179055600280549285169284169290921790915560038054919093169116179055565b6000816001600160a01b03163b60000361143c57506000919050565b6040516301ffc9a760e01b8152636cdb3d1360e11b60048201526001600160a01b038316906301ffc9a790602401602060405180830381865afa9250505080156114a3575060408051601f3d908101601f191682019092526114a091810190611967565b60015b6114af57506000919050565b92915050565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b0381166114af5760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b604482015260640161034d565b6001600160a01b038116811461156157600080fd5b50565b60006020828403121561157657600080fd5b81356115818161154c565b9392505050565b60008083601f84011261159a57600080fd5b5081356001600160401b038111156115b157600080fd5b6020830191508360208260051b85010111156115cc57600080fd5b9250929050565b60008060008060008060006080888a0312156115ee57600080fd5b87356115f98161154c565b965060208801356001600160401b038082111561161557600080fd5b6116218b838c01611588565b909850965060408a013591508082111561163a57600080fd5b6116468b838c01611588565b909650945060608a013591508082111561165f57600080fd5b5061166c8a828b01611588565b989b979a50959850939692959293505050565b60008060006060848603121561169457600080fd5b833561169f8161154c565b95602085013595506040909401359392505050565b600080600080608085870312156116ca57600080fd5b84356116d58161154c565b935060208501356116e58161154c565b93969395505050506040820135916060013590565b6000806000806060858703121561171057600080fd5b8435935060208501356117228161154c565b925060408501356001600160401b038082111561173e57600080fd5b818701915087601f83011261175257600080fd5b81358181111561176157600080fd5b88602082850101111561177357600080fd5b95989497505060200194505050565b6000806000806080858703121561179857600080fd5b84356117a38161154c565b935060208501356117b38161154c565b925060408501356117c38161154c565b915060608501356117d38161154c565b939692955090935050565b600080858511156117ee57600080fd5b838611156117fb57600080fd5b5050820193919092039150565b803560208310156114af57600019602084900360031b1b1692915050565b6020808252602b908201527f4368696c644d696e7461626c65455243313135355072656469636174653a204e60408201526a13d517d0d3d395149050d560aa1b606082015260800190565b60006020828403121561188357600080fd5b81516115818161154c565b6020808252602d908201527f4368696c644d696e7461626c65455243313135355072656469636174653a205560408201526c2726a0a82822a22faa27a5a2a760991b606082015260800190565b634e487b7160e01b600052600160045260246000fd5b81835260006001600160fb1b0383111561190a57600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b038616815260606020820181905260009061194890830186886118f1565b828103604084015261195b8185876118f1565b98975050505050505050565b60006020828403121561197957600080fd5b8151801515811461158157600080fd5b6020808252602a908201527f4368696c644d696e7461626c65455243313135355072656469636174653a204260408201526915549397d1905253115160b21b606082015260800190565b8183526000602080850194508260005b85811015611a115781356119f68161154c565b6001600160a01b0316875295820195908201906001016119e3565b509495945050505050565b8981526001600160a01b0389811660208301528816604082015260c060608201819052600090611a4f908301888a6119d3565b8281036080840152611a628187896118f1565b905082810360a0840152611a778185876118f1565b9c9b505050505050505050505050565b6000815180845260005b81811015611aad57602081850181015186830182015201611a91565b506000602082860101526020601f19601f83011685010191505092915050565b6001600160a01b0383168152604060208201819052600090611af190830184611a87565b949350505050565b606081526000611b0d60608301888a6119d3565b8281036020840152611b208187896118f1565b90508281036040840152611b358185876118f1565b9998505050505050505050565b6001600160a01b039390931683526020830191909152604082015260600190565b600080600080600060a08688031215611b7b57600080fd5b8535611b868161154c565b94506020860135611b968161154c565b93506040860135611ba68161154c565b94979396509394606081013594506080013592915050565b6020808252602a908201527f4368696c644d696e7461626c65455243313135355072656469636174653a204d60408201526912539517d1905253115160b21b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715611c4657611c46611c08565b604052919050565b60006001600160401b03821115611c6757611c67611c08565b5060051b60200190565b600082601f830112611c8257600080fd5b81356020611c97611c9283611c4e565b611c1e565b82815260059290921b84018101918181019086841115611cb657600080fd5b8286015b84811015611cd15780358352918301918301611cba565b509695505050505050565b60008060008060008060c08789031215611cf557600080fd5b86359550602080880135611d088161154c565b95506040880135611d188161154c565b945060608801356001600160401b0380821115611d3457600080fd5b818a0191508a601f830112611d4857600080fd5b8135611d56611c9282611c4e565b81815260059190911b8301840190848101908d831115611d7557600080fd5b938501935b82851015611d9c578435611d8d8161154c565b82529385019390850190611d7a565b9750505060808a0135925080831115611db457600080fd5b611dc08b848c01611c71565b945060a08a0135925080831115611dd657600080fd5b5050611de489828a01611c71565b9150509295509295509295565b600081518084526020808501945080840160005b83811015611a1157815187529582019590820190600101611e05565b606080825284519082018190526000906020906080840190828801845b82811015611e635781516001600160a01b031684529284019290840190600101611e3e565b50505083810382850152611e778187611df1565b9150508281036040840152611e8c8185611df1565b9695505050505050565b600080600060608486031215611eab57600080fd5b83359250602080850135611ebe8161154c565b925060408501356001600160401b0380821115611eda57600080fd5b818701915087601f830112611eee57600080fd5b813581811115611f0057611f00611c08565b611f12601f8201601f19168501611c1e565b91508082528884828501011115611f2857600080fd5b8084840185840137600084828401015250809350505050925092509256fea264697066735822122026a554c5cf45bb8b62f522edf18a711a15c292f92508b7ed5d7fd755e7cb372a64736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106100d55760003560e01c8063b8cd3ec011610087578063b8cd3ec0146101b6578063c5ac2b1c146101c9578063cb10f94c146101f0578063d41f177114610209578063d7c9e3ec14610230578063f43cda8b14610257578063f64512551461026a578063f8c8765e1461029157600080fd5b8063051eb2e2146100da5780637efab4f51461010a57806386937eb41461013357806395c7041c14610148578063b17680651461015b578063b5c5f67214610190578063b68ad1e4146101a3575b600080fd5b6002546100ed906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6100ed610118366004611564565b6004602052600090815260409020546001600160a01b031681565b6101466101413660046115d3565b6102a4565b005b6001546100ed906001600160a01b031681565b6101827f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286981565b604051908152602001610101565b61014661019e36600461167f565b6102bc565b6003546100ed906001600160a01b031681565b6101466101c43660046116b4565b6102cd565b6101827faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d1881565b6000546100ed906201000090046001600160a01b031681565b6101827f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b6101827f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed281565b6101466102653660046116fa565b6102df565b6101827f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b61014661029f366004611782565b610514565b6102b38787878787878761062d565b50505050505050565b6102c8833384846109ba565b505050565b6102d9848484846109ba565b50505050565b6001546001600160a01b031633146103565760405162461bcd60e51b815260206004820152602f60248201527f4368696c644d696e7461626c65455243313135355072656469636174653a204f60448201526e27262cafa2ac24aa2fa422a62822a960891b60648201526084015b60405180910390fd5b6002546001600160a01b038481169116146103ce5760405162461bcd60e51b815260206004820152603260248201527f4368696c644d696e7461626c65455243313135355072656469636174653a204f6044820152714e4c595f524f4f545f50524544494341544560701b606482015260840161034d565b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f8216103fd6020600084866117de565b61040691611808565b036104255761042061041b82602081866117de565b610cd5565b6102d9565b7faf50c8eab81226bc79eee3a10e3fe25db1a2be7241130e392b0675df839b6d186104546020600084866117de565b61045d91611808565b0361046c576104208282610f40565b7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad61049b6020600084866117de565b6104a491611808565b036104b35761042082826111ad565b60405162461bcd60e51b815260206004820152603060248201527f4368696c644d696e7461626c65455243313135355072656469636174653a204960448201526f4e56414c49445f5349474e415455524560801b606482015260840161034d565b600054610100900460ff16158080156105345750600054600160ff909116105b8061054e5750303b15801561054e575060005460ff166001145b6105b15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161034d565b6000805460ff1916600117905580156105d4576000805461ff0019166101001790555b6105e085858585611317565b8015610626576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b8661063781611420565b6106535760405162461bcd60e51b815260040161034d90611826565b6000886001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610693573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106b79190611871565b6001600160a01b038181166000908152600460205260409020549192508a81169116146106f65760405162461bcd60e51b815260040161034d9061188e565b6001600160a01b03811661070c5761070c6118db565b306001600160a01b0316896001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610754573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107789190611871565b6001600160a01b03161461078e5761078e6118db565b868514801561079c57508483145b6107fe5760405162461bcd60e51b815260206004820152602d60248201527f4368696c644d696e7461626c65455243313135355072656469636174653a204960448201526c09cac82989288be988a9c8ea89609b1b606482015260840161034d565b604051631ac8311560e21b81526001600160a01b038a1690636b20c454906108329033908a908a908a908a90600401611923565b6020604051808303816000875af1158015610851573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108759190611967565b6108915760405162461bcd60e51b815260040161034d90611989565b6000546002546040516001600160a01b03620100009093048316926316f198319216906108f2907f5fb452c5a8f2b7c7ef2984e2f1063c7ee9b80b110cdc98ccb98f6654e10b5ed290869033908f908f908f908f908f908f90602001611a1c565b6040516020818303038152906040526040518363ffffffff1660e01b815260040161091e929190611acd565b600060405180830381600087803b15801561093857600080fd5b505af115801561094c573d6000803e3d6000fd5b50505050336001600160a01b0316896001600160a01b0316826001600160a01b03167fdd47868997765508c515e1f8ca079846dafbdfd8f98f6e76bca0891810b9f9d18b8b8b8b8b8b6040516109a796959493929190611af9565b60405180910390a4505050505050505050565b836109c481611420565b6109e05760405162461bcd60e51b815260040161034d90611826565b6000856001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a449190611871565b6001600160a01b03818116600090815260046020526040902054919250878116911614610a835760405162461bcd60e51b815260040161034d9061188e565b6001600160a01b038116610a9957610a996118db565b306001600160a01b0316866001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ae1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b059190611871565b6001600160a01b031614610b1b57610b1b6118db565b604051637a94c56560e11b81526001600160a01b0387169063f5298aca90610b4b90339088908890600401611b42565b6020604051808303816000875af1158015610b6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8e9190611967565b610baa5760405162461bcd60e51b815260040161034d90611989565b600054600254604080517f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e98286960208201526001600160a01b0385811682840152336060830152898116608083015260a0820189905260c08083018990528351808403909101815260e08301938490526316f1983160e01b909352620100009094048416936316f1983193610c429391169160e401611acd565b600060405180830381600087803b158015610c5c57600080fd5b505af1158015610c70573d6000803e3d6000fd5b50505050846001600160a01b0316866001600160a01b0316826001600160a01b03167fda58d73e08ba3c7767de904e68d208be8291494a9faaf70a6d4f736d24ec1f0f338888604051610cc593929190611b42565b60405180910390a4505050505050565b600080808080610ce786880188611b63565b6001600160a01b03808616600090815260046020526040902054959a50939850919650945092501680610d2c5760405162461bcd60e51b815260040161034d9061188e565b610d3581611420565b610d4157610d416118db565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da59190611871565b9050866001600160a01b0316816001600160a01b031614610dc857610dc86118db565b6001600160a01b038116610dde57610dde6118db565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e4a9190611871565b6001600160a01b031614610e6057610e606118db565b604051630ab714fb60e11b81526001600160a01b0383169063156e29f690610e9090889088908890600401611b42565b6020604051808303816000875af1158015610eaf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ed39190611967565b610eef5760405162461bcd60e51b815260040161034d90611bbe565b846001600160a01b0316826001600160a01b0316886001600160a01b03167f76a4cd47013e7e58abe817eedbb692d1614d71080b527412ebfb3f91a085a6de8988886040516109a793929190611b42565b600080808080610f5286880188611cdc565b6001600160a01b03808616600090815260046020526040902054959b509399509197509550935016905080610f995760405162461bcd60e51b815260040161034d9061188e565b610fa281611420565b610fae57610fae6118db565b6000816001600160a01b0316631f2d00656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110129190611871565b9050866001600160a01b0316816001600160a01b031614611035576110356118db565b6001600160a01b03811661104b5761104b6118db565b306001600160a01b0316826001600160a01b031663e61987056040518163ffffffff1660e01b8152600401602060405180830381865afa158015611093573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b79190611871565b6001600160a01b0316146110cd576110cd6118db565b604051635712868360e01b81526001600160a01b038316906357128683906110fd90889088908890600401611e21565b6020604051808303816000875af115801561111c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111409190611967565b61115c5760405162461bcd60e51b815260040161034d90611bbe565b856001600160a01b0316826001600160a01b0316886001600160a01b03167fc244cac13e0edc863dc5a2c3bd2b935f605b2ed225fb052eaef869bc24b76fde8888886040516109a793929190611e21565b6000806111bc83850185611e96565b9093509150506001600160a01b0382166111d8576111d86118db565b6001600160a01b038281166000908152600460205260409020541615611200576112006118db565b6003546040516bffffffffffffffffffffffff19606085901b166020820152600091611250916001600160a01b0390911690603401604051602081830303815290604052805190602001206114b5565b6001600160a01b0384811660009081526004602081905260409182902080546001600160a01b031916938516938417905590516379ccf11760e11b8152929350909163f399e22e916112a6918791879101611acd565b600060405180830381600087803b1580156112c057600080fd5b505af11580156112d4573d6000803e3d6000fd5b50506040516001600160a01b038085169350861691507f0a1eaf9aa124c3f84c9dd77f7016af0f16f67639abb913af1697387db01f5ca590600090a35050505050565b6001600160a01b0384161580159061133757506001600160a01b03831615155b801561134b57506001600160a01b03821615155b801561135f57506001600160a01b03811615155b6113c55760405162461bcd60e51b815260206004820152603160248201527f4368696c644d696e7461626c65455243313135355072656469636174653a204260448201527020a22fa4a724aa24a0a624ad20aa24a7a760791b606482015260840161034d565b600080546001600160a01b03958616620100000262010000600160b01b0319909116179055600180549385166001600160a01b0319948516179055600280549285169284169290921790915560038054919093169116179055565b6000816001600160a01b03163b60000361143c57506000919050565b6040516301ffc9a760e01b8152636cdb3d1360e11b60048201526001600160a01b038316906301ffc9a790602401602060405180830381865afa9250505080156114a3575060408051601f3d908101601f191682019092526114a091810190611967565b60015b6114af57506000919050565b92915050565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b0381166114af5760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b604482015260640161034d565b6001600160a01b038116811461156157600080fd5b50565b60006020828403121561157657600080fd5b81356115818161154c565b9392505050565b60008083601f84011261159a57600080fd5b5081356001600160401b038111156115b157600080fd5b6020830191508360208260051b85010111156115cc57600080fd5b9250929050565b60008060008060008060006080888a0312156115ee57600080fd5b87356115f98161154c565b965060208801356001600160401b038082111561161557600080fd5b6116218b838c01611588565b909850965060408a013591508082111561163a57600080fd5b6116468b838c01611588565b909650945060608a013591508082111561165f57600080fd5b5061166c8a828b01611588565b989b979a50959850939692959293505050565b60008060006060848603121561169457600080fd5b833561169f8161154c565b95602085013595506040909401359392505050565b600080600080608085870312156116ca57600080fd5b84356116d58161154c565b935060208501356116e58161154c565b93969395505050506040820135916060013590565b6000806000806060858703121561171057600080fd5b8435935060208501356117228161154c565b925060408501356001600160401b038082111561173e57600080fd5b818701915087601f83011261175257600080fd5b81358181111561176157600080fd5b88602082850101111561177357600080fd5b95989497505060200194505050565b6000806000806080858703121561179857600080fd5b84356117a38161154c565b935060208501356117b38161154c565b925060408501356117c38161154c565b915060608501356117d38161154c565b939692955090935050565b600080858511156117ee57600080fd5b838611156117fb57600080fd5b5050820193919092039150565b803560208310156114af57600019602084900360031b1b1692915050565b6020808252602b908201527f4368696c644d696e7461626c65455243313135355072656469636174653a204e60408201526a13d517d0d3d395149050d560aa1b606082015260800190565b60006020828403121561188357600080fd5b81516115818161154c565b6020808252602d908201527f4368696c644d696e7461626c65455243313135355072656469636174653a205560408201526c2726a0a82822a22faa27a5a2a760991b606082015260800190565b634e487b7160e01b600052600160045260246000fd5b81835260006001600160fb1b0383111561190a57600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b038616815260606020820181905260009061194890830186886118f1565b828103604084015261195b8185876118f1565b98975050505050505050565b60006020828403121561197957600080fd5b8151801515811461158157600080fd5b6020808252602a908201527f4368696c644d696e7461626c65455243313135355072656469636174653a204260408201526915549397d1905253115160b21b606082015260800190565b8183526000602080850194508260005b85811015611a115781356119f68161154c565b6001600160a01b0316875295820195908201906001016119e3565b509495945050505050565b8981526001600160a01b0389811660208301528816604082015260c060608201819052600090611a4f908301888a6119d3565b8281036080840152611a628187896118f1565b905082810360a0840152611a778185876118f1565b9c9b505050505050505050505050565b6000815180845260005b81811015611aad57602081850181015186830182015201611a91565b506000602082860101526020601f19601f83011685010191505092915050565b6001600160a01b0383168152604060208201819052600090611af190830184611a87565b949350505050565b606081526000611b0d60608301888a6119d3565b8281036020840152611b208187896118f1565b90508281036040840152611b358185876118f1565b9998505050505050505050565b6001600160a01b039390931683526020830191909152604082015260600190565b600080600080600060a08688031215611b7b57600080fd5b8535611b868161154c565b94506020860135611b968161154c565b93506040860135611ba68161154c565b94979396509394606081013594506080013592915050565b6020808252602a908201527f4368696c644d696e7461626c65455243313135355072656469636174653a204d60408201526912539517d1905253115160b21b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715611c4657611c46611c08565b604052919050565b60006001600160401b03821115611c6757611c67611c08565b5060051b60200190565b600082601f830112611c8257600080fd5b81356020611c97611c9283611c4e565b611c1e565b82815260059290921b84018101918181019086841115611cb657600080fd5b8286015b84811015611cd15780358352918301918301611cba565b509695505050505050565b60008060008060008060c08789031215611cf557600080fd5b86359550602080880135611d088161154c565b95506040880135611d188161154c565b945060608801356001600160401b0380821115611d3457600080fd5b818a0191508a601f830112611d4857600080fd5b8135611d56611c9282611c4e565b81815260059190911b8301840190848101908d831115611d7557600080fd5b938501935b82851015611d9c578435611d8d8161154c565b82529385019390850190611d7a565b9750505060808a0135925080831115611db457600080fd5b611dc08b848c01611c71565b945060a08a0135925080831115611dd657600080fd5b5050611de489828a01611c71565b9150509295509295509295565b600081518084526020808501945080840160005b83811015611a1157815187529582019590820190600101611e05565b606080825284519082018190526000906020906080840190828801845b82811015611e635781516001600160a01b031684529284019290840190600101611e3e565b50505083810382850152611e778187611df1565b9150508281036040840152611e8c8185611df1565b9695505050505050565b600080600060608486031215611eab57600080fd5b83359250602080850135611ebe8161154c565b925060408501356001600160401b0380821115611eda57600080fd5b818701915087601f830112611eee57600080fd5b813581811115611f0057611f00611c08565b611f12601f8201601f19168501611c1e565b91508082528884828501011115611f2857600080fd5b8084840185840137600084828401015250809350505050925092509256fea264697066735822122026a554c5cf45bb8b62f522edf18a711a15c292f92508b7ed5d7fd755e7cb372a64736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var CustomSupernetManagerArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"CustomSupernetManager\",\n \"sourceName\": \"contracts/root/staking/CustomSupernetManager.sol\",\n \"abi\": [\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"InvalidSignature\",\n \"type\": \"error\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"message\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"Unauthorized\",\n \"type\": \"error\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"AddedToWhitelist\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amountValidators\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"GenesisFinalized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"previousOwner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"OwnershipTransferStarted\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"previousOwner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"OwnershipTransferred\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"RemovedFromWhitelist\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [],\n \"name\": \"StakingEnabled\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"ValidatorDeactivated\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[4]\",\n \"name\": \"blsKey\",\n \"type\": \"uint256[4]\"\n }\n ],\n \"name\": \"ValidatorRegistered\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"SLASHING_PERCENTAGE\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"acceptOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"domain\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"enableStaking\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"finalizeGenesis\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"genesisSet\",\n \"outputs\": [\n {\n \"components\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"initialStake\",\n \"type\": \"uint256\"\n }\n ],\n \"internalType\": \"struct GenesisValidator[]\",\n \"name\": \"\",\n \"type\": \"tuple[]\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator_\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"getValidator\",\n \"outputs\": [\n {\n \"components\": [\n {\n \"internalType\": \"uint256[4]\",\n \"name\": \"blsKey\",\n \"type\": \"uint256[4]\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"stake\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"isWhitelisted\",\n \"type\": \"bool\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"isActive\",\n \"type\": \"bool\"\n }\n ],\n \"internalType\": \"struct Validator\",\n \"name\": \"\",\n \"type\": \"tuple\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"id\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newStakeManager\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newBls\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newStateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newMatic\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newChildValidatorSet\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newExitHelper\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"string\",\n \"name\": \"newDomain\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"id_\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"onInit\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onL2StateReceive\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"onStake\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"owner\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"pendingOwner\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256[2]\",\n \"name\": \"signature\",\n \"type\": \"uint256[2]\"\n },\n {\n \"internalType\": \"uint256[4]\",\n \"name\": \"pubkey\",\n \"type\": \"uint256[4]\"\n }\n ],\n \"name\": \"register\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"renounceOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newOwner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"transferOwnership\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"validators\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"stake\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"isWhitelisted\",\n \"type\": \"bool\"\n },\n {\n \"internalType\": \"bool\",\n \"name\": \"isActive\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address[]\",\n \"name\": \"validators_\",\n \"type\": \"address[]\"\n }\n ],\n \"name\": \"whitelistValidators\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"withdrawSlashedStake\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b506120de806100206000396000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c80639e19e9c1116100ad578063e30c397811610071578063e30c397814610232578063f2fde38b14610243578063f43cda8b14610256578063fa52c7d814610269578063fd051b4a146102bc57600080fd5b80639e19e9c1146101ed578063af640d0f14610202578063bd8d64d914610219578063c2fb26a614610221578063d11aca621461022a57600080fd5b8063715018a6116100f4578063715018a6146101a857806379ba5097146101b057806385758cc7146101b85780638c087b1c146101c05780638da5cb5b146101d357600080fd5b80631904bb2e146101315780631f6590b81461015a578063344a5e641461016f57806344efbf8414610182578063542c85f214610195575b600080fd5b61014461013f366004611930565b6102cf565b604051610151919061194d565b60405180910390f35b61016d6101683660046119a1565b610359565b005b61016d61017d3660046119e3565b610426565b61016d610190366004611930565b6104a5565b61016d6101a33660046119fc565b61053d565b61016d610598565b61016d6105ac565b61016d610626565b61016d6101ce366004611a71565b610677565b6033546001600160a01b03165b6040516101519190611a9d565b6101f56106ab565b6040516101519190611ab1565b61020b60985481565b604051908152602001610151565b61020b603281565b61020b60d05481565b61016d6106bc565b6065546001600160a01b03166101e0565b61016d610251366004611930565b6106f9565b61016d610264366004611b09565b61076a565b61029f610277366004611930565b60d4602052600090815260409020600481015460059091015460ff8082169161010090041683565b604080519384529115156020840152151590820152606001610151565b61016d6102ca366004611bd9565b6108a7565b6102d761185e565b6001600160a01b038216600090815260d46020526040908190208151610100810190925281608081018260048282826020028201915b81548152602001906001019080831161030d5750505091835250506004820154602082015260059091015460ff8082161515604084015261010090910416151560609091015292915050565b33600090815260d460205260409020600581015460ff166103ae5760405163973d02cb60e01b815260206004820152600960248201526815d2125511531254d560ba1b60448201526064015b60405180910390fd5b6103b9338484610b02565b6103c58183600461188c565b5060058101805461ff0019166101001790556103e033610be1565b336001600160a01b03167f110ae3ae039a4632f836a35dc9b1282df88780883fb28779f22c2f7ccde8dd0a836040516104199190611cde565b60405180910390a2505050565b6097546001600160a01b031633146104505760405162461bcd60e51b81526004016103a590611ced565b609854156104a05760405162461bcd60e51b815260206004820152601f60248201527f53757065726e65744d616e616765723a2049445f414c52454144595f5345540060448201526064016103a5565b609855565b6104ad610c2d565b60cd546040516370a0823160e01b81526000916001600160a01b0316906370a08231906104de903090600401611a9d565b602060405180830381865afa1580156104fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061051f9190611d30565b60cd54909150610539906001600160a01b03168383610c87565b5050565b610545610c2d565b8060005b818110156105925761058084848381811061056657610566611d49565b905060200201602081019061057b9190611930565b610ce2565b8061058a81611d75565b915050610549565b50505050565b6105a0610c2d565b6105aa6000610d31565b565b60655433906001600160a01b0316811461061a5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016103a5565b61062381610d31565b50565b61062e610c2d565b61063860d1610d4a565b7f87f41ee3facb6317b1c2811e539539ac1693525b4460699b4245e8aac9f590cb61066360d1610dc4565b5160405190815260200160405180910390a1565b6097546001600160a01b031633146106a15760405162461bcd60e51b81526004016103a590611ced565b6105398282610e3d565b60606106b760d1610dc4565b905090565b6106c4610c2d565b6106ce60d1610fb6565b6040517fda917aeab736a19e4ba54207413dbe4f8c7d558fde2c14d7e66fc8f7186ea8a390600090a1565b610701610c2d565b606580546001600160a01b0383166001600160a01b031990911681179091556107326033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60cf546001600160a01b031633141580610792575060ce546001600160a01b03848116911614155b156107cd5760405163973d02cb60e01b815260206004820152600a60248201526932bc34ba2432b63832b960b11b60448201526064016103a5565b7f8ca9a95e41b5eece253c93f5b31eed1253aed6b145d8a6e14d913fdf8e7322936107fc602060008486611d8e565b61080591611db8565b0361083c5760008061081a8360208187611d8e565b8101906108279190611a71565b91509150610835828261108d565b5050610592565b7f117f1d6f44fd34ccb7a58f1261fa59e5c4bf68e2712d65f246a8805167a9334461086b602060008486611d8e565b61087491611db8565b036105925760006108888260208186611d8e565b8101906108959190611930565b90506108a0816110fa565b5050505050565b600054610100900460ff16158080156108c75750600054600160ff909116105b806108e15750303b1580156108e1575060005460ff166001145b6109445760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016103a5565b6000805460ff191660011790558015610967576000805461ff0019166101001790555b6001600160a01b0388161580159061098757506001600160a01b03871615155b801561099b57506001600160a01b03861615155b80156109af57506001600160a01b03851615155b80156109c357506001600160a01b03841615155b80156109d757506001600160a01b03831615155b80156109e35750815115155b610a1f5760405162461bcd60e51b815260206004820152600d60248201526c1253959053125117d253941555609a1b60448201526064016103a5565b610a28886111f8565b60cb80546001600160a01b03199081166001600160a01b038a81169190911790925560cc8054821689841617905560cd8054821688841617905560ce8054821687841617905560cf8054909116918516919091179055604051610a8f908390602001611dfa565b60408051601f19818403018152919052805160209091012060d055610ab2611241565b8015610af8576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b8135158015610b1357506020820135155b15610b335782604051633615713d60e21b81526004016103a59190611a9d565b60cb5460009081906001600160a01b031663ebbdac918585610b5489611270565b6040518463ffffffff1660e01b8152600401610b7293929190611e16565b6040805180830381865afa158015610b8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb29190611e6f565b91509150801580610bc1575081155b156108a05784604051633615713d60e21b81526004016103a59190611a9d565b6001600160a01b038116600081815260d46020526040808220600501805460ff19169055517fcdd2e9b91a56913d370075169cefa1602ba36be5301664f752192bb1709df7579190a250565b6033546001600160a01b031633146105aa5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103a5565b610cdd8363a9059cbb60e01b8484604051602401610ca6929190611ea2565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611332565b505050565b6001600160a01b038116600081815260d46020526040808220600501805460ff19166001179055517fa850ae9193f515cbae8d35e8925bd2be26627fc91bce650b8652ed254e9cab039190a250565b606580546001600160a01b031916905561062381611407565b6000600182015460ff166002811115610d6557610d65611ebb565b14610db25760405162461bcd60e51b815260206004820152601d60248201527f47656e657369734c69623a20616c72656164792066696e616c697a656400000060448201526064016103a5565b6001908101805460ff19169091179055565b606081600001805480602002602001604051908101604052809291908181526020016000905b82821015610e32576000848152602090819020604080518082019091526002850290910180546001600160a01b03168252600190810154828401529083529092019101610dea565b505050509050919050565b6001600160a01b038216600090815260d460205260409020600501548290610100900460ff16610e9c5760405163973d02cb60e01b81526020600482015260096024820152682b20a624a220aa27a960b91b60448201526064016103a5565b610ea660d1611459565b15610eb757610cdd60d1848461147d565b610ec160d161158f565b15610f7a5760cc5460ce54604080517f1bcc0f4c3fad314e585165815f94ecca9b96690a26d6417d7876448a9a867a6960208201526001600160a01b038781168284015260608083018890528351808403909101815260808301938490526316f1983160e01b909352938416936316f1983193610f4393911691608401611efd565b600060405180830381600087803b158015610f5d57600080fd5b505af1158015610f71573d6000803e3d6000fd5b50505050505050565b60405163973d02cb60e01b815260206004820152601060248201526f5761697420666f722067656e6573697360801b60448201526064016103a5565b600181015460ff166000816002811115610fd257610fd2611ebb565b0361101b5760405162461bcd60e51b815260206004820152601960248201527811d95b995cda5cd31a588e881b9bdd08199a5b985b1a5e9959603a1b60448201526064016103a5565b600281600281111561102f5761102f611ebb565b0361107c5760405162461bcd60e51b815260206004820152601b60248201527f47656e657369734c69623a20616c726561647920656e61626c6564000000000060448201526064016103a5565b50600101805460ff19166002179055565b609754604051633651bb1d60e01b81526001600160a01b0390911690633651bb1d906110bf9085908590600401611ea2565b600060405180830381600087803b1580156110d957600080fd5b505af11580156110ed573d6000803e3d6000fd5b5050505061053982611598565b609754609854604051633b61c5a760e21b81526000926001600160a01b03169163ed87169c9161112e918691600401611ea2565b602060405180830381865afa15801561114b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061116f9190611d30565b905060006064611180603284611f21565b61118a9190611f38565b609754604051638028a6db60e01b81529192506001600160a01b031690638028a6db906111bd9086908590600401611ea2565b600060405180830381600087803b1580156111d757600080fd5b505af11580156111eb573d6000803e3d6000fd5b50505050610cdd83611598565b600054610100900460ff1661121f5760405162461bcd60e51b81526004016103a590611f5a565b609780546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff166112685760405162461bcd60e51b81526004016103a590611f5a565b6105aa611661565b6112786118ca565b60cb5460d0546040516bffffffffffffffffffffffff19606086811b8216602084015230901b1660348201524660488201526001600160a01b039092169163a850a90991906068016040516020818303038152906040526040518363ffffffff1660e01b81526004016112ec929190611fa5565b6040805180830381865afa158015611308573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061132c9190611fbe565b92915050565b6000611387826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166116919092919063ffffffff16565b90508051600014806113a85750808060200190518101906113a8919061203e565b610cdd5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016103a5565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000805b600183015460ff16600281111561147657611476611ebb565b1492915050565b6000600184015460ff16600281111561149857611498611ebb565b146114a5576114a5612059565b6001600160a01b0382166000908152600284016020526040812054908190036115425783546114d590600161206f565b6001600160a01b03848116600081815260028881016020908152604080842087905580518082019091529384528381018881528a5460018082018d558c86529290942094519390920290930180546001600160a01b03191692909416919091178355519101559050610592565b60008461154f81866116a8565b8154811061155f5761155f611d49565b9060005260206000209060020201905082816001016000828254611583919061206f565b90915550505050505050565b6000600261145d565b609754609854604051633b61c5a760e21b81526001600160a01b039092169163ed87169c916115cc91859190600401611ea2565b602060405180830381865afa1580156115e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061160d9190611d30565b600003610623576001600160a01b038116600081815260d46020526040808220600501805461ff0019169055517f23d934bfe7f1275bc6fd70432159c9cc1c0075d069f89da6a40f43bfe7a94ed39190a250565b600054610100900460ff166116885760405162461bcd60e51b81526004016103a590611f5a565b6105aa33610d31565b60606116a084846000856116e5565b949350505050565b6001600160a01b0381166000908152600283016020526040812054908190036116d3576116d3612059565b6116de600182612082565b9392505050565b6060824710156117465760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016103a5565b600080866001600160a01b031685876040516117629190611dfa565b60006040518083038185875af1925050503d806000811461179f576040519150601f19603f3d011682016040523d82523d6000602084013e6117a4565b606091505b50915091506117b5878383876117c0565b979650505050505050565b6060831561182f578251600003611828576001600160a01b0385163b6118285760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103a5565b50816116a0565b6116a083838151156118445781518083602001fd5b8060405162461bcd60e51b81526004016103a59190612095565b60405180608001604052806118716118e8565b81526000602082018190526040820181905260609091015290565b82600481019282156118ba579160200282015b828111156118ba57823582559160200191906001019061189f565b506118c6929150611906565b5090565b60405180604001604052806002906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b5b808211156118c65760008155600101611907565b6001600160a01b038116811461062357600080fd5b60006020828403121561194257600080fd5b81356116de8161191b565b815160e08201908260005b6004811015611977578251825260209283019290910190600101611958565b505050602083015160808301526040830151151560a0830152606090920151151560c09091015290565b60008060c083850312156119b457600080fd5b60408301848111156119c557600080fd5b8392508460c0850111156119d857600080fd5b809150509250929050565b6000602082840312156119f557600080fd5b5035919050565b60008060208385031215611a0f57600080fd5b823567ffffffffffffffff80821115611a2757600080fd5b818501915085601f830112611a3b57600080fd5b813581811115611a4a57600080fd5b8660208260051b8501011115611a5f57600080fd5b60209290920196919550909350505050565b60008060408385031215611a8457600080fd5b8235611a8f8161191b565b946020939093013593505050565b6001600160a01b0391909116815260200190565b602080825282518282018190526000919060409081850190868401855b82811015611afc57815180516001600160a01b03168552860151868501529284019290850190600101611ace565b5091979650505050505050565b60008060008060608587031215611b1f57600080fd5b843593506020850135611b318161191b565b9250604085013567ffffffffffffffff80821115611b4e57600080fd5b818701915087601f830112611b6257600080fd5b813581811115611b7157600080fd5b886020828501011115611b8357600080fd5b95989497505060200194505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715611bd157611bd1611b92565b604052919050565b600080600080600080600060e0888a031215611bf457600080fd5b8735611bff8161191b565b9650602088810135611c108161191b565b96506040890135611c208161191b565b95506060890135611c308161191b565b94506080890135611c408161191b565b935060a0890135611c508161191b565b925060c089013567ffffffffffffffff80821115611c6d57600080fd5b818b0191508b601f830112611c8157600080fd5b813581811115611c9357611c93611b92565b611ca5601f8201601f19168501611ba8565b91508082528c84828501011115611cbb57600080fd5b808484018584013760008482840101525080935050505092959891949750929550565b60808181019083833792915050565b60208082526023908201527f53757065726e65744d616e616765723a204f4e4c595f5354414b455f4d414e4160408201526223a2a960e91b606082015260800190565b600060208284031215611d4257600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201611d8757611d87611d5f565b5060010190565b60008085851115611d9e57600080fd5b83861115611dab57600080fd5b5050820193919092039150565b8035602083101561132c57600019602084900360031b1b1692915050565b60005b83811015611df1578181015183820152602001611dd9565b50506000910152565b60008251611e0c818460208701611dd6565b9190910192915050565b61010081016040858337608084604084013760c082018360005b6002811015611e4f578151835260209283019290910190600101611e30565b505050949350505050565b80518015158114611e6a57600080fd5b919050565b60008060408385031215611e8257600080fd5b611e8b83611e5a565b9150611e9960208401611e5a565b90509250929050565b6001600160a01b03929092168252602082015260400190565b634e487b7160e01b600052602160045260246000fd5b60008151808452611ee9816020860160208601611dd6565b601f01601f19169290920160200192915050565b6001600160a01b03831681526040602082018190526000906116a090830184611ed1565b808202811582820484141761132c5761132c611d5f565b600082611f5557634e487b7160e01b600052601260045260246000fd5b500490565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b8281526040602082015260006116a06040830184611ed1565b600060408284031215611fd057600080fd5b82601f830112611fdf57600080fd5b6040516040810181811067ffffffffffffffff8211171561200257612002611b92565b806040525080604084018581111561201957600080fd5b845b8181101561203357805183526020928301920161201b565b509195945050505050565b60006020828403121561205057600080fd5b6116de82611e5a565b634e487b7160e01b600052600160045260246000fd5b8082018082111561132c5761132c611d5f565b8181038181111561132c5761132c611d5f565b6020815260006116de6020830184611ed156fea2646970667358221220bc982b5eb2308e71d272d016ed22be05a9dcf98b734fd3bd0b62563ec962766664736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b506004361061012c5760003560e01c80639e19e9c1116100ad578063e30c397811610071578063e30c397814610232578063f2fde38b14610243578063f43cda8b14610256578063fa52c7d814610269578063fd051b4a146102bc57600080fd5b80639e19e9c1146101ed578063af640d0f14610202578063bd8d64d914610219578063c2fb26a614610221578063d11aca621461022a57600080fd5b8063715018a6116100f4578063715018a6146101a857806379ba5097146101b057806385758cc7146101b85780638c087b1c146101c05780638da5cb5b146101d357600080fd5b80631904bb2e146101315780631f6590b81461015a578063344a5e641461016f57806344efbf8414610182578063542c85f214610195575b600080fd5b61014461013f366004611930565b6102cf565b604051610151919061194d565b60405180910390f35b61016d6101683660046119a1565b610359565b005b61016d61017d3660046119e3565b610426565b61016d610190366004611930565b6104a5565b61016d6101a33660046119fc565b61053d565b61016d610598565b61016d6105ac565b61016d610626565b61016d6101ce366004611a71565b610677565b6033546001600160a01b03165b6040516101519190611a9d565b6101f56106ab565b6040516101519190611ab1565b61020b60985481565b604051908152602001610151565b61020b603281565b61020b60d05481565b61016d6106bc565b6065546001600160a01b03166101e0565b61016d610251366004611930565b6106f9565b61016d610264366004611b09565b61076a565b61029f610277366004611930565b60d4602052600090815260409020600481015460059091015460ff8082169161010090041683565b604080519384529115156020840152151590820152606001610151565b61016d6102ca366004611bd9565b6108a7565b6102d761185e565b6001600160a01b038216600090815260d46020526040908190208151610100810190925281608081018260048282826020028201915b81548152602001906001019080831161030d5750505091835250506004820154602082015260059091015460ff8082161515604084015261010090910416151560609091015292915050565b33600090815260d460205260409020600581015460ff166103ae5760405163973d02cb60e01b815260206004820152600960248201526815d2125511531254d560ba1b60448201526064015b60405180910390fd5b6103b9338484610b02565b6103c58183600461188c565b5060058101805461ff0019166101001790556103e033610be1565b336001600160a01b03167f110ae3ae039a4632f836a35dc9b1282df88780883fb28779f22c2f7ccde8dd0a836040516104199190611cde565b60405180910390a2505050565b6097546001600160a01b031633146104505760405162461bcd60e51b81526004016103a590611ced565b609854156104a05760405162461bcd60e51b815260206004820152601f60248201527f53757065726e65744d616e616765723a2049445f414c52454144595f5345540060448201526064016103a5565b609855565b6104ad610c2d565b60cd546040516370a0823160e01b81526000916001600160a01b0316906370a08231906104de903090600401611a9d565b602060405180830381865afa1580156104fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061051f9190611d30565b60cd54909150610539906001600160a01b03168383610c87565b5050565b610545610c2d565b8060005b818110156105925761058084848381811061056657610566611d49565b905060200201602081019061057b9190611930565b610ce2565b8061058a81611d75565b915050610549565b50505050565b6105a0610c2d565b6105aa6000610d31565b565b60655433906001600160a01b0316811461061a5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016103a5565b61062381610d31565b50565b61062e610c2d565b61063860d1610d4a565b7f87f41ee3facb6317b1c2811e539539ac1693525b4460699b4245e8aac9f590cb61066360d1610dc4565b5160405190815260200160405180910390a1565b6097546001600160a01b031633146106a15760405162461bcd60e51b81526004016103a590611ced565b6105398282610e3d565b60606106b760d1610dc4565b905090565b6106c4610c2d565b6106ce60d1610fb6565b6040517fda917aeab736a19e4ba54207413dbe4f8c7d558fde2c14d7e66fc8f7186ea8a390600090a1565b610701610c2d565b606580546001600160a01b0383166001600160a01b031990911681179091556107326033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60cf546001600160a01b031633141580610792575060ce546001600160a01b03848116911614155b156107cd5760405163973d02cb60e01b815260206004820152600a60248201526932bc34ba2432b63832b960b11b60448201526064016103a5565b7f8ca9a95e41b5eece253c93f5b31eed1253aed6b145d8a6e14d913fdf8e7322936107fc602060008486611d8e565b61080591611db8565b0361083c5760008061081a8360208187611d8e565b8101906108279190611a71565b91509150610835828261108d565b5050610592565b7f117f1d6f44fd34ccb7a58f1261fa59e5c4bf68e2712d65f246a8805167a9334461086b602060008486611d8e565b61087491611db8565b036105925760006108888260208186611d8e565b8101906108959190611930565b90506108a0816110fa565b5050505050565b600054610100900460ff16158080156108c75750600054600160ff909116105b806108e15750303b1580156108e1575060005460ff166001145b6109445760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016103a5565b6000805460ff191660011790558015610967576000805461ff0019166101001790555b6001600160a01b0388161580159061098757506001600160a01b03871615155b801561099b57506001600160a01b03861615155b80156109af57506001600160a01b03851615155b80156109c357506001600160a01b03841615155b80156109d757506001600160a01b03831615155b80156109e35750815115155b610a1f5760405162461bcd60e51b815260206004820152600d60248201526c1253959053125117d253941555609a1b60448201526064016103a5565b610a28886111f8565b60cb80546001600160a01b03199081166001600160a01b038a81169190911790925560cc8054821689841617905560cd8054821688841617905560ce8054821687841617905560cf8054909116918516919091179055604051610a8f908390602001611dfa565b60408051601f19818403018152919052805160209091012060d055610ab2611241565b8015610af8576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b8135158015610b1357506020820135155b15610b335782604051633615713d60e21b81526004016103a59190611a9d565b60cb5460009081906001600160a01b031663ebbdac918585610b5489611270565b6040518463ffffffff1660e01b8152600401610b7293929190611e16565b6040805180830381865afa158015610b8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb29190611e6f565b91509150801580610bc1575081155b156108a05784604051633615713d60e21b81526004016103a59190611a9d565b6001600160a01b038116600081815260d46020526040808220600501805460ff19169055517fcdd2e9b91a56913d370075169cefa1602ba36be5301664f752192bb1709df7579190a250565b6033546001600160a01b031633146105aa5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103a5565b610cdd8363a9059cbb60e01b8484604051602401610ca6929190611ea2565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611332565b505050565b6001600160a01b038116600081815260d46020526040808220600501805460ff19166001179055517fa850ae9193f515cbae8d35e8925bd2be26627fc91bce650b8652ed254e9cab039190a250565b606580546001600160a01b031916905561062381611407565b6000600182015460ff166002811115610d6557610d65611ebb565b14610db25760405162461bcd60e51b815260206004820152601d60248201527f47656e657369734c69623a20616c72656164792066696e616c697a656400000060448201526064016103a5565b6001908101805460ff19169091179055565b606081600001805480602002602001604051908101604052809291908181526020016000905b82821015610e32576000848152602090819020604080518082019091526002850290910180546001600160a01b03168252600190810154828401529083529092019101610dea565b505050509050919050565b6001600160a01b038216600090815260d460205260409020600501548290610100900460ff16610e9c5760405163973d02cb60e01b81526020600482015260096024820152682b20a624a220aa27a960b91b60448201526064016103a5565b610ea660d1611459565b15610eb757610cdd60d1848461147d565b610ec160d161158f565b15610f7a5760cc5460ce54604080517f1bcc0f4c3fad314e585165815f94ecca9b96690a26d6417d7876448a9a867a6960208201526001600160a01b038781168284015260608083018890528351808403909101815260808301938490526316f1983160e01b909352938416936316f1983193610f4393911691608401611efd565b600060405180830381600087803b158015610f5d57600080fd5b505af1158015610f71573d6000803e3d6000fd5b50505050505050565b60405163973d02cb60e01b815260206004820152601060248201526f5761697420666f722067656e6573697360801b60448201526064016103a5565b600181015460ff166000816002811115610fd257610fd2611ebb565b0361101b5760405162461bcd60e51b815260206004820152601960248201527811d95b995cda5cd31a588e881b9bdd08199a5b985b1a5e9959603a1b60448201526064016103a5565b600281600281111561102f5761102f611ebb565b0361107c5760405162461bcd60e51b815260206004820152601b60248201527f47656e657369734c69623a20616c726561647920656e61626c6564000000000060448201526064016103a5565b50600101805460ff19166002179055565b609754604051633651bb1d60e01b81526001600160a01b0390911690633651bb1d906110bf9085908590600401611ea2565b600060405180830381600087803b1580156110d957600080fd5b505af11580156110ed573d6000803e3d6000fd5b5050505061053982611598565b609754609854604051633b61c5a760e21b81526000926001600160a01b03169163ed87169c9161112e918691600401611ea2565b602060405180830381865afa15801561114b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061116f9190611d30565b905060006064611180603284611f21565b61118a9190611f38565b609754604051638028a6db60e01b81529192506001600160a01b031690638028a6db906111bd9086908590600401611ea2565b600060405180830381600087803b1580156111d757600080fd5b505af11580156111eb573d6000803e3d6000fd5b50505050610cdd83611598565b600054610100900460ff1661121f5760405162461bcd60e51b81526004016103a590611f5a565b609780546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff166112685760405162461bcd60e51b81526004016103a590611f5a565b6105aa611661565b6112786118ca565b60cb5460d0546040516bffffffffffffffffffffffff19606086811b8216602084015230901b1660348201524660488201526001600160a01b039092169163a850a90991906068016040516020818303038152906040526040518363ffffffff1660e01b81526004016112ec929190611fa5565b6040805180830381865afa158015611308573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061132c9190611fbe565b92915050565b6000611387826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166116919092919063ffffffff16565b90508051600014806113a85750808060200190518101906113a8919061203e565b610cdd5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016103a5565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000805b600183015460ff16600281111561147657611476611ebb565b1492915050565b6000600184015460ff16600281111561149857611498611ebb565b146114a5576114a5612059565b6001600160a01b0382166000908152600284016020526040812054908190036115425783546114d590600161206f565b6001600160a01b03848116600081815260028881016020908152604080842087905580518082019091529384528381018881528a5460018082018d558c86529290942094519390920290930180546001600160a01b03191692909416919091178355519101559050610592565b60008461154f81866116a8565b8154811061155f5761155f611d49565b9060005260206000209060020201905082816001016000828254611583919061206f565b90915550505050505050565b6000600261145d565b609754609854604051633b61c5a760e21b81526001600160a01b039092169163ed87169c916115cc91859190600401611ea2565b602060405180830381865afa1580156115e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061160d9190611d30565b600003610623576001600160a01b038116600081815260d46020526040808220600501805461ff0019169055517f23d934bfe7f1275bc6fd70432159c9cc1c0075d069f89da6a40f43bfe7a94ed39190a250565b600054610100900460ff166116885760405162461bcd60e51b81526004016103a590611f5a565b6105aa33610d31565b60606116a084846000856116e5565b949350505050565b6001600160a01b0381166000908152600283016020526040812054908190036116d3576116d3612059565b6116de600182612082565b9392505050565b6060824710156117465760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016103a5565b600080866001600160a01b031685876040516117629190611dfa565b60006040518083038185875af1925050503d806000811461179f576040519150601f19603f3d011682016040523d82523d6000602084013e6117a4565b606091505b50915091506117b5878383876117c0565b979650505050505050565b6060831561182f578251600003611828576001600160a01b0385163b6118285760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103a5565b50816116a0565b6116a083838151156118445781518083602001fd5b8060405162461bcd60e51b81526004016103a59190612095565b60405180608001604052806118716118e8565b81526000602082018190526040820181905260609091015290565b82600481019282156118ba579160200282015b828111156118ba57823582559160200191906001019061189f565b506118c6929150611906565b5090565b60405180604001604052806002906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b5b808211156118c65760008155600101611907565b6001600160a01b038116811461062357600080fd5b60006020828403121561194257600080fd5b81356116de8161191b565b815160e08201908260005b6004811015611977578251825260209283019290910190600101611958565b505050602083015160808301526040830151151560a0830152606090920151151560c09091015290565b60008060c083850312156119b457600080fd5b60408301848111156119c557600080fd5b8392508460c0850111156119d857600080fd5b809150509250929050565b6000602082840312156119f557600080fd5b5035919050565b60008060208385031215611a0f57600080fd5b823567ffffffffffffffff80821115611a2757600080fd5b818501915085601f830112611a3b57600080fd5b813581811115611a4a57600080fd5b8660208260051b8501011115611a5f57600080fd5b60209290920196919550909350505050565b60008060408385031215611a8457600080fd5b8235611a8f8161191b565b946020939093013593505050565b6001600160a01b0391909116815260200190565b602080825282518282018190526000919060409081850190868401855b82811015611afc57815180516001600160a01b03168552860151868501529284019290850190600101611ace565b5091979650505050505050565b60008060008060608587031215611b1f57600080fd5b843593506020850135611b318161191b565b9250604085013567ffffffffffffffff80821115611b4e57600080fd5b818701915087601f830112611b6257600080fd5b813581811115611b7157600080fd5b886020828501011115611b8357600080fd5b95989497505060200194505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715611bd157611bd1611b92565b604052919050565b600080600080600080600060e0888a031215611bf457600080fd5b8735611bff8161191b565b9650602088810135611c108161191b565b96506040890135611c208161191b565b95506060890135611c308161191b565b94506080890135611c408161191b565b935060a0890135611c508161191b565b925060c089013567ffffffffffffffff80821115611c6d57600080fd5b818b0191508b601f830112611c8157600080fd5b813581811115611c9357611c93611b92565b611ca5601f8201601f19168501611ba8565b91508082528c84828501011115611cbb57600080fd5b808484018584013760008482840101525080935050505092959891949750929550565b60808181019083833792915050565b60208082526023908201527f53757065726e65744d616e616765723a204f4e4c595f5354414b455f4d414e4160408201526223a2a960e91b606082015260800190565b600060208284031215611d4257600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201611d8757611d87611d5f565b5060010190565b60008085851115611d9e57600080fd5b83861115611dab57600080fd5b5050820193919092039150565b8035602083101561132c57600019602084900360031b1b1692915050565b60005b83811015611df1578181015183820152602001611dd9565b50506000910152565b60008251611e0c818460208701611dd6565b9190910192915050565b61010081016040858337608084604084013760c082018360005b6002811015611e4f578151835260209283019290910190600101611e30565b505050949350505050565b80518015158114611e6a57600080fd5b919050565b60008060408385031215611e8257600080fd5b611e8b83611e5a565b9150611e9960208401611e5a565b90509250929050565b6001600160a01b03929092168252602082015260400190565b634e487b7160e01b600052602160045260246000fd5b60008151808452611ee9816020860160208601611dd6565b601f01601f19169290920160200192915050565b6001600160a01b03831681526040602082018190526000906116a090830184611ed1565b808202811582820484141761132c5761132c611d5f565b600082611f5557634e487b7160e01b600052601260045260246000fd5b500490565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b8281526040602082015260006116a06040830184611ed1565b600060408284031215611fd057600080fd5b82601f830112611fdf57600080fd5b6040516040810181811067ffffffffffffffff8211171561200257612002611b92565b806040525080604084018581111561201957600080fd5b845b8181101561203357805183526020928301920161201b565b509195945050505050565b60006020828403121561205057600080fd5b6116de82611e5a565b634e487b7160e01b600052600160045260246000fd5b8082018082111561132c5761132c611d5f565b8181038181111561132c5761132c611d5f565b6020815260006116de6020830184611ed156fea2646970667358221220bc982b5eb2308e71d272d016ed22be05a9dcf98b734fd3bd0b62563ec962766664736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var StakeManagerArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"StakeManager\",\n \"sourceName\": \"contracts/root/staking/StakeManager.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"manager\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"ChildManagerRegistered\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"StakeAdded\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"StakeRemoved\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"recipient\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"StakeWithdrawn\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"ValidatorSlashed\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"manager\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"idFor\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newMatic\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"managerOf\",\n \"outputs\": [\n {\n \"internalType\": \"contract ISupernetManager\",\n \"name\": \"manager\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"manager\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"registerChildChain\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"releaseStakeOf\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"slashStakeOf\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"stakeFor\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"stakeOf\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"totalStake\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"totalStakeOf\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"totalStakeOfChild\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"withdrawStake\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"withdrawableStake\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50610f7d806100206000396000f3fe608060405234801561001057600080fd5b50600436106100bf5760003560e01c8063c60662721161007c578063c606627214610140578063c73a7a1f14610153578063d5364bbf14610166578063d7fbee3d14610179578063e3f56eaa146101a4578063ed87169c146101b7578063f90423fe146101ca57600080fd5b80633651bb1d146100c457806339ed8c90146100d95780638028a6db146100ff5780638b0e9f3f14610112578063b64ddbf61461011a578063c4d66de81461012d575b600080fd5b6100d76100d2366004610ddd565b6101dd565b005b6100ec6100e7366004610e07565b610240565b6040519081526020015b60405180910390f35b6100d761010d366004610ddd565b610256565b6004546100ec565b6100ec610128366004610e20565b610323565b6100d761013b366004610e20565b610431565b6100d761014e366004610ddd565b61055d565b6100d7610161366004610e3b565b610568565b6100ec610174366004610e20565b61068d565b61018c610187366004610e07565b6106ab565b6040516001600160a01b0390911681526020016100f6565b6100ec6101b2366004610e20565b6106b8565b6100ec6101c5366004610ddd565b6106d6565b6100ec6101d8366004610e20565b610702565b60006101e833610702565b90506101f7600484838561070f565b826001600160a01b0316817fcbc2141407acdf7a77731afda2c1369f3c46e04194b90a9d527385c17608eb0d8460405161023391815260200190565b60405180910390a3505050565b6000818152600660205260408120545b92915050565b600061026133610702565b9050600061026f84836106d6565b90508083111561027d578092505b61028a600485848461070f565b6102958433856107eb565b836001600160a01b0316827fcbc2141407acdf7a77731afda2c1369f3c46e04194b90a9d527385c17608eb0d836040516102d191815260200190565b60405180910390a3836001600160a01b0316827fff61f9c95b299671af1bb01c9888e344ed74c6fdff2b1c98eeed2be18714aac08560405161031591815260200190565b60405180910390a350505050565b6001600160a01b0381166000908152600360205260408120541561038e5760405162461bcd60e51b815260206004820152601c60248201527f5374616b654d616e616765723a2049445f414c52454144595f5345540000000060448201526064015b60405180910390fd5b610399600183610859565b604051630d12979960e21b8152600481018290529091506001600160a01b0383169063344a5e6490602401600060405180830381600087803b1580156103de57600080fd5b505af11580156103f2573d6000803e3d6000fd5b50506040516001600160a01b03851692508391507f64566eaf28160aee8cce7464dbf8eb54939f81ac929a8ebeea66865ff57963c490600090a3919050565b600054610100900460ff16158080156104515750600054600160ff909116105b8061046b5750303b15801561046b575060005460ff166001145b6104ce5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610385565b6000805460ff1916600117905580156104f1576000805461ff0019166101001790555b6000805462010000600160b01b031916620100006001600160a01b038516021790558015610559576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b6105593383836107eb565b811580159061057957506001548211155b6105c05760405162461bcd60e51b815260206004820152601860248201527714dd185ad953585b9859d95c8e881253959053125117d25160421b6044820152606401610385565b6000546105de906201000090046001600160a01b031633308461090e565b6105eb600433848461097f565b60006105f6836106ab565b6040516323021ec760e21b8152336004820152602481018490529091506001600160a01b03821690638c087b1c90604401600060405180830381600087803b15801561064157600080fd5b505af1158015610655573d6000803e3d6000fd5b50506040518481523392508591507fc1d3c31619aec7561f6fa519052617aed252a25edaddc5d7428681180516837a90602001610233565b6001600160a01b038116600090815260086020526040812054610250565b6000610250600183610a21565b6001600160a01b038116600090815260076020526040812054610250565b6001600160a01b03821660009081526005602090815260408083208484529091528120545b9392505050565b6000610250600183610a88565b6001600160a01b0383166000908152600185016020908152604080832085845290915281208054839290610744908490610e73565b9091555050600082815260028501602052604081208054839290610769908490610e73565b90915550506001600160a01b038316600090815260038501602052604081208054839290610798908490610e73565b90915550508354819085906000906107b1908490610e73565b90915550506001600160a01b0383166000908152600485016020526040812080548392906107e0908490610e86565b909155505050505050565b6107f760048483610af3565b600054610814906201000090046001600160a01b03168383610b27565b816001600160a01b0316836001600160a01b03167fb7c918e0e249f999e965cafeb6c664271b3f4317d296461500e71da39f0cbda38360405161023391815260200190565b60006001600160a01b0382166108b15760405162461bcd60e51b815260206004820181905260248201527f4368696c644d616e616765724c69623a20494e56414c49445f414444524553536044820152606401610385565b82600001600081546108c290610e99565b91829055506000818152600185016020908152604080832080546001600160a01b039097166001600160a01b031990971687179055948252600290950190945291909220819055919050565b6040516001600160a01b03808516602483015283166044820152606481018290526109799085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610b5c565b50505050565b6001600160a01b03831660009081526001850160209081526040808320858452909152812080548392906109b4908490610e86565b90915550506000828152600285016020526040812080548392906109d9908490610e86565b90915550506001600160a01b038316600090815260038501602052604081208054839290610a08908490610e86565b90915550508354819085906000906107e0908490610e86565b60008181526001830160205260409020546001600160a01b0316806102505760405162461bcd60e51b815260206004820152601b60248201527f4368696c644d616e616765724c69623a20494e56414c49445f494400000000006044820152606401610385565b6001600160a01b0381166000908152600283016020526040812054908190036102505760405162461bcd60e51b815260206004820181905260248201527f4368696c644d616e616765724c69623a20494e56414c49445f4d414e414745526044820152606401610385565b6001600160a01b038216600090815260048401602052604081208054839290610b1d908490610e73565b9091555050505050565b6040516001600160a01b038316602482015260448101829052610b5790849063a9059cbb60e01b90606401610942565b505050565b6000610bb1826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610c319092919063ffffffff16565b9050805160001480610bd2575080806020019051810190610bd29190610eb2565b610b575760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610385565b6060610c408484600085610c48565b949350505050565b606082471015610ca95760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610385565b600080866001600160a01b03168587604051610cc59190610ef8565b60006040518083038185875af1925050503d8060008114610d02576040519150601f19603f3d011682016040523d82523d6000602084013e610d07565b606091505b5091509150610d1887838387610d23565b979650505050505050565b60608315610d92578251600003610d8b576001600160a01b0385163b610d8b5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610385565b5081610c40565b610c408383815115610da75781518083602001fd5b8060405162461bcd60e51b81526004016103859190610f14565b80356001600160a01b0381168114610dd857600080fd5b919050565b60008060408385031215610df057600080fd5b610df983610dc1565b946020939093013593505050565b600060208284031215610e1957600080fd5b5035919050565b600060208284031215610e3257600080fd5b6106fb82610dc1565b60008060408385031215610e4e57600080fd5b50508035926020909101359150565b634e487b7160e01b600052601160045260246000fd5b8181038181111561025057610250610e5d565b8082018082111561025057610250610e5d565b600060018201610eab57610eab610e5d565b5060010190565b600060208284031215610ec457600080fd5b815180151581146106fb57600080fd5b60005b83811015610eef578181015183820152602001610ed7565b50506000910152565b60008251610f0a818460208701610ed4565b9190910192915050565b6020815260008251806020840152610f33816040850160208701610ed4565b601f01601f1916919091016040019291505056fea264697066735822122023b0a75ec2b5e9f66ad966a88679ad7eee0eb952b3bfc7f6dbd5b2adfa2ee0c164736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106100bf5760003560e01c8063c60662721161007c578063c606627214610140578063c73a7a1f14610153578063d5364bbf14610166578063d7fbee3d14610179578063e3f56eaa146101a4578063ed87169c146101b7578063f90423fe146101ca57600080fd5b80633651bb1d146100c457806339ed8c90146100d95780638028a6db146100ff5780638b0e9f3f14610112578063b64ddbf61461011a578063c4d66de81461012d575b600080fd5b6100d76100d2366004610ddd565b6101dd565b005b6100ec6100e7366004610e07565b610240565b6040519081526020015b60405180910390f35b6100d761010d366004610ddd565b610256565b6004546100ec565b6100ec610128366004610e20565b610323565b6100d761013b366004610e20565b610431565b6100d761014e366004610ddd565b61055d565b6100d7610161366004610e3b565b610568565b6100ec610174366004610e20565b61068d565b61018c610187366004610e07565b6106ab565b6040516001600160a01b0390911681526020016100f6565b6100ec6101b2366004610e20565b6106b8565b6100ec6101c5366004610ddd565b6106d6565b6100ec6101d8366004610e20565b610702565b60006101e833610702565b90506101f7600484838561070f565b826001600160a01b0316817fcbc2141407acdf7a77731afda2c1369f3c46e04194b90a9d527385c17608eb0d8460405161023391815260200190565b60405180910390a3505050565b6000818152600660205260408120545b92915050565b600061026133610702565b9050600061026f84836106d6565b90508083111561027d578092505b61028a600485848461070f565b6102958433856107eb565b836001600160a01b0316827fcbc2141407acdf7a77731afda2c1369f3c46e04194b90a9d527385c17608eb0d836040516102d191815260200190565b60405180910390a3836001600160a01b0316827fff61f9c95b299671af1bb01c9888e344ed74c6fdff2b1c98eeed2be18714aac08560405161031591815260200190565b60405180910390a350505050565b6001600160a01b0381166000908152600360205260408120541561038e5760405162461bcd60e51b815260206004820152601c60248201527f5374616b654d616e616765723a2049445f414c52454144595f5345540000000060448201526064015b60405180910390fd5b610399600183610859565b604051630d12979960e21b8152600481018290529091506001600160a01b0383169063344a5e6490602401600060405180830381600087803b1580156103de57600080fd5b505af11580156103f2573d6000803e3d6000fd5b50506040516001600160a01b03851692508391507f64566eaf28160aee8cce7464dbf8eb54939f81ac929a8ebeea66865ff57963c490600090a3919050565b600054610100900460ff16158080156104515750600054600160ff909116105b8061046b5750303b15801561046b575060005460ff166001145b6104ce5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610385565b6000805460ff1916600117905580156104f1576000805461ff0019166101001790555b6000805462010000600160b01b031916620100006001600160a01b038516021790558015610559576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b6105593383836107eb565b811580159061057957506001548211155b6105c05760405162461bcd60e51b815260206004820152601860248201527714dd185ad953585b9859d95c8e881253959053125117d25160421b6044820152606401610385565b6000546105de906201000090046001600160a01b031633308461090e565b6105eb600433848461097f565b60006105f6836106ab565b6040516323021ec760e21b8152336004820152602481018490529091506001600160a01b03821690638c087b1c90604401600060405180830381600087803b15801561064157600080fd5b505af1158015610655573d6000803e3d6000fd5b50506040518481523392508591507fc1d3c31619aec7561f6fa519052617aed252a25edaddc5d7428681180516837a90602001610233565b6001600160a01b038116600090815260086020526040812054610250565b6000610250600183610a21565b6001600160a01b038116600090815260076020526040812054610250565b6001600160a01b03821660009081526005602090815260408083208484529091528120545b9392505050565b6000610250600183610a88565b6001600160a01b0383166000908152600185016020908152604080832085845290915281208054839290610744908490610e73565b9091555050600082815260028501602052604081208054839290610769908490610e73565b90915550506001600160a01b038316600090815260038501602052604081208054839290610798908490610e73565b90915550508354819085906000906107b1908490610e73565b90915550506001600160a01b0383166000908152600485016020526040812080548392906107e0908490610e86565b909155505050505050565b6107f760048483610af3565b600054610814906201000090046001600160a01b03168383610b27565b816001600160a01b0316836001600160a01b03167fb7c918e0e249f999e965cafeb6c664271b3f4317d296461500e71da39f0cbda38360405161023391815260200190565b60006001600160a01b0382166108b15760405162461bcd60e51b815260206004820181905260248201527f4368696c644d616e616765724c69623a20494e56414c49445f414444524553536044820152606401610385565b82600001600081546108c290610e99565b91829055506000818152600185016020908152604080832080546001600160a01b039097166001600160a01b031990971687179055948252600290950190945291909220819055919050565b6040516001600160a01b03808516602483015283166044820152606481018290526109799085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610b5c565b50505050565b6001600160a01b03831660009081526001850160209081526040808320858452909152812080548392906109b4908490610e86565b90915550506000828152600285016020526040812080548392906109d9908490610e86565b90915550506001600160a01b038316600090815260038501602052604081208054839290610a08908490610e86565b90915550508354819085906000906107e0908490610e86565b60008181526001830160205260409020546001600160a01b0316806102505760405162461bcd60e51b815260206004820152601b60248201527f4368696c644d616e616765724c69623a20494e56414c49445f494400000000006044820152606401610385565b6001600160a01b0381166000908152600283016020526040812054908190036102505760405162461bcd60e51b815260206004820181905260248201527f4368696c644d616e616765724c69623a20494e56414c49445f4d414e414745526044820152606401610385565b6001600160a01b038216600090815260048401602052604081208054839290610b1d908490610e73565b9091555050505050565b6040516001600160a01b038316602482015260448101829052610b5790849063a9059cbb60e01b90606401610942565b505050565b6000610bb1826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610c319092919063ffffffff16565b9050805160001480610bd2575080806020019051810190610bd29190610eb2565b610b575760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610385565b6060610c408484600085610c48565b949350505050565b606082471015610ca95760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610385565b600080866001600160a01b03168587604051610cc59190610ef8565b60006040518083038185875af1925050503d8060008114610d02576040519150601f19603f3d011682016040523d82523d6000602084013e610d07565b606091505b5091509150610d1887838387610d23565b979650505050505050565b60608315610d92578251600003610d8b576001600160a01b0385163b610d8b5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610385565b5081610c40565b610c408383815115610da75781518083602001fd5b8060405162461bcd60e51b81526004016103859190610f14565b80356001600160a01b0381168114610dd857600080fd5b919050565b60008060408385031215610df057600080fd5b610df983610dc1565b946020939093013593505050565b600060208284031215610e1957600080fd5b5035919050565b600060208284031215610e3257600080fd5b6106fb82610dc1565b60008060408385031215610e4e57600080fd5b50508035926020909101359150565b634e487b7160e01b600052601160045260246000fd5b8181038181111561025057610250610e5d565b8082018082111561025057610250610e5d565b600060018201610eab57610eab610e5d565b5060010190565b600060208284031215610ec457600080fd5b815180151581146106fb57600080fd5b60005b83811015610eef578181015183820152602001610ed7565b50506000910152565b60008251610f0a818460208701610ed4565b9190910192915050565b6020815260008251806020840152610f33816040850160208701610ed4565b601f01601f1916919091016040019291505056fea264697066735822122023b0a75ec2b5e9f66ad966a88679ad7eee0eb952b3bfc7f6dbd5b2adfa2ee0c164736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var RewardPoolArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"RewardPool\",\n \"sourceName\": \"contracts/child/validator/RewardPool.sol\",\n \"abi\": [\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"only\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"Unauthorized\",\n \"type\": \"error\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"epochId\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"totalReward\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"RewardDistributed\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"ALLOWLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"BLOCKLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TOKEN_CONTRACT\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"READ_ADDRESSLIST_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"SYSTEM\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"baseReward\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"epochId\",\n \"type\": \"uint256\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"address\",\n \"name\": \"validator\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"signedBlocks\",\n \"type\": \"uint256\"\n }\n ],\n \"internalType\": \"struct Uptime[]\",\n \"name\": \"uptime\",\n \"type\": \"tuple[]\"\n }\n ],\n \"name\": \"distributeRewardFor\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newRewardToken\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newRewardWallet\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newValidatorSet\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"newBaseReward\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"paidRewardPerEpoch\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"pendingRewards\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"rewardToken\",\n \"outputs\": [\n {\n \"internalType\": \"contract IERC20Upgradeable\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"rewardWallet\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"validatorSet\",\n \"outputs\": [\n {\n \"internalType\": \"contract IValidatorSet\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"withdrawReward\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50610ee1806100206000396000f3fe608060405234801561001057600080fd5b50600436106101165760003560e01c80638a9cd82d116100a2578063c885bc5811610071578063c885bc581461020f578063cf756fdf14610217578063e0563ab11461022a578063f7c618c114610233578063fb75b2c71461024c57600080fd5b80638a9cd82d146101d45780639426e226146101e9578063947287cf146101fc57806397e5230d1461020557600080fd5b80633b878c22116100e95780633b878c221461019d57806351351d53146101a657806355b01e4d146101b45780635ea5df79146101c257806376ad03bc146101cb57600080fd5b806307358b991461011b57806307b3e2521461014e578063284017f51461017457806331d7a2621461017d575b600080fd5b61013b610129366004610be0565b60366020526000908152604090205481565b6040519081526020015b60405180910390f35b61015c6004600360981b0181565b6040516001600160a01b039091168152602001610145565b61015c61202081565b61013b61018b366004610c15565b60376020526000908152604090205481565b61015c61101081565b61015c6002600160a01b0381565b61015c6004600160991b0181565b61013b61138881565b61013b60355481565b6101e76101e2366004610c37565b61025f565b005b60345461015c906001600160a01b031681565b61013b61520881565b61013b620249f081565b6101e76106a9565b6101e7610225366004610cb6565b6106df565b61015c61203081565b60325461015c906201000090046001600160a01b031681565b60335461015c906001600160a01b031681565b336002600160a01b03146102a85760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b60448201526064015b60405180910390fd5b600083815260366020526040902054156103045760405162461bcd60e51b815260206004820152601a60248201527f5245574152445f414c52454144595f4449535452494255544544000000000000604482015260640161029f565b603454604051633f490b0560e21b8152600481018590526000916001600160a01b03169063fd242c1490602401602060405180830381865afa15801561034e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103729190610d01565b9050806000036103ba5760405162461bcd60e51b8152602060048201526013602482015272115413d0d217d393d517d0d3d3535255151151606a1b604482015260640161029f565b60345460408051636265600360e01b815290516000926001600160a01b03169163626560039160048083019260209291908290030181865afa158015610404573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104289190610d01565b90506000818360355461043b9190610d30565b6104459190610d4d565b603454604051630981b24d60e41b8152600481018990529192506000916001600160a01b039091169063981b24d090602401602060405180830381865afa158015610494573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104b89190610d01565b9050846000805b828110156106495760008989838181106104db576104db610d6f565b9050604002018036038101906104f19190610d85565b905087816020015111156105475760405162461bcd60e51b815260206004820152601b60248201527f5349474e45445f424c4f434b535f455843454544535f544f54414c0000000000604482015260640161029f565b603454815160405163277166bf60e11b81526001600160a01b039182166004820152602481018e90526000929190911690634ee2cd7e90604401602060405180830381865afa15801561059e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c29190610d01565b905060006105d08a88610d30565b60208401516105df848b610d30565b6105e99190610d30565b6105f39190610d4d565b83516001600160a01b0316600090815260376020526040812080549293508392909190610621908490610dea565b9091555061063190508186610dea565b9450505050808061064190610dfd565b9150506104bf565b506000898152603660205260409020819055610664816108b1565b887feaf3d57629d9b1ce95715ccd98d6f5bf48023be1d5a06e09f64ab7f6d8be01d58260405161069691815260200190565b60405180910390a2505050505050505050565b336000818152603760205260408120805491905560325490916106dc916201000090046001600160a01b031690836108d5565b50565b603254610100900460ff16158080156106ff5750603254600160ff909116105b806107195750303b158015610719575060325460ff166001145b61077c5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161029f565b6032805460ff19166001179055801561079f576032805461ff0019166101001790555b6001600160a01b038516158015906107bf57506001600160a01b03841615155b80156107d357506001600160a01b03831615155b61080e5760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b604482015260640161029f565b603280546001600160a01b03808816620100000262010000600160b01b031990921691909117909155603380548683166001600160a01b0319918216179091556034805492861692909116919091179055603582905580156108aa576032805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b6033546032546106dc916001600160a01b036201000090920482169116308461093d565b6040516001600160a01b03831660248201526044810182905261093890849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261097b565b505050565b6040516001600160a01b03808516602483015283166044820152606481018290526109759085906323b872dd60e01b90608401610901565b50505050565b60006109d0826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610a509092919063ffffffff16565b90508051600014806109f15750808060200190518101906109f19190610e16565b6109385760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161029f565b6060610a5f8484600085610a67565b949350505050565b606082471015610ac85760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161029f565b600080866001600160a01b03168587604051610ae49190610e5c565b60006040518083038185875af1925050503d8060008114610b21576040519150601f19603f3d011682016040523d82523d6000602084013e610b26565b606091505b5091509150610b3787838387610b42565b979650505050505050565b60608315610bb1578251600003610baa576001600160a01b0385163b610baa5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161029f565b5081610a5f565b610a5f8383815115610bc65781518083602001fd5b8060405162461bcd60e51b815260040161029f9190610e78565b600060208284031215610bf257600080fd5b5035919050565b80356001600160a01b0381168114610c1057600080fd5b919050565b600060208284031215610c2757600080fd5b610c3082610bf9565b9392505050565b600080600060408486031215610c4c57600080fd5b83359250602084013567ffffffffffffffff80821115610c6b57600080fd5b818601915086601f830112610c7f57600080fd5b813581811115610c8e57600080fd5b8760208260061b8501011115610ca357600080fd5b6020830194508093505050509250925092565b60008060008060808587031215610ccc57600080fd5b610cd585610bf9565b9350610ce360208601610bf9565b9250610cf160408601610bf9565b9396929550929360600135925050565b600060208284031215610d1357600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610d4757610d47610d1a565b92915050565b600082610d6a57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fd5b600060408284031215610d9757600080fd5b6040516040810181811067ffffffffffffffff82111715610dc857634e487b7160e01b600052604160045260246000fd5b604052610dd483610bf9565b8152602083013560208201528091505092915050565b80820180821115610d4757610d47610d1a565b600060018201610e0f57610e0f610d1a565b5060010190565b600060208284031215610e2857600080fd5b81518015158114610c3057600080fd5b60005b83811015610e53578181015183820152602001610e3b565b50506000910152565b60008251610e6e818460208701610e38565b9190910192915050565b6020815260008251806020840152610e97816040850160208701610e38565b601f01601f1916919091016040019291505056fea2646970667358221220d9d5cb95a8c6f1edeb2b53a8eebe52a4d92f5c1ea3f95d4f766548e10cc60cb464736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106101165760003560e01c80638a9cd82d116100a2578063c885bc5811610071578063c885bc581461020f578063cf756fdf14610217578063e0563ab11461022a578063f7c618c114610233578063fb75b2c71461024c57600080fd5b80638a9cd82d146101d45780639426e226146101e9578063947287cf146101fc57806397e5230d1461020557600080fd5b80633b878c22116100e95780633b878c221461019d57806351351d53146101a657806355b01e4d146101b45780635ea5df79146101c257806376ad03bc146101cb57600080fd5b806307358b991461011b57806307b3e2521461014e578063284017f51461017457806331d7a2621461017d575b600080fd5b61013b610129366004610be0565b60366020526000908152604090205481565b6040519081526020015b60405180910390f35b61015c6004600360981b0181565b6040516001600160a01b039091168152602001610145565b61015c61202081565b61013b61018b366004610c15565b60376020526000908152604090205481565b61015c61101081565b61015c6002600160a01b0381565b61015c6004600160991b0181565b61013b61138881565b61013b60355481565b6101e76101e2366004610c37565b61025f565b005b60345461015c906001600160a01b031681565b61013b61520881565b61013b620249f081565b6101e76106a9565b6101e7610225366004610cb6565b6106df565b61015c61203081565b60325461015c906201000090046001600160a01b031681565b60335461015c906001600160a01b031681565b336002600160a01b03146102a85760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b60448201526064015b60405180910390fd5b600083815260366020526040902054156103045760405162461bcd60e51b815260206004820152601a60248201527f5245574152445f414c52454144595f4449535452494255544544000000000000604482015260640161029f565b603454604051633f490b0560e21b8152600481018590526000916001600160a01b03169063fd242c1490602401602060405180830381865afa15801561034e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103729190610d01565b9050806000036103ba5760405162461bcd60e51b8152602060048201526013602482015272115413d0d217d393d517d0d3d3535255151151606a1b604482015260640161029f565b60345460408051636265600360e01b815290516000926001600160a01b03169163626560039160048083019260209291908290030181865afa158015610404573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104289190610d01565b90506000818360355461043b9190610d30565b6104459190610d4d565b603454604051630981b24d60e41b8152600481018990529192506000916001600160a01b039091169063981b24d090602401602060405180830381865afa158015610494573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104b89190610d01565b9050846000805b828110156106495760008989838181106104db576104db610d6f565b9050604002018036038101906104f19190610d85565b905087816020015111156105475760405162461bcd60e51b815260206004820152601b60248201527f5349474e45445f424c4f434b535f455843454544535f544f54414c0000000000604482015260640161029f565b603454815160405163277166bf60e11b81526001600160a01b039182166004820152602481018e90526000929190911690634ee2cd7e90604401602060405180830381865afa15801561059e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c29190610d01565b905060006105d08a88610d30565b60208401516105df848b610d30565b6105e99190610d30565b6105f39190610d4d565b83516001600160a01b0316600090815260376020526040812080549293508392909190610621908490610dea565b9091555061063190508186610dea565b9450505050808061064190610dfd565b9150506104bf565b506000898152603660205260409020819055610664816108b1565b887feaf3d57629d9b1ce95715ccd98d6f5bf48023be1d5a06e09f64ab7f6d8be01d58260405161069691815260200190565b60405180910390a2505050505050505050565b336000818152603760205260408120805491905560325490916106dc916201000090046001600160a01b031690836108d5565b50565b603254610100900460ff16158080156106ff5750603254600160ff909116105b806107195750303b158015610719575060325460ff166001145b61077c5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161029f565b6032805460ff19166001179055801561079f576032805461ff0019166101001790555b6001600160a01b038516158015906107bf57506001600160a01b03841615155b80156107d357506001600160a01b03831615155b61080e5760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b604482015260640161029f565b603280546001600160a01b03808816620100000262010000600160b01b031990921691909117909155603380548683166001600160a01b0319918216179091556034805492861692909116919091179055603582905580156108aa576032805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b6033546032546106dc916001600160a01b036201000090920482169116308461093d565b6040516001600160a01b03831660248201526044810182905261093890849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261097b565b505050565b6040516001600160a01b03808516602483015283166044820152606481018290526109759085906323b872dd60e01b90608401610901565b50505050565b60006109d0826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610a509092919063ffffffff16565b90508051600014806109f15750808060200190518101906109f19190610e16565b6109385760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161029f565b6060610a5f8484600085610a67565b949350505050565b606082471015610ac85760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161029f565b600080866001600160a01b03168587604051610ae49190610e5c565b60006040518083038185875af1925050503d8060008114610b21576040519150601f19603f3d011682016040523d82523d6000602084013e610b26565b606091505b5091509150610b3787838387610b42565b979650505050505050565b60608315610bb1578251600003610baa576001600160a01b0385163b610baa5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161029f565b5081610a5f565b610a5f8383815115610bc65781518083602001fd5b8060405162461bcd60e51b815260040161029f9190610e78565b600060208284031215610bf257600080fd5b5035919050565b80356001600160a01b0381168114610c1057600080fd5b919050565b600060208284031215610c2757600080fd5b610c3082610bf9565b9392505050565b600080600060408486031215610c4c57600080fd5b83359250602084013567ffffffffffffffff80821115610c6b57600080fd5b818601915086601f830112610c7f57600080fd5b813581811115610c8e57600080fd5b8760208260061b8501011115610ca357600080fd5b6020830194508093505050509250925092565b60008060008060808587031215610ccc57600080fd5b610cd585610bf9565b9350610ce360208601610bf9565b9250610cf160408601610bf9565b9396929550929360600135925050565b600060208284031215610d1357600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610d4757610d47610d1a565b92915050565b600082610d6a57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fd5b600060408284031215610d9757600080fd5b6040516040810181811067ffffffffffffffff82111715610dc857634e487b7160e01b600052604160045260246000fd5b604052610dd483610bf9565b8152602083013560208201528091505092915050565b80820180821115610d4757610d47610d1a565b600060018201610e0f57610e0f610d1a565b5060010190565b600060208284031215610e2857600080fd5b81518015158114610c3057600080fd5b60005b83811015610e53578181015183820152602001610e3b565b50506000910152565b60008251610e6e818460208701610e38565b9190910192915050565b6020815260008251806020840152610e97816040850160208701610e38565b601f01601f1916919091016040019291505056fea2646970667358221220d9d5cb95a8c6f1edeb2b53a8eebe52a4d92f5c1ea3f95d4f766548e10cc60cb464736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var ValidatorSetArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"ValidatorSet\",\n \"sourceName\": \"contracts/child/validator/ValidatorSet.sol\",\n \"abi\": [\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"only\",\n \"type\": \"string\"\n }\n ],\n \"name\": \"Unauthorized\",\n \"type\": \"error\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Approval\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"startBlock\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"endBlock\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bytes32\",\n \"name\": \"epochRoot\",\n \"type\": \"bytes32\"\n }\n ],\n \"name\": \"NewEpoch\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"validator\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Slashed\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Snapshot\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Transfer\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Withdrawal\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"WithdrawalRegistered\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"ALLOWLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"BLOCKLIST_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"EPOCH_SIZE\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TOKEN_CONTRACT\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"NATIVE_TRANSFER_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"READ_ADDRESSLIST_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"SYSTEM\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"VALIDATOR_PKCHECK_PRECOMPILE_GAS\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"WITHDRAWAL_WAIT_PERIOD\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"allowance\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"approve\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"balanceOf\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"epochNumber\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"balanceOfAt\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"id\",\n \"type\": \"uint256\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"startBlock\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"endBlock\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"epochRoot\",\n \"type\": \"bytes32\"\n }\n ],\n \"internalType\": \"struct Epoch\",\n \"name\": \"epoch\",\n \"type\": \"tuple\"\n }\n ],\n \"name\": \"commitEpoch\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"currentEpochId\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"decimals\",\n \"outputs\": [\n {\n \"internalType\": \"uint8\",\n \"name\": \"\",\n \"type\": \"uint8\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"subtractedValue\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"decreaseAllowance\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"epochEndBlocks\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"epochs\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"startBlock\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"endBlock\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"epochRoot\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"addedValue\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"increaseAllowance\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"newStateSender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newStateReceiver\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newRootChainManager\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"newEpochSize\",\n \"type\": \"uint256\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"address\",\n \"name\": \"addr\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"stake\",\n \"type\": \"uint256\"\n }\n ],\n \"internalType\": \"struct ValidatorInit[]\",\n \"name\": \"initialValidators\",\n \"type\": \"tuple[]\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"name\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"data\",\n \"type\": \"bytes\"\n }\n ],\n \"name\": \"onStateReceive\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"pendingWithdrawals\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"symbol\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"epochId\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"totalBlocks\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"length\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"totalSupply\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"epochNumber\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"totalSupplyAt\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transfer\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transferFrom\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"unstake\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"withdraw\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"withdrawable\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50612167806100206000396000f3fe608060405234801561001057600080fd5b50600436106102015760003560e01c806361cc276311610125578063c6b61e4c116100ad578063ea0fee4f1161007c578063ea0fee4f1461043d578063eacdc5ff14610445578063eeb499451461044e578063f3f4370314610461578063fd242c141461047457600080fd5b8063c6b61e4c146103c4578063ce513b6f1461040e578063dd62ed3e14610421578063e0563ab11461043457600080fd5b806395d89b41116100f457806395d89b411461037957806397e5230d14610381578063981b24d01461038b578063a457c2d71461039e578063a9059cbb146103b157600080fd5b806361cc276314610341578063626560031461035457806370a082311461035d578063947287cf1461037057600080fd5b8063313ce567116101a85780633fd50001116101775780633fd50001146102f65780634ee2cd7e1461030957806351351d531461031c57806355b01e4d1461032a5780635ea5df791461033857600080fd5b8063313ce567146102c357806339509351146102d25780633b878c22146102e55780633ccfd60b146102ee57600080fd5b806306fdde031461020657806307b3e25214610224578063095ea7b31461024a5780630f50287c1461026d57806318160ddd1461028257806323b872dd14610294578063284017f5146102a75780632e17de78146102b0575b600080fd5b61020e610487565b60405161021b9190611af6565b60405180910390f35b6102326004600360981b0181565b6040516001600160a01b03909116815260200161021b565b61025d610258366004611b1e565b610519565b604051901515815260200161021b565b61028061027b366004611b4a565b610533565b005b6035545b60405190815260200161021b565b61025d6102a2366004611b82565b6107c5565b61023261202081565b6102806102be366004611bc3565b6107e9565b6040516012815260200161021b565b61025d6102e0366004611b1e565b610800565b61023261101081565b610280610822565b610286610304366004611bc3565b610933565b610286610317366004611b1e565b610954565b6102326002600160a01b0381565b6102326004600160991b0181565b61028661138881565b61028061034f366004611c4c565b610967565b61028660cc5481565b61028661036b366004611d65565b610c10565b61028661520881565b61020e610c2b565b610286620249f081565b610286610399366004611bc3565b610c3a565b61025d6103ac366004611b1e565b610c45565b61025d6103bf366004611b1e565b610cc0565b6103f36103d2366004611bc3565b60ce6020526000908152604090208054600182015460029092015490919083565b6040805193845260208401929092529082015260600161021b565b61028661041c366004611d65565b610cce565b61028661042f366004611d82565b610cfc565b61023261203081565b610286600181565b61028660cd5481565b61028061045c366004611dbb565b610d27565b61028661046f366004611d65565b610df9565b610286610482366004611bc3565b610e20565b60606036805461049690611e44565b80601f01602080910402602001604051908101604052809291908181526020018280546104c290611e44565b801561050f5780601f106104e45761010080835404028352916020019161050f565b820191906000526020600020905b8154815290600101906020018083116104f257829003601f168201915b5050505050905090565b600033610527818585610e6a565b60019150505b92915050565b336002600160a01b031461057c5760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b60448201526064015b60405180910390fd5b60cd80546000918261058d83611e94565b9190505590508083146105d85760405162461bcd60e51b815260206004820152601360248201527215539156141150d5115117d15413d0d217d251606a1b6044820152606401610573565b81356020830135116106225760405162461bcd60e51b81526020600482015260136024820152721393d7d09313d0d2d4d7d0d3d3535255151151606a1b6044820152606401610573565b60cc5461063483356020850135611ead565b61063f906001611ec0565b6106499190611ee9565b156106a45760405162461bcd60e51b815260206004820152602560248201527f45504f43485f4d5553545f42455f444956495349424c455f42595f45504f43486044820152645f53495a4560d81b6064820152608401610573565b813560ce60006106b5600185611ead565b81526020019081526020016000206001015460016106d39190611ec0565b146107165760405162461bcd60e51b8152602060048201526013602482015272494e56414c49445f53544152545f424c4f434b60681b6044820152606401610573565b600081815260ce60205260409020829061074782828135815560208201356001820155604082013560028201555050565b505060cf80546001810182556000919091526020838101357facb8d954e2cfef495862221e91bd7523613cf8808827cb33edfe4904cc51bf299092018290556040805190850135815284359186917f0ce8712c4dee4bd5a691f0bc1c39594671591e77395f8ebf6a3fb5f63fbea66a910160405180910390a4505050565b6000336107d3858285610f8f565b6107de858585611003565b506001949350505050565b6107f333826111a7565b6107fd33826112d2565b50565b6000336105278185856108138383610cfc565b61081d9190611ec0565b610e6a565b33600090815260d06020526040812060cd54909190819061084490849061134b565b808555604051828152919350915033907f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b659060200160405180910390a260c95460cb54604080517f8ca9a95e41b5eece253c93f5b31eed1253aed6b145d8a6e14d913fdf8e7322936020820152338183015260608082018790528251808303909101815260808201928390526316f1983160e01b9092526001600160a01b03938416936316f19831936108fc93911691608401611efd565b600060405180830381600087803b15801561091657600080fd5b505af115801561092a573d6000803e3d6000fd5b50505050505050565b60cf818154811061094357600080fd5b600091825260209091200154905081565b600061096083836113bd565b9392505050565b600054610100900460ff16158080156109875750600054600160ff909116105b806109a15750303b1580156109a1575060005460ff166001145b610a045760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610573565b6000805460ff191660011790558015610a27576000805461ff0019166101001790555b6001600160a01b03861615801590610a4757506001600160a01b03851615155b8015610a5b57506001600160a01b03841615155b8015610a6657508215155b610aa25760405162461bcd60e51b815260206004820152600d60248201526c1253959053125117d253941555609a1b6044820152606401610573565b610aec6040518060400160405280600c81526020016b15985b1a59185d1bdc94d95d60a21b815250604051806040016040528060048152602001631594d15560e21b815250611406565b60c980546001600160a01b038089166001600160a01b03199283161790925560ca805488841690831617905560cb80549287169290911691909117905560cc83905560005b8251811015610b8657610b7e838281518110610b4f57610b4f611f21565b602002602001015160000151848381518110610b6d57610b6d611f21565b60200260200101516020015161143b565b600101610b31565b5060cf80546001818101835560009283527facb8d954e2cfef495862221e91bd7523613cf8808827cb33edfe4904cc51bf299091019190915560cd558015610c08576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b6001600160a01b031660009081526033602052604090205490565b60606037805461049690611e44565b600061052d82611445565b60003381610c538286610cfc565b905083811015610cb35760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610573565b6107de8286868403610e6a565b600033610527818585611003565b60cd546001600160a01b038216600090815260d0602052604081209091610cf5919061134b565b5092915050565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b60ca546001600160a01b031633148015610d4e575060cb546001600160a01b038481169116145b610d8b5760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a2a72222a960911b6044820152606401610573565b7f1bcc0f4c3fad314e585165815f94ecca9b96690a26d6417d7876448a9a867a69610dba602060008486611f37565b610dc391611f61565b03610df357600080610dd88360208187611f37565b810190610de59190611b1e565b91509150610c08828261143b565b50505050565b60cd546001600160a01b038216600090815260d060205260408120909161052d9190611470565b600081815260ce60205260408120600101548015610e6157600083815260ce6020526040902054610e519082611ead565b610e5c906001611ec0565b610960565b60009392505050565b6001600160a01b038316610ecc5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610573565b6001600160a01b038216610f2d5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610573565b6001600160a01b0383811660008181526034602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6000610f9b8484610cfc565b90506000198114610df35781811015610ff65760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610573565b610df38484848403610e6a565b6001600160a01b0383166110675760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610573565b6001600160a01b0382166110c95760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610573565b6110d483838361150e565b6001600160a01b0383166000908152603360205260409020548181101561114c5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610573565b6001600160a01b0380851660008181526033602052604080822086860390559286168082529083902080548601905591516000805160206121128339815191529061119a9086815260200190565b60405180910390a3610df3565b6001600160a01b0382166112075760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610573565b6112138260008361150e565b6001600160a01b038216600090815260336020526040902054818110156112875760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610573565b6001600160a01b03831660008181526033602090815260408083208686039055603580548790039055518581529192916000805160206121128339815191529101610f82565b505050565b61130481600160cd546112e59190611ec0565b6001600160a01b038516600090815260d0602052604090209190611577565b816001600160a01b03167f655c1cd0236fb6dc4916f34c8ff10e3b18fcaea5b344dfc16c36fbb1bdfc5df28260405161133f91815260200190565b60405180910390a25050565b81546000905b83600101548110156113b65760008181526002850160209081526040918290208251808401909352805483526001015490820181905284101561139457506113b6565b80516113a09084611ec0565b92505080806113ae90611e94565b915050611351565b9250929050565b6001600160a01b0382166000908152606560205260408120819081906113e49085906116ed565b91509150816113fb576113f685610c10565b6113fd565b805b95945050505050565b600054610100900460ff1661142d5760405162461bcd60e51b815260040161057390611f7f565b61143782826117db565b5050565b611437828261181b565b60008060006114558460666116ed565b915091508161146657603554611468565b805b949350505050565b600182015460009080820361148957600091505061052d565b6000611496600183611ead565b90505b845481106115065760008181526002860160209081526040918290208251808401909352805483526001015490820181905285106114d75750611506565b80516114e39085611ec0565b9350816000036114f35750611506565b50806114fe81611fca565b915050611499565b505092915050565b6001600160a01b038316158061152b57506001600160a01b038216155b61156c5760405162461bcd60e51b81526020600482015260126024820152712a2920a729a322a92fa327a92124a22222a760711b6044820152606401610573565b6112cd8383836118d6565b816000036115d25760405162461bcd60e51b815260206004820152602260248201527f5769746864726177616c51756575654c69623a20494e56414c49445f414d4f55604482015261139560f21b6064820152608401610573565b82546001840154818103611629576040805180820182528581526020808201868152600085815260028a01909252928120915182559151600191820155860180549161161d83611e94565b91905055505050505050565b6000600286018161163b600185611ead565b81526020019081526020016000206001015490508084101561165f5761165f611fe1565b838110156116ae576040805180820182528681526020808201878152600086815260028b0190925292812091518255915160019182015587018054916116a483611e94565b9190505550610c08565b846002870160006116c0600186611ead565b815260200190815260200160002060000160008282546116e09190611ec0565b9091555050505050505050565b600080600084116117395760405162461bcd60e51b815260206004820152601660248201527504552433230536e617073686f743a20696420697320360541b6044820152606401610573565b60cd5484111561178b5760405162461bcd60e51b815260206004820152601d60248201527f4552433230536e617073686f743a206e6f6e6578697374656e742069640000006044820152606401610573565b6000611797848661191e565b845490915081036117af5760008092509250506113b6565b60018460010182815481106117c6576117c6611f21565b906000526020600020015492509250506113b6565b600054610100900460ff166118025760405162461bcd60e51b815260040161057390611f7f565b603661180e838261203d565b5060376112cd828261203d565b6001600160a01b0382166118715760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610573565b61187d6000838361150e565b806035600082825461188f9190611ec0565b90915550506001600160a01b038216600081815260336020908152604080832080548601905551848152600080516020612112833981519152910160405180910390a35050565b6001600160a01b0383166118f5576118ed826119cb565b6112cd6119f5565b6001600160a01b03821661190c576118ed836119cb565b611915836119cb565b6112cd826119cb565b815460009081036119315750600061052d565b82546000905b8082101561197e57600061194b8383611a05565b6000878152602090209091508590820154111561196a57809150611978565b611975816001611ec0565b92505b50611937565b6000821180156119aa5750836119a786611999600186611ead565b600091825260209091200190565b54145b156119c3576119ba600183611ead565b9250505061052d565b50905061052d565b6001600160a01b03811660009081526065602052604090206107fd906119f083610c10565b611a20565b611a0360666119f060355490565b565b6000611a1460028484186120fd565b61096090848416611ec0565b6000611a2b60cd5490565b905080611a3784611a6b565b10156112cd578254600180820185556000858152602080822090930193909355938401805494850181558252902090910155565b80546000908103611a7e57506000919050565b81548290611a8e90600190611ead565b81548110611a9e57611a9e611f21565b90600052602060002001549050919050565b6000815180845260005b81811015611ad657602081850181015186830182015201611aba565b506000602082860101526020601f19601f83011685010191505092915050565b6020815260006109606020830184611ab0565b6001600160a01b03811681146107fd57600080fd5b60008060408385031215611b3157600080fd5b8235611b3c81611b09565b946020939093013593505050565b6000808284036080811215611b5e57600080fd5b833592506060601f1982011215611b7457600080fd5b506020830190509250929050565b600080600060608486031215611b9757600080fd5b8335611ba281611b09565b92506020840135611bb281611b09565b929592945050506040919091013590565b600060208284031215611bd557600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715611c1557611c15611bdc565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611c4457611c44611bdc565b604052919050565b600080600080600060a08688031215611c6457600080fd5b8535611c6f81611b09565b9450602086810135611c8081611b09565b9450604087810135611c9181611b09565b945060608801359350608088013567ffffffffffffffff80821115611cb557600080fd5b818a0191508a601f830112611cc957600080fd5b813581811115611cdb57611cdb611bdc565b611ce9858260051b01611c1b565b818152858101925060069190911b83018501908c821115611d0957600080fd5b928501925b81841015611d525784848e031215611d265760008081fd5b611d2e611bf2565b8435611d3981611b09565b8152848701358782015283529284019291850191611d0e565b8096505050505050509295509295909350565b600060208284031215611d7757600080fd5b813561096081611b09565b60008060408385031215611d9557600080fd5b8235611da081611b09565b91506020830135611db081611b09565b809150509250929050565b60008060008060608587031215611dd157600080fd5b843593506020850135611de381611b09565b9250604085013567ffffffffffffffff80821115611e0057600080fd5b818701915087601f830112611e1457600080fd5b813581811115611e2357600080fd5b886020828501011115611e3557600080fd5b95989497505060200194505050565b600181811c90821680611e5857607f821691505b602082108103611e7857634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b600060018201611ea657611ea6611e7e565b5060010190565b8181038181111561052d5761052d611e7e565b8082018082111561052d5761052d611e7e565b634e487b7160e01b600052601260045260246000fd5b600082611ef857611ef8611ed3565b500690565b6001600160a01b038316815260406020820181905260009061146890830184611ab0565b634e487b7160e01b600052603260045260246000fd5b60008085851115611f4757600080fd5b83861115611f5457600080fd5b5050820193919092039150565b8035602083101561052d57600019602084900360031b1b1692915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b600081611fd957611fd9611e7e565b506000190190565b634e487b7160e01b600052600160045260246000fd5b601f8211156112cd57600081815260208120601f850160051c8101602086101561201e5750805b601f850160051c820191505b81811015610c085782815560010161202a565b815167ffffffffffffffff81111561205757612057611bdc565b61206b816120658454611e44565b84611ff7565b602080601f8311600181146120a057600084156120885750858301515b600019600386901b1c1916600185901b178555610c08565b600085815260208120601f198616915b828110156120cf578886015182559484019460019091019084016120b0565b50858210156120ed5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008261210c5761210c611ed3565b50049056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212203c4d95e2d3f73d67d2168a29cb8be58c25d393af2555dd32816d324aba1cccfc64736f6c63430008130033\",\n \"deployedBytecode\": \"0x608060405234801561001057600080fd5b50600436106102015760003560e01c806361cc276311610125578063c6b61e4c116100ad578063ea0fee4f1161007c578063ea0fee4f1461043d578063eacdc5ff14610445578063eeb499451461044e578063f3f4370314610461578063fd242c141461047457600080fd5b8063c6b61e4c146103c4578063ce513b6f1461040e578063dd62ed3e14610421578063e0563ab11461043457600080fd5b806395d89b41116100f457806395d89b411461037957806397e5230d14610381578063981b24d01461038b578063a457c2d71461039e578063a9059cbb146103b157600080fd5b806361cc276314610341578063626560031461035457806370a082311461035d578063947287cf1461037057600080fd5b8063313ce567116101a85780633fd50001116101775780633fd50001146102f65780634ee2cd7e1461030957806351351d531461031c57806355b01e4d1461032a5780635ea5df791461033857600080fd5b8063313ce567146102c357806339509351146102d25780633b878c22146102e55780633ccfd60b146102ee57600080fd5b806306fdde031461020657806307b3e25214610224578063095ea7b31461024a5780630f50287c1461026d57806318160ddd1461028257806323b872dd14610294578063284017f5146102a75780632e17de78146102b0575b600080fd5b61020e610487565b60405161021b9190611af6565b60405180910390f35b6102326004600360981b0181565b6040516001600160a01b03909116815260200161021b565b61025d610258366004611b1e565b610519565b604051901515815260200161021b565b61028061027b366004611b4a565b610533565b005b6035545b60405190815260200161021b565b61025d6102a2366004611b82565b6107c5565b61023261202081565b6102806102be366004611bc3565b6107e9565b6040516012815260200161021b565b61025d6102e0366004611b1e565b610800565b61023261101081565b610280610822565b610286610304366004611bc3565b610933565b610286610317366004611b1e565b610954565b6102326002600160a01b0381565b6102326004600160991b0181565b61028661138881565b61028061034f366004611c4c565b610967565b61028660cc5481565b61028661036b366004611d65565b610c10565b61028661520881565b61020e610c2b565b610286620249f081565b610286610399366004611bc3565b610c3a565b61025d6103ac366004611b1e565b610c45565b61025d6103bf366004611b1e565b610cc0565b6103f36103d2366004611bc3565b60ce6020526000908152604090208054600182015460029092015490919083565b6040805193845260208401929092529082015260600161021b565b61028661041c366004611d65565b610cce565b61028661042f366004611d82565b610cfc565b61023261203081565b610286600181565b61028660cd5481565b61028061045c366004611dbb565b610d27565b61028661046f366004611d65565b610df9565b610286610482366004611bc3565b610e20565b60606036805461049690611e44565b80601f01602080910402602001604051908101604052809291908181526020018280546104c290611e44565b801561050f5780601f106104e45761010080835404028352916020019161050f565b820191906000526020600020905b8154815290600101906020018083116104f257829003601f168201915b5050505050905090565b600033610527818585610e6a565b60019150505b92915050565b336002600160a01b031461057c5760405163973d02cb60e01b815260206004820152600a60248201526914d654d5115350d0531360b21b60448201526064015b60405180910390fd5b60cd80546000918261058d83611e94565b9190505590508083146105d85760405162461bcd60e51b815260206004820152601360248201527215539156141150d5115117d15413d0d217d251606a1b6044820152606401610573565b81356020830135116106225760405162461bcd60e51b81526020600482015260136024820152721393d7d09313d0d2d4d7d0d3d3535255151151606a1b6044820152606401610573565b60cc5461063483356020850135611ead565b61063f906001611ec0565b6106499190611ee9565b156106a45760405162461bcd60e51b815260206004820152602560248201527f45504f43485f4d5553545f42455f444956495349424c455f42595f45504f43486044820152645f53495a4560d81b6064820152608401610573565b813560ce60006106b5600185611ead565b81526020019081526020016000206001015460016106d39190611ec0565b146107165760405162461bcd60e51b8152602060048201526013602482015272494e56414c49445f53544152545f424c4f434b60681b6044820152606401610573565b600081815260ce60205260409020829061074782828135815560208201356001820155604082013560028201555050565b505060cf80546001810182556000919091526020838101357facb8d954e2cfef495862221e91bd7523613cf8808827cb33edfe4904cc51bf299092018290556040805190850135815284359186917f0ce8712c4dee4bd5a691f0bc1c39594671591e77395f8ebf6a3fb5f63fbea66a910160405180910390a4505050565b6000336107d3858285610f8f565b6107de858585611003565b506001949350505050565b6107f333826111a7565b6107fd33826112d2565b50565b6000336105278185856108138383610cfc565b61081d9190611ec0565b610e6a565b33600090815260d06020526040812060cd54909190819061084490849061134b565b808555604051828152919350915033907f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b659060200160405180910390a260c95460cb54604080517f8ca9a95e41b5eece253c93f5b31eed1253aed6b145d8a6e14d913fdf8e7322936020820152338183015260608082018790528251808303909101815260808201928390526316f1983160e01b9092526001600160a01b03938416936316f19831936108fc93911691608401611efd565b600060405180830381600087803b15801561091657600080fd5b505af115801561092a573d6000803e3d6000fd5b50505050505050565b60cf818154811061094357600080fd5b600091825260209091200154905081565b600061096083836113bd565b9392505050565b600054610100900460ff16158080156109875750600054600160ff909116105b806109a15750303b1580156109a1575060005460ff166001145b610a045760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610573565b6000805460ff191660011790558015610a27576000805461ff0019166101001790555b6001600160a01b03861615801590610a4757506001600160a01b03851615155b8015610a5b57506001600160a01b03841615155b8015610a6657508215155b610aa25760405162461bcd60e51b815260206004820152600d60248201526c1253959053125117d253941555609a1b6044820152606401610573565b610aec6040518060400160405280600c81526020016b15985b1a59185d1bdc94d95d60a21b815250604051806040016040528060048152602001631594d15560e21b815250611406565b60c980546001600160a01b038089166001600160a01b03199283161790925560ca805488841690831617905560cb80549287169290911691909117905560cc83905560005b8251811015610b8657610b7e838281518110610b4f57610b4f611f21565b602002602001015160000151848381518110610b6d57610b6d611f21565b60200260200101516020015161143b565b600101610b31565b5060cf80546001818101835560009283527facb8d954e2cfef495862221e91bd7523613cf8808827cb33edfe4904cc51bf299091019190915560cd558015610c08576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b6001600160a01b031660009081526033602052604090205490565b60606037805461049690611e44565b600061052d82611445565b60003381610c538286610cfc565b905083811015610cb35760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610573565b6107de8286868403610e6a565b600033610527818585611003565b60cd546001600160a01b038216600090815260d0602052604081209091610cf5919061134b565b5092915050565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b60ca546001600160a01b031633148015610d4e575060cb546001600160a01b038481169116145b610d8b5760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a2a72222a960911b6044820152606401610573565b7f1bcc0f4c3fad314e585165815f94ecca9b96690a26d6417d7876448a9a867a69610dba602060008486611f37565b610dc391611f61565b03610df357600080610dd88360208187611f37565b810190610de59190611b1e565b91509150610c08828261143b565b50505050565b60cd546001600160a01b038216600090815260d060205260408120909161052d9190611470565b600081815260ce60205260408120600101548015610e6157600083815260ce6020526040902054610e519082611ead565b610e5c906001611ec0565b610960565b60009392505050565b6001600160a01b038316610ecc5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610573565b6001600160a01b038216610f2d5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610573565b6001600160a01b0383811660008181526034602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6000610f9b8484610cfc565b90506000198114610df35781811015610ff65760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610573565b610df38484848403610e6a565b6001600160a01b0383166110675760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610573565b6001600160a01b0382166110c95760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610573565b6110d483838361150e565b6001600160a01b0383166000908152603360205260409020548181101561114c5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610573565b6001600160a01b0380851660008181526033602052604080822086860390559286168082529083902080548601905591516000805160206121128339815191529061119a9086815260200190565b60405180910390a3610df3565b6001600160a01b0382166112075760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610573565b6112138260008361150e565b6001600160a01b038216600090815260336020526040902054818110156112875760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610573565b6001600160a01b03831660008181526033602090815260408083208686039055603580548790039055518581529192916000805160206121128339815191529101610f82565b505050565b61130481600160cd546112e59190611ec0565b6001600160a01b038516600090815260d0602052604090209190611577565b816001600160a01b03167f655c1cd0236fb6dc4916f34c8ff10e3b18fcaea5b344dfc16c36fbb1bdfc5df28260405161133f91815260200190565b60405180910390a25050565b81546000905b83600101548110156113b65760008181526002850160209081526040918290208251808401909352805483526001015490820181905284101561139457506113b6565b80516113a09084611ec0565b92505080806113ae90611e94565b915050611351565b9250929050565b6001600160a01b0382166000908152606560205260408120819081906113e49085906116ed565b91509150816113fb576113f685610c10565b6113fd565b805b95945050505050565b600054610100900460ff1661142d5760405162461bcd60e51b815260040161057390611f7f565b61143782826117db565b5050565b611437828261181b565b60008060006114558460666116ed565b915091508161146657603554611468565b805b949350505050565b600182015460009080820361148957600091505061052d565b6000611496600183611ead565b90505b845481106115065760008181526002860160209081526040918290208251808401909352805483526001015490820181905285106114d75750611506565b80516114e39085611ec0565b9350816000036114f35750611506565b50806114fe81611fca565b915050611499565b505092915050565b6001600160a01b038316158061152b57506001600160a01b038216155b61156c5760405162461bcd60e51b81526020600482015260126024820152712a2920a729a322a92fa327a92124a22222a760711b6044820152606401610573565b6112cd8383836118d6565b816000036115d25760405162461bcd60e51b815260206004820152602260248201527f5769746864726177616c51756575654c69623a20494e56414c49445f414d4f55604482015261139560f21b6064820152608401610573565b82546001840154818103611629576040805180820182528581526020808201868152600085815260028a01909252928120915182559151600191820155860180549161161d83611e94565b91905055505050505050565b6000600286018161163b600185611ead565b81526020019081526020016000206001015490508084101561165f5761165f611fe1565b838110156116ae576040805180820182528681526020808201878152600086815260028b0190925292812091518255915160019182015587018054916116a483611e94565b9190505550610c08565b846002870160006116c0600186611ead565b815260200190815260200160002060000160008282546116e09190611ec0565b9091555050505050505050565b600080600084116117395760405162461bcd60e51b815260206004820152601660248201527504552433230536e617073686f743a20696420697320360541b6044820152606401610573565b60cd5484111561178b5760405162461bcd60e51b815260206004820152601d60248201527f4552433230536e617073686f743a206e6f6e6578697374656e742069640000006044820152606401610573565b6000611797848661191e565b845490915081036117af5760008092509250506113b6565b60018460010182815481106117c6576117c6611f21565b906000526020600020015492509250506113b6565b600054610100900460ff166118025760405162461bcd60e51b815260040161057390611f7f565b603661180e838261203d565b5060376112cd828261203d565b6001600160a01b0382166118715760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610573565b61187d6000838361150e565b806035600082825461188f9190611ec0565b90915550506001600160a01b038216600081815260336020908152604080832080548601905551848152600080516020612112833981519152910160405180910390a35050565b6001600160a01b0383166118f5576118ed826119cb565b6112cd6119f5565b6001600160a01b03821661190c576118ed836119cb565b611915836119cb565b6112cd826119cb565b815460009081036119315750600061052d565b82546000905b8082101561197e57600061194b8383611a05565b6000878152602090209091508590820154111561196a57809150611978565b611975816001611ec0565b92505b50611937565b6000821180156119aa5750836119a786611999600186611ead565b600091825260209091200190565b54145b156119c3576119ba600183611ead565b9250505061052d565b50905061052d565b6001600160a01b03811660009081526065602052604090206107fd906119f083610c10565b611a20565b611a0360666119f060355490565b565b6000611a1460028484186120fd565b61096090848416611ec0565b6000611a2b60cd5490565b905080611a3784611a6b565b10156112cd578254600180820185556000858152602080822090930193909355938401805494850181558252902090910155565b80546000908103611a7e57506000919050565b81548290611a8e90600190611ead565b81548110611a9e57611a9e611f21565b90600052602060002001549050919050565b6000815180845260005b81811015611ad657602081850181015186830182015201611aba565b506000602082860101526020601f19601f83011685010191505092915050565b6020815260006109606020830184611ab0565b6001600160a01b03811681146107fd57600080fd5b60008060408385031215611b3157600080fd5b8235611b3c81611b09565b946020939093013593505050565b6000808284036080811215611b5e57600080fd5b833592506060601f1982011215611b7457600080fd5b506020830190509250929050565b600080600060608486031215611b9757600080fd5b8335611ba281611b09565b92506020840135611bb281611b09565b929592945050506040919091013590565b600060208284031215611bd557600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715611c1557611c15611bdc565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611c4457611c44611bdc565b604052919050565b600080600080600060a08688031215611c6457600080fd5b8535611c6f81611b09565b9450602086810135611c8081611b09565b9450604087810135611c9181611b09565b945060608801359350608088013567ffffffffffffffff80821115611cb557600080fd5b818a0191508a601f830112611cc957600080fd5b813581811115611cdb57611cdb611bdc565b611ce9858260051b01611c1b565b818152858101925060069190911b83018501908c821115611d0957600080fd5b928501925b81841015611d525784848e031215611d265760008081fd5b611d2e611bf2565b8435611d3981611b09565b8152848701358782015283529284019291850191611d0e565b8096505050505050509295509295909350565b600060208284031215611d7757600080fd5b813561096081611b09565b60008060408385031215611d9557600080fd5b8235611da081611b09565b91506020830135611db081611b09565b809150509250929050565b60008060008060608587031215611dd157600080fd5b843593506020850135611de381611b09565b9250604085013567ffffffffffffffff80821115611e0057600080fd5b818701915087601f830112611e1457600080fd5b813581811115611e2357600080fd5b886020828501011115611e3557600080fd5b95989497505060200194505050565b600181811c90821680611e5857607f821691505b602082108103611e7857634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b600060018201611ea657611ea6611e7e565b5060010190565b8181038181111561052d5761052d611e7e565b8082018082111561052d5761052d611e7e565b634e487b7160e01b600052601260045260246000fd5b600082611ef857611ef8611ed3565b500690565b6001600160a01b038316815260406020820181905260009061146890830184611ab0565b634e487b7160e01b600052603260045260246000fd5b60008085851115611f4757600080fd5b83861115611f5457600080fd5b5050820193919092039150565b8035602083101561052d57600019602084900360031b1b1692915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b600081611fd957611fd9611e7e565b506000190190565b634e487b7160e01b600052600160045260246000fd5b601f8211156112cd57600081815260208120601f850160051c8101602086101561201e5750805b601f850160051c820191505b81811015610c085782815560010161202a565b815167ffffffffffffffff81111561205757612057611bdc565b61206b816120658454611e44565b84611ff7565b602080601f8311600181146120a057600084156120885750858301515b600019600386901b1c1916600185901b178555610c08565b600085815260208120601f198616915b828110156120cf578886015182559484019460019091019084016120b0565b50858210156120ed5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008261210c5761210c611ed3565b50049056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212203c4d95e2d3f73d67d2168a29cb8be58c25d393af2555dd32816d324aba1cccfc64736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" +var EIP1559BurnArtifact string = "{\n \"_format\": \"hh-sol-artifact-1\",\n \"contractName\": \"EIP1559Burn\",\n \"sourceName\": \"contracts/child/EIP1559Burn.sol\",\n \"abi\": [\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"version\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"Initialized\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"burner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"NativeTokenBurnt\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"burnDestination\",\n \"outputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"childERC20Predicate\",\n \"outputs\": [\n {\n \"internalType\": \"contract IChildERC20Predicate\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"contract IChildERC20Predicate\",\n \"name\": \"newChildERC20Predicate\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"newBurnDestination\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"initialize\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"withdraw\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"stateMutability\": \"payable\",\n \"type\": \"receive\"\n }\n ],\n \"bytecode\": \"0x608060405234801561001057600080fd5b50610425806100206000396000f3fe6080604052600436106100435760003560e01c80630fca96871461004f5780633ccfd60b1461008b578063485cc955146100a2578063d57184e4146100c257600080fd5b3661004a57005b600080fd5b34801561005b57600080fd5b5060015461006f906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b34801561009757600080fd5b506100a06100e8565b005b3480156100ae57600080fd5b506100a06100bd3660046103b6565b6101fc565b3480156100ce57600080fd5b5060005461006f906201000090046001600160a01b031681565b6000546201000090046001600160a01b031661014b5760405162461bcd60e51b815260206004820152601a60248201527f454950313535394275726e3a20554e494e495449414c495a454400000000000060448201526064015b60405180910390fd5b6000546001546040516361d9ad3f60e11b815261101060048201526001600160a01b0391821660248201524760448201819052926201000090049091169063c3b35a7e90606401600060405180830381600087803b1580156101ac57600080fd5b505af11580156101c0573d6000803e3d6000fd5b50506040518381523392507feb347a9a474ae97b7b32a903d84decf8fc80dc9cd6129085f5097de5cd3b3256915060200160405180910390a250565b600054610100900460ff161580801561021c5750600054600160ff909116105b806102365750303b158015610236575060005460ff166001145b6102995760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610142565b6000805460ff1916600117905580156102bc576000805461ff0019166101001790555b6001600160a01b0383166103125760405162461bcd60e51b815260206004820152601f60248201527f454950313535394275726e3a204241445f494e495449414c495a4154494f4e006044820152606401610142565b6000805462010000600160b01b031916620100006001600160a01b038681169190910291909117909155600180546001600160a01b0319169184169190911790558015610399576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6001600160a01b03811681146103b357600080fd5b50565b600080604083850312156103c957600080fd5b82356103d48161039e565b915060208301356103e48161039e565b80915050925092905056fea264697066735822122017aa34fe0fb30c4917a2b19c5df8508e7d7149f54977cecd862fec4444e087b364736f6c63430008130033\",\n \"deployedBytecode\": \"0x6080604052600436106100435760003560e01c80630fca96871461004f5780633ccfd60b1461008b578063485cc955146100a2578063d57184e4146100c257600080fd5b3661004a57005b600080fd5b34801561005b57600080fd5b5060015461006f906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b34801561009757600080fd5b506100a06100e8565b005b3480156100ae57600080fd5b506100a06100bd3660046103b6565b6101fc565b3480156100ce57600080fd5b5060005461006f906201000090046001600160a01b031681565b6000546201000090046001600160a01b031661014b5760405162461bcd60e51b815260206004820152601a60248201527f454950313535394275726e3a20554e494e495449414c495a454400000000000060448201526064015b60405180910390fd5b6000546001546040516361d9ad3f60e11b815261101060048201526001600160a01b0391821660248201524760448201819052926201000090049091169063c3b35a7e90606401600060405180830381600087803b1580156101ac57600080fd5b505af11580156101c0573d6000803e3d6000fd5b50506040518381523392507feb347a9a474ae97b7b32a903d84decf8fc80dc9cd6129085f5097de5cd3b3256915060200160405180910390a250565b600054610100900460ff161580801561021c5750600054600160ff909116105b806102365750303b158015610236575060005460ff166001145b6102995760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610142565b6000805460ff1916600117905580156102bc576000805461ff0019166101001790555b6001600160a01b0383166103125760405162461bcd60e51b815260206004820152601f60248201527f454950313535394275726e3a204241445f494e495449414c495a4154494f4e006044820152606401610142565b6000805462010000600160b01b031916620100006001600160a01b038681169190910291909117909155600180546001600160a01b0319169184169190911790558015610399576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6001600160a01b03811681146103b357600080fd5b50565b600080604083850312156103c957600080fd5b82356103d48161039e565b915060208301356103e48161039e565b80915050925092905056fea264697066735822122017aa34fe0fb30c4917a2b19c5df8508e7d7149f54977cecd862fec4444e087b364736f6c63430008130033\",\n \"linkReferences\": {},\n \"deployedLinkReferences\": {}\n}\n" diff --git a/consensus/polybft/contractsapi/helper.go b/consensus/polybft/contractsapi/helper.go index 645598f37d..9eb38707aa 100644 --- a/consensus/polybft/contractsapi/helper.go +++ b/consensus/polybft/contractsapi/helper.go @@ -1,8 +1,6 @@ package contractsapi import ( - "math/big" - "github.com/0xPolygon/polygon-edge/types" "github.com/umbracle/ethgo/abi" ) @@ -29,13 +27,18 @@ func (sse *StateSyncedEvent) EncodeAbi() ([]byte, error) { return stateSyncABIType.Encode([]interface{}{sse}) } -// AddValidatorUptime is an extension (helper) function on a generated Uptime type -// that adds uptime data for given validator to Uptime struct -func (u *Uptime) AddValidatorUptime(address types.Address, count int64) { - u.UptimeData = append(u.UptimeData, &UptimeData{ - Validator: address, - SignedBlocks: big.NewInt(count), - }) +var ( + _ StateTransactionInput = &CommitEpochValidatorSetFn{} + _ StateTransactionInput = &DistributeRewardForRewardPoolFn{} +) + +// IsStake indicates if transfer event (from ERC20 implementation) mints tokens to a non zero address +func (t *TransferEvent) IsStake() bool { + return t.To != types.ZeroAddress && t.From == types.ZeroAddress } -var _ StateTransactionInput = &CommitEpochChildValidatorSetFn{} +// IsUnstake indicates if transfer event (from ERC20 implementation) burns tokens from a non zero address +// meaning, it transfers them to zero address +func (t *TransferEvent) IsUnstake() bool { + return t.To == types.ZeroAddress && t.From != types.ZeroAddress +} diff --git a/consensus/polybft/contractsapi/init.go b/consensus/polybft/contractsapi/init.go index 8f385ca19e..33b76bf157 100644 --- a/consensus/polybft/contractsapi/init.go +++ b/consensus/polybft/contractsapi/init.go @@ -14,28 +14,54 @@ const ( var ( // core-contracts smart contracts - CheckpointManager *artifact.Artifact - ExitHelper *artifact.Artifact - StateSender *artifact.Artifact - RootERC20Predicate *artifact.Artifact - BLS *artifact.Artifact - BLS256 *artifact.Artifact - System *artifact.Artifact - Merkle *artifact.Artifact - ChildValidatorSet *artifact.Artifact - NativeERC20 *artifact.Artifact - NativeERC20Mintable *artifact.Artifact - StateReceiver *artifact.Artifact - ChildERC20 *artifact.Artifact - ChildERC20Predicate *artifact.Artifact - L2StateSender *artifact.Artifact + CheckpointManager *artifact.Artifact + ExitHelper *artifact.Artifact + StateSender *artifact.Artifact + RootERC20Predicate *artifact.Artifact + RootERC721Predicate *artifact.Artifact + RootERC1155Predicate *artifact.Artifact + ChildMintableERC20Predicate *artifact.Artifact + ChildMintableERC721Predicate *artifact.Artifact + ChildMintableERC1155Predicate *artifact.Artifact + BLS *artifact.Artifact + BLS256 *artifact.Artifact + System *artifact.Artifact + Merkle *artifact.Artifact + ChildValidatorSet *artifact.Artifact + NativeERC20 *artifact.Artifact + NativeERC20Mintable *artifact.Artifact + StateReceiver *artifact.Artifact + ChildERC20 *artifact.Artifact + ChildERC20Predicate *artifact.Artifact + ChildERC20PredicateACL *artifact.Artifact + RootMintableERC20Predicate *artifact.Artifact + RootMintableERC20PredicateACL *artifact.Artifact + ChildERC721 *artifact.Artifact + ChildERC721Predicate *artifact.Artifact + ChildERC721PredicateACL *artifact.Artifact + RootMintableERC721Predicate *artifact.Artifact + RootMintableERC721PredicateACL *artifact.Artifact + ChildERC1155 *artifact.Artifact + ChildERC1155Predicate *artifact.Artifact + ChildERC1155PredicateACL *artifact.Artifact + RootMintableERC1155Predicate *artifact.Artifact + RootMintableERC1155PredicateACL *artifact.Artifact + L2StateSender *artifact.Artifact + CustomSupernetManager *artifact.Artifact + StakeManager *artifact.Artifact + RewardPool *artifact.Artifact + ValidatorSet *artifact.Artifact + RootERC721 *artifact.Artifact + RootERC1155 *artifact.Artifact + EIP1559Burn *artifact.Artifact // test smart contracts //go:embed test-contracts/* testContracts embed.FS - TestL1StateReceiver *artifact.Artifact TestWriteBlockMetadata *artifact.Artifact RootERC20 *artifact.Artifact + TestSimple *artifact.Artifact + TestRewardToken *artifact.Artifact ) func init() { @@ -81,6 +107,31 @@ func init() { log.Fatal(err) } + RootERC721Predicate, err = artifact.DecodeArtifact([]byte(RootERC721PredicateArtifact)) + if err != nil { + log.Fatal(err) + } + + RootERC1155Predicate, err = artifact.DecodeArtifact([]byte(RootERC1155PredicateArtifact)) + if err != nil { + log.Fatal(err) + } + + ChildMintableERC20Predicate, err = artifact.DecodeArtifact([]byte(ChildMintableERC20PredicateArtifact)) + if err != nil { + log.Fatal(err) + } + + ChildMintableERC721Predicate, err = artifact.DecodeArtifact([]byte(ChildMintableERC721PredicateArtifact)) + if err != nil { + log.Fatal(err) + } + + ChildMintableERC1155Predicate, err = artifact.DecodeArtifact([]byte(ChildMintableERC1155PredicateArtifact)) + if err != nil { + log.Fatal(err) + } + StateReceiver, err = artifact.DecodeArtifact([]byte(StateReceiverArtifact)) if err != nil { log.Fatal(err) @@ -101,7 +152,67 @@ func init() { log.Fatal(err) } - ChildValidatorSet, err = artifact.DecodeArtifact([]byte(ChildValidatorSetArtifact)) + ChildERC20PredicateACL, err = artifact.DecodeArtifact([]byte(ChildERC20PredicateACLArtifact)) + if err != nil { + log.Fatal(err) + } + + RootMintableERC20Predicate, err = artifact.DecodeArtifact([]byte(RootMintableERC20PredicateArtifact)) + if err != nil { + log.Fatal(err) + } + + RootMintableERC20PredicateACL, err = artifact.DecodeArtifact([]byte(RootMintableERC20PredicateACLArtifact)) + if err != nil { + log.Fatal(err) + } + + ChildERC721, err = artifact.DecodeArtifact([]byte(ChildERC721Artifact)) + if err != nil { + log.Fatal(err) + } + + ChildERC721Predicate, err = artifact.DecodeArtifact([]byte(ChildERC721PredicateArtifact)) + if err != nil { + log.Fatal(err) + } + + ChildERC721PredicateACL, err = artifact.DecodeArtifact([]byte(ChildERC721PredicateACLArtifact)) + if err != nil { + log.Fatal(err) + } + + RootMintableERC721Predicate, err = artifact.DecodeArtifact([]byte(RootMintableERC721PredicateArtifact)) + if err != nil { + log.Fatal(err) + } + + RootMintableERC721PredicateACL, err = artifact.DecodeArtifact([]byte(RootMintableERC721PredicateACLArtifact)) + if err != nil { + log.Fatal(err) + } + + ChildERC1155, err = artifact.DecodeArtifact([]byte(ChildERC1155Artifact)) + if err != nil { + log.Fatal(err) + } + + ChildERC1155Predicate, err = artifact.DecodeArtifact([]byte(ChildERC1155PredicateArtifact)) + if err != nil { + log.Fatal(err) + } + + ChildERC1155PredicateACL, err = artifact.DecodeArtifact([]byte(ChildERC1155PredicateACLArtifact)) + if err != nil { + log.Fatal(err) + } + + RootMintableERC1155Predicate, err = artifact.DecodeArtifact([]byte(RootMintableERC1155PredicateArtifact)) + if err != nil { + log.Fatal(err) + } + + RootMintableERC1155PredicateACL, err = artifact.DecodeArtifact([]byte(RootMintableERC1155PredicateACLArtifact)) if err != nil { log.Fatal(err) } @@ -121,7 +232,12 @@ func init() { log.Fatal(err) } - TestL1StateReceiver, err = artifact.DecodeArtifact(readTestContractContent("TestL1StateReceiver.json")) + RootERC721, err = artifact.DecodeArtifact([]byte(MockERC721Artifact)) + if err != nil { + log.Fatal(err) + } + + RootERC1155, err = artifact.DecodeArtifact([]byte(MockERC1155Artifact)) if err != nil { log.Fatal(err) } @@ -130,6 +246,41 @@ func init() { if err != nil { log.Fatal(err) } + + TestSimple, err = artifact.DecodeArtifact(readTestContractContent("TestSimple.json")) + if err != nil { + log.Fatal(err) + } + + TestRewardToken, err = artifact.DecodeArtifact(readTestContractContent("TestRewardToken.json")) + if err != nil { + log.Fatal(err) + } + + CustomSupernetManager, err = artifact.DecodeArtifact([]byte(CustomSupernetManagerArtifact)) + if err != nil { + log.Fatal(err) + } + + StakeManager, err = artifact.DecodeArtifact([]byte(StakeManagerArtifact)) + if err != nil { + log.Fatal(err) + } + + RewardPool, err = artifact.DecodeArtifact([]byte(RewardPoolArtifact)) + if err != nil { + log.Fatal(err) + } + + ValidatorSet, err = artifact.DecodeArtifact([]byte(ValidatorSetArtifact)) + if err != nil { + log.Fatal(err) + } + + EIP1559Burn, err = artifact.DecodeArtifact([]byte(EIP1559BurnArtifact)) + if err != nil { + log.Fatal(err) + } } func readTestContractContent(contractFileName string) []byte { diff --git a/consensus/polybft/contractsapi/test-contracts/TestL1StateReceiver.json b/consensus/polybft/contractsapi/test-contracts/TestL1StateReceiver.json deleted file mode 100644 index f8e62a97d0..0000000000 --- a/consensus/polybft/contractsapi/test-contracts/TestL1StateReceiver.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "TestL1StateReceiver", - "sourceName": "test-contracts/TestL1StateReceiver.sol", - "abi": [ - { - "inputs": [], - "name": "addr", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "counter", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "data", - "outputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "id", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_id", - "type": "uint256" - }, - { - "internalType": "address", - "name": "_addr", - "type": "address" - }, - { - "internalType": "bytes", - "name": "_data", - "type": "bytes" - } - ], - "name": "onL2StateReceive", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": "0x608060405234801561001057600080fd5b5061048e806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c806361bc221a1461005c57806373d4a13a14610078578063767800de1461008d578063af640d0f146100b8578063f43cda8b146100c1575b600080fd5b61006560035481565b6040519081526020015b60405180910390f35b6100806100d6565b60405161006f91906101ab565b6001546100a0906001600160a01b031681565b6040516001600160a01b03909116815260200161006f565b61006560005481565b6100d46100cf36600461020f565b610164565b005b600280546100e3906102e8565b80601f016020809104026020016040519081016040528092919081815260200182805461010f906102e8565b801561015c5780601f106101315761010080835404028352916020019161015c565b820191906000526020600020905b81548152906001019060200180831161013f57829003601f168201915b505050505081565b6000839055600180546001600160a01b0319166001600160a01b03841617905560026101908282610371565b50600380549060006101a183610431565b9190505550505050565b600060208083528351808285015260005b818110156101d8578581018301518582016040015282016101bc565b506000604082860101526040601f19601f8301168501019250505092915050565b634e487b7160e01b600052604160045260246000fd5b60008060006060848603121561022457600080fd5b8335925060208401356001600160a01b038116811461024257600080fd5b9150604084013567ffffffffffffffff8082111561025f57600080fd5b818601915086601f83011261027357600080fd5b813581811115610285576102856101f9565b604051601f8201601f19908116603f011681019083821181831017156102ad576102ad6101f9565b816040528281528960208487010111156102c657600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b600181811c908216806102fc57607f821691505b60208210810361031c57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561036c57600081815260208120601f850160051c810160208610156103495750805b601f850160051c820191505b8181101561036857828155600101610355565b5050505b505050565b815167ffffffffffffffff81111561038b5761038b6101f9565b61039f8161039984546102e8565b84610322565b602080601f8311600181146103d457600084156103bc5750858301515b600019600386901b1c1916600185901b178555610368565b600085815260208120601f198616915b82811015610403578886015182559484019460019091019084016103e4565b50858210156104215787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60006001820161045157634e487b7160e01b600052601160045260246000fd5b506001019056fea264697066735822122059d4887cdfb5a893df715259d93546c8e85fa890245389c3d2e7e4fb6eb293de64736f6c63430008110033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100575760003560e01c806361bc221a1461005c57806373d4a13a14610078578063767800de1461008d578063af640d0f146100b8578063f43cda8b146100c1575b600080fd5b61006560035481565b6040519081526020015b60405180910390f35b6100806100d6565b60405161006f91906101ab565b6001546100a0906001600160a01b031681565b6040516001600160a01b03909116815260200161006f565b61006560005481565b6100d46100cf36600461020f565b610164565b005b600280546100e3906102e8565b80601f016020809104026020016040519081016040528092919081815260200182805461010f906102e8565b801561015c5780601f106101315761010080835404028352916020019161015c565b820191906000526020600020905b81548152906001019060200180831161013f57829003601f168201915b505050505081565b6000839055600180546001600160a01b0319166001600160a01b03841617905560026101908282610371565b50600380549060006101a183610431565b9190505550505050565b600060208083528351808285015260005b818110156101d8578581018301518582016040015282016101bc565b506000604082860101526040601f19601f8301168501019250505092915050565b634e487b7160e01b600052604160045260246000fd5b60008060006060848603121561022457600080fd5b8335925060208401356001600160a01b038116811461024257600080fd5b9150604084013567ffffffffffffffff8082111561025f57600080fd5b818601915086601f83011261027357600080fd5b813581811115610285576102856101f9565b604051601f8201601f19908116603f011681019083821181831017156102ad576102ad6101f9565b816040528281528960208487010111156102c657600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b600181811c908216806102fc57607f821691505b60208210810361031c57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561036c57600081815260208120601f850160051c810160208610156103495750805b601f850160051c820191505b8181101561036857828155600101610355565b5050505b505050565b815167ffffffffffffffff81111561038b5761038b6101f9565b61039f8161039984546102e8565b84610322565b602080601f8311600181146103d457600084156103bc5750858301515b600019600386901b1c1916600185901b178555610368565b600085815260208120601f198616915b82811015610403578886015182559484019460019091019084016103e4565b50858210156104215787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60006001820161045157634e487b7160e01b600052601160045260246000fd5b506001019056fea264697066735822122059d4887cdfb5a893df715259d93546c8e85fa890245389c3d2e7e4fb6eb293de64736f6c63430008110033", - "linkReferences": {}, - "deployedLinkReferences": {} -} \ No newline at end of file diff --git a/consensus/polybft/contractsapi/test-contracts/TestL1StateReceiver.sol b/consensus/polybft/contractsapi/test-contracts/TestL1StateReceiver.sol deleted file mode 100644 index 0e066c3202..0000000000 --- a/consensus/polybft/contractsapi/test-contracts/TestL1StateReceiver.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.17; - -contract TestL1StateReceiver { - uint256 public id; - address public addr; - bytes public data; - uint256 public counter; - - function onL2StateReceive( - uint256 _id, - address _addr, - bytes memory _data - ) public { - id = _id; - addr = _addr; - data = _data; - counter++; - } -} diff --git a/consensus/polybft/contractsapi/test-contracts/TestRewardToken.json b/consensus/polybft/contractsapi/test-contracts/TestRewardToken.json new file mode 100644 index 0000000000..86f12b2af3 --- /dev/null +++ b/consensus/polybft/contractsapi/test-contracts/TestRewardToken.json @@ -0,0 +1,330 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "TestRewardToken", + "sourceName": "contracts/mocks/TestRewardToken.sol", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x608060405234801561001057600080fd5b50610a87806100206000396000f3fe608060405234801561001057600080fd5b50600436106100bf5760003560e01c806340c10f191161007c57806340c10f191461014c57806370a082311461016157806395d89b411461018a5780639dc29fac14610192578063a457c2d7146101a5578063a9059cbb146101b8578063dd62ed3e146101cb57600080fd5b806306fdde03146100c4578063095ea7b3146100e257806318160ddd1461010557806323b872dd14610117578063313ce5671461012a5780633950935114610139575b600080fd5b6100cc6101de565b6040516100d991906108b1565b60405180910390f35b6100f56100f036600461091b565b610270565b60405190151581526020016100d9565b6035545b6040519081526020016100d9565b6100f5610125366004610945565b61028a565b604051601281526020016100d9565b6100f561014736600461091b565b6102ae565b61015f61015a36600461091b565b6102d0565b005b61010961016f366004610981565b6001600160a01b031660009081526033602052604090205490565b6100cc6102de565b61015f6101a036600461091b565b6102ed565b6100f56101b336600461091b565b6102f7565b6100f56101c636600461091b565b610377565b6101096101d93660046109a3565b610385565b6060603680546101ed906109d6565b80601f0160208091040260200160405190810160405280929190818152602001828054610219906109d6565b80156102665780601f1061023b57610100808354040283529160200191610266565b820191906000526020600020905b81548152906001019060200180831161024957829003601f168201915b5050505050905090565b60003361027e8185856103b0565b60019150505b92915050565b6000336102988582856104d5565b6102a385858561054f565b506001949350505050565b60003361027e8185856102c18383610385565b6102cb9190610a10565b6103b0565b6102da82826106e8565b5050565b6060603780546101ed906109d6565b6102da8282610797565b600033816103058286610385565b90508381101561036a5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b6102a382868684036103b0565b60003361027e81858561054f565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b6001600160a01b0383166104125760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610361565b6001600160a01b0382166104735760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610361565b6001600160a01b0383811660008181526034602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b60006104e18484610385565b90506000198114610549578181101561053c5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610361565b61054984848484036103b0565b50505050565b6001600160a01b0383166105b35760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610361565b6001600160a01b0382166106155760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610361565b6001600160a01b0383166000908152603360205260409020548181101561068d5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610361565b6001600160a01b038085166000818152603360205260408082208686039055928616808252908390208054860190559151600080516020610a32833981519152906106db9086815260200190565b60405180910390a3610549565b6001600160a01b03821661073e5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610361565b80603560008282546107509190610a10565b90915550506001600160a01b038216600081815260336020908152604080832080548601905551848152600080516020610a32833981519152910160405180910390a35050565b6001600160a01b0382166107f75760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610361565b6001600160a01b0382166000908152603360205260409020548181101561086b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610361565b6001600160a01b0383166000818152603360209081526040808320868603905560358054879003905551858152919291600080516020610a3283398151915291016104c8565b600060208083528351808285015260005b818110156108de578581018301518582016040015282016108c2565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b038116811461091657600080fd5b919050565b6000806040838503121561092e57600080fd5b610937836108ff565b946020939093013593505050565b60008060006060848603121561095a57600080fd5b610963846108ff565b9250610971602085016108ff565b9150604084013590509250925092565b60006020828403121561099357600080fd5b61099c826108ff565b9392505050565b600080604083850312156109b657600080fd5b6109bf836108ff565b91506109cd602084016108ff565b90509250929050565b600181811c908216806109ea57607f821691505b602082108103610a0a57634e487b7160e01b600052602260045260246000fd5b50919050565b8082018082111561028457634e487b7160e01b600052601160045260246000fdfeddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212207a3087f7ea340d96d27d018cb7cdeb374c187cb5bf45382f42a2c2793bd19ff264736f6c63430008130033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100bf5760003560e01c806340c10f191161007c57806340c10f191461014c57806370a082311461016157806395d89b411461018a5780639dc29fac14610192578063a457c2d7146101a5578063a9059cbb146101b8578063dd62ed3e146101cb57600080fd5b806306fdde03146100c4578063095ea7b3146100e257806318160ddd1461010557806323b872dd14610117578063313ce5671461012a5780633950935114610139575b600080fd5b6100cc6101de565b6040516100d991906108b1565b60405180910390f35b6100f56100f036600461091b565b610270565b60405190151581526020016100d9565b6035545b6040519081526020016100d9565b6100f5610125366004610945565b61028a565b604051601281526020016100d9565b6100f561014736600461091b565b6102ae565b61015f61015a36600461091b565b6102d0565b005b61010961016f366004610981565b6001600160a01b031660009081526033602052604090205490565b6100cc6102de565b61015f6101a036600461091b565b6102ed565b6100f56101b336600461091b565b6102f7565b6100f56101c636600461091b565b610377565b6101096101d93660046109a3565b610385565b6060603680546101ed906109d6565b80601f0160208091040260200160405190810160405280929190818152602001828054610219906109d6565b80156102665780601f1061023b57610100808354040283529160200191610266565b820191906000526020600020905b81548152906001019060200180831161024957829003601f168201915b5050505050905090565b60003361027e8185856103b0565b60019150505b92915050565b6000336102988582856104d5565b6102a385858561054f565b506001949350505050565b60003361027e8185856102c18383610385565b6102cb9190610a10565b6103b0565b6102da82826106e8565b5050565b6060603780546101ed906109d6565b6102da8282610797565b600033816103058286610385565b90508381101561036a5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b6102a382868684036103b0565b60003361027e81858561054f565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b6001600160a01b0383166104125760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610361565b6001600160a01b0382166104735760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610361565b6001600160a01b0383811660008181526034602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b60006104e18484610385565b90506000198114610549578181101561053c5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610361565b61054984848484036103b0565b50505050565b6001600160a01b0383166105b35760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610361565b6001600160a01b0382166106155760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610361565b6001600160a01b0383166000908152603360205260409020548181101561068d5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610361565b6001600160a01b038085166000818152603360205260408082208686039055928616808252908390208054860190559151600080516020610a32833981519152906106db9086815260200190565b60405180910390a3610549565b6001600160a01b03821661073e5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610361565b80603560008282546107509190610a10565b90915550506001600160a01b038216600081815260336020908152604080832080548601905551848152600080516020610a32833981519152910160405180910390a35050565b6001600160a01b0382166107f75760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610361565b6001600160a01b0382166000908152603360205260409020548181101561086b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610361565b6001600160a01b0383166000818152603360209081526040808320868603905560358054879003905551858152919291600080516020610a3283398151915291016104c8565b600060208083528351808285015260005b818110156108de578581018301518582016040015282016108c2565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b038116811461091657600080fd5b919050565b6000806040838503121561092e57600080fd5b610937836108ff565b946020939093013593505050565b60008060006060848603121561095a57600080fd5b610963846108ff565b9250610971602085016108ff565b9150604084013590509250925092565b60006020828403121561099357600080fd5b61099c826108ff565b9392505050565b600080604083850312156109b657600080fd5b6109bf836108ff565b91506109cd602084016108ff565b90509250929050565b600181811c908216806109ea57607f821691505b602082108103610a0a57634e487b7160e01b600052602260045260246000fd5b50919050565b8082018082111561028457634e487b7160e01b600052601160045260246000fdfeddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212207a3087f7ea340d96d27d018cb7cdeb374c187cb5bf45382f42a2c2793bd19ff264736f6c63430008130033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/consensus/polybft/contractsapi/test-contracts/TestSimple.json b/consensus/polybft/contractsapi/test-contracts/TestSimple.json new file mode 100644 index 0000000000..2772c448ee --- /dev/null +++ b/consensus/polybft/contractsapi/test-contracts/TestSimple.json @@ -0,0 +1,39 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "TestSimple", + "sourceName": "contracts/TestSimple.sol", + "abi": [ + { + "inputs": [], + "name": "getValue", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_val", + "type": "uint256" + } + ], + "name": "setValue", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x608060405234801561001057600080fd5b50610150806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063209652551461003b5780635524107714610059575b600080fd5b610043610075565b60405161005091906100a1565b60405180910390f35b610073600480360381019061006e91906100ed565b61007e565b005b60008054905090565b8060008190555050565b6000819050919050565b61009b81610088565b82525050565b60006020820190506100b66000830184610092565b92915050565b600080fd5b6100ca81610088565b81146100d557600080fd5b50565b6000813590506100e7816100c1565b92915050565b600060208284031215610103576101026100bc565b5b6000610111848285016100d8565b9150509291505056fea2646970667358221220470fde08a8031bec841c7cc72e8ff6af3fefb578f1a87c4d89d5fb45f57a532464736f6c63430008110033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c8063209652551461003b5780635524107714610059575b600080fd5b610043610075565b60405161005091906100a1565b60405180910390f35b610073600480360381019061006e91906100ed565b61007e565b005b60008054905090565b8060008190555050565b6000819050919050565b61009b81610088565b82525050565b60006020820190506100b66000830184610092565b92915050565b600080fd5b6100ca81610088565b81146100d557600080fd5b50565b6000813590506100e7816100c1565b92915050565b600060208284031215610103576101026100bc565b5b6000610111848285016100d8565b9150509291505056fea2646970667358221220470fde08a8031bec841c7cc72e8ff6af3fefb578f1a87c4d89d5fb45f57a532464736f6c63430008110033", + "linkReferences": {}, + "deployedLinkReferences": {} +} + + diff --git a/consensus/polybft/contractsapi/test-contracts/TestSimple.sol b/consensus/polybft/contractsapi/test-contracts/TestSimple.sol new file mode 100644 index 0000000000..9366467e74 --- /dev/null +++ b/consensus/polybft/contractsapi/test-contracts/TestSimple.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.17; + +contract TestSimple { + uint256 val; + + function getValue() public view returns (uint256) { + return val; + } + + function setValue(uint256 _val) public { + val = _val; + } +} diff --git a/consensus/polybft/contractsapi/test-contracts/TestWriteBlockMetadata.sol b/consensus/polybft/contractsapi/test-contracts/TestWriteBlockMetadata.sol index 90fe2a2ee3..c24384b34b 100644 --- a/consensus/polybft/contractsapi/test-contracts/TestWriteBlockMetadata.sol +++ b/consensus/polybft/contractsapi/test-contracts/TestWriteBlockMetadata.sol @@ -13,7 +13,7 @@ contract TestWriteBlockMetadata { data.push(block.gaslimit); data.push(block.chainid); coinbase = block.coinbase; - // data.push(block.basefee); + data.push(block.basefee); // hash = blockhash(block.number); } } \ No newline at end of file diff --git a/consensus/polybft/extra.go b/consensus/polybft/extra.go index 8b7776964a..42ba463738 100644 --- a/consensus/polybft/extra.go +++ b/consensus/polybft/extra.go @@ -1,12 +1,11 @@ package polybft import ( - "bytes" "fmt" "math/big" - "github.com/0xPolygon/polygon-edge/consensus/polybft/bitmap" bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/crypto" "github.com/0xPolygon/polygon-edge/types" "github.com/hashicorp/go-hclog" @@ -27,8 +26,7 @@ var PolyBFTMixDigest = types.StringToHash("adce6e5230abe012342a44e4e9b6d05997d6f // Extra defines the structure of the extra field for Istanbul type Extra struct { - Validators *ValidatorSetDelta - Seal []byte + Validators *validator.ValidatorSetDelta Parent *Signature Committed *Signature Checkpoint *CheckpointData @@ -38,7 +36,7 @@ type Extra struct { func (i *Extra) MarshalRLPTo(dst []byte) []byte { ar := &fastrlp.Arena{} - return i.MarshalRLPWith(ar).MarshalTo(dst) + return append(make([]byte, ExtraVanity), i.MarshalRLPWith(ar).MarshalTo(dst)...) } // MarshalRLPWith defines the marshal function implementation for Extra @@ -52,21 +50,14 @@ func (i *Extra) MarshalRLPWith(ar *fastrlp.Arena) *fastrlp.Value { vv.Set(i.Validators.MarshalRLPWith(ar)) } - // Seal - if len(i.Seal) == 0 { - vv.Set(ar.NewNull()) - } else { - vv.Set(ar.NewBytes(i.Seal)) - } - - // ParentSeal + // Parent Signatures if i.Parent == nil { vv.Set(ar.NewNullArray()) } else { vv.Set(i.Parent.MarshalRLPWith(ar)) } - // CommittedSeal + // Committed Signatures if i.Committed == nil { vv.Set(ar.NewNullArray()) } else { @@ -85,12 +76,12 @@ func (i *Extra) MarshalRLPWith(ar *fastrlp.Arena) *fastrlp.Value { // UnmarshalRLP defines the unmarshal function wrapper for Extra func (i *Extra) UnmarshalRLP(input []byte) error { - return fastrlp.UnmarshalRLP(input, i) + return fastrlp.UnmarshalRLP(input[ExtraVanity:], i) } // UnmarshalRLPWith defines the unmarshal implementation for Extra func (i *Extra) UnmarshalRLPWith(v *fastrlp.Value) error { - const expectedElements = 5 + const expectedElements = 4 elems, err := v.GetElems() if err != nil { @@ -103,39 +94,32 @@ func (i *Extra) UnmarshalRLPWith(v *fastrlp.Value) error { // Validators if elems[0].Elems() > 0 { - i.Validators = &ValidatorSetDelta{} + i.Validators = &validator.ValidatorSetDelta{} if err := i.Validators.UnmarshalRLPWith(elems[0]); err != nil { return err } } - // Seal - if elems[1].Len() > 0 { - if i.Seal, err = elems[1].GetBytes(i.Seal); err != nil { - return err - } - } - - // Parent - if elems[2].Elems() > 0 { + // Parent Signatures + if elems[1].Elems() > 0 { i.Parent = &Signature{} - if err := i.Parent.UnmarshalRLPWith(elems[2]); err != nil { + if err := i.Parent.UnmarshalRLPWith(elems[1]); err != nil { return err } } - // Committed - if elems[3].Elems() > 0 { + // Committed Signatures + if elems[2].Elems() > 0 { i.Committed = &Signature{} - if err := i.Committed.UnmarshalRLPWith(elems[3]); err != nil { + if err := i.Committed.UnmarshalRLPWith(elems[2]); err != nil { return err } } // Checkpoint - if elems[4].Elems() > 0 { + if elems[3].Elems() > 0 { i.Checkpoint = &CheckpointData{} - if err := i.Checkpoint.UnmarshalRLPWith(elems[4]); err != nil { + if err := i.Checkpoint.UnmarshalRLPWith(elems[3]); err != nil { return err } } @@ -186,21 +170,6 @@ func (i *Extra) ValidateFinalizedData(header *types.Header, parent *types.Header return i.Checkpoint.ValidateBasic(parentExtra.Checkpoint) } -// ValidateDelta validates validator set delta provided in the Extra -// with the one being calculated by the validator itself -func (i *Extra) ValidateDelta(oldValidators AccountSet, newValidators AccountSet) error { - delta, err := createValidatorSetDelta(oldValidators, newValidators) - if err != nil { - return err - } - - if !i.Validators.Equals(delta) { - return fmt.Errorf("validator set delta is invalid") - } - - return nil -} - // ValidateParentSignatures validates signatures for parent block func (i *Extra) ValidateParentSignatures(blockNumber uint64, consensusBackend polybftBackend, parents []*types.Header, parent *types.Header, parentExtra *Extra, chainID uint64, domain []byte, logger hclog.Logger) error { @@ -236,190 +205,6 @@ func (i *Extra) ValidateParentSignatures(blockNumber uint64, consensusBackend po return nil } -// createValidatorSetDelta calculates ValidatorSetDelta based on the provided old and new validator sets -func createValidatorSetDelta(oldValidatorSet, newValidatorSet AccountSet) (*ValidatorSetDelta, error) { - var addedValidators, updatedValidators AccountSet - - oldValidatorSetMap := make(map[types.Address]*ValidatorMetadata) - removedValidators := map[types.Address]int{} - - for i, validator := range oldValidatorSet { - if (validator.Address != types.Address{}) { - removedValidators[validator.Address] = i - oldValidatorSetMap[validator.Address] = validator - } - } - - for _, newValidator := range newValidatorSet { - // Check if the validator is among both old and new validator set - oldValidator, validatorExists := oldValidatorSetMap[newValidator.Address] - if validatorExists { - if !oldValidator.EqualAddressAndBlsKey(newValidator) { - return nil, fmt.Errorf("validator '%s' found in both old and new validator set, but its BLS keys differ", - newValidator.Address.String()) - } - - // If it is, then discard it from removed validators... - delete(removedValidators, newValidator.Address) - - if !oldValidator.Equals(newValidator) { - updatedValidators = append(updatedValidators, newValidator) - } - } else { - // ...otherwise it is added - addedValidators = append(addedValidators, newValidator) - } - } - - removedValsBitmap := bitmap.Bitmap{} - for _, i := range removedValidators { - removedValsBitmap.Set(uint64(i)) - } - - delta := &ValidatorSetDelta{ - Added: addedValidators, - Updated: updatedValidators, - Removed: removedValsBitmap, - } - - return delta, nil -} - -// ValidatorSetDelta holds information about added and removed validators compared to the previous epoch -type ValidatorSetDelta struct { - // Added is the slice of added validators - Added AccountSet - // Updated is the slice of updated valiadtors - Updated AccountSet - // Removed is a bitmap of the validators removed from the set - Removed bitmap.Bitmap -} - -// Equals checks validator set delta equality -func (d *ValidatorSetDelta) Equals(other *ValidatorSetDelta) bool { - if other == nil { - return false - } - - return d.Added.Equals(other.Added) && - d.Updated.Equals(other.Updated) && - bytes.Equal(d.Removed, other.Removed) -} - -// MarshalRLPWith marshals ValidatorSetDelta to RLP format -func (d *ValidatorSetDelta) MarshalRLPWith(ar *fastrlp.Arena) *fastrlp.Value { - vv := ar.NewArray() - addedValidatorsRaw := ar.NewArray() - updatedValidatorsRaw := ar.NewArray() - - for _, validatorAccount := range d.Added { - addedValidatorsRaw.Set(validatorAccount.MarshalRLPWith(ar)) - } - - for _, validatorAccount := range d.Updated { - updatedValidatorsRaw.Set(validatorAccount.MarshalRLPWith(ar)) - } - - vv.Set(addedValidatorsRaw) // added - vv.Set(updatedValidatorsRaw) // updated - vv.Set(ar.NewCopyBytes(d.Removed)) // removed - - return vv -} - -// UnmarshalRLPWith unmarshals ValidatorSetDelta from RLP format -func (d *ValidatorSetDelta) UnmarshalRLPWith(v *fastrlp.Value) error { - elems, err := v.GetElems() - if err != nil { - return err - } - - if len(elems) == 0 { - return nil - } else if num := len(elems); num != 3 { - return fmt.Errorf("incorrect elements count to decode validator set delta, expected 3 but found %d", num) - } - - // Validators (added) - { - validatorsRaw, err := elems[0].GetElems() - if err != nil { - return fmt.Errorf("array expected for added validators") - } - - d.Added, err = unmarshalValidators(validatorsRaw) - if err != nil { - return err - } - } - - // Validators (updated) - { - validatorsRaw, err := elems[1].GetElems() - if err != nil { - return fmt.Errorf("array expected for updated validators") - } - - d.Updated, err = unmarshalValidators(validatorsRaw) - if err != nil { - return err - } - } - - // Bitmap (removed) - { - dst, err := elems[2].GetBytes(nil) - if err != nil { - return err - } - - d.Removed = bitmap.Bitmap(dst) - } - - return nil -} - -// unmarshalValidators unmarshals RLP encoded validators and returns AccountSet instance -func unmarshalValidators(validatorsRaw []*fastrlp.Value) (AccountSet, error) { - if len(validatorsRaw) == 0 { - return nil, nil - } - - validators := make(AccountSet, len(validatorsRaw)) - - for i, validatorRaw := range validatorsRaw { - acc := &ValidatorMetadata{} - if err := acc.UnmarshalRLPWith(validatorRaw); err != nil { - return nil, err - } - - validators[i] = acc - } - - return validators, nil -} - -// IsEmpty returns indication whether delta is empty (namely added, updated slices and removed bitmap are empty) -func (d *ValidatorSetDelta) IsEmpty() bool { - return len(d.Added) == 0 && - len(d.Updated) == 0 && - d.Removed.Len() == 0 -} - -// Copy creates deep copy of ValidatorSetDelta -func (d *ValidatorSetDelta) Copy() *ValidatorSetDelta { - added := d.Added.Copy() - removed := make([]byte, len(d.Removed)) - copy(removed, d.Removed) - - return &ValidatorSetDelta{Added: added, Removed: removed} -} - -// fmt.Stringer interface implementation -func (d *ValidatorSetDelta) String() string { - return fmt.Sprintf("Added: \n%v Removed: %v\n Updated: \n%v", d.Added, d.Removed, d.Updated) -} - // Signature represents aggregated signatures of signers accompanied with a bitmap // (in order to be able to determine identities of each signer) type Signature struct { @@ -471,13 +256,13 @@ func (s *Signature) UnmarshalRLPWith(v *fastrlp.Value) error { } // Verify is used to verify aggregated signature based on current validator set, message hash and domain -func (s *Signature) Verify(validators AccountSet, hash types.Hash, domain []byte, logger hclog.Logger) error { +func (s *Signature) Verify(validators validator.AccountSet, hash types.Hash, domain []byte, logger hclog.Logger) error { signers, err := validators.GetFilteredValidators(s.Bitmap) if err != nil { return err } - validatorSet := NewValidatorSet(validators, logger) + validatorSet := validator.NewValidatorSet(validators, logger) if !validatorSet.HasQuorum(signers.GetAddressesAsSet()) { return fmt.Errorf("quorum not reached") } @@ -641,7 +426,8 @@ func (c *CheckpointData) ValidateBasic(parentCheckpoint *CheckpointData) error { // Validate encapsulates validation logic for checkpoint data // (with regards to current and next epoch validators) func (c *CheckpointData) Validate(parentCheckpoint *CheckpointData, - currentValidators AccountSet, nextValidators AccountSet) error { + currentValidators validator.AccountSet, nextValidators validator.AccountSet, + exitRootHash types.Hash) error { if err := c.ValidateBasic(parentCheckpoint); err != nil { return err } @@ -674,6 +460,12 @@ func (c *CheckpointData) Validate(parentCheckpoint *CheckpointData, return fmt.Errorf("epoch number should not change for epoch-ending block") } + // exit root hash of proposer and + // validator that validates proposal have to match + if exitRootHash != c.EventRoot { + return fmt.Errorf("exit root hash not as expected") + } + return nil } @@ -689,7 +481,6 @@ func GetIbftExtraClean(extraRaw []byte) ([]byte, error) { Parent: extra.Parent, Validators: extra.Validators, Checkpoint: extra.Checkpoint, - Seal: []byte{}, Committed: &Signature{}, } @@ -697,20 +488,19 @@ func GetIbftExtraClean(extraRaw []byte) ([]byte, error) { } // GetIbftExtra returns the istanbul extra data field from the passed in header -func GetIbftExtra(extraB []byte) (*Extra, error) { - if len(extraB) < ExtraVanity { - return nil, fmt.Errorf("wrong extra size: %d", len(extraB)) +func GetIbftExtra(extraRaw []byte) (*Extra, error) { + if len(extraRaw) < ExtraVanity { + return nil, fmt.Errorf("wrong extra size: %d", len(extraRaw)) } - data := extraB[ExtraVanity:] extra := &Extra{} - if err := extra.UnmarshalRLP(data); err != nil { + if err := extra.UnmarshalRLP(extraRaw); err != nil { return nil, err } if extra.Validators == nil { - extra.Validators = &ValidatorSetDelta{} + extra.Validators = &validator.ValidatorSetDelta{} } return extra, nil diff --git a/consensus/polybft/extra_test.go b/consensus/polybft/extra_test.go index 1476611ff6..53bac6ca83 100644 --- a/consensus/polybft/extra_test.go +++ b/consensus/polybft/extra_test.go @@ -11,7 +11,9 @@ import ( "github.com/0xPolygon/polygon-edge/chain" "github.com/0xPolygon/polygon-edge/consensus/polybft/bitmap" bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" + "github.com/0xPolygon/polygon-edge/crypto" "github.com/0xPolygon/polygon-edge/types" "github.com/hashicorp/go-hclog" "github.com/stretchr/testify/assert" @@ -23,11 +25,19 @@ import ( func TestExtra_Encoding(t *testing.T) { t.Parallel() - parentStr := []byte("Here is the parent signature") - committedStr := []byte("Here is the committed signature") - bitmapStr := []byte("Here are the bitmap bytes") + digest := crypto.Keccak256([]byte("Dummy content to sign")) + keys := createRandomTestKeys(t, 2) + parentSig, err := keys[0].Sign(digest) + require.NoError(t, err) + + committedSig, err := keys[1].Sign(digest) + require.NoError(t, err) - addedValidators := newTestValidatorsWithAliases(t, []string{"A", "B", "C"}).getPublicIdentities() + bmp := bitmap.Bitmap{} + bmp.Set(1) + bmp.Set(4) + + addedValidators := validator.NewTestValidatorsWithAliases(t, []string{"A", "B", "C"}).GetPublicIdentities() removedValidators := bitmap.Bitmap{} removedValidators.Set(2) @@ -41,20 +51,19 @@ func TestExtra_Encoding(t *testing.T) { }, { &Extra{ - Validators: &ValidatorSetDelta{}, + Validators: &validator.ValidatorSetDelta{}, Parent: &Signature{}, Committed: &Signature{}, }, }, { &Extra{ - Validators: &ValidatorSetDelta{}, - Seal: []byte{3, 4}, + Validators: &validator.ValidatorSetDelta{}, }, }, { &Extra{ - Validators: &ValidatorSetDelta{ + Validators: &validator.ValidatorSetDelta{ Added: addedValidators, }, Parent: &Signature{}, @@ -63,34 +72,34 @@ func TestExtra_Encoding(t *testing.T) { }, { &Extra{ - Validators: &ValidatorSetDelta{ + Validators: &validator.ValidatorSetDelta{ Removed: removedValidators, }, - Parent: &Signature{AggregatedSignature: parentStr, Bitmap: bitmapStr}, + Parent: &Signature{AggregatedSignature: parentSig, Bitmap: bmp}, Committed: &Signature{}, }, }, { &Extra{ - Validators: &ValidatorSetDelta{ + Validators: &validator.ValidatorSetDelta{ Added: addedValidators, Updated: addedValidators[1:], Removed: removedValidators, }, Parent: &Signature{}, - Committed: &Signature{AggregatedSignature: committedStr, Bitmap: bitmapStr}, + Committed: &Signature{AggregatedSignature: committedSig, Bitmap: bmp}, }, }, { &Extra{ - Parent: &Signature{AggregatedSignature: parentStr, Bitmap: bitmapStr}, - Committed: &Signature{AggregatedSignature: committedStr, Bitmap: bitmapStr}, + Parent: &Signature{AggregatedSignature: parentSig, Bitmap: bmp}, + Committed: &Signature{AggregatedSignature: committedSig, Bitmap: bmp}, }, }, { &Extra{ - Parent: &Signature{AggregatedSignature: parentStr, Bitmap: bitmapStr}, - Committed: &Signature{AggregatedSignature: committedStr, Bitmap: bitmapStr}, + Parent: &Signature{AggregatedSignature: parentSig, Bitmap: bmp}, + Committed: &Signature{AggregatedSignature: committedSig, Bitmap: bmp}, Checkpoint: &CheckpointData{ BlockRound: 0, EpochNumber: 3, @@ -126,7 +135,7 @@ func TestExtra_UnmarshalRLPWith_NegativeCases(t *testing.T) { extra := &Extra{} ar := &fastrlp.Arena{} - require.ErrorContains(t, extra.UnmarshalRLPWith(ar.NewArray()), "incorrect elements count to decode Extra, expected 5 but found 0") + require.ErrorContains(t, extra.UnmarshalRLPWith(ar.NewArray()), "incorrect elements count to decode Extra, expected 4 but found 0") }) t.Run("Incorrect ValidatorSetDelta marshalled", func(t *testing.T) { @@ -150,9 +159,8 @@ func TestExtra_UnmarshalRLPWith_NegativeCases(t *testing.T) { extra := &Extra{} ar := &fastrlp.Arena{} extraMarshalled := ar.NewArray() - deltaMarshalled := new(ValidatorSetDelta).MarshalRLPWith(ar) + deltaMarshalled := new(validator.ValidatorSetDelta).MarshalRLPWith(ar) extraMarshalled.Set(deltaMarshalled) // ValidatorSetDelta - extraMarshalled.Set(ar.NewNull()) // Seal extraMarshalled.Set(ar.NewBytes([]byte{})) // Parent extraMarshalled.Set(ar.NewBytes([]byte{})) // Committed require.Error(t, extra.UnmarshalRLPWith(extraMarshalled)) @@ -164,7 +172,7 @@ func TestExtra_UnmarshalRLPWith_NegativeCases(t *testing.T) { extra := &Extra{} ar := &fastrlp.Arena{} extraMarshalled := ar.NewArray() - deltaMarshalled := new(ValidatorSetDelta).MarshalRLPWith(ar) + deltaMarshalled := new(validator.ValidatorSetDelta).MarshalRLPWith(ar) extraMarshalled.Set(deltaMarshalled) // ValidatorSetDelta extraMarshalled.Set(ar.NewBytes([]byte{})) // Seal // Parent @@ -181,7 +189,7 @@ func TestExtra_UnmarshalRLPWith_NegativeCases(t *testing.T) { extra := &Extra{} ar := &fastrlp.Arena{} extraMarshalled := ar.NewArray() - deltaMarshalled := new(ValidatorSetDelta).MarshalRLPWith(ar) + deltaMarshalled := new(validator.ValidatorSetDelta).MarshalRLPWith(ar) extraMarshalled.Set(deltaMarshalled) // ValidatorSetDelta extraMarshalled.Set(ar.NewBytes([]byte{})) // Seal @@ -204,7 +212,7 @@ func TestExtra_UnmarshalRLPWith_NegativeCases(t *testing.T) { ar := &fastrlp.Arena{} extraMarshalled := ar.NewArray() - deltaMarshalled := new(ValidatorSetDelta).MarshalRLPWith(ar) + deltaMarshalled := new(validator.ValidatorSetDelta).MarshalRLPWith(ar) extraMarshalled.Set(deltaMarshalled) // ValidatorSetDelta extraMarshalled.Set(ar.NewBytes([]byte{})) // Seal @@ -246,7 +254,7 @@ func TestExtra_ValidateFinalizedData_UnhappyPath(t *testing.T) { Hash: types.BytesToHash(generateRandomBytes(t)), } - validators := newTestValidators(t, 6) + validators := validator.NewTestValidators(t, 6) polyBackendMock := new(polybftBackendMock) polyBackendMock.On("GetValidators", mock.Anything, mock.Anything).Return(nil, errors.New("validators not found")) @@ -277,9 +285,9 @@ func TestExtra_ValidateFinalizedData_UnhappyPath(t *testing.T) { // failed to verify signatures (quorum not reached) polyBackendMock = new(polybftBackendMock) - polyBackendMock.On("GetValidators", mock.Anything, mock.Anything).Return(validators.getPublicIdentities()) + polyBackendMock.On("GetValidators", mock.Anything, mock.Anything).Return(validators.GetPublicIdentities()) - noQuorumSignature := createSignature(t, validators.getPrivateIdentities("0", "1"), types.BytesToHash([]byte("FooBar")), bls.DomainCheckpointManager) + noQuorumSignature := createSignature(t, validators.GetPrivateIdentities("0", "1"), types.BytesToHash([]byte("FooBar")), bls.DomainCheckpointManager) extra = &Extra{Committed: noQuorumSignature, Checkpoint: checkpoint} checkpointHash, err := checkpoint.Hash(chainID, headerNum, header.Hash) require.NoError(t, err) @@ -290,7 +298,7 @@ func TestExtra_ValidateFinalizedData_UnhappyPath(t *testing.T) { fmt.Sprintf("failed to verify signatures for block %d (proposal hash %s): quorum not reached", headerNum, checkpointHash)) // incorrect parent extra size - validSignature := createSignature(t, validators.getPrivateIdentities(), checkpointHash, bls.DomainCheckpointManager) + validSignature := createSignature(t, validators.GetPrivateIdentities(), checkpointHash, bls.DomainCheckpointManager) extra = &Extra{Committed: validSignature, Checkpoint: checkpoint} err = extra.ValidateFinalizedData( header, parent, nil, chainID, polyBackendMock, bls.DomainCheckpointManager, hclog.NewNullLogger()) @@ -321,9 +329,9 @@ func TestExtra_ValidateParentSignatures(t *testing.T) { require.ErrorContains(t, err, fmt.Sprintf("failed to verify signatures for parent of block %d because signatures are not present", headerNum)) // validators not found - validators := newTestValidators(t, 5) + validators := validator.NewTestValidators(t, 5) incorrectHash := types.BytesToHash([]byte("Hello World")) - invalidSig := createSignature(t, validators.getPrivateIdentities(), incorrectHash, bls.DomainCheckpointManager) + invalidSig := createSignature(t, validators.GetPrivateIdentities(), incorrectHash, bls.DomainCheckpointManager) extra = &Extra{Parent: invalidSig} err = extra.ValidateParentSignatures( headerNum, polyBackendMock, nil, nil, nil, chainID, bls.DomainCheckpointManager, hclog.NewNullLogger()) @@ -332,7 +340,7 @@ func TestExtra_ValidateParentSignatures(t *testing.T) { // incorrect hash is signed polyBackendMock = new(polybftBackendMock) - polyBackendMock.On("GetValidators", mock.Anything, mock.Anything).Return(validators.getPublicIdentities()) + polyBackendMock.On("GetValidators", mock.Anything, mock.Anything).Return(validators.GetPublicIdentities()) parent := &types.Header{Number: headerNum - 1, Hash: types.BytesToHash(generateRandomBytes(t))} parentCheckpoint := &CheckpointData{EpochNumber: 3, BlockRound: 5} @@ -347,7 +355,7 @@ func TestExtra_ValidateParentSignatures(t *testing.T) { fmt.Sprintf("failed to verify signatures for parent of block %d (proposal hash: %s): could not verify aggregated signature", headerNum, parentCheckpointHash)) // valid signature provided - validSig := createSignature(t, validators.getPrivateIdentities(), parentCheckpointHash, bls.DomainCheckpointManager) + validSig := createSignature(t, validators.GetPrivateIdentities(), parentCheckpointHash, bls.DomainCheckpointManager) extra = &Extra{Parent: validSig} err = extra.ValidateParentSignatures( headerNum, polyBackendMock, nil, parent, parentExtra, chainID, bls.DomainCheckpointManager, hclog.NewNullLogger()) @@ -363,18 +371,18 @@ func TestSignature_Verify(t *testing.T) { numValidators := 100 msgHash := types.Hash{0x1} - vals := newTestValidators(t, numValidators) - validatorsMetadata := vals.getPublicIdentities() - validatorSet := vals.toValidatorSet() + vals := validator.NewTestValidators(t, numValidators) + validatorsMetadata := vals.GetPublicIdentities() + validatorSet := vals.ToValidatorSet() var signatures bls.Signatures bitmap := bitmap.Bitmap{} signers := make(map[types.Address]struct{}, len(validatorsMetadata)) - for i, val := range vals.getValidators() { + for i, val := range vals.GetValidators() { bitmap.Set(uint64(i)) - tempSign, err := val.account.Bls.Sign(msgHash[:], bls.DomainCheckpointManager) + tempSign, err := val.Account.Bls.Sign(msgHash[:], bls.DomainCheckpointManager) require.NoError(t, err) signatures = append(signatures, tempSign) @@ -400,7 +408,7 @@ func TestSignature_Verify(t *testing.T) { t.Run("Invalid bitmap provided", func(t *testing.T) { t.Parallel() - validatorSet := newTestValidators(t, 3).getPublicIdentities() + validatorSet := validator.NewTestValidators(t, 3).GetPublicIdentities() bmp := bitmap.Bitmap{} // Make bitmap invalid, by setting some flag larger than length of validator set to 1 @@ -448,7 +456,7 @@ func TestSignature_VerifyRandom(t *testing.T) { t.Parallel() numValidators := 100 - vals := newTestValidators(t, numValidators) + vals := validator.NewTestValidators(t, numValidators) msgHash := types.Hash{0x1} var signature bls.Signatures @@ -456,12 +464,12 @@ func TestSignature_VerifyRandom(t *testing.T) { bitmap := bitmap.Bitmap{} valIndxsRnd := mrand.Perm(numValidators)[:numValidators*2/3+1] - accounts := vals.getValidators() + accounts := vals.GetValidators() for _, index := range valIndxsRnd { bitmap.Set(uint64(index)) - tempSign, err := accounts[index].account.Bls.Sign(msgHash[:], bls.DomainCheckpointManager) + tempSign, err := accounts[index].Account.Bls.Sign(msgHash[:], bls.DomainCheckpointManager) require.NoError(t, err) signature = append(signature, tempSign) @@ -475,167 +483,10 @@ func TestSignature_VerifyRandom(t *testing.T) { Bitmap: bitmap, } - err = s.Verify(vals.getPublicIdentities(), msgHash, bls.DomainCheckpointManager, hclog.NewNullLogger()) + err = s.Verify(vals.GetPublicIdentities(), msgHash, bls.DomainCheckpointManager, hclog.NewNullLogger()) assert.NoError(t, err) } -func TestExtra_CreateValidatorSetDelta_Cases(t *testing.T) { - t.Parallel() - - cases := []struct { - name string - oldSet []string - newSet []string - added []string - updated []string - removed []uint64 - }{ - { - "Simple", - []string{"A", "B", "C", "E", "F"}, - []string{"B", "E", "H"}, - []string{"H"}, - []string{"B", "E"}, - []uint64{0, 2, 4}, - }, - } - - for _, c := range cases { - c := c - t.Run(c.name, func(t *testing.T) { - t.Parallel() - - vals := newTestValidatorsWithAliases(t, []string{}) - - for _, name := range c.oldSet { - vals.create(t, name, 1) - } - for _, name := range c.newSet { - vals.create(t, name, 1) - } - - oldValidatorSet := vals.getPublicIdentities(c.oldSet...) - // update voting power to random value - maxVotingPower := big.NewInt(100) - for _, name := range c.updated { - v := vals.getValidator(name) - vp, err := rand.Int(rand.Reader, maxVotingPower) - require.NoError(t, err) - // make sure generated voting power is different than the original one - v.votingPower += vp.Uint64() + 1 - } - newValidatorSet := vals.getPublicIdentities(c.newSet...) - - delta, err := createValidatorSetDelta(oldValidatorSet, newValidatorSet) - require.NoError(t, err) - - // added validators - require.Len(t, delta.Added, len(c.added)) - for i, name := range c.added { - require.Equal(t, delta.Added[i].Address, vals.getValidator(name).Address()) - } - - // removed validators - for _, i := range c.removed { - require.True(t, delta.Removed.IsSet(i)) - } - - // updated validators - require.Len(t, delta.Updated, len(c.updated)) - for i, name := range c.updated { - require.Equal(t, delta.Updated[i].Address, vals.getValidator(name).Address()) - } - }) - } -} - -func TestExtra_CreateValidatorSetDelta_BlsDiffer(t *testing.T) { - t.Parallel() - - vals := newTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) - oldValidatorSet := vals.getPublicIdentities("A", "B", "C", "D") - - // change the public bls key of 'B' - newValidatorSet := vals.getPublicIdentities("B", "E", "F") - privateKey, err := bls.GenerateBlsKey() - require.NoError(t, err) - - newValidatorSet[0].BlsKey = privateKey.PublicKey() - - _, err = createValidatorSetDelta(oldValidatorSet, newValidatorSet) - require.Error(t, err) -} - -func TestExtra_ValidateDelta(t *testing.T) { - t.Parallel() - - cases := []struct { - name string - oldValidators []string - originalNewValidators []string - changedNewValidators []string - updatedVotingPowers []*big.Int - expectError bool - }{ - { - name: "Valid delta provided", - oldValidators: []string{"A", "B", "F"}, - originalNewValidators: []string{"B", "E", "F"}, - expectError: false, - }, - { - name: "Different added validators", - oldValidators: []string{"A", "B", "F"}, - originalNewValidators: []string{"A", "B", "F", "D"}, - changedNewValidators: []string{"A", "B", "F", "E"}, - expectError: true, - }, - { - name: "Different removed validators", - oldValidators: []string{"A", "B", "F"}, - originalNewValidators: []string{"A", "B"}, - changedNewValidators: []string{"A", "F"}, - expectError: true, - }, - { - name: "Different updated validators", - oldValidators: []string{"A", "B", "F"}, - originalNewValidators: []string{"A", "B", "F"}, - changedNewValidators: []string{"A", "B", "F"}, - updatedVotingPowers: []*big.Int{big.NewInt(100)}, - expectError: true, - }, - } - - for _, c := range cases { - c := c - t.Run(c.name, func(t *testing.T) { - t.Parallel() - - vals := newTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) - oldValidators := vals.getPublicIdentities(c.oldValidators...) - newValidators := vals.getPublicIdentities(c.originalNewValidators...) - for i, votingPower := range c.updatedVotingPowers { - newValidators[i].VotingPower = votingPower - } - - delta, err := createValidatorSetDelta(oldValidators, newValidators) - require.NoError(t, err) - - extra := &Extra{Validators: delta} - - if c.changedNewValidators != nil { - newValidators = vals.getPublicIdentities(c.changedNewValidators...) - } - - if c.expectError { - require.Error(t, extra.ValidateDelta(oldValidators, newValidators)) - } else { - require.NoError(t, extra.ValidateDelta(oldValidators, newValidators)) - } - }) - } -} func TestExtra_InitGenesisValidatorsDelta(t *testing.T) { t.Parallel() @@ -643,21 +494,19 @@ func TestExtra_InitGenesisValidatorsDelta(t *testing.T) { t.Parallel() const validatorsCount = 7 - vals := newTestValidators(t, validatorsCount) - - polyBftConfig := PolyBFTConfig{InitialValidatorSet: vals.getParamValidators()} + vals := validator.NewTestValidators(t, validatorsCount) - delta := &ValidatorSetDelta{ - Added: make(AccountSet, validatorsCount), + delta := &validator.ValidatorSetDelta{ + Added: make(validator.AccountSet, validatorsCount), Removed: bitmap.Bitmap{}, } var i int - for _, validator := range vals.validators { - delta.Added[i] = &ValidatorMetadata{ - Address: types.Address(validator.account.Ecdsa.Address()), - BlsKey: validator.account.Bls.PublicKey(), - VotingPower: new(big.Int).SetUint64(validator.votingPower), + for _, val := range vals.Validators { + delta.Added[i] = &validator.ValidatorMetadata{ + Address: types.Address(val.Account.Ecdsa.Address()), + BlsKey: val.Account.Bls.PublicKey(), + VotingPower: new(big.Int).SetUint64(val.VotingPower), } i++ } @@ -665,10 +514,7 @@ func TestExtra_InitGenesisValidatorsDelta(t *testing.T) { extra := Extra{Validators: delta} genesis := &chain.Genesis{ - Config: &chain.Params{Engine: map[string]interface{}{ - "polybft": polyBftConfig, - }}, - ExtraData: append(make([]byte, ExtraVanity), extra.MarshalRLPTo(nil)...), + ExtraData: extra.MarshalRLPTo(nil), } genesisExtra, err := GetIbftExtra(genesis.ExtraData) @@ -680,13 +526,7 @@ func TestExtra_InitGenesisValidatorsDelta(t *testing.T) { t.Run("Invalid Extra data", func(t *testing.T) { t.Parallel() - validators := newTestValidators(t, 5) - polyBftConfig := PolyBFTConfig{InitialValidatorSet: validators.getParamValidators()} - genesis := &chain.Genesis{ - Config: &chain.Params{Engine: map[string]interface{}{ - "polybft": polyBftConfig, - }}, ExtraData: append(make([]byte, ExtraVanity), []byte{0x2, 0x3}...), } @@ -696,143 +536,56 @@ func TestExtra_InitGenesisValidatorsDelta(t *testing.T) { }) } -func TestValidatorSetDelta_Copy(t *testing.T) { +func Test_GetIbftExtraClean(t *testing.T) { t.Parallel() - const ( - originalValidatorsCount = 10 - addedValidatorsCount = 2 - ) - - oldValidatorSet := newTestValidators(t, originalValidatorsCount).getPublicIdentities() - newValidatorSet := oldValidatorSet[:len(oldValidatorSet)-2] - originalDelta, err := createValidatorSetDelta(oldValidatorSet, newValidatorSet) + key, err := wallet.GenerateAccount() require.NoError(t, err) - require.NotNil(t, originalDelta) - require.Empty(t, originalDelta.Added) - - copiedDelta := originalDelta.Copy() - require.NotNil(t, copiedDelta) - require.NotSame(t, originalDelta, copiedDelta) - require.NotEqual(t, originalDelta, copiedDelta) - require.Empty(t, copiedDelta.Added) - require.Equal(t, copiedDelta.Removed.Len(), originalDelta.Removed.Len()) - - newValidators := newTestValidators(t, addedValidatorsCount).getPublicIdentities() - copiedDelta.Added = append(copiedDelta.Added, newValidators...) - require.Empty(t, originalDelta.Added) - require.Len(t, copiedDelta.Added, addedValidatorsCount) - require.Equal(t, copiedDelta.Removed.Len(), originalDelta.Removed.Len()) -} - -func TestValidatorSetDelta_UnmarshalRLPWith_NegativeCases(t *testing.T) { - t.Parallel() - t.Run("Incorrect RLP value type provided", func(t *testing.T) { - t.Parallel() - - ar := &fastrlp.Arena{} - delta := &ValidatorSetDelta{} - require.ErrorContains(t, delta.UnmarshalRLPWith(ar.NewNull()), "value is not of type array") - }) - - t.Run("Empty RLP array provided", func(t *testing.T) { - t.Parallel() - - ar := &fastrlp.Arena{} - delta := &ValidatorSetDelta{} - require.NoError(t, delta.UnmarshalRLPWith(ar.NewArray())) - }) - - t.Run("Incorrect RLP array size", func(t *testing.T) { - t.Parallel() - - ar := &fastrlp.Arena{} - deltaMarshalled := ar.NewArray() - deltaMarshalled.Set(ar.NewBytes([]byte{0x59})) - deltaMarshalled.Set(ar.NewBytes([]byte{0x33})) - deltaMarshalled.Set(ar.NewBytes([]byte{0x26})) - deltaMarshalled.Set(ar.NewBytes([]byte{0x74})) - delta := &ValidatorSetDelta{} - require.ErrorContains(t, delta.UnmarshalRLPWith(deltaMarshalled), "incorrect elements count to decode validator set delta, expected 3 but found 4") - }) - - t.Run("Incorrect RLP value type for Added field", func(t *testing.T) { - t.Parallel() - - ar := &fastrlp.Arena{} - deltaMarshalled := ar.NewArray() - deltaMarshalled.Set(ar.NewBytes([]byte{0x59})) - deltaMarshalled.Set(ar.NewBytes([]byte{0x33})) - deltaMarshalled.Set(ar.NewBytes([]byte{0x27})) - delta := &ValidatorSetDelta{} - require.ErrorContains(t, delta.UnmarshalRLPWith(deltaMarshalled), "array expected for added validators") - }) - - t.Run("Incorrect RLP value type for ValidatorMetadata in Added field", func(t *testing.T) { - t.Parallel() - - ar := &fastrlp.Arena{} - deltaMarshalled := ar.NewArray() - addedArray := ar.NewArray() - addedArray.Set(ar.NewNull()) - deltaMarshalled.Set(addedArray) - deltaMarshalled.Set(ar.NewNullArray()) - deltaMarshalled.Set(ar.NewNull()) - delta := &ValidatorSetDelta{} - require.ErrorContains(t, delta.UnmarshalRLPWith(deltaMarshalled), "value is not of type array") - }) - - t.Run("Incorrect RLP value type for Removed field", func(t *testing.T) { - t.Parallel() - - ar := &fastrlp.Arena{} - deltaMarshalled := ar.NewArray() - addedValidators := newTestValidators(t, 3).getPublicIdentities() - addedArray := ar.NewArray() - updatedArray := ar.NewArray() - for _, validator := range addedValidators { - addedArray.Set(validator.MarshalRLPWith(ar)) - } - for _, validator := range addedValidators { - votingPower, err := rand.Int(rand.Reader, big.NewInt(100)) - require.NoError(t, err) - - validator.VotingPower = new(big.Int).Set(votingPower) - updatedArray.Set(validator.MarshalRLPWith(ar)) - } - deltaMarshalled.Set(addedArray) - deltaMarshalled.Set(updatedArray) - deltaMarshalled.Set(ar.NewNull()) - delta := &ValidatorSetDelta{} - require.ErrorContains(t, delta.UnmarshalRLPWith(deltaMarshalled), "value is not of type bytes") - }) - - t.Run("Incorrect RLP value type for Updated field", func(t *testing.T) { - t.Parallel() - - ar := &fastrlp.Arena{} - deltaMarshalled := ar.NewArray() - deltaMarshalled.Set(ar.NewArray()) - deltaMarshalled.Set(ar.NewBytes([]byte{0x33})) - deltaMarshalled.Set(ar.NewNull()) - delta := &ValidatorSetDelta{} - require.ErrorContains(t, delta.UnmarshalRLPWith(deltaMarshalled), "array expected for updated validators") - }) + extra := &Extra{ + Validators: &validator.ValidatorSetDelta{ + Added: validator.AccountSet{ + &validator.ValidatorMetadata{ + Address: types.BytesToAddress([]byte{11, 22}), + BlsKey: key.Bls.PublicKey(), + VotingPower: new(big.Int).SetUint64(1000), + IsActive: true, + }, + }, + }, + Committed: &Signature{ + AggregatedSignature: []byte{23, 24}, + Bitmap: []byte{11}, + }, + Parent: &Signature{ + AggregatedSignature: []byte{0, 1}, + Bitmap: []byte{1}, + }, + Checkpoint: &CheckpointData{ + BlockRound: 1, + EpochNumber: 1, + CurrentValidatorsHash: types.BytesToHash([]byte{2, 3}), + NextValidatorsHash: types.BytesToHash([]byte{4, 5}), + EventRoot: types.BytesToHash([]byte{6, 7}), + }, + } - t.Run("Incorrect RLP value type for ValidatorMetadata in Updated field", func(t *testing.T) { - t.Parallel() + extraClean, err := GetIbftExtraClean(extra.MarshalRLPTo(nil)) + require.NoError(t, err) - ar := &fastrlp.Arena{} - deltaMarshalled := ar.NewArray() - updatedArray := ar.NewArray() - updatedArray.Set(ar.NewNull()) - deltaMarshalled.Set(ar.NewArray()) - deltaMarshalled.Set(updatedArray) - deltaMarshalled.Set(ar.NewNull()) - delta := &ValidatorSetDelta{} - require.ErrorContains(t, delta.UnmarshalRLPWith(deltaMarshalled), "value is not of type array") - }) + extraTwo := &Extra{} + require.NoError(t, extraTwo.UnmarshalRLP(extraClean)) + require.True(t, extra.Validators.Equals(extra.Validators)) + require.Equal(t, extra.Checkpoint.BlockRound, extraTwo.Checkpoint.BlockRound) + require.Equal(t, extra.Checkpoint.EpochNumber, extraTwo.Checkpoint.EpochNumber) + require.Equal(t, extra.Checkpoint.CurrentValidatorsHash, extraTwo.Checkpoint.CurrentValidatorsHash) + require.Equal(t, extra.Checkpoint.NextValidatorsHash, extraTwo.Checkpoint.NextValidatorsHash) + require.Equal(t, extra.Checkpoint.NextValidatorsHash, extraTwo.Checkpoint.NextValidatorsHash) + require.Equal(t, extra.Parent.AggregatedSignature, extraTwo.Parent.AggregatedSignature) + require.Equal(t, extra.Parent.Bitmap, extraTwo.Parent.Bitmap) + + require.Nil(t, extraTwo.Committed.AggregatedSignature) + require.Nil(t, extraTwo.Committed.Bitmap) } func Test_GetIbftExtraClean_Fail(t *testing.T) { @@ -876,8 +629,8 @@ func TestCheckpointData_Hash(t *testing.T) { func TestCheckpointData_Validate(t *testing.T) { t.Parallel() - currentValidators := newTestValidators(t, 5).getPublicIdentities() - nextValidators := newTestValidators(t, 3).getPublicIdentities() + currentValidators := validator.NewTestValidators(t, 5).GetPublicIdentities() + nextValidators := validator.NewTestValidators(t, 3).GetPublicIdentities() currentValidatorsHash, err := currentValidators.Hash() require.NoError(t, err) @@ -889,10 +642,11 @@ func TestCheckpointData_Validate(t *testing.T) { name string parentEpochNumber uint64 epochNumber uint64 - currentValidators AccountSet - nextValidators AccountSet + currentValidators validator.AccountSet + nextValidators validator.AccountSet currentValidatorsHash types.Hash nextValidatorsHash types.Hash + exitRootHash types.Hash errString string }{ { @@ -960,6 +714,17 @@ func TestCheckpointData_Validate(t *testing.T) { nextValidatorsHash: nextValidatorsHash, errString: "epoch number should not change for epoch-ending block", }, + { + name: "Invalid exit root hash", + parentEpochNumber: 2, + epochNumber: 2, + currentValidators: currentValidators, + nextValidators: currentValidators, + currentValidatorsHash: currentValidatorsHash, + nextValidatorsHash: currentValidatorsHash, + exitRootHash: types.BytesToHash([]byte{0, 1, 2, 3, 4, 5, 6, 7}), + errString: "exit root hash not as expected", + }, } for _, c := range cases { @@ -970,9 +735,10 @@ func TestCheckpointData_Validate(t *testing.T) { EpochNumber: c.epochNumber, CurrentValidatorsHash: c.currentValidatorsHash, NextValidatorsHash: c.nextValidatorsHash, + EventRoot: c.exitRootHash, } parentCheckpoint := &CheckpointData{EpochNumber: c.parentEpochNumber} - err := checkpoint.Validate(parentCheckpoint, c.currentValidators, c.nextValidators) + err := checkpoint.Validate(parentCheckpoint, c.currentValidators, c.nextValidators, types.ZeroHash) if c.errString != "" { require.ErrorContains(t, err, c.errString) @@ -986,11 +752,11 @@ func TestCheckpointData_Validate(t *testing.T) { func TestCheckpointData_Copy(t *testing.T) { t.Parallel() - validatorAccs := newTestValidators(t, 5) - currentValidatorsHash, err := validatorAccs.getPublicIdentities("0", "1", "2").Hash() + validatorAccs := validator.NewTestValidators(t, 5) + currentValidatorsHash, err := validatorAccs.GetPublicIdentities("0", "1", "2").Hash() require.NoError(t, err) - nextValidatorsHash, err := validatorAccs.getPublicIdentities("1", "3", "4").Hash() + nextValidatorsHash, err := validatorAccs.GetPublicIdentities("1", "3", "4").Hash() require.NoError(t, err) eventRoot := generateRandomBytes(t) diff --git a/consensus/polybft/fsm.go b/consensus/polybft/fsm.go index 8ad9aa66a2..90fe2eb5b8 100644 --- a/consensus/polybft/fsm.go +++ b/consensus/polybft/fsm.go @@ -5,16 +5,19 @@ import ( "errors" "fmt" "math/big" + "time" "github.com/0xPolygon/go-ibft/messages" "github.com/0xPolygon/go-ibft/messages/proto" "github.com/0xPolygon/polygon-edge/consensus/polybft/bitmap" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" "github.com/0xPolygon/polygon-edge/contracts" "github.com/0xPolygon/polygon-edge/state" "github.com/0xPolygon/polygon-edge/types" + "github.com/armon/go-metrics" hcf "github.com/hashicorp/go-hclog" ) @@ -30,9 +33,18 @@ type blockBuilder interface { var ( errCommitEpochTxDoesNotExist = errors.New("commit epoch transaction is not found in the epoch ending block") errCommitEpochTxNotExpected = errors.New("didn't expect commit epoch transaction in a non epoch ending block") - errCommitEpochTxSingleExpected = errors.New("only one commit epoch transaction is allowed in an epoch ending block") - errProposalDontMatch = errors.New("failed to insert proposal, because the validated proposal " + + errCommitEpochTxSingleExpected = errors.New("only one commit epoch transaction is allowed " + + "in an epoch ending block") + errDistributeRewardsTxDoesNotExist = errors.New("distribute rewards transaction is " + + "not found in the epoch ending block") + errDistributeRewardsTxNotExpected = errors.New("didn't expect distribute rewards transaction " + + "in a non epoch ending block") + errDistributeRewardsTxSingleExpected = errors.New("only one distribute rewards transaction is " + + "allowed in an epoch ending block") + errProposalDontMatch = errors.New("failed to insert proposal, because the validated proposal " + "is either nil or it does not match the received one") + errValidatorSetDeltaMismatch = errors.New("validator set delta mismatch") + errValidatorsUpdateInNonEpochEnding = errors.New("trying to update validator set in a non epoch ending block") ) type fsm struct { @@ -49,7 +61,7 @@ type fsm struct { polybftBackend polybftBackend // validators is the list of validators for this round - validators ValidatorSet + validators validator.ValidatorSet // proposerSnapshot keeps information about new proposer proposerSnapshot *ProposerSnapshot @@ -60,10 +72,14 @@ type fsm struct { // epochNumber denotes current epoch number epochNumber uint64 - // commitEpochInput holds info about validators performance during single epoch - // (namely how many times each validator signed block during epoch). + // commitEpochInput holds info about a single epoch // It is populated only for epoch-ending blocks. - commitEpochInput *contractsapi.CommitEpochChildValidatorSetFn + commitEpochInput *contractsapi.CommitEpochValidatorSetFn + + // distributeRewardsInput holds info about validators work in a single epoch + // mainly, how many blocks they signed during given epoch + // It is populated only for epoch-ending blocks. + distributeRewardsInput *contractsapi.DistributeRewardForRewardPoolFn // isEndOfEpoch indicates if epoch reached its end isEndOfEpoch bool @@ -82,10 +98,17 @@ type fsm struct { // exitEventRootHash is the calculated root hash for given checkpoint block exitEventRootHash types.Hash + + // newValidatorsDelta carries the updates of validator set on epoch ending block + newValidatorsDelta *validator.ValidatorSetDelta } // BuildProposal builds a proposal for the current round (used if proposer) func (f *fsm) BuildProposal(currentRound uint64) ([]byte, error) { + start := time.Now().UTC() + defer metrics.SetGauge([]string{consensusMetricsPrefix, "block_building_time"}, + float32(time.Now().UTC().Sub(start).Seconds())) + parent := f.parent extraParent, err := GetIbftExtra(parent.ExtraData) @@ -93,8 +116,6 @@ func (f *fsm) BuildProposal(currentRound uint64) ([]byte, error) { return nil, err } - //nolint:godox - // TODO: we will need to revisit once slashing is implemented (to be fixed in EVM-519) extra := &Extra{Parent: extraParent.Committed} // for non-epoch ending blocks, currentValidatorsHash is the same as the nextValidatorsHash nextValidators := f.validators.Accounts() @@ -112,6 +133,15 @@ func (f *fsm) BuildProposal(currentRound uint64) ([]byte, error) { if err := f.blockBuilder.WriteTx(tx); err != nil { return nil, fmt.Errorf("failed to apply commit epoch transaction: %w", err) } + + tx, err = f.createDistributeRewardsTx() + if err != nil { + return nil, err + } + + if err := f.blockBuilder.WriteTx(tx); err != nil { + return nil, fmt.Errorf("failed to apply distribute rewards transaction: %w", err) + } } if f.config.IsBridgeEnabled() { @@ -123,26 +153,13 @@ func (f *fsm) BuildProposal(currentRound uint64) ([]byte, error) { // fill the block with transactions f.blockBuilder.Fill() - // update extra validators if needed, but only after all transactions has been written - // each transaction can update state and therefore change validators stake for example if f.isEndOfEpoch { - nextValidators, err = f.getCurrentValidators(f.blockBuilder.GetState()) + nextValidators, err = nextValidators.ApplyDelta(f.newValidatorsDelta) if err != nil { return nil, err } - validatorsDelta, err := createValidatorSetDelta(f.validators.Accounts(), nextValidators) - if err != nil { - return nil, fmt.Errorf("failed to create validator set delta: %w", err) - } - - extra.Validators = validatorsDelta - f.logger.Trace("[FSM Build Proposal]", "Validators Delta", validatorsDelta) - - nextValidators, err = f.getValidatorsTransition(validatorsDelta) - if err != nil { - return nil, err - } + extra.Validators = f.newValidatorsDelta } currentValidatorsHash, err := f.validators.Accounts().Hash() @@ -167,7 +184,7 @@ func (f *fsm) BuildProposal(currentRound uint64) ([]byte, error) { "Next validators hash", nextValidatorsHash) stateBlock, err := f.blockBuilder.Build(func(h *types.Header) { - h.ExtraData = append(make([]byte, ExtraVanity), extra.MarshalRLPTo(nil)...) + h.ExtraData = extra.MarshalRLPTo(nil) h.MixHash = PolyBFTMixDigest }) @@ -218,23 +235,13 @@ func (f *fsm) createBridgeCommitmentTx() (*types.Transaction, error) { } // getValidatorsTransition applies delta to the current validators, -// as ChildValidatorSet SC returns validators in different order than the one kept on the Edge -func (f *fsm) getValidatorsTransition(delta *ValidatorSetDelta) (AccountSet, error) { +func (f *fsm) getValidatorsTransition(delta *validator.ValidatorSetDelta) (validator.AccountSet, error) { nextValidators, err := f.validators.Accounts().ApplyDelta(delta) if err != nil { return nil, err } - if f.logger.IsDebug() { - var buf bytes.Buffer - for _, v := range nextValidators { - if _, err := buf.WriteString(fmt.Sprintf("%s\n", v.String())); err != nil { - return nil, err - } - } - - f.logger.Debug("getValidatorsTransition", "Next validators", buf.String()) - } + f.logger.Debug("getValidatorsTransition", "Next validators", nextValidators) return nextValidators, nil } @@ -250,6 +257,17 @@ func (f *fsm) createCommitEpochTx() (*types.Transaction, error) { return createStateTransactionWithData(contracts.ValidatorSetContract, input), nil } +// createDistributeRewardsTx create a StateTransaction, which invokes RewardPool smart contract +// and sends all the necessary metadata to it. +func (f *fsm) createDistributeRewardsTx() (*types.Transaction, error) { + input, err := f.distributeRewardsInput.EncodeAbi() + if err != nil { + return nil, err + } + + return createStateTransactionWithData(contracts.RewardPoolContract, input), nil +} + // ValidateCommit is used to validate that a given commit is valid func (f *fsm) ValidateCommit(signer []byte, seal []byte, proposalHash []byte) error { from := types.BytesToAddress(signer) @@ -279,7 +297,7 @@ func (f *fsm) Validate(proposal []byte) error { } // validate header fields - if err := validateHeaderFields(f.parent, block.Header); err != nil { + if err := validateHeaderFields(f.parent, block.Header, f.config.BlockTimeDrift); err != nil { return fmt.Errorf( "failed to validate header (parent header# %d, current header#%d): %w", f.parent.Number, @@ -316,25 +334,26 @@ func (f *fsm) Validate(proposal []byte) error { } currentValidators := f.validators.Accounts() - nextValidators := f.validators.Accounts() - validateExtraData := func(transition *state.Transition) error { - if f.isEndOfEpoch { - if nextValidators, err = f.getCurrentValidators(transition); err != nil { - return err - } - } - - if err := extra.ValidateDelta(currentValidators, nextValidators); err != nil { - return err + // validate validators delta + if f.isEndOfEpoch { + if !extra.Validators.Equals(f.newValidatorsDelta) { + return errValidatorSetDeltaMismatch } + } else if !extra.Validators.IsEmpty() { + // delta should be empty in non epoch ending blocks + return errValidatorsUpdateInNonEpochEnding + } - nextValidators, err = f.getValidatorsTransition(extra.Validators) - if err != nil { - return err - } + nextValidators, err := f.getValidatorsTransition(extra.Validators) + if err != nil { + return err + } - return extra.Checkpoint.Validate(parentExtra.Checkpoint, currentValidators, nextValidators) + // validate checkpoint data + if err := extra.Checkpoint.Validate(parentExtra.Checkpoint, + currentValidators, nextValidators, f.exitEventRootHash); err != nil { + return err } if f.logger.IsTrace() && block.Number() > 1 { @@ -346,7 +365,7 @@ func (f *fsm) Validate(proposal []byte) error { f.logger.Trace("[FSM Validate]", "Block", block.Number(), "parent validators", validators) } - stateBlock, err := f.backend.ProcessBlock(f.parent, &block, validateExtraData) + stateBlock, err := f.backend.ProcessBlock(f.parent, &block) if err != nil { return err } @@ -392,8 +411,9 @@ func (f *fsm) ValidateSender(msg *proto.Message) error { func (f *fsm) VerifyStateTransactions(transactions []*types.Transaction) error { var ( - commitmentTxExists bool - commitEpochTxExists bool + commitmentTxExists bool + commitEpochTxExists bool + distributeRewardsTxExists bool ) for _, tx := range transactions { @@ -401,7 +421,7 @@ func (f *fsm) VerifyStateTransactions(transactions []*types.Transaction) error { continue } - decodedStateTx, err := decodeStateTransaction(tx.Input) // used to be Data + decodedStateTx, err := decodeStateTransaction(tx.Input) if err != nil { return fmt.Errorf("unknown state transaction: tx = %v, err = %w", tx.Hash, err) } @@ -409,39 +429,19 @@ func (f *fsm) VerifyStateTransactions(transactions []*types.Transaction) error { switch stateTxData := decodedStateTx.(type) { case *CommitmentMessageSigned: if !f.isEndOfSprint { - return fmt.Errorf("found commitment tx in block which should not contain it: tx = %v", tx.Hash) + return fmt.Errorf("found commitment tx in block which should not contain it (tx hash=%s)", tx.Hash) } if commitmentTxExists { - return fmt.Errorf("only one commitment tx is allowed per block: %v", tx.Hash) + return fmt.Errorf("only one commitment tx is allowed per block (tx hash=%s)", tx.Hash) } commitmentTxExists = true - signers, err := f.validators.Accounts().GetFilteredValidators(stateTxData.AggSignature.Bitmap) - if err != nil { - return fmt.Errorf("error for state transaction while retrieving signers: tx = %v, error = %w", tx.Hash, err) - } - - if !f.validators.HasQuorum(signers.GetAddressesAsSet()) { - return fmt.Errorf("quorum size not reached for state tx: %v", tx.Hash) - } - - aggs, err := bls.UnmarshalSignature(stateTxData.AggSignature.AggregatedSignature) - if err != nil { - return fmt.Errorf("error for state transaction while unmarshaling signature: tx = %v, error = %w", tx.Hash, err) - } - - hash, err := stateTxData.Hash() - if err != nil { + if err = verifyBridgeCommitmentTx(tx.Hash, stateTxData, f.validators); err != nil { return err } - - verified := aggs.VerifyAggregated(signers.GetBlsKeys(), hash.Bytes(), bls.DomainStateReceiver) - if !verified { - return fmt.Errorf("invalid signature for tx = %v", tx.Hash) - } - case *contractsapi.CommitEpochChildValidatorSetFn: + case *contractsapi.CommitEpochValidatorSetFn: if commitEpochTxExists { // if we already validated commit epoch tx, // that means someone added more than one commit epoch tx to block, @@ -454,15 +454,36 @@ func (f *fsm) VerifyStateTransactions(transactions []*types.Transaction) error { if err := f.verifyCommitEpochTx(tx); err != nil { return fmt.Errorf("error while verifying commit epoch transaction. error: %w", err) } + case *contractsapi.DistributeRewardForRewardPoolFn: + if distributeRewardsTxExists { + // if we already validated distribute rewards tx, + // that means someone added more than one distribute rewards tx to block, + // which is invalid + return errDistributeRewardsTxSingleExpected + } + + distributeRewardsTxExists = true + + if err := f.verifyDistributeRewardsTx(tx); err != nil { + return fmt.Errorf("error while verifying distribute rewards transaction. error: %w", err) + } default: return fmt.Errorf("invalid state transaction data type: %v", stateTxData) } } - if f.isEndOfEpoch && !commitEpochTxExists { - // this is a check if commit epoch transaction is not in the list of transactions at all - // but it should be - return errCommitEpochTxDoesNotExist + if f.isEndOfEpoch { + if !commitEpochTxExists { + // this is a check if commit epoch transaction is not in the list of transactions at all + // but it should be + return errCommitEpochTxDoesNotExist + } + + if !distributeRewardsTxExists { + // this is a check if distribute rewards transaction is not in the list of transactions at all + // but it should be + return errDistributeRewardsTxDoesNotExist + } } return nil @@ -532,7 +553,7 @@ func (f *fsm) Insert(proposal []byte, committedSeals []*messages.CommittedSeal) } // Write extra data to header - newBlock.Block.Header.ExtraData = append(make([]byte, ExtraVanity), extra.MarshalRLPTo(nil)...) + newBlock.Block.Header.ExtraData = extra.MarshalRLPTo(nil) if err := f.backend.CommitBlock(newBlock); err != nil { return nil, err @@ -547,23 +568,10 @@ func (f *fsm) Height() uint64 { } // ValidatorSet returns the validator set for the current round -func (f *fsm) ValidatorSet() ValidatorSet { +func (f *fsm) ValidatorSet() validator.ValidatorSet { return f.validators } -// getCurrentValidators queries smart contract on the given block height and returns currently active validator set -func (f *fsm) getCurrentValidators(pendingBlockState *state.Transition) (AccountSet, error) { - provider := f.backend.GetStateProvider(pendingBlockState) - systemState := f.backend.GetSystemState(provider) - - newValidators, err := systemState.GetValidatorSet() - if err != nil { - return nil, fmt.Errorf("failed to retrieve validator set for current block: %w", err) - } - - return newValidators, nil -} - // verifyCommitEpochTx creates commit epoch transaction and compares its hash with the one extracted from the block. func (f *fsm) verifyCommitEpochTx(commitEpochTx *types.Transaction) error { if f.isEndOfEpoch { @@ -586,7 +594,65 @@ func (f *fsm) verifyCommitEpochTx(commitEpochTx *types.Transaction) error { return errCommitEpochTxNotExpected } -func validateHeaderFields(parent *types.Header, header *types.Header) error { +// verifyDistributeRewardsTx creates distribute rewards transaction +// and compares its hash with the one extracted from the block. +func (f *fsm) verifyDistributeRewardsTx(distributeRewardsTx *types.Transaction) error { + if f.isEndOfEpoch { + localDistributeRewardsTx, err := f.createDistributeRewardsTx() + if err != nil { + return err + } + + if distributeRewardsTx.Hash != localDistributeRewardsTx.Hash { + return fmt.Errorf( + "invalid distribute rewards transaction. Expected '%s', but got '%s' distribute rewards hash", + localDistributeRewardsTx.Hash, + distributeRewardsTx.Hash, + ) + } + + return nil + } + + return errDistributeRewardsTxNotExpected +} + +// verifyBridgeCommitmentTx validates bridge commitment transaction +func verifyBridgeCommitmentTx(txHash types.Hash, + commitment *CommitmentMessageSigned, + validators validator.ValidatorSet) error { + signers, err := validators.Accounts().GetFilteredValidators(commitment.AggSignature.Bitmap) + if err != nil { + return fmt.Errorf("failed to retrieve signers for state tx (%s): %w", txHash, err) + } + + if !validators.HasQuorum(signers.GetAddressesAsSet()) { + return fmt.Errorf("quorum size not reached for state tx (%s)", txHash) + } + + commitmentHash, err := commitment.Hash() + if err != nil { + return err + } + + signature, err := bls.UnmarshalSignature(commitment.AggSignature.AggregatedSignature) + if err != nil { + return fmt.Errorf("error for state tx (%s) while unmarshaling signature: %w", txHash, err) + } + + verified := signature.VerifyAggregated(signers.GetBlsKeys(), commitmentHash.Bytes(), bls.DomainStateReceiver) + if !verified { + return fmt.Errorf("invalid signature for state tx (%s)", txHash) + } + + return nil +} + +func validateHeaderFields(parent *types.Header, header *types.Header, blockTimeDrift uint64) error { + // header extra data must be higher or equal to ExtraVanity = 32 in order to be compliant with Ethereum blocks + if len(header.ExtraData) < ExtraVanity { + return fmt.Errorf("extra-data shorter than %d bytes (%d)", ExtraVanity, len(header.ExtraData)) + } // verify parent hash if parent.Hash != header.ParentHash { return fmt.Errorf("incorrect header parent hash (parent=%s, header parent=%s)", parent.Hash, header.ParentHash) @@ -595,6 +661,19 @@ func validateHeaderFields(parent *types.Header, header *types.Header) error { if header.Number != parent.Number+1 { return fmt.Errorf("invalid number") } + // verify time is from the future + if header.Timestamp > (uint64(time.Now().UTC().Unix()) + blockTimeDrift) { + return fmt.Errorf("block from the future. block timestamp: %s, configured block time drift %d seconds", + time.Unix(int64(header.Timestamp), 0).Format(time.RFC3339), blockTimeDrift) + } + // verify header nonce is zero + if header.Nonce != types.ZeroNonce { + return fmt.Errorf("invalid nonce") + } + // verify that the gasUsed is <= gasLimit + if header.GasUsed > header.GasLimit { + return fmt.Errorf("invalid gas limit: have %v, max %v", header.GasUsed, header.GasLimit) + } // verify time has passed if header.Timestamp <= parent.Timestamp { return fmt.Errorf("timestamp older than parent") diff --git a/consensus/polybft/fsm_test.go b/consensus/polybft/fsm_test.go index 5faf7f54c3..0d71d15413 100644 --- a/consensus/polybft/fsm_test.go +++ b/consensus/polybft/fsm_test.go @@ -14,9 +14,9 @@ import ( "github.com/0xPolygon/polygon-edge/consensus/polybft/bitmap" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" "github.com/0xPolygon/polygon-edge/contracts" - "github.com/0xPolygon/polygon-edge/state" "github.com/0xPolygon/polygon-edge/types" "github.com/hashicorp/go-hclog" "github.com/stretchr/testify/assert" @@ -27,35 +27,58 @@ import ( func TestFSM_ValidateHeader(t *testing.T) { t.Parallel() + blockTimeDrift := uint64(1) + extra := createTestExtra(validator.AccountSet{}, validator.AccountSet{}, 0, 0, 0) parent := &types.Header{Number: 0, Hash: types.BytesToHash([]byte{1, 2, 3})} header := &types.Header{Number: 0} + // extra data + require.ErrorContains(t, validateHeaderFields(parent, header, blockTimeDrift), "extra-data shorter than") + header.ExtraData = extra + // parent hash - require.ErrorContains(t, validateHeaderFields(parent, header), "incorrect header parent hash") + require.ErrorContains(t, validateHeaderFields(parent, header, blockTimeDrift), "incorrect header parent hash") header.ParentHash = parent.Hash // sequence number - require.ErrorContains(t, validateHeaderFields(parent, header), "invalid number") + require.ErrorContains(t, validateHeaderFields(parent, header, blockTimeDrift), "invalid number") header.Number = 1 // failed timestamp - require.ErrorContains(t, validateHeaderFields(parent, header), "timestamp older than parent") + require.ErrorContains(t, validateHeaderFields(parent, header, blockTimeDrift), "timestamp older than parent") header.Timestamp = 10 + // failed nonce + header.SetNonce(1) + require.ErrorContains(t, validateHeaderFields(parent, header, blockTimeDrift), "invalid nonce") + + header.SetNonce(0) + + // failed gas + header.GasLimit = 10 + header.GasUsed = 11 + require.ErrorContains(t, validateHeaderFields(parent, header, blockTimeDrift), "invalid gas limit") + header.GasLimit = 10 + header.GasUsed = 10 + // mix digest - require.ErrorContains(t, validateHeaderFields(parent, header), "mix digest is not correct") + require.ErrorContains(t, validateHeaderFields(parent, header, blockTimeDrift), "mix digest is not correct") header.MixHash = PolyBFTMixDigest // difficulty header.Difficulty = 0 - require.ErrorContains(t, validateHeaderFields(parent, header), "difficulty should be greater than zero") + require.ErrorContains(t, validateHeaderFields(parent, header, blockTimeDrift), "difficulty should be greater than zero") header.Difficulty = 1 header.Hash = types.BytesToHash([]byte{11, 22, 33}) - require.ErrorContains(t, validateHeaderFields(parent, header), "invalid header hash") + require.ErrorContains(t, validateHeaderFields(parent, header, blockTimeDrift), "invalid header hash") + header.Timestamp = uint64(time.Now().UTC().Unix() + 150) + require.ErrorContains(t, validateHeaderFields(parent, header, blockTimeDrift), "block from the future") + + header.Timestamp = uint64(time.Now().UTC().Unix()) header.ComputeHash() - require.NoError(t, validateHeaderFields(parent, header)) + require.NoError(t, validateHeaderFields(parent, header, blockTimeDrift)) } func TestFSM_verifyCommitEpochTx(t *testing.T) { @@ -63,7 +86,7 @@ func TestFSM_verifyCommitEpochTx(t *testing.T) { fsm := &fsm{ isEndOfEpoch: true, - commitEpochInput: createTestCommitEpochInput(t, 0, nil, 10), + commitEpochInput: createTestCommitEpochInput(t, 0, 10), } // include commit epoch transaction to the epoch ending block @@ -104,9 +127,9 @@ func TestFSM_BuildProposal_WithoutCommitEpochTxGood(t *testing.T) { eventRoot := types.ZeroHash - validators := newTestValidators(t, accountCount) - validatorSet := validators.getPublicIdentities() - extra := createTestExtra(validatorSet, AccountSet{}, accountCount-1, committedCount, parentCount) + validators := validator.NewTestValidators(t, accountCount) + validatorSet := validators.GetPublicIdentities() + extra := createTestExtra(validatorSet, validator.AccountSet{}, accountCount-1, committedCount, parentCount) parent := &types.Header{Number: parentBlockNumber, ExtraData: extra} parent.ComputeHash() @@ -117,13 +140,13 @@ func TestFSM_BuildProposal_WithoutCommitEpochTxGood(t *testing.T) { runtime := &consensusRuntime{ logger: hclog.NewNullLogger(), config: &runtimeConfig{ - Key: wallet.NewKey(validators.getPrivateIdentities()[0]), + Key: wallet.NewKey(validators.GetPrivateIdentities()[0]), blockchain: blockchainMock, }, } fsm := &fsm{parent: parent, blockBuilder: mBlockBuilder, config: &PolyBFTConfig{}, backend: blockchainMock, - validators: validators.toValidatorSet(), exitEventRootHash: eventRoot, logger: hclog.NewNullLogger()} + validators: validators.ToValidatorSet(), exitEventRootHash: eventRoot, logger: hclog.NewNullLogger()} proposal, err := fsm.BuildProposal(currentRound) assert.NoError(t, err) @@ -169,40 +192,33 @@ func TestFSM_BuildProposal_WithCommitEpochTxGood(t *testing.T) { eventRoot := types.ZeroHash - validators := newTestValidators(t, accountCount) - extra := createTestExtra(validators.getPublicIdentities(), AccountSet{}, accountCount-1, committedCount, parentCount) + validators := validator.NewTestValidators(t, accountCount) + extra := createTestExtra(validators.GetPublicIdentities(), validator.AccountSet{}, accountCount-1, committedCount, parentCount) parent := &types.Header{Number: parentBlockNumber, ExtraData: extra} parent.ComputeHash() stateBlock := createDummyStateBlock(parentBlockNumber+1, parent.Hash, extra) - transition := &state.Transition{} mBlockBuilder := newBlockBuilderMock(stateBlock) - mBlockBuilder.On("WriteTx", mock.Anything).Return(error(nil)).Once() - mBlockBuilder.On("GetState").Return(transition).Once() - - systemStateMock := new(systemStateMock) - systemStateMock.On("GetValidatorSet").Return(nil).Once() + mBlockBuilder.On("WriteTx", mock.Anything).Return(error(nil)).Twice() blockChainMock := new(blockchainMock) - blockChainMock.On("GetStateProvider", mock.Anything). - Return(NewStateProvider(transition)).Once() - blockChainMock.On("GetSystemState", mock.Anything).Return(systemStateMock).Once() runtime := &consensusRuntime{ logger: hclog.NewNullLogger(), config: &runtimeConfig{ - Key: wallet.NewKey(validators.getPrivateIdentities()[0]), + Key: wallet.NewKey(validators.GetPrivateIdentities()[0]), blockchain: blockChainMock, }, } fsm := &fsm{parent: parent, blockBuilder: mBlockBuilder, config: &PolyBFTConfig{}, backend: blockChainMock, - isEndOfEpoch: true, - validators: validators.toValidatorSet(), - commitEpochInput: createTestCommitEpochInput(t, 0, nil, 10), - exitEventRootHash: eventRoot, - logger: hclog.NewNullLogger(), + isEndOfEpoch: true, + validators: validators.ToValidatorSet(), + commitEpochInput: createTestCommitEpochInput(t, 0, 10), + distributeRewardsInput: createTestDistributeRewardsInput(t, 0, nil, 10), + exitEventRootHash: eventRoot, + logger: hclog.NewNullLogger(), } proposal, err := fsm.BuildProposal(currentRound) @@ -214,10 +230,10 @@ func TestFSM_BuildProposal_WithCommitEpochTxGood(t *testing.T) { assert.Equal(t, stateBlock.Block.MarshalRLP(), proposal) - currentValidatorsHash, err := validators.getPublicIdentities().Hash() + currentValidatorsHash, err := validators.GetPublicIdentities().Hash() require.NoError(t, err) - nextValidatorsHash, err := AccountSet{}.Hash() + nextValidatorsHash, err := validators.ToValidatorSet().Accounts().Hash() require.NoError(t, err) checkpoint := &CheckpointData{ @@ -235,8 +251,6 @@ func TestFSM_BuildProposal_WithCommitEpochTxGood(t *testing.T) { require.Equal(t, checkpointHash.Bytes(), msg.GetPreprepareData().ProposalHash) mBlockBuilder.AssertExpectations(t) - systemStateMock.AssertExpectations(t) - blockChainMock.AssertExpectations(t) } func TestFSM_BuildProposal_EpochEndingBlock_FailedToApplyStateTx(t *testing.T) { @@ -249,8 +263,8 @@ func TestFSM_BuildProposal_EpochEndingBlock_FailedToApplyStateTx(t *testing.T) { parentBlockNumber = 1023 ) - validators := newTestValidators(t, accountCount) - extra := createTestExtra(validators.getPublicIdentities(), AccountSet{}, accountCount-1, committedCount, parentCount) + validators := validator.NewTestValidators(t, accountCount) + extra := createTestExtra(validators.GetPublicIdentities(), validator.AccountSet{}, accountCount-1, committedCount, parentCount) parent := &types.Header{Number: parentBlockNumber, ExtraData: extra} @@ -258,12 +272,12 @@ func TestFSM_BuildProposal_EpochEndingBlock_FailedToApplyStateTx(t *testing.T) { mBlockBuilder.On("WriteTx", mock.Anything).Return(errors.New("error")).Once() mBlockBuilder.On("Reset").Return(error(nil)).Once() - validatorSet := NewValidatorSet(validators.getPublicIdentities(), hclog.NewNullLogger()) + validatorSet := validator.NewValidatorSet(validators.GetPublicIdentities(), hclog.NewNullLogger()) fsm := &fsm{parent: parent, blockBuilder: mBlockBuilder, backend: &blockchainMock{}, isEndOfEpoch: true, validators: validatorSet, - commitEpochInput: createTestCommitEpochInput(t, 0, nil, 10), + commitEpochInput: createTestCommitEpochInput(t, 0, 10), exitEventRootHash: types.ZeroHash, } @@ -282,40 +296,48 @@ func TestFSM_BuildProposal_EpochEndingBlock_ValidatorsDeltaExists(t *testing.T) parentBlockNumber = 49 ) - validators := newTestValidators(t, validatorsCount).getPublicIdentities() - extra := createTestExtra(validators, AccountSet{}, validatorsCount-1, signaturesCount, signaturesCount) - parent := &types.Header{Number: parentBlockNumber, ExtraData: extra} + validators := validator.NewTestValidators(t, validatorsCount).GetPublicIdentities() + extra := createTestExtraObject(validators, validator.AccountSet{}, validatorsCount-1, signaturesCount, signaturesCount) + extra.Validators = nil + + extraData := extra.MarshalRLPTo(nil) + parent := &types.Header{Number: parentBlockNumber, ExtraData: extraData} parent.ComputeHash() - stateBlock := createDummyStateBlock(parentBlockNumber+1, parent.Hash, extra) + stateBlock := createDummyStateBlock(parentBlockNumber+1, parent.Hash, extraData) - transition := &state.Transition{} blockBuilderMock := newBlockBuilderMock(stateBlock) - blockBuilderMock.On("WriteTx", mock.Anything).Return(error(nil)).Once() - blockBuilderMock.On("GetState").Return(transition).Once() + blockBuilderMock.On("WriteTx", mock.Anything).Return(error(nil)).Twice() + + addedValidators := validator.NewTestValidators(t, 2).GetPublicIdentities() + removedValidators := [3]uint64{3, 4, 5} + removedBitmap := &bitmap.Bitmap{} - newValidators := validators[:remainingValidatorsCount].Copy() - addedValidators := newTestValidators(t, 2).getPublicIdentities() - newValidators = append(newValidators, addedValidators...) - systemStateMock := new(systemStateMock) - systemStateMock.On("GetValidatorSet").Return(newValidators).Once() + for _, i := range removedValidators { + removedBitmap.Set(i) + } + + newDelta := &validator.ValidatorSetDelta{ + Added: addedValidators, + Updated: validator.AccountSet{}, + Removed: *removedBitmap, + } blockChainMock := new(blockchainMock) - blockChainMock.On("GetStateProvider", mock.Anything). - Return(NewStateProvider(transition)).Once() - blockChainMock.On("GetSystemState", mock.Anything, mock.Anything).Return(systemStateMock).Once() - validatorSet := NewValidatorSet(validators, hclog.NewNullLogger()) + validatorSet := validator.NewValidatorSet(validators, hclog.NewNullLogger()) fsm := &fsm{ - parent: parent, - blockBuilder: blockBuilderMock, - config: &PolyBFTConfig{}, - backend: blockChainMock, - isEndOfEpoch: true, - validators: validatorSet, - commitEpochInput: createTestCommitEpochInput(t, 0, validators, 10), - exitEventRootHash: types.ZeroHash, - logger: hclog.NewNullLogger(), + parent: parent, + blockBuilder: blockBuilderMock, + config: &PolyBFTConfig{}, + backend: blockChainMock, + isEndOfEpoch: true, + validators: validatorSet, + commitEpochInput: createTestCommitEpochInput(t, 0, 10), + distributeRewardsInput: createTestDistributeRewardsInput(t, 0, validators, 10), + exitEventRootHash: types.ZeroHash, + logger: hclog.NewNullLogger(), + newValidatorsDelta: newDelta, } proposal, err := fsm.BuildProposal(0) @@ -327,8 +349,6 @@ func TestFSM_BuildProposal_EpochEndingBlock_ValidatorsDeltaExists(t *testing.T) assert.Len(t, blockExtra.Validators.Added, 2) assert.False(t, blockExtra.Validators.IsEmpty()) - removedValidators := [3]uint64{3, 4, 5} - for _, addedValidator := range addedValidators { assert.True(t, blockExtra.Validators.Added.ContainsAddress(addedValidator.Address)) } @@ -342,7 +362,6 @@ func TestFSM_BuildProposal_EpochEndingBlock_ValidatorsDeltaExists(t *testing.T) } blockBuilderMock.AssertExpectations(t) - systemStateMock.AssertExpectations(t) blockChainMock.AssertExpectations(t) } @@ -355,8 +374,8 @@ func TestFSM_BuildProposal_NonEpochEndingBlock_ValidatorsDeltaEmpty(t *testing.T parentBlockNumber = 9 ) - testValidators := newTestValidators(t, accountCount) - extra := createTestExtra(testValidators.getPublicIdentities(), AccountSet{}, accountCount-1, signaturesCount, signaturesCount) + testValidators := validator.NewTestValidators(t, accountCount) + extra := createTestExtra(testValidators.GetPublicIdentities(), validator.AccountSet{}, accountCount-1, signaturesCount, signaturesCount) parent := &types.Header{Number: parentBlockNumber, ExtraData: extra} parent.ComputeHash() stateBlock := createDummyStateBlock(parentBlockNumber+1, parent.Hash, extra) @@ -366,11 +385,9 @@ func TestFSM_BuildProposal_NonEpochEndingBlock_ValidatorsDeltaEmpty(t *testing.T blockBuilderMock.On("Fill").Once() blockBuilderMock.On("Reset").Return(error(nil)).Once() - systemStateMock := new(systemStateMock) - fsm := &fsm{parent: parent, blockBuilder: blockBuilderMock, config: &PolyBFTConfig{}, backend: &blockchainMock{}, - isEndOfEpoch: false, validators: testValidators.toValidatorSet(), + isEndOfEpoch: false, validators: testValidators.ToValidatorSet(), exitEventRootHash: types.ZeroHash, logger: hclog.NewNullLogger()} proposal, err := fsm.BuildProposal(0) @@ -382,10 +399,9 @@ func TestFSM_BuildProposal_NonEpochEndingBlock_ValidatorsDeltaEmpty(t *testing.T assert.True(t, blockExtra.Validators.IsEmpty()) blockBuilderMock.AssertExpectations(t) - systemStateMock.AssertNotCalled(t, "GetValidatorSet") } -func TestFSM_BuildProposal_EpochEndingBlock_FailToCreateValidatorsDelta(t *testing.T) { +func TestFSM_BuildProposal_EpochEndingBlock_FailToGetNextValidatorsHash(t *testing.T) { t.Parallel() const ( @@ -394,51 +410,46 @@ func TestFSM_BuildProposal_EpochEndingBlock_FailToCreateValidatorsDelta(t *testi parentBlockNumber = 49 ) - testValidators := newTestValidators(t, accountCount) - allAccounts := testValidators.getPublicIdentities() - extra := createTestExtra(allAccounts, AccountSet{}, accountCount-1, signaturesCount, signaturesCount) + testValidators := validator.NewTestValidators(t, accountCount) + allAccounts := testValidators.GetPublicIdentities() + extra := createTestExtraObject(allAccounts, validator.AccountSet{}, accountCount-1, signaturesCount, signaturesCount) + extra.Validators = nil - parent := &types.Header{Number: parentBlockNumber, ExtraData: extra} + newValidatorDelta := &validator.ValidatorSetDelta{ + // this will prompt an error since all the validators are already in the validator set + Added: testValidators.ToValidatorSet().Accounts(), + } + + parent := &types.Header{Number: parentBlockNumber, ExtraData: extra.MarshalRLPTo(nil)} - transition := &state.Transition{} blockBuilderMock := new(blockBuilderMock) - blockBuilderMock.On("WriteTx", mock.Anything).Return(error(nil)).Once() - blockBuilderMock.On("GetState").Return(transition).Once() + blockBuilderMock.On("WriteTx", mock.Anything).Return(error(nil)).Twice() blockBuilderMock.On("Reset").Return(error(nil)).Once() blockBuilderMock.On("Fill").Once() - systemStateMock := new(systemStateMock) - systemStateMock.On("GetValidatorSet").Return(nil, errors.New("failed to get validators set")).Once() - - blockChainMock := new(blockchainMock) - blockChainMock.On("GetStateProvider", mock.Anything). - Return(NewStateProvider(transition)).Once() - blockChainMock.On("GetSystemState", mock.Anything, mock.Anything).Return(systemStateMock).Once() - fsm := &fsm{parent: parent, - blockBuilder: blockBuilderMock, - config: &PolyBFTConfig{}, - backend: blockChainMock, - isEndOfEpoch: true, - validators: testValidators.toValidatorSet(), - commitEpochInput: createTestCommitEpochInput(t, 0, allAccounts, 10), - exitEventRootHash: types.ZeroHash, + blockBuilder: blockBuilderMock, + config: &PolyBFTConfig{}, + isEndOfEpoch: true, + validators: testValidators.ToValidatorSet(), + commitEpochInput: createTestCommitEpochInput(t, 0, 10), + distributeRewardsInput: createTestDistributeRewardsInput(t, 0, allAccounts, 10), + exitEventRootHash: types.ZeroHash, + newValidatorsDelta: newValidatorDelta, } proposal, err := fsm.BuildProposal(0) - assert.ErrorContains(t, err, "failed to retrieve validator set for current block: failed to get validators set") + assert.ErrorContains(t, err, "already present in the validators snapshot") assert.Nil(t, proposal) blockBuilderMock.AssertNotCalled(t, "Build") blockBuilderMock.AssertExpectations(t) - systemStateMock.AssertExpectations(t) - blockChainMock.AssertExpectations(t) } func TestFSM_VerifyStateTransactions_MiddleOfEpochWithTransaction(t *testing.T) { t.Parallel() - fsm := &fsm{commitEpochInput: createTestCommitEpochInput(t, 0, nil, 10)} + fsm := &fsm{commitEpochInput: createTestCommitEpochInput(t, 0, 10)} tx, err := fsm.createCommitEpochTx() assert.NoError(t, err) err = fsm.VerifyStateTransactions([]*types.Transaction{tx}) @@ -448,7 +459,7 @@ func TestFSM_VerifyStateTransactions_MiddleOfEpochWithTransaction(t *testing.T) func TestFSM_VerifyStateTransactions_MiddleOfEpochWithoutTransaction(t *testing.T) { t.Parallel() - fsm := &fsm{commitEpochInput: createTestCommitEpochInput(t, 0, nil, 10)} + fsm := &fsm{commitEpochInput: createTestCommitEpochInput(t, 0, 10)} err := fsm.VerifyStateTransactions([]*types.Transaction{}) assert.NoError(t, err) } @@ -456,7 +467,7 @@ func TestFSM_VerifyStateTransactions_MiddleOfEpochWithoutTransaction(t *testing. func TestFSM_VerifyStateTransactions_EndOfEpochWithoutTransaction(t *testing.T) { t.Parallel() - fsm := &fsm{isEndOfEpoch: true, commitEpochInput: createTestCommitEpochInput(t, 0, nil, 10)} + fsm := &fsm{isEndOfEpoch: true, commitEpochInput: createTestCommitEpochInput(t, 0, 10)} assert.EqualError(t, fsm.VerifyStateTransactions([]*types.Transaction{}), "commit epoch transaction is not found in the epoch ending block") } @@ -464,8 +475,8 @@ func TestFSM_VerifyStateTransactions_EndOfEpochWithoutTransaction(t *testing.T) func TestFSM_VerifyStateTransactions_EndOfEpochWrongCommitEpochTx(t *testing.T) { t.Parallel() - fsm := &fsm{isEndOfEpoch: true, commitEpochInput: createTestCommitEpochInput(t, 0, nil, 10)} - commitEpochInput, err := createTestCommitEpochInput(t, 0, nil, 5).EncodeAbi() + fsm := &fsm{isEndOfEpoch: true, commitEpochInput: createTestCommitEpochInput(t, 0, 10)} + commitEpochInput, err := createTestCommitEpochInput(t, 1, 5).EncodeAbi() require.NoError(t, err) commitEpochTx := createStateTransactionWithData(contracts.ValidatorSetContract, commitEpochInput) @@ -489,14 +500,14 @@ func TestFSM_VerifyStateTransactions_EndOfEpochMoreThanOneCommitEpochTx(t *testi t.Parallel() txs := make([]*types.Transaction, 2) - fsm := &fsm{isEndOfEpoch: true, commitEpochInput: createTestCommitEpochInput(t, 0, nil, 10)} + fsm := &fsm{isEndOfEpoch: true, commitEpochInput: createTestCommitEpochInput(t, 0, 10)} commitEpochTxOne, err := fsm.createCommitEpochTx() require.NoError(t, err) txs[0] = commitEpochTxOne - commitEpochTxTwo := createTestCommitEpochInput(t, 0, nil, 100) + commitEpochTxTwo := createTestCommitEpochInput(t, 0, 100) input, err := commitEpochTxTwo.EncodeAbi() require.NoError(t, err) @@ -508,44 +519,49 @@ func TestFSM_VerifyStateTransactions_EndOfEpochMoreThanOneCommitEpochTx(t *testi func TestFSM_VerifyStateTransactions_StateTransactionPass(t *testing.T) { t.Parallel() - validators := newTestValidators(t, 5) + validators := validator.NewTestValidators(t, 5) - validatorSet := NewValidatorSet(validators.getPublicIdentities(), hclog.NewNullLogger()) + validatorSet := validator.NewValidatorSet(validators.GetPublicIdentities(), hclog.NewNullLogger()) fsm := &fsm{ - isEndOfEpoch: true, - isEndOfSprint: true, - validators: validatorSet, - commitEpochInput: createTestCommitEpochInput(t, 0, nil, 10), - logger: hclog.NewNullLogger(), + isEndOfEpoch: true, + isEndOfSprint: true, + validators: validatorSet, + commitEpochInput: createTestCommitEpochInput(t, 0, 10), + distributeRewardsInput: createTestDistributeRewardsInput(t, 0, validators.GetPublicIdentities(), 10), + logger: hclog.NewNullLogger(), } // add commit epoch commitEpochTx to the end of transactions list commitEpochTx, err := fsm.createCommitEpochTx() require.NoError(t, err) - err = fsm.VerifyStateTransactions([]*types.Transaction{commitEpochTx}) + distributeRewardsTx, err := fsm.createDistributeRewardsTx() + require.NoError(t, err) + + err = fsm.VerifyStateTransactions([]*types.Transaction{commitEpochTx, distributeRewardsTx}) require.NoError(t, err) } func TestFSM_VerifyStateTransactions_StateTransactionQuorumNotReached(t *testing.T) { t.Parallel() - validators := newTestValidators(t, 5) - commitment := createTestCommitment(t, validators.getPrivateIdentities()) + validators := validator.NewTestValidators(t, 5) + commitment := createTestCommitment(t, validators.GetPrivateIdentities()) commitment.AggSignature = Signature{ AggregatedSignature: []byte{1, 2}, Bitmap: []byte{}, } - validatorSet := NewValidatorSet(validators.getPublicIdentities(), hclog.NewNullLogger()) + validatorSet := validator.NewValidatorSet(validators.GetPublicIdentities(), hclog.NewNullLogger()) fsm := &fsm{ isEndOfEpoch: true, isEndOfSprint: true, validators: validatorSet, proposerCommitmentToRegister: commitment, - commitEpochInput: createTestCommitEpochInput(t, 0, nil, 10), + commitEpochInput: createTestCommitEpochInput(t, 0, 10), + distributeRewardsInput: createTestDistributeRewardsInput(t, 0, nil, 10), logger: hclog.NewNullLogger(), } @@ -565,13 +581,13 @@ func TestFSM_VerifyStateTransactions_StateTransactionQuorumNotReached(t *testing func TestFSM_VerifyStateTransactions_StateTransactionInvalidSignature(t *testing.T) { t.Parallel() - validators := newTestValidators(t, 5) - commitment := createTestCommitment(t, validators.getPrivateIdentities()) - nonValidators := newTestValidators(t, 3) + validators := validator.NewTestValidators(t, 5) + commitment := createTestCommitment(t, validators.GetPrivateIdentities()) + nonValidators := validator.NewTestValidators(t, 3) aggregatedSigs := bls.Signatures{} - nonValidators.iterAcct(nil, func(t *testValidator) { - aggregatedSigs = append(aggregatedSigs, t.mustSign([]byte("dummyHash"), bls.DomainStateReceiver)) + nonValidators.IterAcct(nil, func(t *validator.TestValidator) { + aggregatedSigs = append(aggregatedSigs, t.MustSign([]byte("dummyHash"), bls.DomainStateReceiver)) }) sig, err := aggregatedSigs.Aggregate().Marshal() @@ -579,14 +595,15 @@ func TestFSM_VerifyStateTransactions_StateTransactionInvalidSignature(t *testing commitment.AggSignature.AggregatedSignature = sig - validatorSet := NewValidatorSet(validators.getPublicIdentities(), hclog.NewNullLogger()) + validatorSet := validator.NewValidatorSet(validators.GetPublicIdentities(), hclog.NewNullLogger()) fsm := &fsm{ isEndOfEpoch: true, isEndOfSprint: true, validators: validatorSet, proposerCommitmentToRegister: commitment, - commitEpochInput: createTestCommitEpochInput(t, 0, nil, 10), + commitEpochInput: createTestCommitEpochInput(t, 0, 10), + distributeRewardsInput: createTestDistributeRewardsInput(t, 0, nil, 10), logger: hclog.NewNullLogger(), } @@ -609,17 +626,17 @@ func TestFSM_ValidateCommit_WrongValidator(t *testing.T) { parentBlockNumber = 10 ) - validators := newTestValidators(t, accountsCount) + validators := validator.NewTestValidators(t, accountsCount) parent := &types.Header{ Number: parentBlockNumber, - ExtraData: createTestExtra(validators.getPublicIdentities(), AccountSet{}, 5, 3, 3), + ExtraData: createTestExtra(validators.GetPublicIdentities(), validator.AccountSet{}, 5, 3, 3), } parent.ComputeHash() stateBlock := createDummyStateBlock(parentBlockNumber+1, parent.Hash, parent.ExtraData) mBlockBuilder := newBlockBuilderMock(stateBlock) fsm := &fsm{parent: parent, blockBuilder: mBlockBuilder, config: &PolyBFTConfig{}, backend: &blockchainMock{}, - validators: validators.toValidatorSet(), logger: hclog.NewNullLogger(), exitEventRootHash: types.ZeroHash} + validators: validators.ToValidatorSet(), logger: hclog.NewNullLogger(), exitEventRootHash: types.ZeroHash} _, err := fsm.BuildProposal(0) require.NoError(t, err) @@ -636,27 +653,27 @@ func TestFSM_ValidateCommit_InvalidHash(t *testing.T) { parentBlockNumber = 10 ) - validators := newTestValidators(t, accountsCount) + validators := validator.NewTestValidators(t, accountsCount) parent := &types.Header{ Number: parentBlockNumber, - ExtraData: createTestExtra(validators.getPublicIdentities(), AccountSet{}, 5, 3, 3), + ExtraData: createTestExtra(validators.GetPublicIdentities(), validator.AccountSet{}, 5, 3, 3), } parent.ComputeHash() stateBlock := createDummyStateBlock(parentBlockNumber+1, parent.Hash, parent.ExtraData) mBlockBuilder := newBlockBuilderMock(stateBlock) fsm := &fsm{parent: parent, blockBuilder: mBlockBuilder, config: &PolyBFTConfig{}, backend: &blockchainMock{}, - validators: validators.toValidatorSet(), exitEventRootHash: types.ZeroHash, logger: hclog.NewNullLogger()} + validators: validators.ToValidatorSet(), exitEventRootHash: types.ZeroHash, logger: hclog.NewNullLogger()} _, err := fsm.BuildProposal(0) require.NoError(t, err) - nonValidatorAcc := newTestValidator(t, "non_validator", 1) - wrongSignature, err := nonValidatorAcc.mustSign([]byte("Foo"), bls.DomainCheckpointManager).Marshal() + nonValidatorAcc := validator.NewTestValidator(t, "non_validator", 1) + wrongSignature, err := nonValidatorAcc.MustSign([]byte("Foo"), bls.DomainCheckpointManager).Marshal() require.NoError(t, err) - err = fsm.ValidateCommit(validators.getValidator("0").Address().Bytes(), wrongSignature, []byte{}) + err = fsm.ValidateCommit(validators.GetValidator("0").Address().Bytes(), wrongSignature, []byte{}) require.ErrorContains(t, err, "incorrect commit signature from") } @@ -665,15 +682,15 @@ func TestFSM_ValidateCommit_Good(t *testing.T) { const parentBlockNumber = 10 - validators := newTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E"}) - validatorsMetadata := validators.getPublicIdentities() + validators := validator.NewTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E"}) + validatorsMetadata := validators.GetPublicIdentities() - parent := &types.Header{Number: parentBlockNumber, ExtraData: createTestExtra(validatorsMetadata, AccountSet{}, 5, 3, 3)} + parent := &types.Header{Number: parentBlockNumber, ExtraData: createTestExtra(validatorsMetadata, validator.AccountSet{}, 5, 3, 3)} parent.ComputeHash() stateBlock := createDummyStateBlock(parentBlockNumber+1, parent.Hash, parent.ExtraData) mBlockBuilder := newBlockBuilderMock(stateBlock) - validatorSet := NewValidatorSet(validatorsMetadata, hclog.NewNullLogger()) + validatorSet := validator.NewValidatorSet(validatorsMetadata, hclog.NewNullLogger()) fsm := &fsm{parent: parent, blockBuilder: mBlockBuilder, config: &PolyBFTConfig{}, backend: &blockchainMock{}, validators: validatorSet, @@ -686,13 +703,240 @@ func TestFSM_ValidateCommit_Good(t *testing.T) { block := types.Block{} require.NoError(t, block.UnmarshalRLP(proposal)) - validator := validators.getValidator("A") - seal, err := validator.mustSign(block.Hash().Bytes(), bls.DomainCheckpointManager).Marshal() + validator := validators.GetValidator("A") + seal, err := validator.MustSign(block.Hash().Bytes(), bls.DomainCheckpointManager).Marshal() require.NoError(t, err) err = fsm.ValidateCommit(validator.Key().Address().Bytes(), seal, block.Hash().Bytes()) require.NoError(t, err) } +func TestFSM_Validate_ExitEventRootNotExpected(t *testing.T) { + t.Parallel() + + const ( + accountsCount = 5 + parentBlockNumber = 25 + signaturesCount = 3 + ) + + validators := validator.NewTestValidators(t, accountsCount) + parentExtra := createTestExtraObject(validators.GetPublicIdentities(), validator.AccountSet{}, 4, signaturesCount, signaturesCount) + parentExtra.Validators = nil + + parent := &types.Header{ + Number: parentBlockNumber, + ExtraData: parentExtra.MarshalRLPTo(nil), + } + parent.ComputeHash() + + polybftBackendMock := new(polybftBackendMock) + polybftBackendMock.On("GetValidators", mock.Anything, mock.Anything).Return(validators.GetPublicIdentities(), nil).Once() + + extra := createTestExtraObject(validators.GetPublicIdentities(), validator.AccountSet{}, 4, signaturesCount, signaturesCount) + extra.Validators = nil + parentCheckpointHash, err := extra.Checkpoint.Hash(0, parentBlockNumber, parent.Hash) + require.NoError(t, err) + + currentValSetHash, err := validators.GetPublicIdentities().Hash() + require.NoError(t, err) + + extra.Parent = createSignature(t, validators.GetPrivateIdentities(), parentCheckpointHash, bls.DomainCheckpointManager) + extra.Checkpoint.EpochNumber = 1 + extra.Checkpoint.CurrentValidatorsHash = currentValSetHash + extra.Checkpoint.NextValidatorsHash = currentValSetHash + + stateBlock := createDummyStateBlock(parent.Number+1, types.Hash{100, 15}, extra.MarshalRLPTo(nil)) + + proposalHash, err := extra.Checkpoint.Hash(0, stateBlock.Block.Number(), stateBlock.Block.Hash()) + require.NoError(t, err) + + stateBlock.Block.Header.Hash = proposalHash + stateBlock.Block.Header.ParentHash = parent.Hash + stateBlock.Block.Header.Timestamp = uint64(time.Now().UTC().Unix()) + stateBlock.Block.Transactions = []*types.Transaction{} + + proposal := stateBlock.Block.MarshalRLP() + + fsm := &fsm{ + parent: parent, + backend: new(blockchainMock), + validators: validators.ToValidatorSet(), + logger: hclog.NewNullLogger(), + polybftBackend: polybftBackendMock, + config: &PolyBFTConfig{BlockTimeDrift: 1}, + exitEventRootHash: types.BytesToHash([]byte{0, 1, 2, 3, 4}), // expect this to be in proposal extra + } + + err = fsm.Validate(proposal) + require.ErrorContains(t, err, "exit root hash not as expected") + + polybftBackendMock.AssertExpectations(t) +} + +func TestFSM_Validate_EpochEndingBlock_MismatchInDeltas(t *testing.T) { + t.Parallel() + + const ( + accountsCount = 5 + parentBlockNumber = 25 + signaturesCount = 3 + ) + + validators := validator.NewTestValidators(t, accountsCount) + parentExtra := createTestExtraObject(validators.GetPublicIdentities(), validator.AccountSet{}, 4, signaturesCount, signaturesCount) + parentExtra.Validators = nil + + parent := &types.Header{ + Number: parentBlockNumber, + ExtraData: parentExtra.MarshalRLPTo(nil), + } + parent.ComputeHash() + + polybftBackendMock := new(polybftBackendMock) + polybftBackendMock.On("GetValidators", mock.Anything, mock.Anything).Return(validators.GetPublicIdentities(), nil).Once() + + extra := createTestExtraObject(validators.GetPublicIdentities(), validator.AccountSet{}, 4, signaturesCount, signaturesCount) + parentCheckpointHash, err := extra.Checkpoint.Hash(0, parentBlockNumber, parent.Hash) + require.NoError(t, err) + + extra.Validators = nil // this will cause test to fail + extra.Parent = createSignature(t, validators.GetPrivateIdentities(), parentCheckpointHash, bls.DomainCheckpointManager) + + stateBlock := createDummyStateBlock(parent.Number+1, types.Hash{100, 15}, extra.MarshalRLPTo(nil)) + + proposalHash, err := new(CheckpointData).Hash(0, stateBlock.Block.Number(), stateBlock.Block.Hash()) + require.NoError(t, err) + + commitEpoch := createTestCommitEpochInput(t, 1, 10) + commitEpochTxInput, err := commitEpoch.EncodeAbi() + require.NoError(t, err) + + distributeRewards := createTestDistributeRewardsInput(t, 1, validators.GetPublicIdentities(), 10) + distributeRewardsTxInput, err := distributeRewards.EncodeAbi() + require.NoError(t, err) + + stateBlock.Block.Header.Hash = proposalHash + stateBlock.Block.Header.ParentHash = parent.Hash + stateBlock.Block.Header.Timestamp = uint64(time.Now().UTC().Unix()) + stateBlock.Block.Transactions = []*types.Transaction{ + createStateTransactionWithData(contracts.ValidatorSetContract, commitEpochTxInput), + createStateTransactionWithData(contracts.RewardPoolContract, distributeRewardsTxInput), + } + + proposal := stateBlock.Block.MarshalRLP() + + blockchainMock := new(blockchainMock) + blockchainMock.On("ProcessBlock", mock.Anything, mock.Anything). + Return(stateBlock, error(nil)). + Maybe() + + // a new validator is added to delta which proposers block does not have + privateKey, err := bls.GenerateBlsKey() + require.NoError(t, err) + + newValidatorDelta := &validator.ValidatorSetDelta{ + Added: validator.AccountSet{&validator.ValidatorMetadata{ + Address: types.BytesToAddress([]byte{0, 1, 2, 3}), + BlsKey: privateKey.PublicKey(), + VotingPower: new(big.Int).SetUint64(1), + IsActive: true, + }}, + } + + fsm := &fsm{ + parent: parent, + backend: blockchainMock, + validators: validators.ToValidatorSet(), + logger: hclog.NewNullLogger(), + isEndOfEpoch: true, + commitEpochInput: commitEpoch, + distributeRewardsInput: distributeRewards, + polybftBackend: polybftBackendMock, + newValidatorsDelta: newValidatorDelta, + config: &PolyBFTConfig{BlockTimeDrift: 1}, + } + + err = fsm.Validate(proposal) + require.ErrorIs(t, err, errValidatorSetDeltaMismatch) + + polybftBackendMock.AssertExpectations(t) + blockchainMock.AssertExpectations(t) +} + +func TestFSM_Validate_EpochEndingBlock_UpdatingValidatorSetInNonEpochEndingBlock(t *testing.T) { + t.Parallel() + + const ( + accountsCount = 5 + parentBlockNumber = 25 + signaturesCount = 3 + ) + + validators := validator.NewTestValidators(t, accountsCount) + parentExtra := createTestExtraObject(validators.GetPublicIdentities(), validator.AccountSet{}, 4, signaturesCount, signaturesCount) + parentExtra.Validators = nil + + parent := &types.Header{ + Number: parentBlockNumber, + ExtraData: parentExtra.MarshalRLPTo(nil), + } + parent.ComputeHash() + + polybftBackendMock := new(polybftBackendMock) + polybftBackendMock.On("GetValidators", mock.Anything, mock.Anything).Return(validators.GetPublicIdentities(), nil).Once() + + // a new validator is added to delta which proposers block does not have + privateKey, err := bls.GenerateBlsKey() + require.NoError(t, err) + + newValidatorDelta := &validator.ValidatorSetDelta{ + Added: validator.AccountSet{&validator.ValidatorMetadata{ + Address: types.BytesToAddress([]byte{0, 1, 2, 3}), + BlsKey: privateKey.PublicKey(), + VotingPower: new(big.Int).SetUint64(1), + IsActive: true, + }}, + } + + extra := createTestExtraObject(validators.GetPublicIdentities(), validator.AccountSet{}, 4, signaturesCount, signaturesCount) + parentCheckpointHash, err := extra.Checkpoint.Hash(0, parentBlockNumber, parent.Hash) + require.NoError(t, err) + + extra.Validators = newValidatorDelta // this will cause test to fail + extra.Parent = createSignature(t, validators.GetPrivateIdentities(), parentCheckpointHash, bls.DomainCheckpointManager) + + stateBlock := createDummyStateBlock(parent.Number+1, types.Hash{100, 15}, extra.MarshalRLPTo(nil)) + + proposalHash, err := new(CheckpointData).Hash(0, stateBlock.Block.Number(), stateBlock.Block.Hash()) + require.NoError(t, err) + + stateBlock.Block.Header.Hash = proposalHash + stateBlock.Block.Header.ParentHash = parent.Hash + stateBlock.Block.Header.Timestamp = uint64(time.Now().UTC().Unix()) + + proposal := stateBlock.Block.MarshalRLP() + + blockchainMock := new(blockchainMock) + blockchainMock.On("ProcessBlock", mock.Anything, mock.Anything). + Return(stateBlock, error(nil)). + Maybe() + + fsm := &fsm{ + parent: parent, + backend: blockchainMock, + validators: validators.ToValidatorSet(), + logger: hclog.NewNullLogger(), + polybftBackend: polybftBackendMock, + config: &PolyBFTConfig{BlockTimeDrift: 1}, + } + + err = fsm.Validate(proposal) + require.ErrorIs(t, err, errValidatorsUpdateInNonEpochEnding) + + polybftBackendMock.AssertExpectations(t) + blockchainMock.AssertExpectations(t) +} + func TestFSM_Validate_IncorrectHeaderParentHash(t *testing.T) { t.Parallel() @@ -702,15 +946,22 @@ func TestFSM_Validate_IncorrectHeaderParentHash(t *testing.T) { signaturesCount = 3 ) - validators := newTestValidators(t, accountsCount) + validators := validator.NewTestValidators(t, accountsCount) parent := &types.Header{ Number: parentBlockNumber, - ExtraData: createTestExtra(validators.getPublicIdentities(), AccountSet{}, 4, signaturesCount, signaturesCount), + ExtraData: createTestExtra(validators.GetPublicIdentities(), validator.AccountSet{}, 4, signaturesCount, signaturesCount), } parent.ComputeHash() - fsm := &fsm{parent: parent, backend: &blockchainMock{}, - validators: validators.toValidatorSet(), logger: hclog.NewNullLogger()} + fsm := &fsm{ + parent: parent, + backend: &blockchainMock{}, + validators: validators.ToValidatorSet(), + logger: hclog.NewNullLogger(), + config: &PolyBFTConfig{ + BlockTimeDrift: 1, + }, + } stateBlock := createDummyStateBlock(parent.Number+1, types.Hash{100, 15}, parent.ExtraData) @@ -733,10 +984,10 @@ func TestFSM_Validate_InvalidNumber(t *testing.T) { signaturesCount = 3 ) - validators := newTestValidators(t, accountsCount) + validators := validator.NewTestValidators(t, accountsCount) parent := &types.Header{ Number: parentBlockNumber, - ExtraData: createTestExtra(validators.getPublicIdentities(), AccountSet{}, 4, signaturesCount, signaturesCount), + ExtraData: createTestExtra(validators.GetPublicIdentities(), validator.AccountSet{}, 4, signaturesCount, signaturesCount), } parent.ComputeHash() @@ -744,8 +995,14 @@ func TestFSM_Validate_InvalidNumber(t *testing.T) { for _, blockNum := range []uint64{parentBlockNumber - 1, parentBlockNumber, parentBlockNumber + 2} { stateBlock := createDummyStateBlock(blockNum, parent.Hash, parent.ExtraData) mBlockBuilder := newBlockBuilderMock(stateBlock) - fsm := &fsm{parent: parent, blockBuilder: mBlockBuilder, backend: &blockchainMock{}, - validators: validators.toValidatorSet(), logger: hclog.NewNullLogger()} + fsm := &fsm{ + parent: parent, + blockBuilder: mBlockBuilder, + backend: &blockchainMock{}, + validators: validators.ToValidatorSet(), + logger: hclog.NewNullLogger(), + config: &PolyBFTConfig{BlockTimeDrift: 1}, + } proposalHash, err := new(CheckpointData).Hash(fsm.backend.GetChainID(), stateBlock.Block.Number(), stateBlock.Block.Hash()) require.NoError(t, err) @@ -763,10 +1020,10 @@ func TestFSM_Validate_TimestampOlder(t *testing.T) { const parentBlockNumber = 10 - validators := newTestValidators(t, 5) + validators := validator.NewTestValidators(t, 5) parent := &types.Header{ Number: parentBlockNumber, - ExtraData: createTestExtra(validators.getPublicIdentities(), AccountSet{}, 4, 3, 3), + ExtraData: createTestExtra(validators.GetPublicIdentities(), validator.AccountSet{}, 4, 3, 3), Timestamp: uint64(time.Now().UTC().Unix()), } parent.ComputeHash() @@ -780,8 +1037,14 @@ func TestFSM_Validate_TimestampOlder(t *testing.T) { ExtraData: parent.ExtraData, } stateBlock := &types.FullBlock{Block: consensus.BuildBlock(consensus.BuildBlockParams{Header: header})} - fsm := &fsm{parent: parent, backend: &blockchainMock{}, - validators: validators.toValidatorSet(), logger: hclog.NewNullLogger()} + fsm := &fsm{ + parent: parent, + backend: &blockchainMock{}, + validators: validators.ToValidatorSet(), + logger: hclog.NewNullLogger(), + config: &PolyBFTConfig{ + BlockTimeDrift: 1, + }} checkpointHash, err := new(CheckpointData).Hash(fsm.backend.GetChainID(), header.Number, header.Hash) require.NoError(t, err) @@ -799,10 +1062,10 @@ func TestFSM_Validate_IncorrectMixHash(t *testing.T) { const parentBlockNumber = 10 - validators := newTestValidators(t, 5) + validators := validator.NewTestValidators(t, 5) parent := &types.Header{ Number: parentBlockNumber, - ExtraData: createTestExtra(validators.getPublicIdentities(), AccountSet{}, 4, 3, 3), + ExtraData: createTestExtra(validators.GetPublicIdentities(), validator.AccountSet{}, 4, 3, 3), Timestamp: uint64(100), } parent.ComputeHash() @@ -820,8 +1083,11 @@ func TestFSM_Validate_IncorrectMixHash(t *testing.T) { fsm := &fsm{ parent: parent, backend: &blockchainMock{}, - validators: validators.toValidatorSet(), + validators: validators.ToValidatorSet(), logger: hclog.NewNullLogger(), + config: &PolyBFTConfig{ + BlockTimeDrift: 1, + }, } rlpBlock := buildBlock.Block.MarshalRLP() @@ -842,13 +1108,13 @@ func TestFSM_Insert_Good(t *testing.T) { ) setupFn := func() (*fsm, []*messages.CommittedSeal, *types.FullBlock, *blockchainMock) { - validators := newTestValidators(t, accountCount) - allAccounts := validators.getPrivateIdentities() - validatorsMetadata := validators.getPublicIdentities() + validators := validator.NewTestValidators(t, accountCount) + allAccounts := validators.GetPrivateIdentities() + validatorsMetadata := validators.GetPublicIdentities() - extraParent := createTestExtra(validatorsMetadata, AccountSet{}, len(allAccounts)-1, signaturesCount, signaturesCount) + extraParent := createTestExtra(validatorsMetadata, validator.AccountSet{}, len(allAccounts)-1, signaturesCount, signaturesCount) parent := &types.Header{Number: parentBlockNumber, ExtraData: extraParent} - extraBlock := createTestExtra(validatorsMetadata, AccountSet{}, len(allAccounts)-1, signaturesCount, signaturesCount) + extraBlock := createTestExtra(validatorsMetadata, validator.AccountSet{}, len(allAccounts)-1, signaturesCount, signaturesCount) block := consensus.BuildBlock( consensus.BuildBlockParams{ Header: &types.Header{Number: parentBlockNumber + 1, ParentHash: parent.Hash, ExtraData: extraBlock}, @@ -859,7 +1125,7 @@ func TestFSM_Insert_Good(t *testing.T) { builderMock := newBlockBuilderMock(builtBlock) chainMock := &blockchainMock{} chainMock.On("CommitBlock", mock.Anything).Return(error(nil)).Once() - chainMock.On("ProcessBlock", mock.Anything, mock.Anything, mock.Anything). + chainMock.On("ProcessBlock", mock.Anything, mock.Anything). Return(builtBlock, error(nil)). Maybe() @@ -868,7 +1134,7 @@ func TestFSM_Insert_Good(t *testing.T) { blockBuilder: builderMock, target: builtBlock, backend: chainMock, - validators: NewValidatorSet(validatorsMetadata[0:len(validatorsMetadata)-1], hclog.NewNullLogger()), + validators: validator.NewValidatorSet(validatorsMetadata[0:len(validatorsMetadata)-1], hclog.NewNullLogger()), logger: hclog.NewNullLogger(), } @@ -934,13 +1200,13 @@ func TestFSM_Insert_InvalidNode(t *testing.T) { signaturesCount = 3 ) - validators := newTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E"}) - validatorsMetadata := validators.getPublicIdentities() + validators := validator.NewTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E"}) + validatorsMetadata := validators.GetPublicIdentities() parent := &types.Header{Number: parentBlockNumber} parent.ComputeHash() - extraBlock := createTestExtra(validatorsMetadata, AccountSet{}, len(validators.validators)-1, signaturesCount, signaturesCount) + extraBlock := createTestExtra(validatorsMetadata, validator.AccountSet{}, len(validators.Validators)-1, signaturesCount, signaturesCount) finalBlock := consensus.BuildBlock( consensus.BuildBlockParams{ Header: &types.Header{Number: parentBlockNumber + 1, ParentHash: parent.Hash, ExtraData: extraBlock}, @@ -949,25 +1215,25 @@ func TestFSM_Insert_InvalidNode(t *testing.T) { buildBlock := &types.FullBlock{Block: finalBlock, Receipts: []*types.Receipt{}} mBlockBuilder := newBlockBuilderMock(buildBlock) - validatorSet := NewValidatorSet(validatorsMetadata[0:len(validatorsMetadata)-1], hclog.NewNullLogger()) + validatorSet := validator.NewValidatorSet(validatorsMetadata[0:len(validatorsMetadata)-1], hclog.NewNullLogger()) fsm := &fsm{parent: parent, blockBuilder: mBlockBuilder, backend: &blockchainMock{}, validators: validatorSet, } proposal := buildBlock.Block.MarshalRLP() - validatorA := validators.getValidator("A") - validatorB := validators.getValidator("B") + validatorA := validators.GetValidator("A") + validatorB := validators.GetValidator("B") proposalHash := buildBlock.Block.Hash().Bytes() - sigA, err := validatorA.mustSign(proposalHash, bls.DomainCheckpointManager).Marshal() + sigA, err := validatorA.MustSign(proposalHash, bls.DomainCheckpointManager).Marshal() require.NoError(t, err) - sigB, err := validatorB.mustSign(proposalHash, bls.DomainCheckpointManager).Marshal() + sigB, err := validatorB.MustSign(proposalHash, bls.DomainCheckpointManager).Marshal() require.NoError(t, err) // create test account outside of validator set - nonValidatorAccount := newTestValidator(t, "non_validator", 1) - nonValidatorSignature, err := nonValidatorAccount.mustSign(proposalHash, bls.DomainCheckpointManager).Marshal() + nonValidatorAccount := validator.NewTestValidator(t, "non_validator", 1) + nonValidatorSignature, err := nonValidatorAccount.MustSign(proposalHash, bls.DomainCheckpointManager).Marshal() require.NoError(t, err) commitedSeals := []*messages.CommittedSeal{ @@ -1004,7 +1270,8 @@ func TestFSM_DecodeCommitmentStateTxs(t *testing.T) { f := &fsm{ proposerCommitmentToRegister: signedCommitment, - commitEpochInput: createTestCommitEpochInput(t, 0, nil, 10), + commitEpochInput: createTestCommitEpochInput(t, 0, 10), + distributeRewardsInput: createTestDistributeRewardsInput(t, 0, nil, 10), logger: hclog.NewNullLogger(), } @@ -1022,7 +1289,7 @@ func TestFSM_DecodeCommitmentStateTxs(t *testing.T) { func TestFSM_DecodeCommitEpochStateTx(t *testing.T) { t.Parallel() - commitEpoch := createTestCommitEpochInput(t, 0, nil, 10) + commitEpoch := createTestCommitEpochInput(t, 0, 10) input, err := commitEpoch.EncodeAbi() require.NoError(t, err) require.NotNil(t, input) @@ -1031,14 +1298,12 @@ func TestFSM_DecodeCommitEpochStateTx(t *testing.T) { decodedInputData, err := decodeStateTransaction(tx.Input) require.NoError(t, err) - decodedCommitEpoch, ok := decodedInputData.(*contractsapi.CommitEpochChildValidatorSetFn) + decodedCommitEpoch, ok := decodedInputData.(*contractsapi.CommitEpochValidatorSetFn) require.True(t, ok) require.True(t, commitEpoch.ID.Cmp(decodedCommitEpoch.ID) == 0) require.NotNil(t, decodedCommitEpoch.Epoch) require.True(t, commitEpoch.Epoch.StartBlock.Cmp(decodedCommitEpoch.Epoch.StartBlock) == 0) require.True(t, commitEpoch.Epoch.EndBlock.Cmp(decodedCommitEpoch.Epoch.EndBlock) == 0) - require.NotNil(t, decodedCommitEpoch.Uptime) - require.True(t, commitEpoch.Uptime.TotalBlocks.Cmp(decodedCommitEpoch.Uptime.TotalBlocks) == 0) } func TestFSM_VerifyStateTransaction_ValidBothTypesOfStateTransactions(t *testing.T) { @@ -1050,7 +1315,7 @@ func TestFSM_VerifyStateTransaction_ValidBothTypesOfStateTransactions(t *testing signedCommitments [2]*CommitmentMessageSigned ) - validators := newTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E"}) + validators := validator.NewTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E"}) commitments[0], signedCommitments[0], stateSyncs[0] = buildCommitmentAndStateSyncs(t, 10, uint64(3), 2) commitments[1], signedCommitments[1], stateSyncs[1] = buildCommitmentAndStateSyncs(t, 10, uint64(3), 12) @@ -1059,13 +1324,13 @@ func TestFSM_VerifyStateTransaction_ValidBothTypesOfStateTransactions(t *testing // add register commitment state transaction hash, err := sc.Hash() require.NoError(t, err) - signature := createSignature(t, validators.getPrivateIdentities(aliases...), hash, bls.DomainStateReceiver) + signature := createSignature(t, validators.GetPrivateIdentities(aliases...), hash, bls.DomainStateReceiver) sc.AggSignature = *signature } f := &fsm{ isEndOfSprint: true, - validators: validators.toValidatorSet(), + validators: validators.ToValidatorSet(), } var txns []*types.Transaction @@ -1104,11 +1369,11 @@ func TestFSM_VerifyStateTransaction_InvalidTypeOfStateTransactions(t *testing.T) func TestFSM_VerifyStateTransaction_QuorumNotReached(t *testing.T) { t.Parallel() - validators := newTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) + validators := validator.NewTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) _, commitmentMessageSigned, _ := buildCommitmentAndStateSyncs(t, 10, uint64(3), 2) f := &fsm{ isEndOfSprint: true, - validators: validators.toValidatorSet(), + validators: validators.ToValidatorSet(), } hash, err := commitmentMessageSigned.Hash() @@ -1116,7 +1381,7 @@ func TestFSM_VerifyStateTransaction_QuorumNotReached(t *testing.T) { var txns []*types.Transaction - signature := createSignature(t, validators.getPrivateIdentities("A", "B"), hash, bls.DomainStateReceiver) + signature := createSignature(t, validators.GetPrivateIdentities("A", "B"), hash, bls.DomainStateReceiver) commitmentMessageSigned.AggSignature = *signature inputData, err := commitmentMessageSigned.EncodeAbi() @@ -1132,11 +1397,11 @@ func TestFSM_VerifyStateTransaction_QuorumNotReached(t *testing.T) { func TestFSM_VerifyStateTransaction_InvalidSignature(t *testing.T) { t.Parallel() - validators := newTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) + validators := validator.NewTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) _, commitmentMessageSigned, _ := buildCommitmentAndStateSyncs(t, 10, uint64(3), 2) f := &fsm{ isEndOfSprint: true, - validators: validators.toValidatorSet(), + validators: validators.ToValidatorSet(), } hash, err := commitmentMessageSigned.Hash() @@ -1144,9 +1409,9 @@ func TestFSM_VerifyStateTransaction_InvalidSignature(t *testing.T) { var txns []*types.Transaction - signature := createSignature(t, validators.getPrivateIdentities("A", "B", "C", "D"), hash, bls.DomainStateReceiver) - invalidValidator := newTestValidator(t, "G", 1) - invalidSignature, err := invalidValidator.mustSign([]byte("malicious message"), bls.DomainStateReceiver).Marshal() + signature := createSignature(t, validators.GetPrivateIdentities("A", "B", "C", "D"), hash, bls.DomainStateReceiver) + invalidValidator := validator.NewTestValidator(t, "G", 1) + invalidSignature, err := invalidValidator.MustSign([]byte("malicious message"), bls.DomainStateReceiver).Marshal() require.NoError(t, err) commitmentMessageSigned.AggSignature = Signature{ @@ -1160,17 +1425,16 @@ func TestFSM_VerifyStateTransaction_InvalidSignature(t *testing.T) { txns = append(txns, createStateTransactionWithData(contracts.StateReceiverContract, inputData)) - err = f.VerifyStateTransactions(txns) - require.ErrorContains(t, err, "invalid signature for tx") + require.ErrorContains(t, f.VerifyStateTransactions(txns), "invalid signature for state tx") } func TestFSM_VerifyStateTransaction_TwoCommitmentMessages(t *testing.T) { t.Parallel() - validators := newTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) + validators := validator.NewTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) _, commitmentMessageSigned, _ := buildCommitmentAndStateSyncs(t, 10, uint64(3), 2) - validatorSet := NewValidatorSet(validators.getPublicIdentities(), hclog.NewNullLogger()) + validatorSet := validator.NewValidatorSet(validators.GetPublicIdentities(), hclog.NewNullLogger()) f := &fsm{ isEndOfSprint: true, @@ -1182,7 +1446,7 @@ func TestFSM_VerifyStateTransaction_TwoCommitmentMessages(t *testing.T) { var txns []*types.Transaction - signature := createSignature(t, validators.getPrivateIdentities("A", "B", "C", "D"), hash, bls.DomainStateReceiver) + signature := createSignature(t, validators.GetPrivateIdentities("A", "B", "C", "D"), hash, bls.DomainStateReceiver) commitmentMessageSigned.AggSignature = *signature inputData, err := commitmentMessageSigned.EncodeAbi() @@ -1208,24 +1472,24 @@ func TestFSM_Validate_FailToVerifySignatures(t *testing.T) { signaturesCount = 3 ) - validators := newTestValidators(t, accountsCount) - validatorsMetadata := validators.getPublicIdentities() + validators := validator.NewTestValidators(t, accountsCount) + validatorsMetadata := validators.GetPublicIdentities() - extra := createTestExtraObject(validatorsMetadata, AccountSet{}, 4, signaturesCount, signaturesCount) + extra := createTestExtraObject(validatorsMetadata, validator.AccountSet{}, 4, signaturesCount, signaturesCount) validatorsHash, err := validatorsMetadata.Hash() require.NoError(t, err) extra.Checkpoint = &CheckpointData{CurrentValidatorsHash: validatorsHash, NextValidatorsHash: validatorsHash} parent := &types.Header{ Number: parentBlockNumber, - ExtraData: append(make([]byte, ExtraVanity), extra.MarshalRLPTo(nil)...), + ExtraData: extra.MarshalRLPTo(nil), } parent.ComputeHash() polybftBackendMock := new(polybftBackendMock) polybftBackendMock.On("GetValidators", mock.Anything, mock.Anything).Return(validatorsMetadata, nil).Once() - validatorSet := NewValidatorSet(validatorsMetadata, hclog.NewNullLogger()) + validatorSet := validator.NewValidatorSet(validatorsMetadata, hclog.NewNullLogger()) fsm := &fsm{ parent: parent, @@ -1233,6 +1497,9 @@ func TestFSM_Validate_FailToVerifySignatures(t *testing.T) { polybftBackend: polybftBackendMock, validators: validatorSet, logger: hclog.NewNullLogger(), + config: &PolyBFTConfig{ + BlockTimeDrift: 1, + }, } finalBlock := consensus.BuildBlock(consensus.BuildBlockParams{ @@ -1264,6 +1531,7 @@ func createDummyStateBlock(blockNumber uint64, parentHash types.Hash, extraData ParentHash: parentHash, Difficulty: 1, ExtraData: extraData, + MixHash: PolyBFTMixDigest, }, }) @@ -1272,17 +1540,14 @@ func createDummyStateBlock(blockNumber uint64, parentHash types.Hash, extraData func createTestExtra( allAccounts, - previousValidatorSet AccountSet, + previousValidatorSet validator.AccountSet, validatorsCount, committedSignaturesCount, parentSignaturesCount int, ) []byte { extraData := createTestExtraObject(allAccounts, previousValidatorSet, validatorsCount, committedSignaturesCount, parentSignaturesCount) - marshaled := extraData.MarshalRLPTo(nil) - result := make([]byte, ExtraVanity+len(marshaled)) - copy(result[ExtraVanity:], marshaled) - return result + return extraData.MarshalRLPTo(nil) } func createTestCommitment(t *testing.T, accounts []*wallet.Account) *CommitmentMessageSigned { @@ -1343,7 +1608,7 @@ func newBlockBuilderMock(stateBlock *types.FullBlock) *blockBuilderMock { } func createTestExtraObject(allAccounts, - previousValidatorSet AccountSet, + previousValidatorSet validator.AccountSet, validatorsCount, committedSignaturesCount, parentSignaturesCount int) *Extra { @@ -1368,13 +1633,13 @@ func createTestExtraObject(allAccounts, return extraData } -func generateValidatorDelta(validatorCount int, allAccounts, previousValidatorSet AccountSet) (vd *ValidatorSetDelta) { +func generateValidatorDelta(validatorCount int, allAccounts, previousValidatorSet validator.AccountSet) (vd *validator.ValidatorSetDelta) { oldMap := make(map[types.Address]int, previousValidatorSet.Len()) for i, x := range previousValidatorSet { oldMap[x.Address] = i } - vd = &ValidatorSetDelta{} + vd = &validator.ValidatorSetDelta{} vd.Removed = bitmap.Bitmap{} for _, id := range rand.Perm(len(allAccounts))[:validatorCount] { diff --git a/consensus/polybft/handlers.go b/consensus/polybft/handlers.go index f566b276b7..686e386a03 100644 --- a/consensus/polybft/handlers.go +++ b/consensus/polybft/handlers.go @@ -1,6 +1,9 @@ package polybft -import "github.com/0xPolygon/polygon-edge/types" +import ( + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" + "github.com/0xPolygon/polygon-edge/types" +) type PostBlockRequest struct { // FullBlock is a reference of the executed block @@ -23,5 +26,5 @@ type PostEpochRequest struct { SystemState SystemState // ValidatorSet is the validator set for the new epoch - ValidatorSet *validatorSet + ValidatorSet validator.ValidatorSet } diff --git a/consensus/polybft/hash_test.go b/consensus/polybft/hash_test.go index 9dbfda7cac..314a9dcc51 100644 --- a/consensus/polybft/hash_test.go +++ b/consensus/polybft/hash_test.go @@ -5,6 +5,7 @@ import ( "github.com/0xPolygon/polygon-edge/consensus/polybft/bitmap" bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" "github.com/0xPolygon/polygon-edge/types" "github.com/stretchr/testify/assert" @@ -12,10 +13,9 @@ import ( func Test_setupHeaderHashFunc(t *testing.T) { extra := &Extra{ - Validators: &ValidatorSetDelta{Removed: bitmap.Bitmap{1}}, + Validators: &validator.ValidatorSetDelta{Removed: bitmap.Bitmap{1}}, Parent: createSignature(t, []*wallet.Account{generateTestAccount(t)}, types.ZeroHash, bls.DomainCheckpointManager), Checkpoint: &CheckpointData{}, - Seal: []byte{}, Committed: &Signature{}, } @@ -25,12 +25,11 @@ func Test_setupHeaderHashFunc(t *testing.T) { Timestamp: 18, } - header.ExtraData = append(make([]byte, ExtraVanity), extra.MarshalRLPTo(nil)...) + header.ExtraData = extra.MarshalRLPTo(nil) notFullExtraHash := types.HeaderHash(header) - extra.Seal = []byte{1, 2, 3, 255} extra.Committed = createSignature(t, []*wallet.Account{generateTestAccount(t)}, types.ZeroHash, bls.DomainCheckpointManager) - header.ExtraData = append(make([]byte, ExtraVanity), extra.MarshalRLPTo(nil)...) + header.ExtraData = extra.MarshalRLPTo(nil) fullExtraHash := types.HeaderHash(header) assert.Equal(t, notFullExtraHash, fullExtraHash) diff --git a/consensus/polybft/helpers_test.go b/consensus/polybft/helpers_test.go index eec39068b8..7d8ed09231 100644 --- a/consensus/polybft/helpers_test.go +++ b/consensus/polybft/helpers_test.go @@ -12,6 +12,7 @@ import ( "github.com/0xPolygon/polygon-edge/consensus/polybft/bitmap" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" "github.com/0xPolygon/polygon-edge/types" "github.com/hashicorp/go-hclog" @@ -58,39 +59,47 @@ func createSignature(t *testing.T, accounts []*wallet.Account, hash types.Hash, } func createTestCommitEpochInput(t *testing.T, epochID uint64, - validatorSet AccountSet, epochSize uint64) *contractsapi.CommitEpochChildValidatorSetFn { + epochSize uint64) *contractsapi.CommitEpochValidatorSetFn { t.Helper() - if validatorSet == nil { - validatorSet = newTestValidators(t, 5).getPublicIdentities() - } - var startBlock uint64 = 0 if epochID > 1 { startBlock = (epochID - 1) * epochSize } - uptime := &contractsapi.Uptime{ - EpochID: new(big.Int).SetUint64(epochID), - UptimeData: []*contractsapi.UptimeData{}, - TotalBlocks: new(big.Int).SetUint64(epochSize), - } - - commitEpoch := &contractsapi.CommitEpochChildValidatorSetFn{ - ID: uptime.EpochID, + commitEpoch := &contractsapi.CommitEpochValidatorSetFn{ + ID: new(big.Int).SetUint64(epochID), Epoch: &contractsapi.Epoch{ StartBlock: new(big.Int).SetUint64(startBlock + 1), EndBlock: new(big.Int).SetUint64(epochSize * epochID), EpochRoot: types.Hash{}, }, - Uptime: uptime, } - for i := range validatorSet { - uptime.AddValidatorUptime(validatorSet[i].Address, int64(epochSize)) + return commitEpoch +} + +func createTestDistributeRewardsInput(t *testing.T, epochID uint64, + validatorSet validator.AccountSet, epochSize uint64) *contractsapi.DistributeRewardForRewardPoolFn { + t.Helper() + + if validatorSet == nil { + validatorSet = validator.NewTestValidators(t, 5).GetPublicIdentities() } - return commitEpoch + uptime := make([]*contractsapi.Uptime, len(validatorSet)) + + for i, v := range validatorSet { + uptime[i] = &contractsapi.Uptime{ + Validator: v.Address, + SignedBlocks: new(big.Int).SetUint64(epochSize), + } + } + + return &contractsapi.DistributeRewardForRewardPoolFn{ + EpochID: new(big.Int).SetUint64(epochID), + Uptime: uptime, + } } func generateStateSyncEvents(t *testing.T, eventsCount int, startIdx uint64) []*contractsapi.StateSyncedEvent { @@ -134,35 +143,54 @@ func getEpochNumber(t *testing.T, blockNumber, epochSize uint64) uint64 { } // newTestState creates new instance of state used by tests. -func newTestState(t *testing.T) *State { - t.Helper() +func newTestState(tb testing.TB) *State { + tb.Helper() dir := fmt.Sprintf("/tmp/consensus-temp_%v", time.Now().UTC().Format(time.RFC3339Nano)) err := os.Mkdir(dir, 0775) if err != nil { - t.Fatal(err) + tb.Fatal(err) } state, err := newState(path.Join(dir, "my.db"), hclog.NewNullLogger(), make(chan struct{})) if err != nil { - t.Fatal(err) + tb.Fatal(err) } - t.Cleanup(func() { + tb.Cleanup(func() { if err := os.RemoveAll(dir); err != nil { - t.Fatal(err) + tb.Fatal(err) } }) return state } -func generateTestAccount(t *testing.T) *wallet.Account { - t.Helper() +func generateTestAccount(tb testing.TB) *wallet.Account { + tb.Helper() acc, err := wallet.GenerateAccount() - require.NoError(t, err) + require.NoError(tb, err) return acc } + +// createTestBridgeConfig creates test bridge configuration with hard-coded addresses +func createTestBridgeConfig() *BridgeConfig { + return &BridgeConfig{ + StateSenderAddr: types.StringToAddress("1"), + CheckpointManagerAddr: types.StringToAddress("2"), + ExitHelperAddr: types.StringToAddress("3"), + RootERC20PredicateAddr: types.StringToAddress("4"), + ChildMintableERC20PredicateAddr: types.StringToAddress("5"), + RootNativeERC20Addr: types.StringToAddress("6"), + RootERC721PredicateAddr: types.StringToAddress("8"), + ChildMintableERC721PredicateAddr: types.StringToAddress("9"), + RootERC1155PredicateAddr: types.StringToAddress("11"), + ChildMintableERC1155PredicateAddr: types.StringToAddress("12"), + CustomSupernetManagerAddr: types.StringToAddress("13"), + StakeManagerAddr: types.StringToAddress("14"), + JSONRPCEndpoint: "http://localhost:8545", + } +} diff --git a/consensus/polybft/mocks_test.go b/consensus/polybft/mocks_test.go index 9eff33161d..750067ba92 100644 --- a/consensus/polybft/mocks_test.go +++ b/consensus/polybft/mocks_test.go @@ -1,17 +1,10 @@ package polybft import ( - "fmt" - "math/big" - "sort" - "strconv" - "testing" "time" "github.com/0xPolygon/polygon-edge/blockchain" - bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" - "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" - "github.com/0xPolygon/polygon-edge/helper/hex" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/helper/progress" "github.com/0xPolygon/polygon-edge/state" "github.com/0xPolygon/polygon-edge/syncer" @@ -47,8 +40,8 @@ func (m *blockchainMock) NewBlockBuilder(parent *types.Header, coinbase types.Ad return args.Get(0).(blockBuilder), args.Error(1) //nolint:forcetypeassert } -func (m *blockchainMock) ProcessBlock(parent *types.Header, block *types.Block, callback func(*state.Transition) error) (*types.FullBlock, error) { - args := m.Called(parent, block, callback) +func (m *blockchainMock) ProcessBlock(parent *types.Header, block *types.Block) (*types.FullBlock, error) { + args := m.Called(parent, block) return args.Get(0).(*types.FullBlock), args.Error(1) //nolint:forcetypeassert } @@ -126,6 +119,12 @@ func (m *blockchainMock) GetChainID() uint64 { return 0 } +func (m *blockchainMock) GetReceiptsByHash(hash types.Hash) ([]*types.Receipt, error) { + args := m.Called(hash) + + return args.Get(0).([]*types.Receipt), args.Error(1) //nolint:forcetypeassert +} + var _ polybftBackend = (*polybftBackendMock)(nil) type polybftBackendMock struct { @@ -133,14 +132,14 @@ type polybftBackendMock struct { } // GetValidators retrieves validator set for the given block -func (p *polybftBackendMock) GetValidators(blockNumber uint64, parents []*types.Header) (AccountSet, error) { +func (p *polybftBackendMock) GetValidators(blockNumber uint64, parents []*types.Header) (validator.AccountSet, error) { args := p.Called(blockNumber, parents) if len(args) == 1 { - accountSet, _ := args.Get(0).(AccountSet) + accountSet, _ := args.Get(0).(validator.AccountSet) return accountSet, nil } else if len(args) == 2 { - accountSet, _ := args.Get(0).(AccountSet) + accountSet, _ := args.Get(0).(validator.AccountSet) return accountSet, args.Error(1) } @@ -204,21 +203,6 @@ type systemStateMock struct { mock.Mock } -func (m *systemStateMock) GetValidatorSet() (AccountSet, error) { - args := m.Called() - if len(args) == 1 { - accountSet, _ := args.Get(0).(AccountSet) - - return accountSet, nil - } else if len(args) == 2 { - accountSet, _ := args.Get(0).(AccountSet) - - return accountSet, args.Error(1) - } - - panic("systemStateMock.GetValidatorSet doesn't support such combination of arguments") //nolint:gocritic -} - func (m *systemStateMock) GetNextCommittedIndex() (uint64, error) { args := m.Called() @@ -278,175 +262,6 @@ func (t *transportMock) Multicast(msg interface{}) { _ = t.Called(msg) } -type testValidators struct { - validators map[string]*testValidator -} - -func newTestValidators(t *testing.T, validatorsCount int) *testValidators { - t.Helper() - - aliases := make([]string, validatorsCount) - for i := 0; i < validatorsCount; i++ { - aliases[i] = strconv.Itoa(i) - } - - return newTestValidatorsWithAliases(t, aliases) -} - -func newTestValidatorsWithAliases(t *testing.T, aliases []string, votingPowers ...[]uint64) *testValidators { - t.Helper() - - validators := map[string]*testValidator{} - - for i, alias := range aliases { - votingPower := uint64(1) - if len(votingPowers) == 1 { - votingPower = votingPowers[0][i] - } - - validators[alias] = newTestValidator(t, alias, votingPower) - } - - return &testValidators{validators: validators} -} - -func (v *testValidators) create(t *testing.T, alias string, votingPower uint64) { - t.Helper() - - if _, ok := v.validators[alias]; !ok { - v.validators[alias] = newTestValidator(t, alias, votingPower) - } -} - -func (v *testValidators) iterAcct(aliases []string, handle func(t *testValidator)) { - if len(aliases) == 0 { - // loop over the whole set - for k := range v.validators { - aliases = append(aliases, k) - } - // sort the names since they get queried randomly - sort.Strings(aliases) - } - - for _, alias := range aliases { - handle(v.getValidator(alias)) - } -} - -func (v *testValidators) getParamValidators(aliases ...string) (res []*Validator) { - v.iterAcct(aliases, func(t *testValidator) { - res = append(res, t.paramsValidator()) - }) - - return -} - -func (v *testValidators) getValidators(aliases ...string) (res []*testValidator) { - v.iterAcct(aliases, func(t *testValidator) { - res = append(res, t) - }) - - return -} - -func (v *testValidators) getPublicIdentities(aliases ...string) (res AccountSet) { - v.iterAcct(aliases, func(t *testValidator) { - res = append(res, t.ValidatorMetadata()) - }) - - return -} - -func (v *testValidators) getPrivateIdentities(aliases ...string) (res []*wallet.Account) { - v.iterAcct(aliases, func(t *testValidator) { - res = append(res, t.account) - }) - - return -} - -func (v *testValidators) getValidator(alias string) *testValidator { - vv, ok := v.validators[alias] - if !ok { - panic(fmt.Sprintf("Validator %s does not exist", alias)) //nolint:gocritic - } - - return vv -} - -func (v *testValidators) toValidatorSet() *validatorSet { - return NewValidatorSet(v.getPublicIdentities(), hclog.NewNullLogger()) -} - -func (v *testValidators) updateVotingPowers(votingPowersMap map[string]uint64) AccountSet { - if len(votingPowersMap) == 0 { - return AccountSet{} - } - - aliases := []string{} - for alias := range votingPowersMap { - aliases = append(aliases, alias) - } - - v.iterAcct(aliases, func(t *testValidator) { - t.votingPower = votingPowersMap[t.alias] - }) - - return v.getPublicIdentities(aliases...) -} - -type testValidator struct { - alias string - account *wallet.Account - votingPower uint64 -} - -func newTestValidator(t *testing.T, alias string, votingPower uint64) *testValidator { - t.Helper() - - return &testValidator{ - alias: alias, - votingPower: votingPower, - account: generateTestAccount(t), - } -} - -func (v *testValidator) Address() types.Address { - return types.Address(v.account.Ecdsa.Address()) -} - -func (v *testValidator) Key() *wallet.Key { - return wallet.NewKey(v.account) -} - -func (v *testValidator) paramsValidator() *Validator { - bls := v.account.Bls.PublicKey().Marshal() - - return &Validator{ - Address: v.Address(), - BlsKey: hex.EncodeToString(bls), - Balance: big.NewInt(1000), - Stake: big.NewInt(1000), - } -} - -func (v *testValidator) ValidatorMetadata() *ValidatorMetadata { - return &ValidatorMetadata{ - Address: types.Address(v.account.Ecdsa.Address()), - BlsKey: v.account.Bls.PublicKey(), - VotingPower: new(big.Int).SetUint64(v.votingPower), - } -} - -func (v *testValidator) mustSign(hash, domain []byte) *bls.Signature { - signature, err := v.account.Bls.Sign(hash, domain) - if err != nil { - panic(fmt.Sprintf("BUG: failed to sign: %v", err)) //nolint:gocritic - } - - return signature -} - type testHeadersMap struct { headersByNumber map[uint64]*types.Header } @@ -488,8 +303,8 @@ type txPoolMock struct { mock.Mock } -func (tp *txPoolMock) Prepare() { - tp.Called() +func (tp *txPoolMock) Prepare(baseFee uint64) { + tp.Called(baseFee) } func (tp *txPoolMock) Length() uint64 { diff --git a/consensus/polybft/polybft.go b/consensus/polybft/polybft.go index 25c1e1d38c..b4fabbf8bd 100644 --- a/consensus/polybft/polybft.go +++ b/consensus/polybft/polybft.go @@ -2,8 +2,11 @@ package polybft import ( + "context" "encoding/json" + "errors" "fmt" + "math/big" "path/filepath" "time" @@ -11,6 +14,7 @@ import ( "github.com/0xPolygon/polygon-edge/consensus" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" "github.com/0xPolygon/polygon-edge/contracts" "github.com/0xPolygon/polygon-edge/helper/common" @@ -28,10 +32,14 @@ const ( bridgeProto = "/bridge/0.2" ) +var ( + errMissingBridgeConfig = errors.New("invalid genesis configuration, missing bridge configuration") +) + // polybftBackend is an interface defining polybft methods needed by fsm and sync tracker type polybftBackend interface { // GetValidators retrieves validator set for the given block - GetValidators(blockNumber uint64, parents []*types.Header) (AccountSet, error) + GetValidators(blockNumber uint64, parents []*types.Header) (validator.AccountSet, error) } // Factory is the factory function to create a discovery consensus @@ -118,40 +126,209 @@ func GenesisPostHookFactory(config *chain.Chain, engineName string) func(txn *st return err } - // initialize ChildValidatorSet SC - input, err := getInitChildValidatorSetInput(polyBFTConfig) - if err != nil { + // calculate initial total supply of native erc20 token + // we skip zero address, since its a special case address + // that is used for minting and burning native token + initialTotalSupply := big.NewInt(0) + + for addr, alloc := range config.Genesis.Alloc { + if addr == types.ZeroAddress { + continue + } + + initialTotalSupply.Add(initialTotalSupply, alloc.Balance) + } + + bridgeCfg := polyBFTConfig.Bridge + if bridgeCfg == nil { + return errMissingBridgeConfig + } + + // initialize ValidatorSet SC + if err = initValidatorSet(polyBFTConfig, transition); err != nil { return err } - if err = initContract(contracts.ValidatorSetContract, input, "ChildValidatorSet", transition); err != nil { + // approve reward pool + if err = approveRewardPoolAsSpender(polyBFTConfig, transition); err != nil { return err } - // initialize ChildERC20Predicate SC - input, err = getInitChildERC20PredicateInput(polyBFTConfig.Bridge) - if err != nil { + // mint reward tokens to reward wallet + if err = mintRewardTokensToWallet(polyBFTConfig, transition); err != nil { return err } - if err = initContract(contracts.ChildERC20PredicateContract, input, "ChildERC20Predicate", transition); err != nil { + // initialize RewardPool SC + if err = initRewardPool(polyBFTConfig, transition); err != nil { return err } - rootNativeERC20Token := types.ZeroAddress - if polyBFTConfig.Bridge != nil { - rootNativeERC20Token = polyBFTConfig.Bridge.RootNativeERC20Addr + // check if there are Bridge Allow List Admins and Bridge Block List Admins + // and if there are, get the first address as the Admin + var bridgeAllowListAdmin types.Address + if config.Params.BridgeAllowList != nil && len(config.Params.BridgeAllowList.AdminAddresses) > 0 { + bridgeAllowListAdmin = config.Params.BridgeAllowList.AdminAddresses[0] + } + + bridgeBlockListAdmin := types.ZeroAddress + if config.Params.BridgeBlockList != nil && len(config.Params.BridgeBlockList.AdminAddresses) > 0 { + bridgeBlockListAdmin = config.Params.BridgeBlockList.AdminAddresses[0] + } + + // initialize Predicate SCs + if bridgeAllowListAdmin != types.ZeroAddress || bridgeBlockListAdmin != types.ZeroAddress { + // The owner of the contract will be the allow list admin or the block list admin, if any of them is set. + owner := contracts.SystemCaller + if bridgeAllowListAdmin != types.ZeroAddress { + owner = bridgeAllowListAdmin + } else if bridgeBlockListAdmin != types.ZeroAddress { + owner = bridgeBlockListAdmin + } + + // initialize ChildERC20PredicateAccessList SC + input, err := getInitERC20PredicateACLInput(polyBFTConfig.Bridge, owner, false) + if err != nil { + return err + } + + if err = callContract(contracts.SystemCaller, contracts.ChildERC20PredicateContract, input, + "ChildERC20PredicateAccessList", transition); err != nil { + return err + } + + // initialize ChildERC721PredicateAccessList SC + input, err = getInitERC721PredicateACLInput(polyBFTConfig.Bridge, owner, false) + if err != nil { + return err + } + + if err = callContract(contracts.SystemCaller, contracts.ChildERC721PredicateContract, input, + "ChildERC721PredicateAccessList", transition); err != nil { + return err + } + + // initialize ChildERC1155PredicateAccessList SC + input, err = getInitERC1155PredicateACLInput(polyBFTConfig.Bridge, owner, false) + if err != nil { + return err + } + + if err = callContract(contracts.SystemCaller, contracts.ChildERC1155PredicateContract, input, + "ChildERC1155PredicateAccessList", transition); err != nil { + return err + } + + // initialize RootMintableERC20PredicateAccessList SC + input, err = getInitERC20PredicateACLInput(polyBFTConfig.Bridge, owner, true) + if err != nil { + return err + } + + if err = callContract(contracts.SystemCaller, contracts.RootMintableERC20PredicateContract, input, + "RootMintableERC20PredicateAccessList", transition); err != nil { + return err + } + + // initialize RootMintableERC721PredicateAccessList SC + input, err = getInitERC721PredicateACLInput(polyBFTConfig.Bridge, owner, true) + if err != nil { + return err + } + + if err = callContract(contracts.SystemCaller, contracts.RootMintableERC721PredicateContract, input, + "RootMintableERC721PredicateAccessList", transition); err != nil { + return err + } + + // initialize RootMintableERC1155PredicateAccessList SC + input, err = getInitERC1155PredicateACLInput(polyBFTConfig.Bridge, owner, true) + if err != nil { + return err + } + + if err = callContract(contracts.SystemCaller, contracts.RootMintableERC1155PredicateContract, input, + "RootMintableERC1155PredicateAccessList", transition); err != nil { + return err + } + } else { + // initialize ChildERC20Predicate SC + input, err := getInitERC20PredicateInput(bridgeCfg, false) + if err != nil { + return err + } + + if err = callContract(contracts.SystemCaller, contracts.ChildERC20PredicateContract, input, + "ChildERC20Predicate", transition); err != nil { + return err + } + + // initialize ChildERC721Predicate SC + input, err = getInitERC721PredicateInput(bridgeCfg, false) + if err != nil { + return err + } + + if err = callContract(contracts.SystemCaller, contracts.ChildERC721PredicateContract, input, + "ChildERC721Predicate", transition); err != nil { + return err + } + + // initialize ChildERC1155Predicate SC + input, err = getInitERC1155PredicateInput(bridgeCfg, false) + if err != nil { + return err + } + + if err = callContract(contracts.SystemCaller, contracts.ChildERC1155PredicateContract, input, + "ChildERC1155Predicate", transition); err != nil { + return err + } + + // initialize RootMintableERC20Predicate SC + input, err = getInitERC20PredicateInput(bridgeCfg, true) + if err != nil { + return err + } + + if err = callContract(contracts.SystemCaller, contracts.RootMintableERC20PredicateContract, input, + "RootMintableERC20Predicate", transition); err != nil { + return err + } + + // initialize RootMintableERC721Predicate SC + input, err = getInitERC721PredicateInput(bridgeCfg, true) + if err != nil { + return err + } + + if err = callContract(contracts.SystemCaller, contracts.RootMintableERC721PredicateContract, input, + "RootMintableERC721Predicate", transition); err != nil { + return err + } + + // initialize RootMintableERC1155Predicate SC + input, err = getInitERC1155PredicateInput(bridgeCfg, true) + if err != nil { + return err + } + + if err = callContract(contracts.SystemCaller, contracts.RootMintableERC1155PredicateContract, input, + "RootMintableERC1155Predicate", transition); err != nil { + return err + } } - if polyBFTConfig.MintableERC20Token { + if polyBFTConfig.NativeTokenConfig.IsMintable { // initialize NativeERC20Mintable SC params := &contractsapi.InitializeNativeERC20MintableFn{ - Predicate_: contracts.ChildERC20PredicateContract, - Owner_: polyBFTConfig.Governance, - RootToken_: rootNativeERC20Token, - Name_: nativeTokenName, - Symbol_: nativeTokenSymbol, - Decimals_: nativeTokenDecimals, + Predicate_: contracts.ChildERC20PredicateContract, + Owner_: polyBFTConfig.NativeTokenConfig.Owner, + RootToken_: types.ZeroAddress, // in case native mintable token is used, it is always root token + Name_: polyBFTConfig.NativeTokenConfig.Name, + Symbol_: polyBFTConfig.NativeTokenConfig.Symbol, + Decimals_: polyBFTConfig.NativeTokenConfig.Decimals, + TokenSupply_: initialTotalSupply, } input, err := params.EncodeAbi() @@ -159,17 +336,19 @@ func GenesisPostHookFactory(config *chain.Chain, engineName string) func(txn *st return err } - if err = initContract(contracts.NativeERC20TokenContract, input, "NativeERC20Mintable", transition); err != nil { + if err = callContract(contracts.SystemCaller, + contracts.NativeERC20TokenContract, input, "NativeERC20Mintable", transition); err != nil { return err } } else { // initialize NativeERC20 SC params := &contractsapi.InitializeNativeERC20Fn{ - Name_: nativeTokenName, - Symbol_: nativeTokenSymbol, - Decimals_: nativeTokenDecimals, - RootToken_: rootNativeERC20Token, - Predicate_: contracts.ChildERC20PredicateContract, + Name_: polyBFTConfig.NativeTokenConfig.Name, + Symbol_: polyBFTConfig.NativeTokenConfig.Symbol, + Decimals_: polyBFTConfig.NativeTokenConfig.Decimals, + RootToken_: polyBFTConfig.Bridge.RootNativeERC20Addr, + Predicate_: contracts.ChildERC20PredicateContract, + TokenSupply_: initialTotalSupply, } input, err := params.EncodeAbi() @@ -177,15 +356,50 @@ func GenesisPostHookFactory(config *chain.Chain, engineName string) func(txn *st return err } - if err = initContract(contracts.NativeERC20TokenContract, input, "NativeERC20", transition); err != nil { + if err = callContract(contracts.SystemCaller, + contracts.NativeERC20TokenContract, input, "NativeERC20", transition); err != nil { return err } + + // initialize EIP1559Burn SC + if config.Params.BurnContract != nil && + len(config.Params.BurnContract) == 1 && + !polyBFTConfig.NativeTokenConfig.IsMintable { + var contractAddress types.Address + for _, address := range config.Params.BurnContract { + contractAddress = address + } + + // contract address exists in allocations + if _, ok := config.Genesis.Alloc[contractAddress]; ok { + burnParams := &contractsapi.InitializeEIP1559BurnFn{ + NewChildERC20Predicate: contracts.ChildERC20PredicateContract, + NewBurnDestination: config.Params.BurnContractDestinationAddress, + } + + input, err = burnParams.EncodeAbi() + if err != nil { + return err + } + + if err = callContract(contracts.SystemCaller, + contractAddress, + input, "EIP1559Burn", transition); err != nil { + return err + } + } + } } return nil } } +func ForkManagerFactory(forks *chain.Forks) error { + // place fork manager handler registration here + return nil +} + // Initialize initializes the consensus (e.g. setup data) func (p *Polybft) Initialize() error { p.logger.Info("initializing polybft...") @@ -250,6 +464,21 @@ func (p *Polybft) Initialize() error { return nil } +func ForkManagerInitialParamsFactory(config *chain.Chain) (*chain.ForkParams, error) { + pbftConfig, err := GetPolyBFTConfig(config) + if err != nil { + return nil, err + } + + return &chain.ForkParams{ + MaxValidatorSetSize: &pbftConfig.MaxValidatorSetSize, + EpochSize: &pbftConfig.EpochSize, + SprintSize: &pbftConfig.SprintSize, + BlockTime: &pbftConfig.BlockTime, + BlockTimeDrift: &pbftConfig.BlockTimeDrift, + }, nil +} + // Start starts the consensus and servers func (p *Polybft) Start() error { p.logger.Info("starting polybft consensus", "signer", p.key.String()) @@ -259,18 +488,21 @@ func (p *Polybft) Start() error { return fmt.Errorf("failed to start syncer. Error: %w", err) } - // start syncing - go func() { + // sync concurrently, retrying indefinitely + go common.RetryForever(context.Background(), time.Second, func(context.Context) error { blockHandler := func(b *types.FullBlock) bool { p.runtime.OnBlockInserted(b) return false } - if err := p.syncer.Sync(blockHandler); err != nil { p.logger.Error("blocks synchronization failed", "error", err) + + return err } - }() + + return nil + }) // start consensus runtime if err := p.startRuntime(); err != nil { @@ -321,6 +553,8 @@ func (p *Polybft) startConsensusProtocol() { return } + p.logger.Debug("peers connected") + newBlockSub := p.blockchain.SubscribeEvents() defer newBlockSub.Close() @@ -446,12 +680,12 @@ func (p *Polybft) VerifyHeader(header *types.Header) error { ) } - return p.verifyHeaderImpl(parent, header, nil) + return p.verifyHeaderImpl(parent, header, p.consensusConfig.BlockTimeDrift, nil) } -func (p *Polybft) verifyHeaderImpl(parent, header *types.Header, parents []*types.Header) error { +func (p *Polybft) verifyHeaderImpl(parent, header *types.Header, blockTimeDrift uint64, parents []*types.Header) error { // validate header fields - if err := validateHeaderFields(parent, header); err != nil { + if err := validateHeaderFields(parent, header, blockTimeDrift); err != nil { return fmt.Errorf("failed to validate header for block %d. error = %w", header.Number, err) } @@ -466,7 +700,7 @@ func (p *Polybft) verifyHeaderImpl(parent, header *types.Header, parents []*type header, parent, parents, p.blockchain.GetChainID(), p, bls.DomainCheckpointManager, p.logger) } -func (p *Polybft) GetValidators(blockNumber uint64, parents []*types.Header) (AccountSet, error) { +func (p *Polybft) GetValidators(blockNumber uint64, parents []*types.Header) (validator.AccountSet, error) { return p.validatorsCache.GetSnapshot(blockNumber, parents) } @@ -482,12 +716,52 @@ func (p *Polybft) GetBlockCreator(h *types.Header) (types.Address, error) { } // PreCommitState a hook to be called before finalizing state transition on inserting block -func (p *Polybft) PreCommitState(_ *types.Header, _ *state.Transition) error { - // Not required +func (p *Polybft) PreCommitState(block *types.Block, _ *state.Transition) error { + commitmentTxExists := false + + validators, err := p.GetValidators(block.Number()-1, nil) + if err != nil { + return err + } + + // validate commitment state transactions + for _, tx := range block.Transactions { + if tx.Type != types.StateTx { + continue + } + + decodedStateTx, err := decodeStateTransaction(tx.Input) + if err != nil { + return fmt.Errorf("unknown state transaction: tx=%v, error: %w", tx.Hash, err) + } + + if signedCommitment, ok := decodedStateTx.(*CommitmentMessageSigned); ok { + if commitmentTxExists { + return fmt.Errorf("only one commitment state tx is allowed per block: %v", tx.Hash) + } + + commitmentTxExists = true + + if err := verifyBridgeCommitmentTx( + tx.Hash, + signedCommitment, + validator.NewValidatorSet(validators, p.logger)); err != nil { + return err + } + } + } + return nil } -// GetBridgeProvider returns an instance of BridgeDataProvider +// GetBridgeProvider is an implementation of Consensus interface +// Returns an instance of BridgeDataProvider func (p *Polybft) GetBridgeProvider() consensus.BridgeDataProvider { return p.runtime } + +// GetBridgeProvider is an implementation of Consensus interface +// Filters extra data to not contain Committed field +func (p *Polybft) FilterExtra(extra []byte) ([]byte, error) { + return GetIbftExtraClean(extra) +} diff --git a/consensus/polybft/polybft_config.go b/consensus/polybft/polybft_config.go index 35fa509c99..feb39a1d56 100644 --- a/consensus/polybft/polybft_config.go +++ b/consensus/polybft/polybft_config.go @@ -1,25 +1,21 @@ package polybft import ( - "encoding/hex" "encoding/json" - "fmt" "math/big" - "os" - "path/filepath" - "time" "github.com/0xPolygon/polygon-edge/chain" - "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" - bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/helper/common" "github.com/0xPolygon/polygon-edge/types" ) +const ConsensusName = "polybft" + // PolyBFTConfig is the configuration file for the Polybft consensus protocol. type PolyBFTConfig struct { // InitialValidatorSet are the genesis validators - InitialValidatorSet []*Validator `json:"initialValidatorSet"` + InitialValidatorSet []*validator.GenesisValidator `json:"initialValidatorSet"` // Bridge is the rootchain bridge configuration Bridge *BridgeConfig `json:"bridge"` @@ -34,40 +30,84 @@ type PolyBFTConfig struct { SprintSize uint64 `json:"sprintSize"` // BlockTime is target frequency of blocks production - BlockTime time.Duration `json:"blockTime"` + BlockTime common.Duration `json:"blockTime"` // Governance is the initial governance address Governance types.Address `json:"governance"` - // MintableERC20Token denotes whether mintable ERC20 token is used - MintableERC20Token bool `json:"mintableERC20"` + // NativeTokenConfig defines name, symbol and decimal count of the native token + NativeTokenConfig *TokenConfig `json:"nativeTokenConfig"` InitialTrieRoot types.Hash `json:"initialTrieRoot"` + + // SupernetID indicates ID of given supernet generated by stake manager contract + SupernetID int64 `json:"supernetID"` + + // MinValidatorSetSize indicates the minimum size of validator set + MinValidatorSetSize uint64 `json:"minValidatorSetSize"` + + // MaxValidatorSetSize indicates the maximum size of validator set + MaxValidatorSetSize uint64 `json:"maxValidatorSetSize"` + + // RewardConfig defines rewards configuration + RewardConfig *RewardsConfig `json:"rewardConfig"` + + // BlockTimeDrift defines the time slot in which a new block can be created + BlockTimeDrift uint64 `json:"blockTimeDrift"` +} + +// LoadPolyBFTConfig loads chain config from provided path and unmarshals PolyBFTConfig +func LoadPolyBFTConfig(chainConfigFile string) (PolyBFTConfig, error) { + chainCfg, err := chain.ImportFromFile(chainConfigFile) + if err != nil { + return PolyBFTConfig{}, err + } + + polybftConfig, err := GetPolyBFTConfig(chainCfg) + if err != nil { + return PolyBFTConfig{}, err + } + + return polybftConfig, err } // GetPolyBFTConfig deserializes provided chain config and returns PolyBFTConfig func GetPolyBFTConfig(chainConfig *chain.Chain) (PolyBFTConfig, error) { - consensusConfigJSON, err := json.Marshal(chainConfig.Params.Engine["polybft"]) + consensusConfigJSON, err := json.Marshal(chainConfig.Params.Engine[ConsensusName]) if err != nil { return PolyBFTConfig{}, err } var polyBFTConfig PolyBFTConfig - err = json.Unmarshal(consensusConfigJSON, &polyBFTConfig) - - if err != nil { + if err = json.Unmarshal(consensusConfigJSON, &polyBFTConfig); err != nil { return PolyBFTConfig{}, err } return polyBFTConfig, nil } -// BridgeConfig is the rootchain bridge configuration +// BridgeConfig is the rootchain configuration, needed for bridging type BridgeConfig struct { - BridgeAddr types.Address `json:"stateSenderAddr"` - CheckpointAddr types.Address `json:"checkpointAddr"` - RootERC20PredicateAddr types.Address `json:"rootERC20PredicateAddr"` - RootNativeERC20Addr types.Address `json:"rootNativeERC20Addr"` + StateSenderAddr types.Address `json:"stateSenderAddress"` + CheckpointManagerAddr types.Address `json:"checkpointManagerAddress"` + ExitHelperAddr types.Address `json:"exitHelperAddress"` + RootERC20PredicateAddr types.Address `json:"erc20PredicateAddress"` + ChildMintableERC20PredicateAddr types.Address `json:"erc20ChildMintablePredicateAddress"` + RootNativeERC20Addr types.Address `json:"nativeERC20Address"` + RootERC721PredicateAddr types.Address `json:"erc721PredicateAddress"` + ChildMintableERC721PredicateAddr types.Address `json:"erc721ChildMintablePredicateAddress"` + RootERC1155PredicateAddr types.Address `json:"erc1155PredicateAddress"` + ChildMintableERC1155PredicateAddr types.Address `json:"erc1155ChildMintablePredicateAddress"` + ChildERC20Addr types.Address `json:"childERC20Address"` + ChildERC721Addr types.Address `json:"childERC721Address"` + ChildERC1155Addr types.Address `json:"childERC1155Address"` + CustomSupernetManagerAddr types.Address `json:"customSupernetManagerAddr"` + StakeManagerAddr types.Address `json:"stakeManagerAddr"` + // only populated if stake-manager-deploy command is executed, and used for e2e tests + StakeTokenAddr types.Address `json:"stakeTokenAddr,omitempty"` + BLSAddress types.Address `json:"blsAddr"` + BN256G2Address types.Address `json:"bn256G2Addr"` + JSONRPCEndpoint string `json:"jsonRPCEndpoint"` EventTrackerStartBlocks map[types.Address]uint64 `json:"eventTrackerStartBlocks"` } @@ -76,186 +116,115 @@ func (p *PolyBFTConfig) IsBridgeEnabled() bool { return p.Bridge != nil } -// Validator represents public information about validator accounts which are the part of genesis -type Validator struct { - Address types.Address - BlsPrivateKey *bls.PrivateKey - BlsKey string - BlsSignature string - Balance *big.Int - Stake *big.Int - MultiAddr string -} - -type validatorRaw struct { - Address types.Address `json:"address"` - BlsKey string `json:"blsKey"` - BlsSignature string `json:"blsSignature"` - Balance *string `json:"balance"` - Stake *string `json:"stake"` - MultiAddr string `json:"multiAddr"` -} - -func (v *Validator) MarshalJSON() ([]byte, error) { - raw := &validatorRaw{Address: v.Address, BlsKey: v.BlsKey, MultiAddr: v.MultiAddr, BlsSignature: v.BlsSignature} - raw.Balance = types.EncodeBigInt(v.Balance) - raw.Stake = types.EncodeBigInt(v.Stake) - - return json.Marshal(raw) +// RootchainConfig contains rootchain metadata (such as JSON RPC endpoint and contract addresses) +type RootchainConfig struct { + JSONRPCAddr string + + StateSenderAddress types.Address + CheckpointManagerAddress types.Address + BLSAddress types.Address + BN256G2Address types.Address + ExitHelperAddress types.Address + RootERC20PredicateAddress types.Address + ChildMintableERC20PredicateAddress types.Address + RootNativeERC20Address types.Address + ChildERC20Address types.Address + RootERC721PredicateAddress types.Address + ChildMintableERC721PredicateAddress types.Address + ChildERC721Address types.Address + RootERC1155PredicateAddress types.Address + ChildMintableERC1155PredicateAddress types.Address + ChildERC1155Address types.Address + CustomSupernetManagerAddress types.Address + StakeManagerAddress types.Address + StakeTokenAddress types.Address } -func (v *Validator) UnmarshalJSON(data []byte) error { - var ( - raw validatorRaw - err error - ) - - if err = json.Unmarshal(data, &raw); err != nil { - return err - } - - v.Address = raw.Address - v.BlsKey = raw.BlsKey - v.BlsSignature = raw.BlsSignature - v.MultiAddr = raw.MultiAddr - - v.Balance, err = types.ParseUint256orHex(raw.Balance) - if err != nil { - return err - } - - v.Stake, err = types.ParseUint256orHex(raw.Stake) - if err != nil { - return err - } - - return nil -} +// ToBridgeConfig creates BridgeConfig instance +func (r *RootchainConfig) ToBridgeConfig() *BridgeConfig { + return &BridgeConfig{ + JSONRPCEndpoint: r.JSONRPCAddr, -// UnmarshalBLSPublicKey unmarshals the hex encoded BLS public key -func (v *Validator) UnmarshalBLSPublicKey() (*bls.PublicKey, error) { - decoded, err := hex.DecodeString(v.BlsKey) - if err != nil { - return nil, err + StateSenderAddr: r.StateSenderAddress, + CheckpointManagerAddr: r.CheckpointManagerAddress, + ExitHelperAddr: r.ExitHelperAddress, + RootERC20PredicateAddr: r.RootERC20PredicateAddress, + ChildMintableERC20PredicateAddr: r.ChildMintableERC20PredicateAddress, + RootNativeERC20Addr: r.RootNativeERC20Address, + RootERC721PredicateAddr: r.RootERC721PredicateAddress, + ChildMintableERC721PredicateAddr: r.ChildMintableERC721PredicateAddress, + RootERC1155PredicateAddr: r.RootERC1155PredicateAddress, + ChildMintableERC1155PredicateAddr: r.ChildMintableERC1155PredicateAddress, + ChildERC20Addr: r.ChildERC20Address, + ChildERC721Addr: r.ChildERC721Address, + ChildERC1155Addr: r.ChildERC1155Address, + CustomSupernetManagerAddr: r.CustomSupernetManagerAddress, + StakeManagerAddr: r.StakeManagerAddress, + BLSAddress: r.BLSAddress, + BN256G2Address: r.BN256G2Address, } - - return bls.UnmarshalPublicKey(decoded) } -// UnmarshalBLSSignature unmarshals the hex encoded BLS signature -func (v *Validator) UnmarshalBLSSignature() (*bls.Signature, error) { - decoded, err := hex.DecodeString(v.BlsSignature) - if err != nil { - return nil, err - } - - return bls.UnmarshalSignature(decoded) +// TokenConfig is the configuration of native token used by edge network +type TokenConfig struct { + Name string `json:"name"` + Symbol string `json:"symbol"` + Decimals uint8 `json:"decimals"` + IsMintable bool `json:"isMintable"` + Owner types.Address `json:"owner"` } -// ToValidatorInitAPIBinding converts Validator to instance of contractsapi.ValidatorInit -func (v Validator) ToValidatorInitAPIBinding() (*contractsapi.ValidatorInit, error) { - blsSignature, err := v.UnmarshalBLSSignature() - if err != nil { - return nil, err - } - - signBigInts, err := blsSignature.ToBigInt() - if err != nil { - return nil, err - } +type RewardsConfig struct { + // TokenAddress is the address of reward token on child chain + TokenAddress types.Address - pubKey, err := v.UnmarshalBLSPublicKey() - if err != nil { - return nil, err - } + // WalletAddress is the address of reward wallet on child chain + WalletAddress types.Address - return &contractsapi.ValidatorInit{ - Addr: v.Address, - Pubkey: pubKey.ToBigInt(), - Signature: signBigInts, - Stake: new(big.Int).Set(v.Stake), - }, nil + // WalletAmount is the amount of tokens in reward wallet + WalletAmount *big.Int } -// ToValidatorMetadata creates ValidatorMetadata instance -func (v *Validator) ToValidatorMetadata() (*ValidatorMetadata, error) { - blsKey, err := v.UnmarshalBLSPublicKey() - if err != nil { - return nil, err +func (r *RewardsConfig) MarshalJSON() ([]byte, error) { + raw := &rewardsConfigRaw{ + TokenAddress: r.TokenAddress, + WalletAddress: r.WalletAddress, + WalletAmount: types.EncodeBigInt(r.WalletAmount), } - metadata := &ValidatorMetadata{ - Address: v.Address, - BlsKey: blsKey, - VotingPower: new(big.Int).Set(v.Stake), - IsActive: true, - } - - return metadata, nil -} - -// String implements fmt.Stringer interface -func (v *Validator) String() string { - return fmt.Sprintf("Address=%s; Balance=%d; P2P Multi addr=%s; BLS Key=%s;", - v.Address, v.Balance, v.MultiAddr, v.BlsKey) + return json.Marshal(raw) } -// RootchainConfig contains information about rootchain contract addresses -// as well as rootchain admin account address -type RootchainConfig struct { - StateSenderAddress types.Address `json:"stateSenderAddress"` - CheckpointManagerAddress types.Address `json:"checkpointManagerAddress"` - BLSAddress types.Address `json:"blsAddress"` - BN256G2Address types.Address `json:"bn256G2Address"` - ExitHelperAddress types.Address `json:"exitHelperAddress"` - RootERC20PredicateAddress types.Address `json:"rootERC20PredicateAddress"` - RootNativeERC20Address types.Address `json:"rootNativeERC20Address"` - ERC20TemplateAddress types.Address `json:"erc20TemplateAddress"` -} +func (r *RewardsConfig) UnmarshalJSON(data []byte) error { + var ( + raw rewardsConfigRaw + err error + ) -// ToBridgeConfig creates BridgeConfig instance -func (r *RootchainConfig) ToBridgeConfig() *BridgeConfig { - return &BridgeConfig{ - BridgeAddr: r.StateSenderAddress, - CheckpointAddr: r.CheckpointManagerAddress, - RootERC20PredicateAddr: r.RootERC20PredicateAddress, - RootNativeERC20Addr: r.RootNativeERC20Address, + if err = json.Unmarshal(data, &raw); err != nil { + return err } -} -// Manifest holds metadata, such as genesis validators and rootchain configuration -type Manifest struct { - GenesisValidators []*Validator `json:"validators"` - RootchainConfig *RootchainConfig `json:"rootchain"` - ChainID int64 `json:"chainID"` -} + r.TokenAddress = raw.TokenAddress + r.WalletAddress = raw.WalletAddress -// LoadManifest deserializes Manifest instance -func LoadManifest(metadataFile string) (*Manifest, error) { - data, err := os.ReadFile(metadataFile) + r.WalletAmount, err = types.ParseUint256orHex(raw.WalletAmount) if err != nil { - return nil, err - } - - var manifest Manifest - - if err := json.Unmarshal(data, &manifest); err != nil { - return nil, err + return err } - return &manifest, nil + return nil } -// Save marshals RootchainManifest instance to json and persists it to given location -func (m *Manifest) Save(manifestPath string) error { - data, err := json.MarshalIndent(m, "", " ") - if err != nil { - return fmt.Errorf("failed to marshal rootchain manifest to JSON: %w", err) - } - - if err := common.SaveFileSafe(filepath.Clean(manifestPath), data, 0660); err != nil { - return fmt.Errorf("failed to save rootchain manifest file: %w", err) - } +type rewardsConfigRaw struct { + TokenAddress types.Address `json:"rewardTokenAddress"` + WalletAddress types.Address `json:"rewardWalletAddress"` + WalletAmount *string `json:"rewardWalletAmount"` +} - return nil +// BurnContractInfo contains metadata for burn contract, which is part of EIP-1559 specification +type BurnContractInfo struct { + BlockNumber uint64 + Address types.Address + DestinationAddress types.Address } diff --git a/consensus/polybft/polybft_test.go b/consensus/polybft/polybft_test.go index f57cbdffc1..5ee111d3cb 100644 --- a/consensus/polybft/polybft_test.go +++ b/consensus/polybft/polybft_test.go @@ -5,9 +5,10 @@ import ( "testing" "time" + "github.com/0xPolygon/polygon-edge/chain" "github.com/0xPolygon/polygon-edge/consensus" - "github.com/0xPolygon/polygon-edge/consensus/ibft/signer" bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" "github.com/0xPolygon/polygon-edge/helper/progress" "github.com/0xPolygon/polygon-edge/txpool" @@ -16,6 +17,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/umbracle/ethgo" ) // the test initializes polybft and chain mock (map of headers) after which a new header is verified @@ -32,7 +34,7 @@ func TestPolybft_VerifyHeader(t *testing.T) { ) updateHeaderExtra := func(header *types.Header, - validators *ValidatorSetDelta, + validators *validator.ValidatorSetDelta, parentSignature *Signature, checkpointData *CheckpointData, committedAccounts []*wallet.Account) *Signature { @@ -41,14 +43,13 @@ func TestPolybft_VerifyHeader(t *testing.T) { Parent: parentSignature, Checkpoint: checkpointData, Committed: &Signature{}, - Seal: []byte{}, } if extra.Checkpoint == nil { extra.Checkpoint = &CheckpointData{} } - header.ExtraData = append(make([]byte, ExtraVanity), extra.MarshalRLPTo(nil)...) + header.ExtraData = extra.MarshalRLPTo(nil) header.ComputeHash() if len(committedAccounts) > 0 { @@ -56,24 +57,25 @@ func TestPolybft_VerifyHeader(t *testing.T) { require.NoError(t, err) extra.Committed = createSignature(t, committedAccounts, checkpointHash, bls.DomainCheckpointManager) - header.ExtraData = append(make([]byte, signer.IstanbulExtraVanity), extra.MarshalRLPTo(nil)...) + header.ExtraData = extra.MarshalRLPTo(nil) } return extra.Committed } // create all validators - validators := newTestValidators(t, allValidatorsSize) + validators := validator.NewTestValidators(t, allValidatorsSize) // create configuration polyBftConfig := PolyBFTConfig{ - InitialValidatorSet: validators.getParamValidators(), + InitialValidatorSet: validators.GetParamValidators(), EpochSize: fixedEpochSize, SprintSize: 5, + BlockTimeDrift: 10, } - validatorSet := validators.getPublicIdentities() - accounts := validators.getPrivateIdentities() + validatorSet := validators.GetPublicIdentities() + accounts := validators.GetPrivateIdentities() // calculate validators before and after the end of the first epoch validatorSetParent, validatorSetCurrent := validatorSet[:len(validatorSet)-1], validatorSet[1:] @@ -83,7 +85,7 @@ func TestPolybft_VerifyHeader(t *testing.T) { headersMap := &testHeadersMap{} // create genesis header - genesisDelta, err := createValidatorSetDelta(nil, validatorSetParent) + genesisDelta, err := validator.CreateValidatorSetDelta(nil, validatorSetParent) require.NoError(t, err) genesisHeader := &types.Header{Number: 0} @@ -94,7 +96,7 @@ func TestPolybft_VerifyHeader(t *testing.T) { // create headers from 1 to 9 for i := uint64(1); i < polyBftConfig.EpochSize; i++ { - delta, err := createValidatorSetDelta(validatorSetParent, validatorSetParent) + delta, err := validator.CreateValidatorSetDelta(validatorSetParent, validatorSetParent) require.NoError(t, err) header := &types.Header{Number: i} @@ -123,12 +125,12 @@ func TestPolybft_VerifyHeader(t *testing.T) { } // create parent header (block 10) - parentDelta, err := createValidatorSetDelta(validatorSetParent, validatorSetCurrent) + parentDelta, err := validator.CreateValidatorSetDelta(validatorSetParent, validatorSetCurrent) require.NoError(t, err) parentHeader := &types.Header{ Number: polyBftConfig.EpochSize, - Timestamp: uint64(time.Now().UTC().UnixMilli()), + Timestamp: uint64(time.Now().UTC().Unix()), } parentCommitment := updateHeaderExtra(parentHeader, parentDelta, nil, &CheckpointData{EpochNumber: 1}, accountSetParent) @@ -136,7 +138,7 @@ func TestPolybft_VerifyHeader(t *testing.T) { headersMap.addHeader(parentHeader) // create current header (block 11) with all appropriate fields required for validation - currentDelta, err := createValidatorSetDelta(validatorSetCurrent, validatorSetCurrent) + currentDelta, err := validator.CreateValidatorSetDelta(validatorSetCurrent, validatorSetCurrent) require.NoError(t, err) currentHeader := &types.Header{ @@ -271,3 +273,75 @@ func Test_Factory(t *testing.T) { assert.Equal(t, epochSize, polybft.consensusConfig.EpochSize) assert.Equal(t, params, polybft.config) } + +func Test_GenesisPostHookFactory(t *testing.T) { + t.Parallel() + + const ( + epochSize = 15 + maxValidators = 150 + ) + + validators := validator.NewTestValidators(t, 6) + bridgeCfg := createTestBridgeConfig() + cases := []struct { + name string + config *PolyBFTConfig + bridgeAllowList *chain.AddressListConfig + expectedErr error + }{ + { + name: "non-mintable native token; access lists disabled", + config: &PolyBFTConfig{ + InitialValidatorSet: validators.GetParamValidators(), + Bridge: bridgeCfg, + EpochSize: epochSize, + RewardConfig: &RewardsConfig{WalletAmount: ethgo.Ether(1000)}, + NativeTokenConfig: &TokenConfig{Name: "Test", Symbol: "TEST", Decimals: 18}, + MaxValidatorSetSize: maxValidators, + }, + }, + { + name: "mintable native token; access lists enabled", + config: &PolyBFTConfig{ + InitialValidatorSet: validators.GetParamValidators(), + Bridge: bridgeCfg, + EpochSize: epochSize, + RewardConfig: &RewardsConfig{WalletAmount: ethgo.Ether(1000)}, + NativeTokenConfig: &TokenConfig{Name: "Test Mintable", Symbol: "TEST_MNT", Decimals: 18, IsMintable: true}, + MaxValidatorSetSize: maxValidators, + }, + bridgeAllowList: &chain.AddressListConfig{ + AdminAddresses: []types.Address{validators.Validators["0"].Address()}, + EnabledAddresses: []types.Address{validators.Validators["1"].Address()}, + }, + }, + { + name: "missing bridge configuration", + config: &PolyBFTConfig{}, + expectedErr: errMissingBridgeConfig, + }, + } + + for _, tc := range cases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + params := &chain.Params{ + Engine: map[string]interface{}{ConsensusName: tc.config}, + BridgeAllowList: tc.bridgeAllowList, + } + chainConfig := &chain.Chain{Params: params, Genesis: &chain.Genesis{Alloc: make(map[types.Address]*chain.GenesisAccount)}} + initHandler := GenesisPostHookFactory(chainConfig, ConsensusName) + require.NotNil(t, initHandler) + + transition := newTestTransition(t, nil) + if tc.expectedErr == nil { + require.NoError(t, initHandler(transition)) + } else { + require.ErrorIs(t, initHandler(transition), tc.expectedErr) + } + }) + } +} diff --git a/consensus/polybft/proposer_calculator.go b/consensus/polybft/proposer_calculator.go index acbc301991..9c280bb9ae 100644 --- a/consensus/polybft/proposer_calculator.go +++ b/consensus/polybft/proposer_calculator.go @@ -5,6 +5,7 @@ import ( "fmt" "math/big" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/helper/common" "github.com/0xPolygon/polygon-edge/types" "github.com/hashicorp/go-hclog" @@ -19,7 +20,7 @@ var ( // PrioritizedValidator holds ValidatorMetadata together with priority type PrioritizedValidator struct { - Metadata *ValidatorMetadata + Metadata *validator.ValidatorMetadata ProposerPriority *big.Int } @@ -52,7 +53,7 @@ func NewProposerSnapshotFromState(config *runtimeConfig) (*ProposerSnapshot, err } // NewProposerSnapshot creates ProposerSnapshot with height and validators with all priorities set to zero -func NewProposerSnapshot(height uint64, validators []*ValidatorMetadata) *ProposerSnapshot { +func NewProposerSnapshot(height uint64, validators []*validator.ValidatorMetadata) *ProposerSnapshot { validatorsSnap := make([]*PrioritizedValidator, len(validators)) for i, x := range validators { @@ -235,7 +236,7 @@ func (pc *ProposerCalculator) updatePerBlock(blockNumber uint64) error { return fmt.Errorf("cannot get block header and extra while updating proposers snapshot %d: %w", blockNumber, err) } - var newValidatorSet AccountSet = nil + var newValidatorSet validator.AccountSet = nil if extra.Validators != nil && !extra.Validators.IsEmpty() { newValidatorSet, err = pc.config.polybftBackend.GetValidators(blockNumber, nil) @@ -294,7 +295,7 @@ func incrementProposerPriorityNTimes(snapshot *ProposerSnapshot, times uint64) ( return proposer, nil } -func updateValidators(snapshot *ProposerSnapshot, newValidatorSet AccountSet) error { +func updateValidators(snapshot *ProposerSnapshot, newValidatorSet validator.AccountSet) error { if newValidatorSet.Len() == 0 { return nil } diff --git a/consensus/polybft/proposer_calculator_test.go b/consensus/polybft/proposer_calculator_test.go index 7e51a606c9..a746468e21 100644 --- a/consensus/polybft/proposer_calculator_test.go +++ b/consensus/polybft/proposer_calculator_test.go @@ -6,6 +6,7 @@ import ( "testing" bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/types" "github.com/hashicorp/go-hclog" "github.com/stretchr/testify/assert" @@ -15,10 +16,10 @@ import ( func TestProposerCalculator_SetIndex(t *testing.T) { t.Parallel() - validators := newTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E"}, []uint64{10, 100, 1, 50, 30}) - metadata := validators.getPublicIdentities() + validators := validator.NewTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E"}, []uint64{10, 100, 1, 50, 30}) + metadata := validators.GetPublicIdentities() - vs := validators.toValidatorSet() + vs := validators.ToValidatorSet() snapshot := NewProposerSnapshot(1, metadata) @@ -39,8 +40,8 @@ func TestProposerCalculator_SetIndex(t *testing.T) { func TestProposerCalculator_RegularFlow(t *testing.T) { t.Parallel() - validators := newTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E"}, []uint64{1, 2, 3, 4, 5}) - metadata := validators.getPublicIdentities() + validators := validator.NewTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E"}, []uint64{1, 2, 3, 4, 5}) + metadata := validators.GetPublicIdentities() snapshot := NewProposerSnapshot(0, metadata) @@ -80,7 +81,7 @@ func TestProposerCalculator_SamePriority(t *testing.T) { require.NoError(t, err) // at some point priorities will be the same and bytes address will be compared - vs := NewValidatorSet([]*ValidatorMetadata{ + vs := validator.NewValidatorSet([]*validator.ValidatorMetadata{ { BlsKey: keys[0].PublicKey(), Address: types.Address{0x1}, @@ -126,7 +127,7 @@ func TestProposerCalculator_InversePriorityOrderWithExpectedListOfSelection(t *t require.NoError(t, err) // priorities are from high to low vp in validator set - vset := NewValidatorSet([]*ValidatorMetadata{ + vset := validator.NewValidatorSet([]*validator.ValidatorMetadata{ { BlsKey: keys[0].PublicKey(), Address: types.Address{0x1}, @@ -175,7 +176,7 @@ func TestProposerCalculator_IncrementProposerPrioritySameVotingPower(t *testing. keys, err := bls.CreateRandomBlsKeys(3) require.NoError(t, err) - vs := NewValidatorSet([]*ValidatorMetadata{ + vs := validator.NewValidatorSet([]*validator.ValidatorMetadata{ { BlsKey: keys[0].PublicKey(), Address: types.Address{0x1}, @@ -231,7 +232,7 @@ func TestProposerCalculator_AveragingInIncrementProposerPriorityWithVotingPower( vp2 := int64(1) total := vp0 + vp1 + vp2 avg := (vp0 + vp1 + vp2 - total) / 3 - valz := []*ValidatorMetadata{ + valz := []*validator.ValidatorMetadata{ { BlsKey: keys[0].PublicKey(), Address: types.Address{0x1}, @@ -375,11 +376,11 @@ func TestProposerCalculator_UpdatesForNewValidatorSet(t *testing.T) { keys, err := bls.CreateRandomBlsKeys(2) require.NoError(t, err) - v1 := &ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[0].PublicKey(), VotingPower: big.NewInt(100)} - v2 := &ValidatorMetadata{Address: types.Address{0x2}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(100)} + v1 := &validator.ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[0].PublicKey(), VotingPower: big.NewInt(100)} + v2 := &validator.ValidatorMetadata{Address: types.Address{0x2}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(100)} - accountSet := []*ValidatorMetadata{v1, v2} - vs := NewValidatorSet(accountSet, hclog.NewNullLogger()) + accountSet := []*validator.ValidatorMetadata{v1, v2} + vs := validator.NewValidatorSet(accountSet, hclog.NewNullLogger()) snapshot := NewProposerSnapshot(0, vs.Accounts()) @@ -402,7 +403,8 @@ func TestProposerCalculator_UpdatesForNewValidatorSet(t *testing.T) { // verify that priorities are scaled diff := computeMaxMinPriorityDiff(snapshot.Validators) - diffMax := new(big.Int).Mul(priorityWindowSizeFactor, vs.totalVotingPower) + totalVotingPower := vs.TotalVotingPower() + diffMax := new(big.Int).Mul(priorityWindowSizeFactor, &totalVotingPower) assert.True(t, diff.Cmp(diffMax) <= 0, "expected priority distance < %d. Got %d", diffMax, diff) } @@ -414,7 +416,7 @@ func TestProposerCalculator_GetLatestProposer(t *testing.T) { count = 10 ) - validatorSet := newTestValidators(t, count).getPublicIdentities() + validatorSet := validator.NewTestValidators(t, count).GetPublicIdentities() snapshot := NewProposerSnapshot(0, validatorSet) snapshot.Validators[bestIdx].ProposerPriority = big.NewInt(1000000) @@ -447,13 +449,13 @@ func TestProposerCalculator_UpdateValidatorsSameVpUpdatedAndNewAdded(t *testing. keys, err := bls.CreateRandomBlsKeys(8) require.NoError(t, err) - v1 := &ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[0].PublicKey(), VotingPower: big.NewInt(100)} - v2 := &ValidatorMetadata{Address: types.Address{0x2}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(100)} - v3 := &ValidatorMetadata{Address: types.Address{0x3}, BlsKey: keys[2].PublicKey(), VotingPower: big.NewInt(100)} - v4 := &ValidatorMetadata{Address: types.Address{0x4}, BlsKey: keys[3].PublicKey(), VotingPower: big.NewInt(100)} - v5 := &ValidatorMetadata{Address: types.Address{0x5}, BlsKey: keys[4].PublicKey(), VotingPower: big.NewInt(100)} + v1 := &validator.ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[0].PublicKey(), VotingPower: big.NewInt(100)} + v2 := &validator.ValidatorMetadata{Address: types.Address{0x2}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(100)} + v3 := &validator.ValidatorMetadata{Address: types.Address{0x3}, BlsKey: keys[2].PublicKey(), VotingPower: big.NewInt(100)} + v4 := &validator.ValidatorMetadata{Address: types.Address{0x4}, BlsKey: keys[3].PublicKey(), VotingPower: big.NewInt(100)} + v5 := &validator.ValidatorMetadata{Address: types.Address{0x5}, BlsKey: keys[4].PublicKey(), VotingPower: big.NewInt(100)} - vs := NewValidatorSet([]*ValidatorMetadata{v1, v2, v3, v4, v5}, hclog.NewNullLogger()) + vs := validator.NewValidatorSet([]*validator.ValidatorMetadata{v1, v2, v3, v4, v5}, hclog.NewNullLogger()) snapshot := NewProposerSnapshot(0, vs.Accounts()) @@ -466,12 +468,12 @@ func TestProposerCalculator_UpdateValidatorsSameVpUpdatedAndNewAdded(t *testing. } // updated old validators - u1 := &ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(10)} - u2 := &ValidatorMetadata{Address: types.Address{0x2}, BlsKey: keys[2].PublicKey(), VotingPower: big.NewInt(10)} + u1 := &validator.ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(10)} + u2 := &validator.ValidatorMetadata{Address: types.Address{0x2}, BlsKey: keys[2].PublicKey(), VotingPower: big.NewInt(10)} // added new validator - a1 := &ValidatorMetadata{Address: types.Address{0x9}, BlsKey: keys[7].PublicKey(), VotingPower: big.NewInt(100)} + a1 := &validator.ValidatorMetadata{Address: types.Address{0x9}, BlsKey: keys[7].PublicKey(), VotingPower: big.NewInt(100)} - newAccountSet := []*ValidatorMetadata{u1, u2, a1} + newAccountSet := []*validator.ValidatorMetadata{u1, u2, a1} require.NoError(t, updateValidators(snapshot, newAccountSet)) assert.Equal(t, 3, len(snapshot.Validators)) @@ -512,11 +514,11 @@ func TestProposerCalculator_UpdateValidators(t *testing.T) { keys, err := bls.CreateRandomBlsKeys(4) require.NoError(t, err) - v1 := &ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[0].PublicKey(), VotingPower: big.NewInt(10)} - v2 := &ValidatorMetadata{Address: types.Address{0x2}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(20)} - v3 := &ValidatorMetadata{Address: types.Address{0x3}, BlsKey: keys[2].PublicKey(), VotingPower: big.NewInt(30)} + v1 := &validator.ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[0].PublicKey(), VotingPower: big.NewInt(10)} + v2 := &validator.ValidatorMetadata{Address: types.Address{0x2}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(20)} + v3 := &validator.ValidatorMetadata{Address: types.Address{0x3}, BlsKey: keys[2].PublicKey(), VotingPower: big.NewInt(30)} - vs := NewValidatorSet([]*ValidatorMetadata{v1, v2, v3}, hclog.NewNullLogger()) + vs := validator.NewValidatorSet([]*validator.ValidatorMetadata{v1, v2, v3}, hclog.NewNullLogger()) snapshot := NewProposerSnapshot(0, vs.Accounts()) require.Equal(t, big.NewInt(60), snapshot.GetTotalVotingPower()) @@ -534,13 +536,13 @@ func TestProposerCalculator_UpdateValidators(t *testing.T) { require.NoError(t, err) // updated - u1 := &ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[0].PublicKey(), VotingPower: big.NewInt(100)} - u2 := &ValidatorMetadata{Address: types.Address{0x2}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(200)} - u3 := &ValidatorMetadata{Address: types.Address{0x3}, BlsKey: keys[2].PublicKey(), VotingPower: big.NewInt(300)} + u1 := &validator.ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[0].PublicKey(), VotingPower: big.NewInt(100)} + u2 := &validator.ValidatorMetadata{Address: types.Address{0x2}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(200)} + u3 := &validator.ValidatorMetadata{Address: types.Address{0x3}, BlsKey: keys[2].PublicKey(), VotingPower: big.NewInt(300)} // added - a1 := &ValidatorMetadata{Address: types.Address{0x4}, BlsKey: keys[3].PublicKey(), VotingPower: big.NewInt(400)} + a1 := &validator.ValidatorMetadata{Address: types.Address{0x4}, BlsKey: keys[3].PublicKey(), VotingPower: big.NewInt(400)} - require.NoError(t, updateValidators(snapshot, []*ValidatorMetadata{u1, u2, u3, a1})) + require.NoError(t, updateValidators(snapshot, []*validator.ValidatorMetadata{u1, u2, u3, a1})) require.Equal(t, 4, len(snapshot.Validators)) // priorities are from previous iteration @@ -560,11 +562,11 @@ func TestProposerCalculator_ScaleAfterDelete(t *testing.T) { keys, err := bls.CreateRandomBlsKeys(3) require.NoError(t, err) - v1 := &ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[0].PublicKey(), VotingPower: big.NewInt(10)} - v2 := &ValidatorMetadata{Address: types.Address{0x2}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(10)} - v3 := &ValidatorMetadata{Address: types.Address{0x3}, BlsKey: keys[2].PublicKey(), VotingPower: big.NewInt(80000)} + v1 := &validator.ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[0].PublicKey(), VotingPower: big.NewInt(10)} + v2 := &validator.ValidatorMetadata{Address: types.Address{0x2}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(10)} + v3 := &validator.ValidatorMetadata{Address: types.Address{0x3}, BlsKey: keys[2].PublicKey(), VotingPower: big.NewInt(80000)} - vs := NewValidatorSet([]*ValidatorMetadata{v1, v2, v3}, hclog.NewNullLogger()) + vs := validator.NewValidatorSet([]*validator.ValidatorMetadata{v1, v2, v3}, hclog.NewNullLogger()) snapshot := NewProposerSnapshot(0, vs.Accounts()) assert.Equal(t, big.NewInt(80020), snapshot.GetTotalVotingPower()) @@ -584,13 +586,13 @@ func TestProposerCalculator_ScaleAfterDelete(t *testing.T) { assert.Equal(t, types.Address{0x3}, proposer.Metadata.Address) // reduce validator voting power from 8k to 1 - u1 := &ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[0].PublicKey(), VotingPower: big.NewInt(10)} - u2 := &ValidatorMetadata{Address: types.Address{0x2}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(10)} + u1 := &validator.ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[0].PublicKey(), VotingPower: big.NewInt(10)} + u2 := &validator.ValidatorMetadata{Address: types.Address{0x2}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(10)} require.Equal(t, big.NewInt(-40010), snapshot.Validators[0].ProposerPriority) require.Equal(t, big.NewInt(40010), snapshot.Validators[1].ProposerPriority) - require.NoError(t, updateValidators(snapshot, []*ValidatorMetadata{u1, u2})) + require.NoError(t, updateValidators(snapshot, []*validator.ValidatorMetadata{u1, u2})) // maxdiff = 2*tvp = 40 // diff(min,max) (-40010, 40010) = 80020 @@ -607,11 +609,11 @@ func TestProposerCalculator_ShiftAfterUpdate(t *testing.T) { keys, err := bls.CreateRandomBlsKeys(3) require.NoError(t, err) - v1 := &ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[0].PublicKey(), VotingPower: big.NewInt(50)} - v2 := &ValidatorMetadata{Address: types.Address{0x2}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(80)} - v3 := &ValidatorMetadata{Address: types.Address{0x3}, BlsKey: keys[2].PublicKey(), VotingPower: big.NewInt(100000)} + v1 := &validator.ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[0].PublicKey(), VotingPower: big.NewInt(50)} + v2 := &validator.ValidatorMetadata{Address: types.Address{0x2}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(80)} + v3 := &validator.ValidatorMetadata{Address: types.Address{0x3}, BlsKey: keys[2].PublicKey(), VotingPower: big.NewInt(100000)} - vs := NewValidatorSet([]*ValidatorMetadata{v1, v2, v3}, hclog.NewNullLogger()) + vs := validator.NewValidatorSet([]*validator.ValidatorMetadata{v1, v2, v3}, hclog.NewNullLogger()) snapshot := NewProposerSnapshot(0, vs.Accounts()) assert.Equal(t, big.NewInt(100130), snapshot.GetTotalVotingPower()) @@ -620,10 +622,10 @@ func TestProposerCalculator_ShiftAfterUpdate(t *testing.T) { require.NoError(t, err) // updates - u1 := &ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[0].PublicKey(), VotingPower: big.NewInt(5)} - u2 := &ValidatorMetadata{Address: types.Address{0x2}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(8)} + u1 := &validator.ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[0].PublicKey(), VotingPower: big.NewInt(5)} + u2 := &validator.ValidatorMetadata{Address: types.Address{0x2}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(8)} - require.NoError(t, updateValidators(snapshot, []*ValidatorMetadata{u1, u2})) + require.NoError(t, updateValidators(snapshot, []*validator.ValidatorMetadata{u1, u2})) // maxdiff = 2*tvp = 26 // diff(min,max) (-260, 19610) = 19870 @@ -641,11 +643,11 @@ func TestProposerCalculator_UpdateValidatorSet(t *testing.T) { keys, err := bls.CreateRandomBlsKeys(3) require.NoError(t, err) - v1 := &ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[0].PublicKey(), VotingPower: big.NewInt(1)} - v2 := &ValidatorMetadata{Address: types.Address{0x2}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(8)} - v3 := &ValidatorMetadata{Address: types.Address{0x3}, BlsKey: keys[2].PublicKey(), VotingPower: big.NewInt(15)} + v1 := &validator.ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[0].PublicKey(), VotingPower: big.NewInt(1)} + v2 := &validator.ValidatorMetadata{Address: types.Address{0x2}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(8)} + v3 := &validator.ValidatorMetadata{Address: types.Address{0x3}, BlsKey: keys[2].PublicKey(), VotingPower: big.NewInt(15)} - vs := NewValidatorSet([]*ValidatorMetadata{v1, v2, v3}, hclog.NewNullLogger()) + vs := validator.NewValidatorSet([]*validator.ValidatorMetadata{v1, v2, v3}, hclog.NewNullLogger()) snapshot := NewProposerSnapshot(0, vs.Accounts()) assert.Equal(t, big.NewInt(24), snapshot.GetTotalVotingPower()) @@ -654,11 +656,11 @@ func TestProposerCalculator_UpdateValidatorSet(t *testing.T) { require.NoError(t, err) // modified validator - u1 := &ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[0].PublicKey(), VotingPower: big.NewInt(5)} + u1 := &validator.ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[0].PublicKey(), VotingPower: big.NewInt(5)} // added validator - a1 := &ValidatorMetadata{Address: types.Address{0x4}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(8)} + a1 := &validator.ValidatorMetadata{Address: types.Address{0x4}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(8)} - require.NoError(t, updateValidators(snapshot, []*ValidatorMetadata{u1, a1})) + require.NoError(t, updateValidators(snapshot, []*validator.ValidatorMetadata{u1, a1})) // expecting 2 validators with updated voting power and total voting power require.Equal(t, 2, len(snapshot.Validators)) require.Equal(t, types.Address{0x1}, snapshot.Validators[0].Metadata.Address) @@ -677,10 +679,10 @@ func TestProposerCalculator_AddValidator(t *testing.T) { keys, err := bls.CreateRandomBlsKeys(3) require.NoError(t, err) - v1 := &ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[0].PublicKey(), VotingPower: big.NewInt(3)} - v2 := &ValidatorMetadata{Address: types.Address{0x2}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(1)} + v1 := &validator.ValidatorMetadata{Address: types.Address{0x1}, BlsKey: keys[0].PublicKey(), VotingPower: big.NewInt(3)} + v2 := &validator.ValidatorMetadata{Address: types.Address{0x2}, BlsKey: keys[1].PublicKey(), VotingPower: big.NewInt(1)} - vs := NewValidatorSet([]*ValidatorMetadata{v1, v2}, hclog.NewNullLogger()) + vs := validator.NewValidatorSet([]*validator.ValidatorMetadata{v1, v2}, hclog.NewNullLogger()) snapshot := NewProposerSnapshot(0, vs.Accounts()) assert.Equal(t, big.NewInt(4), snapshot.GetTotalVotingPower()) @@ -696,9 +698,9 @@ func TestProposerCalculator_AddValidator(t *testing.T) { require.Equal(t, big.NewInt(-2), snapshot.Validators[0].ProposerPriority) require.Equal(t, big.NewInt(2), snapshot.Validators[1].ProposerPriority) - a1 := &ValidatorMetadata{Address: types.Address{0x3}, BlsKey: keys[2].PublicKey(), VotingPower: big.NewInt(8)} + a1 := &validator.ValidatorMetadata{Address: types.Address{0x3}, BlsKey: keys[2].PublicKey(), VotingPower: big.NewInt(8)} - require.NoError(t, updateValidators(snapshot, []*ValidatorMetadata{v1, v2, a1})) + require.NoError(t, updateValidators(snapshot, []*validator.ValidatorMetadata{v1, v2, a1})) // updated vp: 8+3+1 = 12 // added validator priority = -1.125*8 ~ -13 diff --git a/consensus/polybft/runtime_helpers_test.go b/consensus/polybft/runtime_helpers_test.go index fdf1fa1e43..078129d9cc 100644 --- a/consensus/polybft/runtime_helpers_test.go +++ b/consensus/polybft/runtime_helpers_test.go @@ -5,6 +5,7 @@ import ( "github.com/0xPolygon/polygon-edge/blockchain" "github.com/0xPolygon/polygon-edge/consensus/polybft/bitmap" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/types" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -13,11 +14,11 @@ import ( func TestHelpers_isEpochEndingBlock_DeltaNotEmpty(t *testing.T) { t.Parallel() - validators := newTestValidators(t, 3).getPublicIdentities() + validators := validator.NewTestValidators(t, 3).GetPublicIdentities() bitmap := bitmap.Bitmap{} bitmap.Set(0) - delta := &ValidatorSetDelta{ + delta := &validator.ValidatorSetDelta{ Added: validators[1:], Removed: bitmap, } @@ -36,7 +37,7 @@ func TestHelpers_isEpochEndingBlock_NoBlock(t *testing.T) { blockchainMock := new(blockchainMock) blockchainMock.On("GetHeaderByNumber", mock.Anything).Return(&types.Header{}, false) - extra := &Extra{Checkpoint: &CheckpointData{EpochNumber: 2}, Validators: &ValidatorSetDelta{}} + extra := &Extra{Checkpoint: &CheckpointData{EpochNumber: 2}, Validators: &validator.ValidatorSetDelta{}} blockNumber := uint64(20) isEndOfEpoch, err := isEpochEndingBlock(blockNumber, extra, blockchainMock) @@ -49,15 +50,15 @@ func TestHelpers_isEpochEndingBlock_EpochsNotTheSame(t *testing.T) { blockchainMock := new(blockchainMock) - nextBlockExtra := &Extra{Checkpoint: &CheckpointData{EpochNumber: 3}, Validators: &ValidatorSetDelta{}} + nextBlockExtra := &Extra{Checkpoint: &CheckpointData{EpochNumber: 3}, Validators: &validator.ValidatorSetDelta{}} nextBlock := &types.Header{ Number: 21, - ExtraData: append(make([]byte, ExtraVanity), nextBlockExtra.MarshalRLPTo(nil)...), + ExtraData: nextBlockExtra.MarshalRLPTo(nil), } blockchainMock.On("GetHeaderByNumber", mock.Anything).Return(nextBlock, true) - extra := &Extra{Checkpoint: &CheckpointData{EpochNumber: 2}, Validators: &ValidatorSetDelta{}} + extra := &Extra{Checkpoint: &CheckpointData{EpochNumber: 2}, Validators: &validator.ValidatorSetDelta{}} blockNumber := uint64(20) isEndOfEpoch, err := isEpochEndingBlock(blockNumber, extra, blockchainMock) @@ -70,15 +71,15 @@ func TestHelpers_isEpochEndingBlock_EpochsAreTheSame(t *testing.T) { blockchainMock := new(blockchainMock) - nextBlockExtra := &Extra{Checkpoint: &CheckpointData{EpochNumber: 2}, Validators: &ValidatorSetDelta{}} + nextBlockExtra := &Extra{Checkpoint: &CheckpointData{EpochNumber: 2}, Validators: &validator.ValidatorSetDelta{}} nextBlock := &types.Header{ Number: 16, - ExtraData: append(make([]byte, ExtraVanity), nextBlockExtra.MarshalRLPTo(nil)...), + ExtraData: nextBlockExtra.MarshalRLPTo(nil), } blockchainMock.On("GetHeaderByNumber", mock.Anything).Return(nextBlock, true) - extra := &Extra{Checkpoint: &CheckpointData{EpochNumber: 2}, Validators: &ValidatorSetDelta{}} + extra := &Extra{Checkpoint: &CheckpointData{EpochNumber: 2}, Validators: &validator.ValidatorSetDelta{}} blockNumber := uint64(15) isEndOfEpoch, err := isEpochEndingBlock(blockNumber, extra, blockchainMock) diff --git a/consensus/polybft/sc_integration_test.go b/consensus/polybft/sc_integration_test.go index 9f9aa7ec76..c850705553 100644 --- a/consensus/polybft/sc_integration_test.go +++ b/consensus/polybft/sc_integration_test.go @@ -1,45 +1,53 @@ package polybft import ( - "encoding/hex" "math" "math/big" "strconv" "testing" - "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/umbracle/ethgo" + "github.com/umbracle/ethgo/abi" "github.com/0xPolygon/polygon-edge/chain" "github.com/0xPolygon/polygon-edge/consensus/polybft/bitmap" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi/artifact" bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" - "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/contracts" - secretsHelper "github.com/0xPolygon/polygon-edge/secrets/helper" + "github.com/0xPolygon/polygon-edge/crypto" + "github.com/0xPolygon/polygon-edge/helper/hex" "github.com/0xPolygon/polygon-edge/state" "github.com/0xPolygon/polygon-edge/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/umbracle/ethgo" - "github.com/umbracle/ethgo/abi" ) func TestIntegratoin_PerformExit(t *testing.T) { t.Parallel() - // create validator set - currentValidators := newTestValidatorsWithAliases(t, []string{"A", "B", "C", "D"}, []uint64{100, 100, 100, 100}) - accSet := currentValidators.getPublicIdentities() + const gasLimit = 1000000000000 - senderAddress := types.Address{1} - bn256Addr := types.Address{2} - l1StateReceiverAddr := types.Address{3} + // create validator set and checkpoint mngr + currentValidators := validator.NewTestValidatorsWithAliases(t, []string{"A", "B", "C", "D"}, []uint64{100, 100, 100, 100}) + accSet := currentValidators.GetPublicIdentities() + cm := checkpointManager{blockchain: &blockchainMock{}} + + deployerAddress := types.Address{76, 76, 1} // account that will deploy contracts + senderAddress := types.Address{1} // account that sends exit/withdraw transactions + receiverAddr := types.Address{6} // account that receive tokens + amount1 := big.NewInt(3) // amount of the first widrawal + amount2 := big.NewInt(2) // amount of the second widrawal + bn256Addr := types.Address{2} // bls contract + stateSenderAddr := types.Address{5} // generic bridge contract on rootchain alloc := map[types.Address]*chain.GenesisAccount{ - senderAddress: {Balance: big.NewInt(100000000000)}, + senderAddress: {Balance: new(big.Int).Add(amount1, amount2)}, // give some ethers to sender + deployerAddress: {Balance: ethgo.Ether(100)}, // give 100 ethers to deployer contracts.BLSContract: {Code: contractsapi.BLS.DeployedBytecode}, bn256Addr: {Code: contractsapi.BLS256.DeployedBytecode}, - l1StateReceiverAddr: {Code: contractsapi.TestL1StateReceiver.DeployedBytecode}, + stateSenderAddr: {Code: contractsapi.StateSender.DeployedBytecode}, } transition := newTestTransition(t, alloc) @@ -47,37 +55,47 @@ func TestIntegratoin_PerformExit(t *testing.T) { input, err := abi.GetMethod(function).Encode(args) require.NoError(t, err) - result := transition.Call2(senderAddress, addr, input, big.NewInt(0), 1000000000) - require.NoError(t, result.Err) + result := transition.Call2(deployerAddress, addr, input, big.NewInt(0), gasLimit) require.True(t, result.Succeeded()) - require.False(t, result.Failed()) return result.ReturnValue } + // deploy MockERC20 as root chain ERC 20 token + rootERC20Addr := deployAndInitContract(t, transition, contractsapi.RootERC20, deployerAddress, nil) + + // deploy CheckpointManager checkpointManagerInit := func() ([]byte, error) { - initialize := contractsapi.InitializeCheckpointManagerFn{ + return (&contractsapi.InitializeCheckpointManagerFn{ NewBls: contracts.BLSContract, NewBn256G2: bn256Addr, NewValidatorSet: accSet.ToAPIBinding(), ChainID_: big.NewInt(0), - } - - return initialize.EncodeAbi() + }).EncodeAbi() } + checkpointManagerAddr := deployAndInitContract(t, transition, contractsapi.CheckpointManager, deployerAddress, checkpointManagerInit) - checkpointManagerAddr := deployAndInitContract(t, transition, contractsapi.CheckpointManager, senderAddress, checkpointManagerInit) - + // deploy ExitHelper exitHelperInit := func() ([]byte, error) { - return contractsapi.ExitHelper.Abi.GetMethod("initialize").Encode([]interface{}{ethgo.Address(checkpointManagerAddr)}) + return (&contractsapi.InitializeExitHelperFn{NewCheckpointManager: checkpointManagerAddr}).EncodeAbi() + } + exitHelperContractAddress := deployAndInitContract(t, transition, contractsapi.ExitHelper, deployerAddress, exitHelperInit) + + // deploy RootERC20Predicate + rootERC20PredicateInit := func() ([]byte, error) { + return (&contractsapi.InitializeRootERC20PredicateFn{ + NewStateSender: stateSenderAddr, + NewExitHelper: exitHelperContractAddress, + NewChildERC20Predicate: contracts.ChildERC20PredicateContract, + NewChildTokenTemplate: contracts.ChildERC20Contract, + NativeTokenRootAddress: contracts.NativeERC20TokenContract, + }).EncodeAbi() } - exitHelperContractAddress := deployAndInitContract(t, transition, contractsapi.ExitHelper, senderAddress, exitHelperInit) + rootERC20PredicateAddr := deployAndInitContract(t, transition, contractsapi.RootERC20Predicate, deployerAddress, rootERC20PredicateInit) + // validate initialization of CheckpointManager require.Equal(t, getField(checkpointManagerAddr, contractsapi.CheckpointManager.Abi, "currentCheckpointBlockNumber")[31], uint8(0)) - cm := checkpointManager{ - blockchain: &blockchainMock{}, - } accSetHash, err := accSet.Hash() require.NoError(t, err) @@ -86,26 +104,81 @@ func TestIntegratoin_PerformExit(t *testing.T) { epochNumber := uint64(1) blockRound := uint64(1) + // mint + mintInput, err := (&contractsapi.MintRootERC20Fn{ + To: senderAddress, + Amount: alloc[senderAddress].Balance, + }).EncodeAbi() + require.NoError(t, err) + + result := transition.Call2(deployerAddress, rootERC20Addr, mintInput, nil, gasLimit) + require.NoError(t, result.Err) + + // approve + approveInput, err := (&contractsapi.ApproveRootERC20Fn{ + Spender: rootERC20PredicateAddr, + Amount: alloc[senderAddress].Balance, + }).EncodeAbi() + require.NoError(t, err) + + result = transition.Call2(senderAddress, rootERC20Addr, approveInput, big.NewInt(0), gasLimit) + require.NoError(t, result.Err) + + // deposit + depositInput, err := (&contractsapi.DepositToRootERC20PredicateFn{ + RootToken: rootERC20Addr, + Receiver: receiverAddr, + Amount: new(big.Int).Add(amount1, amount2), + }).EncodeAbi() + require.NoError(t, err) + + // send sync events to childchain so that receiver can obtain tokens + result = transition.Call2(senderAddress, rootERC20PredicateAddr, depositInput, big.NewInt(0), gasLimit) + require.NoError(t, result.Err) + + // simulate withdrawal from childchain to rootchain + widthdrawSig := crypto.Keccak256([]byte("WITHDRAW")) + erc20DataType := abi.MustNewType( + "tuple(bytes32 withdrawSignature, address rootToken, address withdrawer, address receiver, uint256 amount)") + + exitData1, err := erc20DataType.Encode(map[string]interface{}{ + "withdrawSignature": widthdrawSig, + "rootToken": ethgo.Address(rootERC20Addr), + "withdrawer": ethgo.Address(senderAddress), + "receiver": ethgo.Address(receiverAddr), + "amount": amount1, + }) + require.NoError(t, err) + + exitData2, err := erc20DataType.Encode(map[string]interface{}{ + "withdrawSignature": widthdrawSig, + "rootToken": ethgo.Address(rootERC20Addr), + "withdrawer": ethgo.Address(senderAddress), + "receiver": ethgo.Address(receiverAddr), + "amount": amount2, + }) + require.NoError(t, err) + exits := []*ExitEvent{ { ID: 1, - Sender: ethgo.Address{7}, - Receiver: ethgo.Address(l1StateReceiverAddr), - Data: []byte{123}, + Sender: ethgo.Address(contracts.ChildERC20PredicateContract), + Receiver: ethgo.Address(rootERC20PredicateAddr), + Data: exitData1, }, { ID: 2, - Sender: ethgo.Address{7}, - Receiver: ethgo.Address(l1StateReceiverAddr), - Data: []byte{21}, + Sender: ethgo.Address(contracts.ChildERC20PredicateContract), + Receiver: ethgo.Address(rootERC20PredicateAddr), + Data: exitData2, }, } - exitTrie, err := createExitTree(exits) + exitTree, err := createExitTree(exits) require.NoError(t, err) - eventRoot := exitTrie.Hash() + eventRoot := exitTree.Hash() - checkpointData := CheckpointData{ + checkpointData := &CheckpointData{ BlockRound: blockRound, EpochNumber: epochNumber, CurrentValidatorsHash: accSetHash, @@ -119,13 +192,12 @@ func TestIntegratoin_PerformExit(t *testing.T) { blockHash) require.NoError(t, err) - bmp := bitmap.Bitmap{} i := uint64(0) + bmp := bitmap.Bitmap{} + signatures := bls.Signatures(nil) - var signatures bls.Signatures - - currentValidators.iterAcct(nil, func(v *testValidator) { - signatures = append(signatures, v.mustSign(checkpointHash[:], bls.DomainCheckpointManager)) + currentValidators.IterAcct(nil, func(v *validator.TestValidator) { + signatures = append(signatures, v.MustSign(checkpointHash[:], bls.DomainCheckpointManager)) bmp.Set(i) i++ }) @@ -134,78 +206,65 @@ func TestIntegratoin_PerformExit(t *testing.T) { require.NoError(t, err) extra := &Extra{ - Checkpoint: &checkpointData, - } - extra.Committed = &Signature{ - AggregatedSignature: aggSignature, - Bitmap: bmp, + Checkpoint: checkpointData, + Committed: &Signature{ + AggregatedSignature: aggSignature, + Bitmap: bmp, + }, } - submitCheckpointEncoded, err := cm.abiEncodeCheckpointBlock( - blockNumber, - blockHash, - extra, - accSet) + // submit a checkpoint + submitCheckpointEncoded, err := cm.abiEncodeCheckpointBlock(blockNumber, blockHash, extra, accSet) require.NoError(t, err) - result := transition.Call2(senderAddress, checkpointManagerAddr, submitCheckpointEncoded, big.NewInt(0), 1000000000) + result = transition.Call2(senderAddress, checkpointManagerAddr, submitCheckpointEncoded, big.NewInt(0), gasLimit) require.NoError(t, result.Err) require.Equal(t, getField(checkpointManagerAddr, contractsapi.CheckpointManager.Abi, "currentCheckpointBlockNumber")[31], uint8(1)) - //check that the exit havent performed + // check that the exit hasn't performed res := getField(exitHelperContractAddress, contractsapi.ExitHelper.Abi, "processedExits", exits[0].ID) - require.Equal(t, int(res[31]), 0) + require.Equal(t, 0, int(res[31])) var exitEventAPI contractsapi.L2StateSyncedEvent proofExitEvent, err := exitEventAPI.Encode(exits[0]) require.NoError(t, err) - proof, err := exitTrie.GenerateProof(proofExitEvent) + proof, err := exitTree.GenerateProof(proofExitEvent) require.NoError(t, err) - leafIndex, err := exitTrie.LeafIndex(proofExitEvent) + leafIndex, err := exitTree.LeafIndex(proofExitEvent) require.NoError(t, err) - ehExit, err := contractsapi.ExitHelper.Abi.GetMethod("exit").Encode([]interface{}{ - blockNumber, - leafIndex, - proofExitEvent, - proof, - }) + exitFnInput, err := (&contractsapi.ExitExitHelperFn{ + BlockNumber: new(big.Int).SetUint64(blockNumber), + LeafIndex: new(big.Int).SetUint64(leafIndex), + UnhashedLeaf: proofExitEvent, + Proof: proof, + }).EncodeAbi() require.NoError(t, err) - result = transition.Call2(senderAddress, exitHelperContractAddress, ehExit, big.NewInt(0), 1000000000) + result = transition.Call2(senderAddress, exitHelperContractAddress, exitFnInput, big.NewInt(0), gasLimit) require.NoError(t, result.Err) - // check true + // check that first exit event is processed res = getField(exitHelperContractAddress, contractsapi.ExitHelper.Abi, "processedExits", exits[0].ID) - require.Equal(t, int(res[31]), 1) + require.Equal(t, 1, int(res[31])) - lastID := getField(l1StateReceiverAddr, contractsapi.TestL1StateReceiver.Abi, "id") - require.Equal(t, uint8(1), lastID[31]) - - lastAddr := getField(l1StateReceiverAddr, contractsapi.TestL1StateReceiver.Abi, "addr") - require.Equal(t, exits[0].Sender[:], lastAddr[12:]) - - lastCounter := getField(l1StateReceiverAddr, contractsapi.TestL1StateReceiver.Abi, "counter") - require.Equal(t, lastCounter[31], uint8(1)) + res = getField(rootERC20Addr, contractsapi.RootERC20.Abi, "balanceOf", receiverAddr) + require.Equal(t, amount1, new(big.Int).SetBytes(res)) } func TestIntegration_CommitEpoch(t *testing.T) { t.Parallel() // init validator sets - // (cannot run test case with more than 100 validators at the moment, - // because active validator set is capped to 100 on smart contract side) validatorSetSize := []int{5, 10, 50, 100} - // number of delegators per validator - delegatorsPerValidator := 100 - intialBalance := uint64(5 * math.Pow(10, 18)) // 5 tokens - reward := uint64(math.Pow(10, 18)) // 1 token - delegateAmount := uint64(math.Pow(10, 18)) / 2 // 0.5 token + intialBalance := uint64(5 * math.Pow(10, 18)) // 5 tokens + reward := uint64(math.Pow(10, 18)) // 1 token + walletAddress := types.StringToAddress("1234889893") - validatorSets := make([]*testValidators, len(validatorSetSize), len(validatorSetSize)) + validatorSets := make([]*validator.TestValidators, len(validatorSetSize), len(validatorSetSize)) // create all validator sets which will be used in test for i, size := range validatorSetSize { @@ -217,113 +276,114 @@ func TestIntegration_CommitEpoch(t *testing.T) { vps[j] = intialBalance } - validatorSets[i] = newTestValidatorsWithAliases(t, aliases, vps) + validatorSets[i] = validator.NewTestValidatorsWithAliases(t, aliases, vps) } // iterate through the validator set and do the test for each of them for _, currentValidators := range validatorSets { - accSet := currentValidators.getPublicIdentities() - accSetPrivateKeys := currentValidators.getPrivateIdentities() - valid2deleg := make(map[types.Address][]*wallet.Key, accSet.Len()) // delegators assigned to validators + accSet := currentValidators.GetPublicIdentities() + // validator data for polybft config + initValidators := make([]*validator.GenesisValidator, accSet.Len()) // add contracts to genesis data alloc := map[types.Address]*chain.GenesisAccount{ contracts.ValidatorSetContract: { - Code: contractsapi.ChildValidatorSet.DeployedBytecode, + Code: contractsapi.ValidatorSet.DeployedBytecode, + }, + contracts.RewardPoolContract: { + Code: contractsapi.RewardPool.DeployedBytecode, }, - contracts.BLSContract: { - Code: contractsapi.BLS.DeployedBytecode, + contracts.NativeERC20TokenContract: { + Code: contractsapi.NativeERC20.DeployedBytecode, + }, + walletAddress: { + Balance: new(big.Int).SetUint64(intialBalance), }, } - // validator data for polybft config - initValidators := make([]*Validator, accSet.Len()) - - for i, validator := range accSet { + for i, val := range accSet { // add validator to genesis data - alloc[validator.Address] = &chain.GenesisAccount{ - Balance: validator.VotingPower, + alloc[val.Address] = &chain.GenesisAccount{ + Balance: val.VotingPower, } - signature, err := secretsHelper.MakeKOSKSignature(accSetPrivateKeys[i].Bls, validator.Address, 0, bls.DomainValidatorSet) - require.NoError(t, err) - - signatureBytes, err := signature.Marshal() - require.NoError(t, err) - // create validator data for polybft config - initValidators[i] = &Validator{ - Address: validator.Address, - Balance: validator.VotingPower, - Stake: validator.VotingPower, - BlsKey: hex.EncodeToString(validator.BlsKey.Marshal()), - BlsSignature: hex.EncodeToString(signatureBytes), + initValidators[i] = &validator.GenesisValidator{ + Address: val.Address, + Balance: val.VotingPower, + Stake: val.VotingPower, + BlsKey: hex.EncodeToString(val.BlsKey.Marshal()), } - - // create delegators - delegatorAccs := createRandomTestKeys(t, delegatorsPerValidator) - - // add delegators to genesis data - for j := 0; j < delegatorsPerValidator; j++ { - delegator := delegatorAccs[j] - alloc[types.Address(delegator.Address())] = &chain.GenesisAccount{ - Balance: new(big.Int).SetUint64(intialBalance), - } - } - - valid2deleg[validator.Address] = delegatorAccs } - transition := newTestTransition(t, alloc) - polyBFTConfig := PolyBFTConfig{ InitialValidatorSet: initValidators, - BlockTime: 2 * time.Second, EpochSize: 24 * 60 * 60 / 2, SprintSize: 5, EpochReward: reward, // use 1st account as governance address - Governance: currentValidators.toValidatorSet().validators.GetAddresses()[0], + Governance: currentValidators.ToValidatorSet().Accounts().GetAddresses()[0], + RewardConfig: &RewardsConfig{ + TokenAddress: contracts.NativeERC20TokenContract, + WalletAddress: walletAddress, + WalletAmount: new(big.Int).SetUint64(intialBalance), + }, + Bridge: &BridgeConfig{ + CustomSupernetManagerAddr: types.StringToAddress("0x12312451"), + }, } - // get data for ChildValidatorSet initialization - initInput, err := getInitChildValidatorSetInput(polyBFTConfig) - require.NoError(t, err) + transition := newTestTransition(t, alloc) - // init ChildValidatorSet - err = initContract(contracts.ValidatorSetContract, initInput, "ChildValidatorSet", transition) + // init ValidatorSet + err := initValidatorSet(polyBFTConfig, transition) require.NoError(t, err) - // delegate amounts to validators - for valAddress, delegators := range valid2deleg { - for _, delegator := range delegators { - encoded, err := contractsapi.ChildValidatorSet.Abi.Methods["delegate"].Encode( - []interface{}{valAddress, false}) - require.NoError(t, err) + // init RewardPool + err = initRewardPool(polyBFTConfig, transition) + require.NoError(t, err) - result := transition.Call2(types.Address(delegator.Address()), contracts.ValidatorSetContract, encoded, new(big.Int).SetUint64(delegateAmount), 1000000000000) - require.False(t, result.Failed()) - } - } + // approve reward pool as reward token spender + err = approveRewardPoolAsSpender(polyBFTConfig, transition) + require.NoError(t, err) // create input for commit epoch - commitEpoch := createTestCommitEpochInput(t, 1, accSet, polyBFTConfig.EpochSize) + commitEpoch := createTestCommitEpochInput(t, 1, polyBFTConfig.EpochSize) input, err := commitEpoch.EncodeAbi() require.NoError(t, err) // call commit epoch result := transition.Call2(contracts.SystemCaller, contracts.ValidatorSetContract, input, big.NewInt(0), 10000000000) require.NoError(t, result.Err) - t.Logf("Number of validators %d when we add %d of delegators, Gas used %+v\n", accSet.Len(), accSet.Len()*delegatorsPerValidator, result.GasUsed) + t.Logf("Number of validators %d on commit epoch, Gas used %+v\n", accSet.Len(), result.GasUsed) + + // create input for distribute rewards + distributeRewards := createTestDistributeRewardsInput(t, 1, accSet, polyBFTConfig.EpochSize) + input, err = distributeRewards.EncodeAbi() + require.NoError(t, err) + + // call reward distributor + result = transition.Call2(contracts.SystemCaller, contracts.RewardPoolContract, input, big.NewInt(0), 10000000000) + require.NoError(t, result.Err) + t.Logf("Number of validators %d on reward distribution, Gas used %+v\n", accSet.Len(), result.GasUsed) - commitEpoch = createTestCommitEpochInput(t, 2, accSet, polyBFTConfig.EpochSize) + commitEpoch = createTestCommitEpochInput(t, 2, polyBFTConfig.EpochSize) input, err = commitEpoch.EncodeAbi() require.NoError(t, err) // call commit epoch result = transition.Call2(contracts.SystemCaller, contracts.ValidatorSetContract, input, big.NewInt(0), 10000000000) require.NoError(t, result.Err) - t.Logf("Number of validators %d, Number of delegator %d, Gas used %+v\n", accSet.Len(), accSet.Len()*delegatorsPerValidator, result.GasUsed) + t.Logf("Number of validators %d on commit epoch, Gas used %+v\n", accSet.Len(), result.GasUsed) + + distributeRewards = createTestDistributeRewardsInput(t, 2, accSet, polyBFTConfig.EpochSize) + input, err = distributeRewards.EncodeAbi() + require.NoError(t, err) + + // call reward distributor + result = transition.Call2(contracts.SystemCaller, contracts.RewardPoolContract, input, big.NewInt(0), 10000000000) + require.NoError(t, result.Err) + t.Logf("Number of validators %d on reward distribution, Gas used %+v\n", accSet.Len(), result.GasUsed) } } @@ -331,17 +391,16 @@ func deployAndInitContract(t *testing.T, transition *state.Transition, scArtifac initCallback func() ([]byte, error)) types.Address { t.Helper() - result := transition.Create2(sender, scArtifact.Bytecode, big.NewInt(0), 1e9) - assert.NoError(t, result.Err) - addr := result.Address + deployResult := transition.Create2(sender, scArtifact.Bytecode, big.NewInt(0), 1e9) + assert.NoError(t, deployResult.Err) if initCallback != nil { initInput, err := initCallback() require.NoError(t, err) - result = transition.Call2(sender, addr, initInput, big.NewInt(0), 1e9) + result := transition.Call2(sender, deployResult.Address, initInput, big.NewInt(0), 1e9) require.NoError(t, result.Err) } - return addr + return deployResult.Address } diff --git a/consensus/polybft/signer/common.go b/consensus/polybft/signer/common.go index 5ca4ea4c07..e39f26cbe6 100644 --- a/consensus/polybft/signer/common.go +++ b/consensus/polybft/signer/common.go @@ -12,6 +12,13 @@ import ( bn256 "github.com/umbracle/go-eth-bn256" ) +const ( + DomainValidatorSetString = "DOMAIN_CHILD_VALIDATOR_SET" + DomainCheckpointManagerString = "DOMAIN_CHECKPOINT_MANAGER" + DomainCommonSigningString = "DOMAIN_COMMON_SIGNING" + DomainStateReceiverString = "DOMAIN_STATE_RECEIVER" +) + var errInfinityPoint = fmt.Errorf("infinity point") var ( @@ -22,13 +29,13 @@ var ( g2Point = mustG2Point("198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa") //nolint // domain used to map hash to G1 used by (child) validator set - DomainValidatorSet = pcrypto.Keccak256([]byte("DOMAIN_CHILD_VALIDATOR_SET")) + DomainValidatorSet = pcrypto.Keccak256([]byte(DomainValidatorSetString)) // domain used to map hash to G1 used by child checkpoint manager - DomainCheckpointManager = pcrypto.Keccak256([]byte("DOMAIN_CHECKPOINT_MANAGER")) + DomainCheckpointManager = pcrypto.Keccak256([]byte(DomainCheckpointManagerString)) - DomainCommonSigning = pcrypto.Keccak256([]byte("DOMAIN_COMMON_SIGNING")) - DomainStateReceiver = pcrypto.Keccak256([]byte("DOMAIN_STATE_RECEIVER")) + DomainCommonSigning = pcrypto.Keccak256([]byte(DomainCommonSigningString)) + DomainStateReceiver = pcrypto.Keccak256([]byte(DomainStateReceiverString)) ) func mustG2Point(str string) *bn256.G2 { diff --git a/consensus/polybft/signer/utils.go b/consensus/polybft/signer/utils.go index b8d24f3ed6..0117714517 100644 --- a/consensus/polybft/signer/utils.go +++ b/consensus/polybft/signer/utils.go @@ -1,8 +1,17 @@ package bls import ( + "bytes" "crypto/rand" "math/big" + + "github.com/0xPolygon/polygon-edge/types" + "github.com/umbracle/ethgo/abi" +) + +var ( + addressABIType = abi.MustNewType("address") + uint256ABIType = abi.MustNewType("uint256") ) // GenerateBlsKey creates a random private and its corresponding public keys @@ -46,3 +55,28 @@ func MarshalMessageToBigInt(message, domain []byte) ([2]*big.Int, error) { new(big.Int).SetBytes(buf[32:64]), }, nil } + +// MakeKOSKSignature creates KOSK signature which prevents rogue attack +func MakeKOSKSignature(privateKey *PrivateKey, address types.Address, + chainID int64, domain []byte, supernetManagerAddr types.Address) (*Signature, error) { + spenderABI, err := addressABIType.Encode(address) + if err != nil { + return nil, err + } + + supernetManagerABI, err := addressABIType.Encode(supernetManagerAddr) + if err != nil { + return nil, err + } + + chainIDABI, err := uint256ABIType.Encode(big.NewInt(chainID)) + if err != nil { + return nil, err + } + + // ethgo pads address to 32 bytes, but solidity doesn't (keeps it 20 bytes) + // that's why we are skipping first 12 bytes + message := bytes.Join([][]byte{spenderABI[12:], supernetManagerABI[12:], chainIDABI}, nil) + + return privateKey.Sign(message, domain) +} diff --git a/consensus/polybft/signer/utils_test.go b/consensus/polybft/signer/utils_test.go index 5cb95107d4..56646de1ea 100644 --- a/consensus/polybft/signer/utils_test.go +++ b/consensus/polybft/signer/utils_test.go @@ -1,8 +1,10 @@ package bls import ( + "encoding/hex" "testing" + "github.com/0xPolygon/polygon-edge/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -66,3 +68,32 @@ func Test_AggregatedSign(t *testing.T) { assert.False(t, isOk) } } + +func Test_MakeKOSKSignature(t *testing.T) { + t.Parallel() + + expected := "03441ebc4bbca37664455b293cfc371ccf9a4f21e40c19a3a25beee77bf6e97d16cdd264c188a01d415ee99865f52567a402044a1c13aa6915a1237a41d35e9e" + bytes, _ := hex.DecodeString("3139343634393730313533353434353137333331343333303931343932303731313035313730303336303738373134363131303435323837383335373237343933383834303135343336383231") + + pk, err := UnmarshalPrivateKey(bytes) + require.NoError(t, err) + + supernetManagerAddr := types.StringToAddress("0x1010101") + address := types.BytesToAddress((pk.PublicKey().Marshal())[:types.AddressLength]) + + signature, err := MakeKOSKSignature(pk, address, 10, DomainValidatorSet, supernetManagerAddr) + require.NoError(t, err) + + signatureBytes, err := signature.Marshal() + require.NoError(t, err) + + assert.Equal(t, expected, hex.EncodeToString(signatureBytes)) + + signature, err = MakeKOSKSignature(pk, address, 100, DomainValidatorSet, supernetManagerAddr) + require.NoError(t, err) + + signatureBytes, err = signature.Marshal() + require.NoError(t, err) + + assert.NotEqual(t, expected, hex.EncodeToString(signatureBytes)) +} diff --git a/consensus/polybft/stake_manager.go b/consensus/polybft/stake_manager.go new file mode 100644 index 0000000000..e140ca6eee --- /dev/null +++ b/consensus/polybft/stake_manager.go @@ -0,0 +1,437 @@ +package polybft + +import ( + "bytes" + "encoding/json" + "fmt" + "math/big" + "sort" + "strings" + + "github.com/0xPolygon/polygon-edge/blockchain" + "github.com/0xPolygon/polygon-edge/consensus/polybft/bitmap" + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" + bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" + "github.com/0xPolygon/polygon-edge/helper/hex" + "github.com/0xPolygon/polygon-edge/txrelayer" + "github.com/0xPolygon/polygon-edge/types" + "github.com/hashicorp/go-hclog" + "github.com/umbracle/ethgo" + "github.com/umbracle/ethgo/abi" +) + +var ( + bigZero = big.NewInt(0) + validatorTypeABI = abi.MustNewType("tuple(uint256[4] blsKey, uint256 stake, bool isWhitelisted, bool isActive)") +) + +// StakeManager interface provides functions for handling stake change of validators +// and updating validator set based on changed stake +type StakeManager interface { + PostBlock(req *PostBlockRequest) error + PostEpoch(req *PostEpochRequest) error + UpdateValidatorSet(epoch uint64, currentValidatorSet validator.AccountSet) (*validator.ValidatorSetDelta, error) +} + +// dummyStakeManager is a dummy implementation of StakeManager interface +// used only for unit testing +type dummyStakeManager struct{} + +func (d *dummyStakeManager) PostBlock(req *PostBlockRequest) error { return nil } +func (d *dummyStakeManager) PostEpoch(req *PostEpochRequest) error { return nil } +func (d *dummyStakeManager) UpdateValidatorSet(epoch uint64, + currentValidatorSet validator.AccountSet) (*validator.ValidatorSetDelta, error) { + return &validator.ValidatorSetDelta{}, nil +} + +var _ StakeManager = (*stakeManager)(nil) + +// stakeManager saves transfer events that happened in each block +// and calculates updated validator set based on changed stake +type stakeManager struct { + logger hclog.Logger + state *State + rootChainRelayer txrelayer.TxRelayer + key ethgo.Key + validatorSetContract types.Address + supernetManagerContract types.Address + maxValidatorSetSize int + blockchain blockchainBackend +} + +// newStakeManager returns a new instance of stake manager +func newStakeManager( + logger hclog.Logger, + state *State, + rootchainRelayer txrelayer.TxRelayer, + key ethgo.Key, + validatorSetAddr, supernetManagerAddr types.Address, + blockchain blockchainBackend, + maxValidatorSetSize int, +) *stakeManager { + return &stakeManager{ + logger: logger, + state: state, + rootChainRelayer: rootchainRelayer, + key: key, + validatorSetContract: validatorSetAddr, + supernetManagerContract: supernetManagerAddr, + maxValidatorSetSize: maxValidatorSetSize, + blockchain: blockchain, + } +} + +// PostEpoch saves the initial validator set to db +func (s *stakeManager) PostEpoch(req *PostEpochRequest) error { + if req.NewEpochID != 1 { + return nil + } + + // save initial validator set as full validator set in db + return s.state.StakeStore.insertFullValidatorSet(validatorSetState{ + BlockNumber: 0, + EpochID: 0, + UpdatedAtBlockNumber: 0, + Validators: newValidatorStakeMap(req.ValidatorSet.Accounts()), + }) +} + +// PostBlock is called on every insert of finalized block (either from consensus or syncer) +// It will read any transfer event that happened in block and update full validator set in db +func (s *stakeManager) PostBlock(req *PostBlockRequest) error { + fullValidatorSet, err := s.state.StakeStore.getFullValidatorSet() + if err != nil { + return err + } + + s.logger.Debug("Stake manager on post block", "block", req.FullBlock.Block.Number(), + "last saved", fullValidatorSet.BlockNumber, "last updated", fullValidatorSet.UpdatedAtBlockNumber) + + // update with missing blocks + for i := fullValidatorSet.BlockNumber + 1; i < req.FullBlock.Block.Number(); i++ { + blockHeader, found := s.blockchain.GetHeaderByNumber(i) + if !found { + return blockchain.ErrNoBlock + } + + receipts, err := s.blockchain.GetReceiptsByHash(blockHeader.Hash) + if err != nil { + return err + } + + if err := s.updateWithReceipts(&fullValidatorSet, receipts, i); err != nil { + return err + } + } + + // finally update with received block + err = s.updateWithReceipts(&fullValidatorSet, req.FullBlock.Receipts, req.FullBlock.Block.Number()) + if err != nil { + return err + } + + fullValidatorSet.EpochID = req.Epoch + fullValidatorSet.BlockNumber = req.FullBlock.Block.Number() + + return s.state.StakeStore.insertFullValidatorSet(fullValidatorSet) +} + +func (s *stakeManager) updateWithReceipts( + fullValidatorSet *validatorSetState, receipts []*types.Receipt, block uint64) error { + events, err := s.getTransferEventsFromReceipts(receipts) + if err != nil { + return err + } + + s.logger.Debug("Full validator set before", + "block", block-1, "evnts", len(events), "data", fullValidatorSet.Validators) + + if len(events) == 0 { + return nil + } + + for _, event := range events { + if event.IsStake() { + s.logger.Debug("Stake transfer event", "to", event.To, "value", event.Value) + + // then this amount was minted To validator address + fullValidatorSet.Validators.addStake(event.To, event.Value) + } else if event.IsUnstake() { + s.logger.Debug("Unstake transfer event", "from", event.From, "value", event.Value) + + // then this amount was burned From validator address + fullValidatorSet.Validators.removeStake(event.From, event.Value) + } else { + // this should not happen, but lets log it if it does + s.logger.Warn("Found a transfer event that represents neither stake nor unstake") + } + } + + for addr, data := range fullValidatorSet.Validators { + if data.BlsKey == nil { + data.BlsKey, err = s.getBlsKey(data.Address) + if err != nil { + s.logger.Warn("Could not get info for new validator", "block", block, "address", addr) + } + } + + data.IsActive = data.VotingPower.Cmp(bigZero) > 0 + } + + fullValidatorSet.UpdatedAtBlockNumber = block // mark on which block validator set has been updated + + s.logger.Debug("Full validator set after", "block", block, "data", fullValidatorSet.Validators) + + return nil +} + +// UpdateValidatorSet returns an updated validator set +// based on stake change (transfer) events from ValidatorSet contract +func (s *stakeManager) UpdateValidatorSet( + epoch uint64, oldValidatorSet validator.AccountSet) (*validator.ValidatorSetDelta, error) { + s.logger.Info("Calculating validators set update...", "epoch", epoch) + + fullValidatorSet, err := s.state.StakeStore.getFullValidatorSet() + if err != nil { + return nil, fmt.Errorf("failed to get full validators set. Epoch: %d. Error: %w", epoch, err) + } + + // stake map that holds stakes for all validators + stakeMap := fullValidatorSet.Validators + + // slice of all validator set + newValidatorSet := stakeMap.getSorted(s.maxValidatorSetSize) + // set of all addresses that will be in next validator set + addressesSet := make(map[types.Address]struct{}, len(newValidatorSet)) + + for _, si := range newValidatorSet { + addressesSet[si.Address] = struct{}{} + } + + removedBitmap := bitmap.Bitmap{} + updatedValidators := validator.AccountSet{} + addedValidators := validator.AccountSet{} + oldActiveMap := make(map[types.Address]*validator.ValidatorMetadata) + + for i, validator := range oldValidatorSet { + oldActiveMap[validator.Address] = validator + // remove existing validators from validator set if they did not make it to the set + if _, exists := addressesSet[validator.Address]; !exists { + removedBitmap.Set(uint64(i)) + } + } + + for _, newValidator := range newValidatorSet { + // check if its already in existing validator set + if oldValidator, exists := oldActiveMap[newValidator.Address]; exists { + if oldValidator.VotingPower.Cmp(newValidator.VotingPower) != 0 { + updatedValidators = append(updatedValidators, newValidator) + } + } else { + if newValidator.BlsKey == nil { + newValidator.BlsKey, err = s.getBlsKey(newValidator.Address) + if err != nil { + return nil, fmt.Errorf("could not retrieve validator data. Address: %v. Error: %w", + newValidator.Address, err) + } + } + + addedValidators = append(addedValidators, newValidator) + } + } + + s.logger.Info("Calculating validators set update finished.", "epoch", epoch) + + delta := &validator.ValidatorSetDelta{ + Added: addedValidators, + Updated: updatedValidators, + Removed: removedBitmap, + } + + if s.logger.IsDebug() { + newValidatorSet, err := oldValidatorSet.Copy().ApplyDelta(delta) + if err != nil { + return nil, err + } + + s.logger.Debug("New validator set", "validatorSet", newValidatorSet) + } + + return delta, nil +} + +// getTransferEventsFromReceipts parses logs from receipts to find transfer events +func (s *stakeManager) getTransferEventsFromReceipts(receipts []*types.Receipt) ([]*contractsapi.TransferEvent, error) { + events := make([]*contractsapi.TransferEvent, 0) + + for i := 0; i < len(receipts); i++ { + if receipts[i].Status == nil || *receipts[i].Status != types.ReceiptSuccess { + continue + } + + for _, log := range receipts[i].Logs { + if log.Address != s.validatorSetContract { + continue + } + + var transferEvent contractsapi.TransferEvent + + doesMatch, err := transferEvent.ParseLog(convertLog(log)) + if err != nil { + return nil, err + } + + if !doesMatch { + continue + } + + events = append(events, &transferEvent) + } + } + + return events, nil +} + +// getBlsKey returns bls key for validator from the supernet contract +func (s *stakeManager) getBlsKey(address types.Address) (*bls.PublicKey, error) { + getValidatorFn := &contractsapi.GetValidatorCustomSupernetManagerFn{ + Validator_: address, + } + + encoded, err := getValidatorFn.EncodeAbi() + if err != nil { + return nil, err + } + + response, err := s.rootChainRelayer.Call( + s.key.Address(), + ethgo.Address(s.supernetManagerContract), + encoded) + if err != nil { + return nil, fmt.Errorf("failed to invoke validators function on the supernet manager: %w", err) + } + + byteResponse, err := hex.DecodeHex(response) + if err != nil { + return nil, fmt.Errorf("unable to decode hex response, %w", err) + } + + decoded, err := validatorTypeABI.Decode(byteResponse) + if err != nil { + return nil, err + } + + output, ok := decoded.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("could not convert decoded outputs to map") + } + + blsKey, ok := output["blsKey"].([4]*big.Int) + if !ok { + return nil, fmt.Errorf("failed to decode blskey") + } + + pubKey, err := bls.UnmarshalPublicKeyFromBigInt(blsKey) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal BLS public key: %w", err) + } + + return pubKey, nil +} + +type validatorSetState struct { + BlockNumber uint64 `json:"block"` + EpochID uint64 `json:"epoch"` + UpdatedAtBlockNumber uint64 `json:"updated_at_block"` + Validators validatorStakeMap `json:"validators"` +} + +func (vs validatorSetState) Marshal() ([]byte, error) { + return json.Marshal(vs) +} + +func (vs *validatorSetState) Unmarshal(b []byte) error { + return json.Unmarshal(b, vs) +} + +// validatorStakeMap holds ValidatorMetadata for each validator address +type validatorStakeMap map[types.Address]*validator.ValidatorMetadata + +// newValidatorStakeMap returns a new instance of validatorStakeMap +func newValidatorStakeMap(validatorSet validator.AccountSet) validatorStakeMap { + stakeMap := make(validatorStakeMap, len(validatorSet)) + + for _, v := range validatorSet { + stakeMap[v.Address] = v.Copy() + } + + return stakeMap +} + +// addStake adds given amount to a validator defined by address +func (sc *validatorStakeMap) addStake(address types.Address, amount *big.Int) { + if metadata, exists := (*sc)[address]; exists { + metadata.VotingPower.Add(metadata.VotingPower, amount) + metadata.IsActive = metadata.VotingPower.Cmp(bigZero) > 0 + } else { + (*sc)[address] = &validator.ValidatorMetadata{ + VotingPower: new(big.Int).Set(amount), + Address: address, + IsActive: amount.Cmp(bigZero) > 0, + } + } +} + +// removeStake removes given amount from validator defined by address +func (sc *validatorStakeMap) removeStake(address types.Address, amount *big.Int) { + stakeData := (*sc)[address] + stakeData.VotingPower.Sub(stakeData.VotingPower, amount) + stakeData.IsActive = stakeData.VotingPower.Cmp(bigZero) > 0 +} + +// getSorted returns validators (*ValidatorMetadata) in sorted order +func (sc validatorStakeMap) getSorted(maxValidatorSetSize int) validator.AccountSet { + activeValidators := make(validator.AccountSet, 0, len(sc)) + + for _, v := range sc { + if v.VotingPower.Cmp(bigZero) > 0 { + activeValidators = append(activeValidators, v) + } + } + + sort.Slice(activeValidators, func(i, j int) bool { + v1, v2 := activeValidators[i], activeValidators[j] + + switch v1.VotingPower.Cmp(v2.VotingPower) { + case 1: + return true + case 0: + return bytes.Compare(v1.Address[:], v2.Address[:]) < 0 + default: + return false + } + }) + + if len(activeValidators) <= maxValidatorSetSize { + return activeValidators + } + + return activeValidators[:maxValidatorSetSize] +} + +func (sc validatorStakeMap) String() string { + var sb strings.Builder + + for _, x := range sc.getSorted(len(sc)) { + bls := "" + if x.BlsKey != nil { + bls = hex.EncodeToString(x.BlsKey.Marshal()) + } + + sb.WriteString(fmt.Sprintf("%s:%s:%s:%t\n", + x.Address, x.VotingPower, bls, x.IsActive)) + } + + return sb.String() +} diff --git a/consensus/polybft/stake_manager_fuzz_test.go b/consensus/polybft/stake_manager_fuzz_test.go new file mode 100644 index 0000000000..9f49f0f2e3 --- /dev/null +++ b/consensus/polybft/stake_manager_fuzz_test.go @@ -0,0 +1,286 @@ +package polybft + +import ( + "encoding/json" + "errors" + "fmt" + "math/big" + "reflect" + "testing" + + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" + "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" + "github.com/0xPolygon/polygon-edge/types" + "github.com/hashicorp/go-hclog" + "github.com/stretchr/testify/require" +) + +type epochIDValidatorsF struct { + EpochID uint64 + Validators []*validator.ValidatorMetadata +} + +type postBlockStructF struct { + EpochID uint64 + ValidatorID uint64 + BlockID uint64 + StakeValue uint64 +} + +type updateValidatorSetF struct { + EpochID uint64 + Index uint64 + VotingPower int64 +} + +func FuzzTestStakeManagerPostEpoch(f *testing.F) { + state := newTestState(f) + + seeds := []epochIDValidatorsF{ + { + EpochID: 0, + Validators: validator.NewTestValidators(f, 6).GetPublicIdentities(), + }, + { + EpochID: 1, + Validators: validator.NewTestValidators(f, 42).GetPublicIdentities(), + }, + { + EpochID: 42, + Validators: validator.NewTestValidators(f, 6).GetPublicIdentities(), + }, + } + + for _, seed := range seeds { + data, err := json.Marshal(seed) + if err != nil { + return + } + + f.Add(data) + } + + f.Fuzz(func(t *testing.T, input []byte) { + stakeManager := &stakeManager{ + logger: hclog.NewNullLogger(), + state: state, + maxValidatorSetSize: 10, + } + + var data epochIDValidatorsF + if err := json.Unmarshal(input, &data); err != nil { + t.Skip(err) + } + + invalidDataFormat := false + for _, v := range data.Validators { + if err := ValidateStruct(*v); err != nil { + invalidDataFormat = true + } + } + if invalidDataFormat { + t.Skip() + } + + err := stakeManager.PostEpoch(&PostEpochRequest{ + NewEpochID: data.EpochID, + ValidatorSet: validator.NewValidatorSet( + data.Validators, + stakeManager.logger, + ), + }) + require.NoError(t, err) + }) +} + +func FuzzTestStakeManagerPostBlock(f *testing.F) { + var ( + allAliases = []string{"A", "B", "C", "D", "E", "F"} + initialSetAliases = []string{"A", "B", "C", "D", "E"} + validators = validator.NewTestValidatorsWithAliases(f, allAliases) + state = newTestState(f) + ) + + seeds := []postBlockStructF{ + { + EpochID: 0, + ValidatorID: 1, + BlockID: 1, + StakeValue: 30, + }, + { + EpochID: 5, + ValidatorID: 30, + BlockID: 4, + StakeValue: 60, + }, + { + EpochID: 1, + ValidatorID: 42, + BlockID: 11, + StakeValue: 70, + }, + } + + for _, seed := range seeds { + data, err := json.Marshal(seed) + if err != nil { + return + } + + f.Add(data) + } + + f.Fuzz(func(t *testing.T, input []byte) { + t.Parallel() + + var data postBlockStructF + if err := json.Unmarshal(input, &data); err != nil { + t.Skip(err) + } + + if err := ValidateStruct(data); err != nil { + t.Skip(err) + } + + if data.ValidatorID > uint64(len(initialSetAliases)-1) { + t.Skip() + } + + stakeManager := newStakeManager( + hclog.NewNullLogger(), + state, + nil, + wallet.NewEcdsaSigner(validators.GetValidator("A").Key()), + types.StringToAddress("0x0001"), + types.StringToAddress("0x0002"), + nil, + 5, + ) + + // insert initial full validator set + require.NoError(t, state.StakeStore.insertFullValidatorSet(validatorSetState{ + Validators: newValidatorStakeMap(validators.GetPublicIdentities(initialSetAliases...)), + })) + + receipt := &types.Receipt{ + Logs: []*types.Log{ + createTestLogForTransferEvent( + t, + stakeManager.validatorSetContract, + validators.GetValidator(initialSetAliases[data.ValidatorID]).Address(), + types.ZeroAddress, + data.StakeValue, + ), + }, + } + + req := &PostBlockRequest{ + FullBlock: &types.FullBlock{Block: &types.Block{Header: &types.Header{Number: data.BlockID}}, + Receipts: []*types.Receipt{receipt}, + }, + Epoch: data.EpochID, + } + err := stakeManager.PostBlock(req) + require.NoError(t, err) + }) +} + +func FuzzTestStakeManagerUpdateValidatorSet(f *testing.F) { + var ( + aliases = []string{"A", "B", "C", "D", "E"} + stakes = []uint64{10, 10, 10, 10, 10} + ) + + validators := validator.NewTestValidatorsWithAliases(f, aliases, stakes) + state := newTestState(f) + + stakeManager := newStakeManager( + hclog.NewNullLogger(), + state, + nil, + wallet.NewEcdsaSigner(validators.GetValidator("A").Key()), + types.StringToAddress("0x0001"), types.StringToAddress("0x0002"), + nil, + 10, + ) + + seeds := []updateValidatorSetF{ + { + EpochID: 0, + Index: 1, + VotingPower: 30, + }, + { + EpochID: 1, + Index: 4, + VotingPower: 1, + }, + { + EpochID: 2, + Index: 3, + VotingPower: -2, + }, + } + + for _, seed := range seeds { + data, err := json.Marshal(seed) + if err != nil { + return + } + + f.Add(data) + } + + f.Fuzz(func(t *testing.T, input []byte) { + var data updateValidatorSetF + if err := json.Unmarshal(input, &data); err != nil { + t.Skip(err) + } + + if err := ValidateStruct(data); err != nil { + t.Skip(err) + } + + if data.Index > uint64(len(aliases)-1) { + t.Skip() + } + + err := state.StakeStore.insertFullValidatorSet(validatorSetState{ + Validators: newValidatorStakeMap(validators.GetPublicIdentities())}) + require.NoError(t, err) + + _, err = stakeManager.UpdateValidatorSet(data.EpochID, validators.GetPublicIdentities(aliases[data.Index:]...)) + require.NoError(t, err) + + fullValidatorSet := validators.GetPublicIdentities().Copy() + validatorToUpdate := fullValidatorSet[data.Index] + validatorToUpdate.VotingPower = big.NewInt(data.VotingPower) + + _, err = stakeManager.UpdateValidatorSet(data.EpochID, validators.GetPublicIdentities()) + require.NoError(t, err) + }) +} + +func ValidateStruct(s interface{}) (err error) { + structType := reflect.TypeOf(s) + if structType.Kind() != reflect.Struct { + return errors.New("input param should be a struct") + } + + structVal := reflect.ValueOf(s) + fieldNum := structVal.NumField() + + for i := 0; i < fieldNum; i++ { + field := structVal.Field(i) + fieldName := structType.Field(i).Name + + isSet := field.IsValid() && !field.IsZero() + + if !isSet { + err = fmt.Errorf("%w%s is not set; ", err, fieldName) + } + } + + return err +} diff --git a/consensus/polybft/stake_manager_test.go b/consensus/polybft/stake_manager_test.go new file mode 100644 index 0000000000..5546216450 --- /dev/null +++ b/consensus/polybft/stake_manager_test.go @@ -0,0 +1,559 @@ +package polybft + +import ( + "math/big" + "testing" + + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" + "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" + "github.com/0xPolygon/polygon-edge/helper/hex" + "github.com/0xPolygon/polygon-edge/txrelayer" + "github.com/0xPolygon/polygon-edge/types" + "github.com/hashicorp/go-hclog" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/umbracle/ethgo" + "github.com/umbracle/ethgo/abi" + "github.com/umbracle/ethgo/jsonrpc" +) + +func TestStakeManager_PostEpoch(t *testing.T) { + validators := validator.NewTestValidators(t, 5).GetPublicIdentities() + state := newTestState(t) + + stakeManager := &stakeManager{ + logger: hclog.NewNullLogger(), + state: state, + maxValidatorSetSize: 10, + } + + t.Run("Not first epoch", func(t *testing.T) { + require.NoError(t, stakeManager.PostEpoch(&PostEpochRequest{ + NewEpochID: 2, + ValidatorSet: validator.NewValidatorSet(validators, stakeManager.logger), + })) + + _, err := state.StakeStore.getFullValidatorSet() + require.ErrorIs(t, errNoFullValidatorSet, err) + }) + + t.Run("First epoch", func(t *testing.T) { + require.NoError(t, stakeManager.PostEpoch(&PostEpochRequest{ + NewEpochID: 1, + ValidatorSet: validator.NewValidatorSet(validators, stakeManager.logger), + })) + + fullValidatorSet, err := state.StakeStore.getFullValidatorSet() + require.NoError(t, err) + require.Len(t, fullValidatorSet.Validators, len(validators)) + require.Equal(t, uint64(0), fullValidatorSet.EpochID) + require.Equal(t, uint64(0), fullValidatorSet.BlockNumber) + }) +} + +func TestStakeManager_PostBlock(t *testing.T) { + t.Parallel() + + var ( + allAliases = []string{"A", "B", "C", "D", "E", "F"} + initialSetAliases = []string{"A", "B", "C", "D", "E"} + epoch = uint64(1) + block = uint64(10) + newStake = uint64(100) + firstValidator = uint64(0) + secondValidator = uint64(1) + ) + + state := newTestState(t) + t.Run("PostBlock - unstake to zero", func(t *testing.T) { + t.Parallel() + + validators := validator.NewTestValidatorsWithAliases(t, allAliases) + stakeManager := newStakeManager( + hclog.NewNullLogger(), + state, + nil, + wallet.NewEcdsaSigner(validators.GetValidator("A").Key()), + types.StringToAddress("0x0001"), types.StringToAddress("0x0002"), + nil, + 5, + ) + + // insert initial full validator set + require.NoError(t, state.StakeStore.insertFullValidatorSet(validatorSetState{ + Validators: newValidatorStakeMap(validators.GetPublicIdentities(initialSetAliases...)), + BlockNumber: block - 1, + })) + + receipt := &types.Receipt{ + Logs: []*types.Log{ + createTestLogForTransferEvent( + t, + stakeManager.validatorSetContract, + validators.GetValidator(initialSetAliases[firstValidator]).Address(), + types.ZeroAddress, + 1, // initial validator stake was 1 + ), + }, + } + + receipt.SetStatus(types.ReceiptSuccess) + + req := &PostBlockRequest{ + FullBlock: &types.FullBlock{Block: &types.Block{Header: &types.Header{Number: block}}, + Receipts: []*types.Receipt{receipt}, + }, + Epoch: epoch, + } + + require.NoError(t, stakeManager.PostBlock(req)) + + fullValidatorSet, err := state.StakeStore.getFullValidatorSet() + require.NoError(t, err) + var firstValidatorMeta *validator.ValidatorMetadata + firstValidatorMeta = nil + for _, validator := range fullValidatorSet.Validators { + if validator.Address.String() == validators.GetValidator(initialSetAliases[firstValidator]).Address().String() { + firstValidatorMeta = validator + } + } + require.NotNil(t, firstValidatorMeta) + require.Equal(t, bigZero, firstValidatorMeta.VotingPower) + require.False(t, firstValidatorMeta.IsActive) + }) + t.Run("PostBlock - add stake to one validator", func(t *testing.T) { + t.Parallel() + + validators := validator.NewTestValidatorsWithAliases(t, allAliases) + stakeManager := newStakeManager( + hclog.NewNullLogger(), + state, + nil, + wallet.NewEcdsaSigner(validators.GetValidator("A").Key()), + types.StringToAddress("0x0001"), types.StringToAddress("0x0002"), + nil, + 5, + ) + + // insert initial full validator set + require.NoError(t, state.StakeStore.insertFullValidatorSet(validatorSetState{ + Validators: newValidatorStakeMap(validators.GetPublicIdentities(initialSetAliases...)), + BlockNumber: block - 1, + })) + + receipt := &types.Receipt{ + Logs: []*types.Log{ + createTestLogForTransferEvent( + t, + stakeManager.validatorSetContract, + types.ZeroAddress, + validators.GetValidator(initialSetAliases[secondValidator]).Address(), + 250, + ), + }, + } + + receipt.SetStatus(types.ReceiptSuccess) + + req := &PostBlockRequest{ + FullBlock: &types.FullBlock{Block: &types.Block{Header: &types.Header{Number: block}}, + Receipts: []*types.Receipt{receipt}, + }, + Epoch: epoch, + } + + require.NoError(t, stakeManager.PostBlock(req)) + + fullValidatorSet, err := state.StakeStore.getFullValidatorSet() + require.NoError(t, err) + var firstValidaotor *validator.ValidatorMetadata + firstValidaotor = nil + for _, validator := range fullValidatorSet.Validators { + if validator.Address.String() == validators.GetValidator(initialSetAliases[secondValidator]).Address().String() { + firstValidaotor = validator + } + } + require.NotNil(t, firstValidaotor) + require.Equal(t, big.NewInt(251), firstValidaotor.VotingPower) // 250 + initial 1 + require.True(t, firstValidaotor.IsActive) + }) + + t.Run("PostBlock - add validator and stake", func(t *testing.T) { + t.Parallel() + + validators := validator.NewTestValidatorsWithAliases(t, allAliases, []uint64{1, 2, 3, 4, 5, 6}) + + txRelayerMock := newDummyStakeTxRelayer(t, func() *validator.ValidatorMetadata { + return validators.GetValidator("F").ValidatorMetadata() + }) + + // just mock the call however, the dummy relayer should do its magic + txRelayerMock.On("Call", mock.Anything, mock.Anything, mock.Anything). + Return(nil, error(nil)) + + stakeManager := newStakeManager( + hclog.NewNullLogger(), + state, + txRelayerMock, + wallet.NewEcdsaSigner(validators.GetValidator("A").Key()), + types.StringToAddress("0x0001"), types.StringToAddress("0x0002"), + nil, + 5, + ) + + // insert initial full validator set + require.NoError(t, state.StakeStore.insertFullValidatorSet(validatorSetState{ + Validators: newValidatorStakeMap(validators.GetPublicIdentities(initialSetAliases...)), + BlockNumber: block - 1, + })) + + receipts := make([]*types.Receipt, len(allAliases)) + for i := 0; i < len(allAliases); i++ { + receipts[i] = &types.Receipt{Logs: []*types.Log{ + createTestLogForTransferEvent( + t, + stakeManager.validatorSetContract, + types.ZeroAddress, + validators.GetValidator(allAliases[i]).Address(), + newStake, + ), + }} + receipts[i].SetStatus(types.ReceiptSuccess) + } + + req := &PostBlockRequest{ + FullBlock: &types.FullBlock{Block: &types.Block{Header: &types.Header{Number: block}}, + Receipts: receipts}, + Epoch: epoch, + } + + require.NoError(t, stakeManager.PostBlock(req)) + + fullValidatorSet, err := state.StakeStore.getFullValidatorSet() + require.NoError(t, err) + require.Len(t, fullValidatorSet.Validators, len(allAliases)) + + validatorsCount := validators.ToValidatorSet().Len() + for i, v := range fullValidatorSet.Validators.getSorted(validatorsCount) { + require.Equal(t, newStake+uint64(validatorsCount)-uint64(i)-1, v.VotingPower.Uint64()) + } + }) + + t.Run("PostBlock - add stake to one validator + missing block", func(t *testing.T) { + t.Parallel() + + receipt := &types.Receipt{} + header1, header2 := &types.Header{Hash: types.Hash{3, 2}}, &types.Header{Hash: types.Hash{6, 4}} + + bcMock := new(blockchainMock) + bcMock.On("GetHeaderByNumber", block-2).Return(header1, true).Once() + bcMock.On("GetHeaderByNumber", block-1).Return(header2, true).Once() + bcMock.On("GetReceiptsByHash", header1.Hash).Return([]*types.Receipt{receipt}, error(nil)).Once() + bcMock.On("GetReceiptsByHash", header2.Hash).Return([]*types.Receipt{}, error(nil)).Once() + + validators := validator.NewTestValidatorsWithAliases(t, allAliases) + stakeManager := newStakeManager( + hclog.NewNullLogger(), + state, + nil, + wallet.NewEcdsaSigner(validators.GetValidator("A").Key()), + types.StringToAddress("0x0001"), types.StringToAddress("0x0002"), + bcMock, + 5, + ) + + // insert initial full validator set + require.NoError(t, state.StakeStore.insertFullValidatorSet(validatorSetState{ + Validators: newValidatorStakeMap(validators.GetPublicIdentities(initialSetAliases...)), + BlockNumber: block - 3, + })) + + receipt.Logs = []*types.Log{ + createTestLogForTransferEvent( + t, + stakeManager.validatorSetContract, + types.ZeroAddress, + validators.GetValidator(initialSetAliases[secondValidator]).Address(), + 250, + ), + } + receipt.SetStatus(types.ReceiptSuccess) + + req := &PostBlockRequest{ + FullBlock: &types.FullBlock{Block: &types.Block{Header: &types.Header{Number: block}}, + Receipts: []*types.Receipt{receipt}, + }, + Epoch: epoch, + } + + require.NoError(t, stakeManager.PostBlock(req)) + + fullValidatorSet, err := state.StakeStore.getFullValidatorSet() + require.NoError(t, err) + var firstValidaotor *validator.ValidatorMetadata + firstValidaotor = nil + for _, validator := range fullValidatorSet.Validators { + if validator.Address.String() == validators.GetValidator(initialSetAliases[secondValidator]).Address().String() { + firstValidaotor = validator + } + } + require.NotNil(t, firstValidaotor) + require.Equal(t, big.NewInt(501), firstValidaotor.VotingPower) // 250 + 250 + initial 1 + require.True(t, firstValidaotor.IsActive) + + bcMock.AssertExpectations(t) + }) +} + +func TestStakeManager_UpdateValidatorSet(t *testing.T) { + var ( + aliases = []string{"A", "B", "C", "D", "E"} + stakes = []uint64{10, 10, 10, 10, 10} + epoch = uint64(1) + ) + + validators := validator.NewTestValidatorsWithAliases(t, aliases, stakes) + state := newTestState(t) + + stakeManager := newStakeManager( + hclog.NewNullLogger(), + state, + nil, + wallet.NewEcdsaSigner(validators.GetValidator("A").Key()), + types.StringToAddress("0x0001"), types.StringToAddress("0x0002"), + nil, + 10, + ) + + t.Run("UpdateValidatorSet - only update", func(t *testing.T) { + fullValidatorSet := validators.GetPublicIdentities().Copy() + validatorToUpdate := fullValidatorSet[0] + validatorToUpdate.VotingPower = big.NewInt(11) + + require.NoError(t, state.StakeStore.insertFullValidatorSet(validatorSetState{ + Validators: newValidatorStakeMap(fullValidatorSet), + })) + + updateDelta, err := stakeManager.UpdateValidatorSet(epoch, validators.GetPublicIdentities()) + require.NoError(t, err) + require.Len(t, updateDelta.Added, 0) + require.Len(t, updateDelta.Updated, 1) + require.Len(t, updateDelta.Removed, 0) + require.Equal(t, updateDelta.Updated[0].Address, validatorToUpdate.Address) + require.Equal(t, updateDelta.Updated[0].VotingPower.Uint64(), validatorToUpdate.VotingPower.Uint64()) + }) + + t.Run("UpdateValidatorSet - one unstake", func(t *testing.T) { + fullValidatorSet := validators.GetPublicIdentities(aliases[1:]...) + + require.NoError(t, state.StakeStore.insertFullValidatorSet(validatorSetState{ + Validators: newValidatorStakeMap(fullValidatorSet), + })) + + updateDelta, err := stakeManager.UpdateValidatorSet(epoch+1, validators.GetPublicIdentities()) + require.NoError(t, err) + require.Len(t, updateDelta.Added, 0) + require.Len(t, updateDelta.Updated, 0) + require.Len(t, updateDelta.Removed, 1) + }) + + t.Run("UpdateValidatorSet - one new validator", func(t *testing.T) { + addedValidator := validators.GetValidator("A") + + require.NoError(t, state.StakeStore.insertFullValidatorSet(validatorSetState{ + Validators: newValidatorStakeMap(validators.GetPublicIdentities()), + })) + + updateDelta, err := stakeManager.UpdateValidatorSet(epoch+2, + validators.GetPublicIdentities(aliases[1:]...)) + require.NoError(t, err) + require.Len(t, updateDelta.Added, 1) + require.Len(t, updateDelta.Updated, 0) + require.Len(t, updateDelta.Removed, 0) + require.Equal(t, addedValidator.Address(), updateDelta.Added[0].Address) + require.Equal(t, addedValidator.VotingPower, updateDelta.Added[0].VotingPower.Uint64()) + }) + t.Run("UpdateValidatorSet - remove some stake", func(t *testing.T) { + fullValidatorSet := validators.GetPublicIdentities().Copy() + validatorToUpdate := fullValidatorSet[2] + validatorToUpdate.VotingPower = big.NewInt(5) + require.NoError(t, state.StakeStore.insertFullValidatorSet(validatorSetState{ + Validators: newValidatorStakeMap(fullValidatorSet), + })) + + updateDelta, err := stakeManager.UpdateValidatorSet(epoch+3, validators.GetPublicIdentities()) + require.NoError(t, err) + require.Len(t, updateDelta.Added, 0) + require.Len(t, updateDelta.Updated, 1) + require.Len(t, updateDelta.Removed, 0) + require.Equal(t, updateDelta.Updated[0].Address, validatorToUpdate.Address) + require.Equal(t, updateDelta.Updated[0].VotingPower.Uint64(), validatorToUpdate.VotingPower.Uint64()) + }) + t.Run("UpdateValidatorSet - remove entire stake", func(t *testing.T) { + fullValidatorSet := validators.GetPublicIdentities().Copy() + validatorToUpdate := fullValidatorSet[3] + validatorToUpdate.VotingPower = bigZero + require.NoError(t, state.StakeStore.insertFullValidatorSet(validatorSetState{ + Validators: newValidatorStakeMap(fullValidatorSet), + })) + + updateDelta, err := stakeManager.UpdateValidatorSet(epoch+4, validators.GetPublicIdentities()) + require.NoError(t, err) + require.Len(t, updateDelta.Added, 0) + require.Len(t, updateDelta.Updated, 0) + require.Len(t, updateDelta.Removed, 1) + }) + t.Run("UpdateValidatorSet - voting power negative", func(t *testing.T) { + fullValidatorSet := validators.GetPublicIdentities().Copy() + validatorsToUpdate := fullValidatorSet[4] + validatorsToUpdate.VotingPower = bigZero + require.NoError(t, state.StakeStore.insertFullValidatorSet(validatorSetState{ + Validators: newValidatorStakeMap(fullValidatorSet), + })) + + updateDelta, err := stakeManager.UpdateValidatorSet(epoch+5, validators.GetPublicIdentities()) + require.NoError(t, err) + require.Len(t, updateDelta.Added, 0) + require.Len(t, updateDelta.Updated, 0) + require.Len(t, updateDelta.Removed, 1) + }) + + t.Run("UpdateValidatorSet - max validator set size reached", func(t *testing.T) { + // because we now have 5 validators, and the new validator has more stake + stakeManager.maxValidatorSetSize = 4 + + fullValidatorSet := validators.GetPublicIdentities().Copy() + validatorToAdd := fullValidatorSet[0] + validatorToAdd.VotingPower = big.NewInt(11) + + require.NoError(t, state.StakeStore.insertFullValidatorSet(validatorSetState{ + Validators: newValidatorStakeMap(fullValidatorSet), + })) + + updateDelta, err := stakeManager.UpdateValidatorSet(epoch+6, + validators.GetPublicIdentities(aliases[1:]...)) + + require.NoError(t, err) + require.Len(t, updateDelta.Added, 1) + require.Len(t, updateDelta.Updated, 0) + require.Len(t, updateDelta.Removed, 1) + require.Equal(t, validatorToAdd.Address, updateDelta.Added[0].Address) + require.Equal(t, validatorToAdd.VotingPower.Uint64(), updateDelta.Added[0].VotingPower.Uint64()) + }) +} + +func TestStakeCounter_ShouldBeDeterministic(t *testing.T) { + t.Parallel() + + const timesToExecute = 100 + + stakes := [][]uint64{ + {103, 102, 101, 51, 50, 30, 10}, + {100, 100, 100, 50, 50, 30, 10}, + {103, 102, 101, 51, 50, 30, 10}, + {100, 100, 100, 50, 50, 30, 10}, + } + maxValidatorSetSizes := []int{1000, 1000, 5, 6} + + for ind, stake := range stakes { + maxValidatorSetSize := maxValidatorSetSizes[ind] + + aliases := []string{"A", "B", "C", "D", "E", "F", "G"} + validators := validator.NewTestValidatorsWithAliases(t, aliases, stake) + + test := func() []*validator.ValidatorMetadata { + stakeCounter := newValidatorStakeMap(validators.GetPublicIdentities("A", "B", "C", "D", "E")) + + return stakeCounter.getSorted(maxValidatorSetSize) + } + + initialSlice := test() + + // stake counter and stake map should always be deterministic + for i := 0; i < timesToExecute; i++ { + currentSlice := test() + + require.Len(t, currentSlice, len(initialSlice)) + + for i, si := range currentSlice { + initialSi := initialSlice[i] + require.Equal(t, si.Address, initialSi.Address) + require.Equal(t, si.VotingPower.Uint64(), initialSi.VotingPower.Uint64()) + } + } + } +} + +func createTestLogForTransferEvent(t *testing.T, validatorSet, from, to types.Address, stake uint64) *types.Log { + t.Helper() + + var transferEvent contractsapi.TransferEvent + + topics := make([]types.Hash, 3) + topics[0] = types.Hash(transferEvent.Sig()) + topics[1] = types.BytesToHash(from.Bytes()) + topics[2] = types.BytesToHash(to.Bytes()) + encodedData, err := abi.MustNewType("uint256").Encode(new(big.Int).SetUint64(stake)) + require.NoError(t, err) + + return &types.Log{ + Address: validatorSet, + Topics: topics, + Data: encodedData, + } +} + +var _ txrelayer.TxRelayer = (*dummyStakeTxRelayer)(nil) + +type dummyStakeTxRelayer struct { + mock.Mock + callback func() *validator.ValidatorMetadata + t *testing.T +} + +func newDummyStakeTxRelayer(t *testing.T, callback func() *validator.ValidatorMetadata) *dummyStakeTxRelayer { + t.Helper() + + return &dummyStakeTxRelayer{ + t: t, + callback: callback, + } +} + +func (d *dummyStakeTxRelayer) Call(from ethgo.Address, to ethgo.Address, input []byte) (string, error) { + args := d.Called(from, to, input) + + if d.callback != nil { + validatorMetaData := d.callback() + encoded, err := validatorTypeABI.Encode(map[string]interface{}{ + "blsKey": validatorMetaData.BlsKey.ToBigInt(), + "stake": validatorMetaData.VotingPower, + "isWhitelisted": true, + "isActive": true, + }) + + require.NoError(d.t, err) + + return hex.EncodeToHex(encoded), nil + } + + return args.String(0), args.Error(1) +} + +func (d *dummyStakeTxRelayer) SendTransaction(transaction *ethgo.Transaction, key ethgo.Key) (*ethgo.Receipt, error) { + args := d.Called(transaction, key) + + return args.Get(0).(*ethgo.Receipt), args.Error(1) //nolint:forcetypeassert +} + +// SendTransactionLocal sends non-signed transaction (this is only for testing purposes) +func (d *dummyStakeTxRelayer) SendTransactionLocal(txn *ethgo.Transaction) (*ethgo.Receipt, error) { + args := d.Called(txn) + + return args.Get(0).(*ethgo.Receipt), args.Error(1) //nolint:forcetypeassert +} + +func (d *dummyStakeTxRelayer) Client() *jsonrpc.Client { + return nil +} diff --git a/consensus/polybft/state.go b/consensus/polybft/state.go index 83a71650f6..3e36e1ee01 100644 --- a/consensus/polybft/state.go +++ b/consensus/polybft/state.go @@ -54,6 +54,7 @@ type State struct { CheckpointStore *CheckpointStore EpochStore *EpochStore ProposerSnapshotStore *ProposerSnapshotStore + StakeStore *StakeStore } // newState creates new instance of State @@ -70,6 +71,7 @@ func newState(path string, logger hclog.Logger, closeCh chan struct{}) (*State, CheckpointStore: &CheckpointStore{db: db}, EpochStore: &EpochStore{db: db}, ProposerSnapshotStore: &ProposerSnapshotStore{db: db}, + StakeStore: &StakeStore{db: db}, } if err = s.initStorages(); err != nil { @@ -82,7 +84,7 @@ func newState(path string, logger hclog.Logger, closeCh chan struct{}) (*State, // initStorages initializes data storages func (s *State) initStorages() error { // init the buckets - err := s.db.Update(func(tx *bolt.Tx) error { + return s.db.Update(func(tx *bolt.Tx) error { if err := s.StateSyncStore.initialize(tx); err != nil { return err } @@ -96,10 +98,8 @@ func (s *State) initStorages() error { return err } - return nil + return s.StakeStore.initialize(tx) }) - - return err } // bucketStats returns stats for the given bucket in db diff --git a/consensus/polybft/state_store_checkpoint.go b/consensus/polybft/state_store_checkpoint.go index 6f5803baa2..4f56a36af8 100644 --- a/consensus/polybft/state_store_checkpoint.go +++ b/consensus/polybft/state_store_checkpoint.go @@ -173,14 +173,14 @@ func decodeExitEvent(log *ethgo.Log, epoch, block uint64) (*ExitEvent, error) { var l2StateSyncedEvent contractsapi.L2StateSyncedEvent doesMatch, err := l2StateSyncedEvent.ParseLog(log) - if !doesMatch { - return nil, nil - } - if err != nil { return nil, err } + if !doesMatch { + return nil, nil + } + return &ExitEvent{ ID: l2StateSyncedEvent.ID.Uint64(), Sender: ethgo.Address(l2StateSyncedEvent.Sender), @@ -195,10 +195,12 @@ func decodeExitEvent(log *ethgo.Log, epoch, block uint64) (*ExitEvent, error) { func convertLog(log *types.Log) *ethgo.Log { l := ðgo.Log{ Address: ethgo.Address(log.Address), - Data: log.Data, + Data: make([]byte, len(log.Data)), Topics: make([]ethgo.Hash, len(log.Topics)), } + copy(l.Data, log.Data) + for i, topic := range log.Topics { l.Topics[i] = ethgo.Hash(topic) } diff --git a/consensus/polybft/state_store_epoch.go b/consensus/polybft/state_store_epoch.go index 88b1fd3fbf..e1b7e5e983 100644 --- a/consensus/polybft/state_store_epoch.go +++ b/consensus/polybft/state_store_epoch.go @@ -33,6 +33,9 @@ epochs/ |--> epochNumber |--> hash -> []*MessageSignatures (json marshalled) +epochs/ +|--> epochNumber -> []*TransferEvent (json marshalled) + validatorSnapshots/ |--> epochNumber -> *AccountSet (json marshalled) */ @@ -110,6 +113,9 @@ func (s *EpochStore) insertEpoch(epoch uint64) error { return err } _, err = epochBucket.CreateBucketIfNotExists(messageVotesBucket) + if err != nil { + return err + } return err }) @@ -217,3 +223,18 @@ func (s *EpochStore) epochsDBStats() (*bolt.BucketStats, error) { func (s *EpochStore) validatorSnapshotsDBStats() (*bolt.BucketStats, error) { return bucketStats(validatorSnapshotsBucket, s.db) } + +// getNestedBucketInEpoch returns a nested (child) bucket from db associated with given epoch +func getNestedBucketInEpoch(tx *bolt.Tx, epoch uint64, bucketKey []byte) (*bolt.Bucket, error) { + epochBucket, err := getEpochBucket(tx, epoch) + if err != nil { + return nil, err + } + + bucket := epochBucket.Bucket(bucketKey) + if bucket == nil { + return nil, fmt.Errorf("could not find %v bucket for epoch: %v", string(bucketKey), epoch) + } + + return bucket, nil +} diff --git a/consensus/polybft/state_store_epoch_test.go b/consensus/polybft/state_store_epoch_test.go index 34a32a7b2d..15fb4604c3 100644 --- a/consensus/polybft/state_store_epoch_test.go +++ b/consensus/polybft/state_store_epoch_test.go @@ -6,6 +6,7 @@ import ( "testing" bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -24,10 +25,10 @@ func TestState_insertAndGetValidatorSnapshot(t *testing.T) { require.NoError(t, err) - snapshot := AccountSet{ - &ValidatorMetadata{Address: types.BytesToAddress([]byte{0x18}), BlsKey: keys[0].PublicKey()}, - &ValidatorMetadata{Address: types.BytesToAddress([]byte{0x23}), BlsKey: keys[1].PublicKey()}, - &ValidatorMetadata{Address: types.BytesToAddress([]byte{0x37}), BlsKey: keys[2].PublicKey()}, + snapshot := validator.AccountSet{ + &validator.ValidatorMetadata{Address: types.BytesToAddress([]byte{0x18}), BlsKey: keys[0].PublicKey()}, + &validator.ValidatorMetadata{Address: types.BytesToAddress([]byte{0x23}), BlsKey: keys[1].PublicKey()}, + &validator.ValidatorMetadata{Address: types.BytesToAddress([]byte{0x37}), BlsKey: keys[2].PublicKey()}, } assert.NoError(t, state.EpochStore.insertValidatorSnapshot(&validatorSnapshot{epoch, epochEndingBlock, snapshot})) @@ -53,10 +54,10 @@ func TestState_cleanValidatorSnapshotsFromDb(t *testing.T) { keys, err := bls.CreateRandomBlsKeys(3) require.NoError(t, err) - snapshot := AccountSet{ - &ValidatorMetadata{Address: types.BytesToAddress([]byte{0x18}), BlsKey: keys[0].PublicKey()}, - &ValidatorMetadata{Address: types.BytesToAddress([]byte{0x23}), BlsKey: keys[1].PublicKey()}, - &ValidatorMetadata{Address: types.BytesToAddress([]byte{0x37}), BlsKey: keys[2].PublicKey()}, + snapshot := validator.AccountSet{ + &validator.ValidatorMetadata{Address: types.BytesToAddress([]byte{0x18}), BlsKey: keys[0].PublicKey()}, + &validator.ValidatorMetadata{Address: types.BytesToAddress([]byte{0x23}), BlsKey: keys[1].PublicKey()}, + &validator.ValidatorMetadata{Address: types.BytesToAddress([]byte{0x37}), BlsKey: keys[2].PublicKey()}, } var epoch uint64 @@ -198,9 +199,9 @@ func TestState_getLastSnapshot(t *testing.T) { require.NoError(t, err) - var snapshot AccountSet + var snapshot validator.AccountSet for j := 0; j < numberOfValidators; j++ { - snapshot = append(snapshot, &ValidatorMetadata{Address: types.BytesToAddress(generateRandomBytes(t)), BlsKey: keys[j].PublicKey()}) + snapshot = append(snapshot, &validator.ValidatorMetadata{Address: types.BytesToAddress(generateRandomBytes(t)), BlsKey: keys[j].PublicKey()}) } require.NoError(t, state.EpochStore.insertValidatorSnapshot(&validatorSnapshot{i, i * fixedEpochSize, snapshot})) diff --git a/consensus/polybft/state_store_stake.go b/consensus/polybft/state_store_stake.go new file mode 100644 index 0000000000..ae2080c662 --- /dev/null +++ b/consensus/polybft/state_store_stake.go @@ -0,0 +1,58 @@ +package polybft + +import ( + "errors" + "fmt" + + bolt "go.etcd.io/bbolt" +) + +var ( + // bucket to store full validator set + validatorSetBucket = []byte("fullValidatorSetBucket") + // key of the full validator set in bucket + fullValidatorSetKey = []byte("fullValidatorSet") + // error returned if full validator set does not exists in db + errNoFullValidatorSet = errors.New("full validator set not in db") +) + +type StakeStore struct { + db *bolt.DB +} + +// initialize creates necessary buckets in DB if they don't already exist +func (s *StakeStore) initialize(tx *bolt.Tx) error { + if _, err := tx.CreateBucketIfNotExists(validatorSetBucket); err != nil { + return fmt.Errorf("failed to create bucket=%s: %w", string(epochsBucket), err) + } + + return nil +} + +// insertFullValidatorSet inserts full validator set to its bucket (or updates it if exists) +func (s *StakeStore) insertFullValidatorSet(fullValidatorSet validatorSetState) error { + return s.db.Update(func(tx *bolt.Tx) error { + raw, err := fullValidatorSet.Marshal() + if err != nil { + return err + } + + return tx.Bucket(validatorSetBucket).Put(fullValidatorSetKey, raw) + }) +} + +// getFullValidatorSet returns full validator set from its bucket if exists +func (s *StakeStore) getFullValidatorSet() (validatorSetState, error) { + var fullValidatorSet validatorSetState + + err := s.db.View(func(tx *bolt.Tx) error { + raw := tx.Bucket(validatorSetBucket).Get(fullValidatorSetKey) + if raw == nil { + return errNoFullValidatorSet + } + + return fullValidatorSet.Unmarshal(raw) + }) + + return fullValidatorSet, err +} diff --git a/consensus/polybft/state_store_stake_test.go b/consensus/polybft/state_store_stake_test.go new file mode 100644 index 0000000000..4db0c2dc34 --- /dev/null +++ b/consensus/polybft/state_store_stake_test.go @@ -0,0 +1,51 @@ +package polybft + +import ( + "testing" + + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestState_Insert_And_Get_FullValidatorSet(t *testing.T) { + state := newTestState(t) + + t.Run("No full validator set", func(t *testing.T) { + _, err := state.StakeStore.getFullValidatorSet() + + require.ErrorIs(t, err, errNoFullValidatorSet) + }) + + t.Run("Insert validator set", func(t *testing.T) { + validators := validator.NewTestValidators(t, 5).GetPublicIdentities() + + assert.NoError(t, state.StakeStore.insertFullValidatorSet(validatorSetState{ + BlockNumber: 100, + EpochID: 10, + Validators: newValidatorStakeMap(validators), + })) + + fullValidatorSet, err := state.StakeStore.getFullValidatorSet() + require.NoError(t, err) + assert.Equal(t, uint64(100), fullValidatorSet.BlockNumber) + assert.Equal(t, uint64(10), fullValidatorSet.EpochID) + assert.Len(t, fullValidatorSet.Validators, len(validators)) + }) + + t.Run("Update validator set", func(t *testing.T) { + validators := validator.NewTestValidators(t, 10).GetPublicIdentities() + + assert.NoError(t, state.StakeStore.insertFullValidatorSet(validatorSetState{ + BlockNumber: 40, + EpochID: 4, + Validators: newValidatorStakeMap(validators), + })) + + fullValidatorSet, err := state.StakeStore.getFullValidatorSet() + require.NoError(t, err) + assert.Len(t, fullValidatorSet.Validators, len(validators)) + assert.Equal(t, uint64(40), fullValidatorSet.BlockNumber) + assert.Equal(t, uint64(4), fullValidatorSet.EpochID) + }) +} diff --git a/consensus/polybft/state_store_state_sync.go b/consensus/polybft/state_store_state_sync.go index 67cfb91db3..d15606500b 100644 --- a/consensus/polybft/state_store_state_sync.go +++ b/consensus/polybft/state_store_state_sync.go @@ -59,10 +59,6 @@ func (s *StateSyncStore) initialize(tx *bolt.Tx) error { return fmt.Errorf("failed to create bucket=%s: %w", string(stateSyncProofsBucket), err) } - if _, err := tx.CreateBucketIfNotExists(messageVotesBucket); err != nil { - return fmt.Errorf("failed to create bucket=%s: %w", string(messageVotesBucket), err) - } - return nil } @@ -224,11 +220,7 @@ func (s *StateSyncStore) insertMessageVote(epoch uint64, key []byte, vote *Messa return err } - if err := bucket.Put(key, raw); err != nil { - return err - } - - return nil + return bucket.Put(key, raw) }) if err != nil { @@ -279,21 +271,6 @@ func (s *StateSyncStore) getMessageVotesLocked(tx *bolt.Tx, epoch uint64, hash [ return signatures, nil } -// getNestedBucketInEpoch returns a nested (child) bucket from db associated with given epoch -func getNestedBucketInEpoch(tx *bolt.Tx, epoch uint64, bucketKey []byte) (*bolt.Bucket, error) { - epochBucket, err := getEpochBucket(tx, epoch) - if err != nil { - return nil, err - } - - bucket := epochBucket.Bucket(bucketKey) - if bucket == nil { - return nil, fmt.Errorf("could not find %v bucket for epoch: %v", string(bucketKey), epoch) - } - - return bucket, nil -} - // insertStateSyncProofs inserts the provided state sync proofs to db func (s *StateSyncStore) insertStateSyncProofs(stateSyncProof []*StateSyncProof) error { return s.db.Update(func(tx *bolt.Tx) error { diff --git a/consensus/polybft/state_sync_commitment.go b/consensus/polybft/state_sync_commitment.go new file mode 100644 index 0000000000..6f109d834f --- /dev/null +++ b/consensus/polybft/state_sync_commitment.go @@ -0,0 +1,202 @@ +package polybft + +import ( + "bytes" + "errors" + "fmt" + + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" + "github.com/0xPolygon/polygon-edge/crypto" + "github.com/0xPolygon/polygon-edge/merkle-tree" + "github.com/0xPolygon/polygon-edge/state/runtime/precompiled" + "github.com/0xPolygon/polygon-edge/types" +) + +const ( + stTypeBridgeCommitment = "commitment" + stTypeEndEpoch = "end-epoch" +) + +// PendingCommitment holds merkle trie of bridge transactions accompanied by epoch number +type PendingCommitment struct { + *contractsapi.StateSyncCommitment + MerkleTree *merkle.MerkleTree + Epoch uint64 +} + +// NewPendingCommitment creates a new commitment object +func NewPendingCommitment(epoch uint64, stateSyncEvents []*contractsapi.StateSyncedEvent) (*PendingCommitment, error) { + tree, err := createMerkleTree(stateSyncEvents) + if err != nil { + return nil, err + } + + return &PendingCommitment{ + MerkleTree: tree, + Epoch: epoch, + StateSyncCommitment: &contractsapi.StateSyncCommitment{ + StartID: stateSyncEvents[0].ID, + EndID: stateSyncEvents[len(stateSyncEvents)-1].ID, + Root: tree.Hash(), + }, + }, nil +} + +// Hash calculates hash value for commitment object. +func (cm *PendingCommitment) Hash() (types.Hash, error) { + data, err := cm.StateSyncCommitment.EncodeAbi() + if err != nil { + return types.Hash{}, err + } + + return crypto.Keccak256Hash(data), nil +} + +var _ contractsapi.StateTransactionInput = &CommitmentMessageSigned{} + +// CommitmentMessageSigned encapsulates commitment message with aggregated signatures +type CommitmentMessageSigned struct { + Message *contractsapi.StateSyncCommitment + AggSignature Signature + PublicKeys [][]byte +} + +// Hash calculates hash value for commitment object. +func (cm *CommitmentMessageSigned) Hash() (types.Hash, error) { + data, err := cm.Message.EncodeAbi() + if err != nil { + return types.Hash{}, err + } + + return crypto.Keccak256Hash(data), nil +} + +// VerifyStateSyncProof validates given state sync proof +// against merkle tree root hash contained in the CommitmentMessage +func (cm *CommitmentMessageSigned) VerifyStateSyncProof(proof []types.Hash, + stateSync *contractsapi.StateSyncedEvent) error { + if stateSync == nil { + return errors.New("no state sync event") + } + + if stateSync.ID.Uint64() < cm.Message.StartID.Uint64() || + stateSync.ID.Uint64() > cm.Message.EndID.Uint64() { + return errors.New("invalid state sync ID") + } + + hash, err := stateSync.EncodeAbi() + if err != nil { + return err + } + + return merkle.VerifyProof(stateSync.ID.Uint64()-cm.Message.StartID.Uint64(), + hash, proof, cm.Message.Root) +} + +// ContainsStateSync checks if commitment contains given state sync event +func (cm *CommitmentMessageSigned) ContainsStateSync(stateSyncID uint64) bool { + return cm.Message.StartID.Uint64() <= stateSyncID && cm.Message.EndID.Uint64() >= stateSyncID +} + +// EncodeAbi contains logic for encoding arbitrary data into ABI format +func (cm *CommitmentMessageSigned) EncodeAbi() ([]byte, error) { + blsVerificationPart, err := precompiled.BlsVerificationABIType.Encode( + [2]interface{}{cm.PublicKeys, cm.AggSignature.Bitmap}) + if err != nil { + return nil, err + } + + commit := &contractsapi.CommitStateReceiverFn{ + Commitment: cm.Message, + Signature: cm.AggSignature.AggregatedSignature, + Bitmap: blsVerificationPart, + } + + return commit.EncodeAbi() +} + +// DecodeAbi contains logic for decoding given ABI data +func (cm *CommitmentMessageSigned) DecodeAbi(txData []byte) error { + if len(txData) < abiMethodIDLength { + return fmt.Errorf("invalid commitment data, len = %d", len(txData)) + } + + commit := contractsapi.CommitStateReceiverFn{} + + err := commit.DecodeAbi(txData) + if err != nil { + return err + } + + decoded, err := precompiled.BlsVerificationABIType.Decode(commit.Bitmap) + if err != nil { + return err + } + + blsMap, isOk := decoded.(map[string]interface{}) + if !isOk { + return fmt.Errorf("invalid commitment data. Bls verification part not in correct format") + } + + publicKeys, isOk := blsMap["0"].([][]byte) + if !isOk { + return fmt.Errorf("invalid commitment data. Could not find public keys part") + } + + bitmap, isOk := blsMap["1"].([]byte) + if !isOk { + return fmt.Errorf("invalid commitment data. Could not find bitmap part") + } + + *cm = CommitmentMessageSigned{ + Message: commit.Commitment, + AggSignature: Signature{ + AggregatedSignature: commit.Signature, + Bitmap: bitmap, + }, + PublicKeys: publicKeys, + } + + return nil +} + +// getCommitmentMessageSignedTx returns a CommitmentMessageSigned object from a commit state transaction +func getCommitmentMessageSignedTx(txs []*types.Transaction) (*CommitmentMessageSigned, error) { + var commitFn contractsapi.CommitStateReceiverFn + for _, tx := range txs { + // skip non state CommitmentMessageSigned transactions + if tx.Type != types.StateTx || + len(tx.Input) < abiMethodIDLength || + !bytes.Equal(tx.Input[:abiMethodIDLength], commitFn.Sig()) { + continue + } + + obj := &CommitmentMessageSigned{} + + if err := obj.DecodeAbi(tx.Input); err != nil { + return nil, fmt.Errorf("get commitment message signed tx error: %w", err) + } + + return obj, nil + } + + return nil, nil +} + +// createMerkleTree creates a merkle tree from provided state sync events +// if only one state sync event is provided, a second, empty leaf will be added to merkle tree +// so that we can have a commitment with a single state sync event +func createMerkleTree(stateSyncEvents []*contractsapi.StateSyncedEvent) (*merkle.MerkleTree, error) { + stateSyncData := make([][]byte, len(stateSyncEvents)) + + for i, sse := range stateSyncEvents { + data, err := sse.EncodeAbi() + if err != nil { + return nil, err + } + + stateSyncData[i] = data + } + + return merkle.NewMerkleTree(stateSyncData) +} diff --git a/consensus/polybft/state_sync_commitment_test.go b/consensus/polybft/state_sync_commitment_test.go new file mode 100644 index 0000000000..61018f7517 --- /dev/null +++ b/consensus/polybft/state_sync_commitment_test.go @@ -0,0 +1,178 @@ +package polybft + +import ( + "math/big" + "testing" + + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" + "github.com/0xPolygon/polygon-edge/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestCommitmentMessage_Hash(t *testing.T) { + t.Parallel() + + const ( + eventsCount = 10 + ) + + stateSyncEvents := generateStateSyncEvents(t, eventsCount, 0) + + trie1, err := createMerkleTree(stateSyncEvents) + require.NoError(t, err) + + trie2, err := createMerkleTree(stateSyncEvents[0 : len(stateSyncEvents)-1]) + require.NoError(t, err) + + commitmentMessage1 := newTestCommitmentSigned(t, trie1.Hash(), 2, 8) + commitmentMessage2 := newTestCommitmentSigned(t, trie1.Hash(), 2, 8) + commitmentMessage3 := newTestCommitmentSigned(t, trie1.Hash(), 6, 10) + commitmentMessage4 := newTestCommitmentSigned(t, trie2.Hash(), 2, 8) + + hash1, err := commitmentMessage1.Hash() + require.NoError(t, err) + hash2, err := commitmentMessage2.Hash() + require.NoError(t, err) + hash3, err := commitmentMessage3.Hash() + require.NoError(t, err) + hash4, err := commitmentMessage4.Hash() + require.NoError(t, err) + + require.Equal(t, hash1, hash2) + require.NotEqual(t, hash1, hash3) + require.NotEqual(t, hash1, hash4) + require.NotEqual(t, hash3, hash4) +} + +func TestCommitmentMessage_ToRegisterCommitmentInputData(t *testing.T) { + t.Parallel() + + const epoch, eventsCount = uint64(100), 11 + pendingCommitment, _, _ := buildCommitmentAndStateSyncs(t, eventsCount, epoch, uint64(2)) + expectedSignedCommitmentMsg := &CommitmentMessageSigned{ + Message: pendingCommitment.StateSyncCommitment, + AggSignature: Signature{ + Bitmap: []byte{5, 1}, + AggregatedSignature: []byte{1, 1}, + }, + PublicKeys: [][]byte{{0, 1}, {2, 3}, {4, 5}}, + } + inputData, err := expectedSignedCommitmentMsg.EncodeAbi() + require.NoError(t, err) + require.NotEmpty(t, inputData) + + var actualSignedCommitmentMsg CommitmentMessageSigned + + require.NoError(t, actualSignedCommitmentMsg.DecodeAbi(inputData)) + require.NoError(t, err) + require.Equal(t, *expectedSignedCommitmentMsg.Message, *actualSignedCommitmentMsg.Message) + require.Equal(t, expectedSignedCommitmentMsg.AggSignature, actualSignedCommitmentMsg.AggSignature) +} + +func TestCommitmentMessage_VerifyProof(t *testing.T) { + t.Parallel() + + const epoch, eventsCount = uint64(100), 11 + commitment, commitmentSigned, stateSyncs := buildCommitmentAndStateSyncs(t, eventsCount, epoch, 0) + require.Equal(t, uint64(10), commitment.EndID.Sub(commitment.EndID, commitment.StartID).Uint64()) + + for _, stateSync := range stateSyncs { + leaf, err := stateSync.EncodeAbi() + require.NoError(t, err) + + proof, err := commitment.MerkleTree.GenerateProof(leaf) + require.NoError(t, err) + + execute := &contractsapi.ExecuteStateReceiverFn{ + Proof: proof, + Obj: (*contractsapi.StateSync)(stateSync), + } + + inputData, err := execute.EncodeAbi() + require.NoError(t, err) + + executionStateSync := &contractsapi.ExecuteStateReceiverFn{} + require.NoError(t, executionStateSync.DecodeAbi(inputData)) + require.Equal(t, stateSync.ID.Uint64(), executionStateSync.Obj.ID.Uint64()) + require.Equal(t, stateSync.Sender, executionStateSync.Obj.Sender) + require.Equal(t, stateSync.Receiver, executionStateSync.Obj.Receiver) + require.Equal(t, stateSync.Data, executionStateSync.Obj.Data) + require.Equal(t, proof, executionStateSync.Proof) + + err = commitmentSigned.VerifyStateSyncProof(executionStateSync.Proof, + (*contractsapi.StateSyncedEvent)(executionStateSync.Obj)) + require.NoError(t, err) + } +} + +func TestCommitmentMessage_VerifyProof_NoStateSyncsInCommitment(t *testing.T) { + t.Parallel() + + commitment := &CommitmentMessageSigned{Message: &contractsapi.StateSyncCommitment{StartID: big.NewInt(1), EndID: big.NewInt(10)}} + err := commitment.VerifyStateSyncProof([]types.Hash{}, nil) + assert.ErrorContains(t, err, "no state sync event") +} + +func TestCommitmentMessage_VerifyProof_StateSyncHashNotEqualToProof(t *testing.T) { + t.Parallel() + + const ( + fromIndex = 0 + toIndex = 4 + ) + + stateSyncs := generateStateSyncEvents(t, 5, 0) + tree, err := createMerkleTree(stateSyncs) + require.NoError(t, err) + + leaf, err := stateSyncs[0].EncodeAbi() + require.NoError(t, err) + + proof, err := tree.GenerateProof(leaf) + require.NoError(t, err) + + commitment := &CommitmentMessageSigned{ + Message: &contractsapi.StateSyncCommitment{ + StartID: big.NewInt(fromIndex), + EndID: big.NewInt(toIndex), + Root: tree.Hash(), + }, + } + + assert.ErrorContains(t, commitment.VerifyStateSyncProof(proof, stateSyncs[4]), "not a member of merkle tree") +} + +func newTestCommitmentSigned(t *testing.T, root types.Hash, startID, endID int64) *CommitmentMessageSigned { + t.Helper() + + return &CommitmentMessageSigned{ + Message: &contractsapi.StateSyncCommitment{ + StartID: big.NewInt(startID), + EndID: big.NewInt(endID), + Root: root, + }, + AggSignature: Signature{}, + PublicKeys: [][]byte{}, + } +} + +func buildCommitmentAndStateSyncs(t *testing.T, stateSyncsCount int, + epoch, startIdx uint64) (*PendingCommitment, *CommitmentMessageSigned, []*contractsapi.StateSyncedEvent) { + t.Helper() + + stateSyncEvents := generateStateSyncEvents(t, stateSyncsCount, startIdx) + commitment, err := NewPendingCommitment(epoch, stateSyncEvents) + require.NoError(t, err) + + commitmentSigned := &CommitmentMessageSigned{ + Message: commitment.StateSyncCommitment, + AggSignature: Signature{ + AggregatedSignature: []byte{}, + Bitmap: []byte{}, + }, + PublicKeys: [][]byte{}, + } + + return commitment, commitmentSigned, stateSyncEvents +} diff --git a/consensus/polybft/state_sync_manager.go b/consensus/polybft/state_sync_manager.go index 4a8959bd32..3d7d3d352d 100644 --- a/consensus/polybft/state_sync_manager.go +++ b/consensus/polybft/state_sync_manager.go @@ -13,6 +13,7 @@ import ( "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" polybftProto "github.com/0xPolygon/polygon-edge/consensus/polybft/proto" bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" "github.com/0xPolygon/polygon-edge/tracker" "github.com/0xPolygon/polygon-edge/types" @@ -22,12 +23,6 @@ import ( "google.golang.org/protobuf/proto" ) -const ( - // minimum number of stateSyncEvents that a commitment can have - // (minimum number is 2 because smart contract expects that the merkle tree has at least two leaves) - minCommitmentSize = 2 -) - type StateSyncProof struct { Proof []types.Hash StateSync *contractsapi.StateSyncedEvent @@ -83,7 +78,7 @@ type stateSyncManager struct { // per epoch fields lock sync.RWMutex pendingCommitments []*PendingCommitment - validatorSet ValidatorSet + validatorSet validator.ValidatorSet epoch uint64 nextCommittedIndex uint64 } @@ -95,15 +90,13 @@ type topic interface { } // newStateSyncManager creates a new instance of state sync manager -func newStateSyncManager(logger hclog.Logger, state *State, config *stateSyncConfig) (*stateSyncManager, error) { - s := &stateSyncManager{ +func newStateSyncManager(logger hclog.Logger, state *State, config *stateSyncConfig) *stateSyncManager { + return &stateSyncManager{ logger: logger, state: state, config: config, closeCh: make(chan struct{}), } - - return s, nil } // Init subscribes to bridge topics (getting votes) and start the event tracker routine @@ -205,7 +198,7 @@ func (s *stateSyncManager) saveVote(msg *TransportMessage) error { } // Verifies signature of the message against the public key of the signer and checks if the signer is a validator -func (s *stateSyncManager) verifyVoteSignature(valSet ValidatorSet, signer types.Address, signature []byte, +func (s *stateSyncManager) verifyVoteSignature(valSet validator.ValidatorSet, signer types.Address, signature []byte, hash []byte) error { validator := valSet.Accounts().GetValidatorMetadata(signer) if validator == nil { @@ -502,17 +495,14 @@ func (s *stateSyncManager) buildCommitment() error { s.lock.Lock() defer s.lock.Unlock() - epoch := s.epoch - fromIndex := s.nextCommittedIndex - - stateSyncEvents, err := s.state.StateSyncStore.getStateSyncEventsForCommitment(fromIndex, - fromIndex+s.config.maxCommitmentSize-1) + stateSyncEvents, err := s.state.StateSyncStore.getStateSyncEventsForCommitment(s.nextCommittedIndex, + s.nextCommittedIndex+s.config.maxCommitmentSize-1) if err != nil && !errors.Is(err, errNotEnoughStateSyncs) { return fmt.Errorf("failed to get state sync events for commitment. Error: %w", err) } - if len(stateSyncEvents) < minCommitmentSize { - // there is not enough state sync events to build at least the minimum commitment + if len(stateSyncEvents) == 0 { + // there are no state sync events return nil } @@ -522,7 +512,7 @@ func (s *stateSyncManager) buildCommitment() error { return nil } - commitment, err := NewPendingCommitment(epoch, stateSyncEvents) + commitment, err := NewPendingCommitment(s.epoch, stateSyncEvents) if err != nil { return err } @@ -544,7 +534,7 @@ func (s *stateSyncManager) buildCommitment() error { Signature: signature, } - if _, err = s.state.StateSyncStore.insertMessageVote(epoch, hashBytes, sig); err != nil { + if _, err = s.state.StateSyncStore.insertMessageVote(s.epoch, hashBytes, sig); err != nil { return fmt.Errorf( "failed to insert signature for hash=%v to the state. Error: %w", hex.EncodeToString(hashBytes), @@ -557,7 +547,7 @@ func (s *stateSyncManager) buildCommitment() error { Hash: hashBytes, Signature: signature, From: s.config.key.String(), - EpochNumber: epoch, + EpochNumber: s.epoch, }) s.logger.Debug( diff --git a/consensus/polybft/state_sync_manager_test.go b/consensus/polybft/state_sync_manager_test.go index f5db485169..b716338792 100644 --- a/consensus/polybft/state_sync_manager_test.go +++ b/consensus/polybft/state_sync_manager_test.go @@ -7,10 +7,6 @@ import ( "testing" "time" - "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" - bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" - "github.com/0xPolygon/polygon-edge/merkle-tree" - "github.com/0xPolygon/polygon-edge/types" "github.com/hashicorp/go-hclog" "github.com/libp2p/go-libp2p/core/peer" "github.com/stretchr/testify/require" @@ -18,9 +14,15 @@ import ( "github.com/umbracle/ethgo/abi" "github.com/umbracle/ethgo/testutil" "google.golang.org/protobuf/proto" + + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" + bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" + "github.com/0xPolygon/polygon-edge/merkle-tree" + "github.com/0xPolygon/polygon-edge/types" ) -func newTestStateSyncManager(t *testing.T, key *testValidator) *stateSyncManager { +func newTestStateSyncManager(t *testing.T, key *validator.TestValidator) *stateSyncManager { t.Helper() tmpDir, err := os.MkdirTemp("/tmp", "test-data-dir-state-sync") @@ -31,7 +33,7 @@ func newTestStateSyncManager(t *testing.T, key *testValidator) *stateSyncManager topic := &mockTopic{} - s, err := newStateSyncManager(hclog.NewNullLogger(), state, + s := newStateSyncManager(hclog.NewNullLogger(), state, &stateSyncConfig{ stateSenderAddr: types.Address{}, jsonrpcAddr: "", @@ -41,8 +43,6 @@ func newTestStateSyncManager(t *testing.T, key *testValidator) *stateSyncManager maxCommitmentSize: maxCommitmentSize, }) - require.NoError(t, err) - t.Cleanup(func() { os.RemoveAll(tmpDir) }) @@ -51,8 +51,8 @@ func newTestStateSyncManager(t *testing.T, key *testValidator) *stateSyncManager } func TestStateSyncManager_PostEpoch_BuildCommitment(t *testing.T) { - vals := newTestValidators(t, 5) - s := newTestStateSyncManager(t, vals.getValidator("0")) + vals := validator.NewTestValidators(t, 5) + s := newTestStateSyncManager(t, vals.GetValidator("0")) // there are no state syncs require.NoError(t, s.buildCommitment()) @@ -87,9 +87,9 @@ func TestStateSyncManager_PostEpoch_BuildCommitment(t *testing.T) { } func TestStateSyncManager_MessagePool_OldEpoch(t *testing.T) { - vals := newTestValidators(t, 5) + vals := validator.NewTestValidators(t, 5) - s := newTestStateSyncManager(t, vals.getValidator("0")) + s := newTestStateSyncManager(t, vals.GetValidator("0")) s.epoch = 1 msg := &TransportMessage{ @@ -117,8 +117,8 @@ func (m *mockMsg) WithHash(hash []byte) *mockMsg { return m } -func (m *mockMsg) sign(val *testValidator, domain []byte) (*TransportMessage, error) { - signature, err := val.mustSign(m.hash, domain).Marshal() +func (m *mockMsg) sign(val *validator.TestValidator, domain []byte) (*TransportMessage, error) { + signature, err := val.MustSign(m.hash, domain).Marshal() if err != nil { return nil, err } @@ -132,12 +132,12 @@ func (m *mockMsg) sign(val *testValidator, domain []byte) (*TransportMessage, er } func TestStateSyncManager_MessagePool_SenderIsNoValidator(t *testing.T) { - vals := newTestValidators(t, 5) + vals := validator.NewTestValidators(t, 5) - s := newTestStateSyncManager(t, vals.getValidator("0")) - s.validatorSet = vals.toValidatorSet() + s := newTestStateSyncManager(t, vals.GetValidator("0")) + s.validatorSet = vals.ToValidatorSet() - badVal := newTestValidator(t, "a", 0) + badVal := validator.NewTestValidator(t, "a", 0) msg, err := newMockMsg().sign(badVal, bls.DomainStateReceiver) require.NoError(t, err) @@ -147,13 +147,13 @@ func TestStateSyncManager_MessagePool_SenderIsNoValidator(t *testing.T) { func TestStateSyncManager_MessagePool_InvalidEpoch(t *testing.T) { t.Parallel() - vals := newTestValidators(t, 5) + vals := validator.NewTestValidators(t, 5) - s := newTestStateSyncManager(t, vals.getValidator("0")) - s.validatorSet = vals.toValidatorSet() + s := newTestStateSyncManager(t, vals.GetValidator("0")) + s.validatorSet = vals.ToValidatorSet() val := newMockMsg() - msg, err := val.sign(vals.getValidator("0"), bls.DomainStateReceiver) + msg, err := val.sign(vals.GetValidator("0"), bls.DomainStateReceiver) require.NoError(t, err) msg.EpochNumber = 1 @@ -173,39 +173,39 @@ func TestStateSyncManager_MessagePool_InvalidEpoch(t *testing.T) { func TestStateSyncManager_MessagePool_SenderAndSignatureMissmatch(t *testing.T) { t.Parallel() - vals := newTestValidators(t, 5) + vals := validator.NewTestValidators(t, 5) - s := newTestStateSyncManager(t, vals.getValidator("0")) - s.validatorSet = vals.toValidatorSet() + s := newTestStateSyncManager(t, vals.GetValidator("0")) + s.validatorSet = vals.ToValidatorSet() // validator signs the msg in behalf of another validator val := newMockMsg() - msg, err := val.sign(vals.getValidator("0"), bls.DomainStateReceiver) + msg, err := val.sign(vals.GetValidator("0"), bls.DomainStateReceiver) require.NoError(t, err) - msg.From = vals.getValidator("1").Address().String() + msg.From = vals.GetValidator("1").Address().String() require.Error(t, s.saveVote(msg)) // non validator signs the msg in behalf of a validator - badVal := newTestValidator(t, "a", 0) + badVal := validator.NewTestValidator(t, "a", 0) msg, err = newMockMsg().sign(badVal, bls.DomainStateReceiver) require.NoError(t, err) - msg.From = vals.getValidator("1").Address().String() + msg.From = vals.GetValidator("1").Address().String() require.Error(t, s.saveVote(msg)) } func TestStateSyncManager_MessagePool_SenderVotes(t *testing.T) { - vals := newTestValidators(t, 5) + vals := validator.NewTestValidators(t, 5) - s := newTestStateSyncManager(t, vals.getValidator("0")) - s.validatorSet = vals.toValidatorSet() + s := newTestStateSyncManager(t, vals.GetValidator("0")) + s.validatorSet = vals.ToValidatorSet() msg := newMockMsg() - val1signed, err := msg.sign(vals.getValidator("1"), bls.DomainStateReceiver) + val1signed, err := msg.sign(vals.GetValidator("1"), bls.DomainStateReceiver) require.NoError(t, err) - val2signed, err := msg.sign(vals.getValidator("2"), bls.DomainStateReceiver) + val2signed, err := msg.sign(vals.GetValidator("2"), bls.DomainStateReceiver) require.NoError(t, err) // vote with validator 1 @@ -227,10 +227,10 @@ func TestStateSyncManager_MessagePool_SenderVotes(t *testing.T) { } func TestStateSyncManager_BuildCommitment(t *testing.T) { - vals := newTestValidators(t, 5) + vals := validator.NewTestValidators(t, 5) - s := newTestStateSyncManager(t, vals.getValidator("0")) - s.validatorSet = vals.toValidatorSet() + s := newTestStateSyncManager(t, vals.GetValidator("0")) + s.validatorSet = vals.ToValidatorSet() // commitment is empty commitment, err := s.Commitment() @@ -258,10 +258,10 @@ func TestStateSyncManager_BuildCommitment(t *testing.T) { // validators 0 and 1 vote for the proposal, there is not enough // voting power for the proposal - signedMsg1, err := msg.sign(vals.getValidator("0"), bls.DomainStateReceiver) + signedMsg1, err := msg.sign(vals.GetValidator("0"), bls.DomainStateReceiver) require.NoError(t, err) - signedMsg2, err := msg.sign(vals.getValidator("1"), bls.DomainStateReceiver) + signedMsg2, err := msg.sign(vals.GetValidator("1"), bls.DomainStateReceiver) require.NoError(t, err) require.NoError(t, s.saveVote(signedMsg1)) @@ -273,10 +273,10 @@ func TestStateSyncManager_BuildCommitment(t *testing.T) { // validator 2 and 3 vote for the proposal, there is enough voting power now - signedMsg1, err = msg.sign(vals.getValidator("2"), bls.DomainStateReceiver) + signedMsg1, err = msg.sign(vals.GetValidator("2"), bls.DomainStateReceiver) require.NoError(t, err) - signedMsg2, err = msg.sign(vals.getValidator("3"), bls.DomainStateReceiver) + signedMsg2, err = msg.sign(vals.GetValidator("3"), bls.DomainStateReceiver) require.NoError(t, err) require.NoError(t, s.saveVote(signedMsg1)) @@ -288,9 +288,9 @@ func TestStateSyncManager_BuildCommitment(t *testing.T) { } func TestStateSyncerManager_BuildProofs(t *testing.T) { - vals := newTestValidators(t, 5) + vals := validator.NewTestValidators(t, 5) - s := newTestStateSyncManager(t, vals.getValidator("0")) + s := newTestStateSyncManager(t, vals.GetValidator("0")) for _, evnt := range generateStateSyncEvents(t, 20, 0) { require.NoError(t, s.state.StateSyncStore.insertStateSyncEvent(evnt)) @@ -330,9 +330,9 @@ func TestStateSyncerManager_BuildProofs(t *testing.T) { } func TestStateSyncerManager_AddLog_BuildCommitments(t *testing.T) { - vals := newTestValidators(t, 5) + vals := validator.NewTestValidators(t, 5) - s := newTestStateSyncManager(t, vals.getValidator("0")) + s := newTestStateSyncManager(t, vals.GetValidator("0")) // empty log which is not an state sync s.AddLog(ðgo.Log{}) @@ -371,16 +371,18 @@ func TestStateSyncerManager_AddLog_BuildCommitments(t *testing.T) { stateSyncs, err = s.state.StateSyncStore.getStateSyncEventsForCommitment(0, 0) require.NoError(t, err) require.Len(t, stateSyncs, 1) - require.Len(t, s.pendingCommitments, 0) + require.Len(t, s.pendingCommitments, 1) + require.Equal(t, uint64(0), s.pendingCommitments[0].StartID.Uint64()) + require.Equal(t, uint64(0), s.pendingCommitments[0].EndID.Uint64()) // add one more log to have a minimum commitment goodLog2 := goodLog.Copy() goodLog2.Topics[1] = ethgo.BytesToHash([]byte{0x1}) // state sync index 1 s.AddLog(goodLog2) - require.Len(t, s.pendingCommitments, 1) - require.Equal(t, uint64(0), s.pendingCommitments[0].StartID.Uint64()) - require.Equal(t, uint64(1), s.pendingCommitments[0].EndID.Uint64()) + require.Len(t, s.pendingCommitments, 2) + require.Equal(t, uint64(0), s.pendingCommitments[1].StartID.Uint64()) + require.Equal(t, uint64(1), s.pendingCommitments[1].EndID.Uint64()) // add two more logs to have larger commitments goodLog3 := goodLog.Copy() @@ -391,52 +393,50 @@ func TestStateSyncerManager_AddLog_BuildCommitments(t *testing.T) { goodLog4.Topics[1] = ethgo.BytesToHash([]byte{0x3}) // state sync index 3 s.AddLog(goodLog4) - require.Len(t, s.pendingCommitments, 3) - require.Equal(t, uint64(0), s.pendingCommitments[2].StartID.Uint64()) - require.Equal(t, uint64(3), s.pendingCommitments[2].EndID.Uint64()) + require.Len(t, s.pendingCommitments, 4) + require.Equal(t, uint64(0), s.pendingCommitments[3].StartID.Uint64()) + require.Equal(t, uint64(3), s.pendingCommitments[3].EndID.Uint64()) } func TestStateSyncerManager_EventTracker_Sync(t *testing.T) { t.Parallel() - vals := newTestValidators(t, 5) - s := newTestStateSyncManager(t, vals.getValidator("0")) + vals := validator.NewTestValidators(t, 5) + s := newTestStateSyncManager(t, vals.GetValidator("0")) server := testutil.DeployTestServer(t, nil) - //nolint:godox - // TODO: Deploy local artifacts (to be fixed in EVM-542) - cc := &testutil.Contract{} - cc.AddCallback(func() string { - return ` - event StateSynced(uint256 indexed id, address indexed sender, address indexed receiver, bytes data); - uint256 indx; - - function emitEvent() public payable { - emit StateSynced(indx, msg.sender, msg.sender, bytes("")); - indx++; - } - ` + // Deploy contract + contractReceipt, err := server.SendTxn(ðgo.Transaction{ + Input: contractsapi.StateSender.Bytecode, }) + require.NoError(t, err) - _, addr, err := server.DeployContract(cc) + // Create contract function call payload + encodedSyncStateData, err := (&contractsapi.SyncStateStateSenderFn{ + Receiver: types.BytesToAddress(server.Account(0).Bytes()), + Data: []byte{}, + }).EncodeAbi() require.NoError(t, err) // prefill with 10 events for i := 0; i < 10; i++ { - receipt, err := server.TxnTo(addr, "emitEvent") + receipt, err := server.SendTxn(ðgo.Transaction{ + To: &contractReceipt.ContractAddress, + Input: encodedSyncStateData, + }) require.NoError(t, err) require.Equal(t, uint64(types.ReceiptSuccess), receipt.Status) } - s.config.stateSenderAddr = types.Address(addr) + s.config.stateSenderAddr = types.Address(contractReceipt.ContractAddress) s.config.jsonrpcAddr = server.HTTPAddr() require.NoError(t, s.initTracker()) time.Sleep(2 * time.Second) - events, err := s.state.StateSyncStore.getStateSyncEventsForCommitment(0, 9) + events, err := s.state.StateSyncStore.getStateSyncEventsForCommitment(1, 10) require.NoError(t, err) require.Len(t, events, 10) } @@ -444,7 +444,7 @@ func TestStateSyncerManager_EventTracker_Sync(t *testing.T) { func TestStateSyncManager_Close(t *testing.T) { t.Parallel() - mgr := newTestStateSyncManager(t, newTestValidator(t, "A", 100)) + mgr := newTestStateSyncManager(t, validator.NewTestValidator(t, "A", 100)) require.NotPanics(t, func() { mgr.Close() }) } diff --git a/consensus/polybft/state_transaction.go b/consensus/polybft/state_transaction.go index 6b59db3ce5..0d98d3faf4 100644 --- a/consensus/polybft/state_transaction.go +++ b/consensus/polybft/state_transaction.go @@ -2,164 +2,12 @@ package polybft import ( "bytes" - "errors" "fmt" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" - "github.com/0xPolygon/polygon-edge/crypto" - "github.com/0xPolygon/polygon-edge/merkle-tree" - "github.com/0xPolygon/polygon-edge/state/runtime/precompiled" - "github.com/0xPolygon/polygon-edge/types" ) -const ( - abiMethodIDLength = 4 - stTypeBridgeCommitment = "commitment" - stTypeEndEpoch = "end-epoch" -) - -// PendingCommitment holds merkle trie of bridge transactions accompanied by epoch number -type PendingCommitment struct { - *contractsapi.StateSyncCommitment - MerkleTree *merkle.MerkleTree - Epoch uint64 -} - -// NewPendingCommitment creates a new commitment object -func NewPendingCommitment(epoch uint64, stateSyncEvents []*contractsapi.StateSyncedEvent) (*PendingCommitment, error) { - tree, err := createMerkleTree(stateSyncEvents) - if err != nil { - return nil, err - } - - return &PendingCommitment{ - MerkleTree: tree, - Epoch: epoch, - StateSyncCommitment: &contractsapi.StateSyncCommitment{ - StartID: stateSyncEvents[0].ID, - EndID: stateSyncEvents[len(stateSyncEvents)-1].ID, - Root: tree.Hash(), - }, - }, nil -} - -// Hash calculates hash value for commitment object. -func (cm *PendingCommitment) Hash() (types.Hash, error) { - data, err := cm.StateSyncCommitment.EncodeAbi() - if err != nil { - return types.Hash{}, err - } - - return crypto.Keccak256Hash(data), nil -} - -var _ contractsapi.StateTransactionInput = &CommitmentMessageSigned{} - -// CommitmentMessageSigned encapsulates commitment message with aggregated signatures -type CommitmentMessageSigned struct { - Message *contractsapi.StateSyncCommitment - AggSignature Signature - PublicKeys [][]byte -} - -// Hash calculates hash value for commitment object. -func (cm *CommitmentMessageSigned) Hash() (types.Hash, error) { - data, err := cm.Message.EncodeAbi() - if err != nil { - return types.Hash{}, err - } - - return crypto.Keccak256Hash(data), nil -} - -// VerifyStateSyncProof validates given state sync proof -// against merkle tree root hash contained in the CommitmentMessage -func (cm *CommitmentMessageSigned) VerifyStateSyncProof(proof []types.Hash, - stateSync *contractsapi.StateSyncedEvent) error { - if stateSync == nil { - return errors.New("no state sync event") - } - - if stateSync.ID.Uint64() < cm.Message.StartID.Uint64() || - stateSync.ID.Uint64() > cm.Message.EndID.Uint64() { - return errors.New("invalid state sync ID") - } - - hash, err := stateSync.EncodeAbi() - if err != nil { - return err - } - - return merkle.VerifyProof(stateSync.ID.Uint64()-cm.Message.StartID.Uint64(), - hash, proof, cm.Message.Root) -} - -// ContainsStateSync checks if commitment contains given state sync event -func (cm *CommitmentMessageSigned) ContainsStateSync(stateSyncID uint64) bool { - return cm.Message.StartID.Uint64() <= stateSyncID && cm.Message.EndID.Uint64() >= stateSyncID -} - -// EncodeAbi contains logic for encoding arbitrary data into ABI format -func (cm *CommitmentMessageSigned) EncodeAbi() ([]byte, error) { - blsVerificationPart, err := precompiled.BlsVerificationABIType.Encode( - [2]interface{}{cm.PublicKeys, cm.AggSignature.Bitmap}) - if err != nil { - return nil, err - } - - commit := &contractsapi.CommitStateReceiverFn{ - Commitment: cm.Message, - Signature: cm.AggSignature.AggregatedSignature, - Bitmap: blsVerificationPart, - } - - return commit.EncodeAbi() -} - -// DecodeAbi contains logic for decoding given ABI data -func (cm *CommitmentMessageSigned) DecodeAbi(txData []byte) error { - if len(txData) < abiMethodIDLength { - return fmt.Errorf("invalid commitment data, len = %d", len(txData)) - } - - commit := contractsapi.CommitStateReceiverFn{} - - err := commit.DecodeAbi(txData) - if err != nil { - return err - } - - decoded, err := precompiled.BlsVerificationABIType.Decode(commit.Bitmap) - if err != nil { - return err - } - - blsMap, isOk := decoded.(map[string]interface{}) - if !isOk { - return fmt.Errorf("invalid commitment data. Bls verification part not in correct format") - } - - publicKeys, isOk := blsMap["0"].([][]byte) - if !isOk { - return fmt.Errorf("invalid commitment data. Could not find public keys part") - } - - bitmap, isOk := blsMap["1"].([]byte) - if !isOk { - return fmt.Errorf("invalid commitment data. Could not find bitmap part") - } - - *cm = CommitmentMessageSigned{ - Message: commit.Commitment, - AggSignature: Signature{ - AggregatedSignature: commit.Signature, - Bitmap: bitmap, - }, - PublicKeys: publicKeys, - } - - return nil -} +const abiMethodIDLength = 4 func decodeStateTransaction(txData []byte) (contractsapi.StateTransactionInput, error) { if len(txData) < abiMethodIDLength { @@ -169,9 +17,10 @@ func decodeStateTransaction(txData []byte) (contractsapi.StateTransactionInput, sig := txData[:abiMethodIDLength] var ( - commitFn contractsapi.CommitStateReceiverFn - commitEpochFn contractsapi.CommitEpochChildValidatorSetFn - obj contractsapi.StateTransactionInput + commitFn contractsapi.CommitStateReceiverFn + commitEpochFn contractsapi.CommitEpochValidatorSetFn + distributeRewardsFn contractsapi.DistributeRewardForRewardPoolFn + obj contractsapi.StateTransactionInput ) if bytes.Equal(sig, commitFn.Sig()) { @@ -179,7 +28,10 @@ func decodeStateTransaction(txData []byte) (contractsapi.StateTransactionInput, obj = &CommitmentMessageSigned{} } else if bytes.Equal(sig, commitEpochFn.Sig()) { // commit epoch - obj = &contractsapi.CommitEpochChildValidatorSetFn{} + obj = &contractsapi.CommitEpochValidatorSetFn{} + } else if bytes.Equal(sig, distributeRewardsFn.Sig()) { + // distribute rewards + obj = &contractsapi.DistributeRewardForRewardPoolFn{} } else { return nil, fmt.Errorf("unknown state transaction") } @@ -190,40 +42,3 @@ func decodeStateTransaction(txData []byte) (contractsapi.StateTransactionInput, return obj, nil } - -func getCommitmentMessageSignedTx(txs []*types.Transaction) (*CommitmentMessageSigned, error) { - var commitFn contractsapi.CommitStateReceiverFn - for _, tx := range txs { - // skip non state CommitmentMessageSigned transactions - if tx.Type != types.StateTx || - len(tx.Input) < abiMethodIDLength || - !bytes.Equal(tx.Input[:abiMethodIDLength], commitFn.Sig()) { - continue - } - - obj := &CommitmentMessageSigned{} - - if err := obj.DecodeAbi(tx.Input); err != nil { - return nil, fmt.Errorf("get commitment message signed tx error: %w", err) - } - - return obj, nil - } - - return nil, nil -} - -func createMerkleTree(stateSyncEvents []*contractsapi.StateSyncedEvent) (*merkle.MerkleTree, error) { - ssh := make([][]byte, len(stateSyncEvents)) - - for i, sse := range stateSyncEvents { - data, err := sse.EncodeAbi() - if err != nil { - return nil, err - } - - ssh[i] = data - } - - return merkle.NewMerkleTree(ssh) -} diff --git a/consensus/polybft/state_transaction_test.go b/consensus/polybft/state_transaction_test.go index 89407db5ed..78129342e9 100644 --- a/consensus/polybft/state_transaction_test.go +++ b/consensus/polybft/state_transaction_test.go @@ -13,171 +13,6 @@ import ( "github.com/umbracle/ethgo/abi" ) -func newTestCommitmentSigned(root types.Hash, startID, endID int64) *CommitmentMessageSigned { - return &CommitmentMessageSigned{ - Message: &contractsapi.StateSyncCommitment{ - StartID: big.NewInt(startID), - EndID: big.NewInt(endID), - Root: root, - }, - AggSignature: Signature{}, - PublicKeys: [][]byte{}, - } -} - -func TestCommitmentMessage_Hash(t *testing.T) { - t.Parallel() - - const ( - eventsCount = 10 - ) - - stateSyncEvents := generateStateSyncEvents(t, eventsCount, 0) - - trie1, err := createMerkleTree(stateSyncEvents) - require.NoError(t, err) - - trie2, err := createMerkleTree(stateSyncEvents[0 : len(stateSyncEvents)-1]) - require.NoError(t, err) - - commitmentMessage1 := newTestCommitmentSigned(trie1.Hash(), 2, 8) - commitmentMessage2 := newTestCommitmentSigned(trie1.Hash(), 2, 8) - commitmentMessage3 := newTestCommitmentSigned(trie1.Hash(), 6, 10) - commitmentMessage4 := newTestCommitmentSigned(trie2.Hash(), 2, 8) - - hash1, err := commitmentMessage1.Hash() - require.NoError(t, err) - hash2, err := commitmentMessage2.Hash() - require.NoError(t, err) - hash3, err := commitmentMessage3.Hash() - require.NoError(t, err) - hash4, err := commitmentMessage4.Hash() - require.NoError(t, err) - - require.Equal(t, hash1, hash2) - require.NotEqual(t, hash1, hash3) - require.NotEqual(t, hash1, hash4) - require.NotEqual(t, hash3, hash4) -} - -func TestCommitmentMessage_ToRegisterCommitmentInputData(t *testing.T) { - t.Parallel() - - const epoch, eventsCount = uint64(100), 11 - pendingCommitment, _, _ := buildCommitmentAndStateSyncs(t, eventsCount, epoch, uint64(2)) - expectedSignedCommitmentMsg := &CommitmentMessageSigned{ - Message: pendingCommitment.StateSyncCommitment, - AggSignature: Signature{ - Bitmap: []byte{5, 1}, - AggregatedSignature: []byte{1, 1}, - }, - PublicKeys: [][]byte{{0, 1}, {2, 3}, {4, 5}}, - } - inputData, err := expectedSignedCommitmentMsg.EncodeAbi() - require.NoError(t, err) - require.NotEmpty(t, inputData) - - var actualSignedCommitmentMsg CommitmentMessageSigned - - require.NoError(t, actualSignedCommitmentMsg.DecodeAbi(inputData)) - require.NoError(t, err) - require.Equal(t, *expectedSignedCommitmentMsg.Message, *actualSignedCommitmentMsg.Message) - require.Equal(t, expectedSignedCommitmentMsg.AggSignature, actualSignedCommitmentMsg.AggSignature) -} - -func TestCommitmentMessage_VerifyProof(t *testing.T) { - t.Parallel() - - const epoch, eventsCount = uint64(100), 11 - commitment, commitmentSigned, stateSyncs := buildCommitmentAndStateSyncs(t, eventsCount, epoch, 0) - require.Equal(t, uint64(10), commitment.EndID.Sub(commitment.EndID, commitment.StartID).Uint64()) - - for _, stateSync := range stateSyncs { - leaf, err := stateSync.EncodeAbi() - require.NoError(t, err) - - proof, err := commitment.MerkleTree.GenerateProof(leaf) - require.NoError(t, err) - - execute := &contractsapi.ExecuteStateReceiverFn{ - Proof: proof, - Obj: (*contractsapi.StateSync)(stateSync), - } - - inputData, err := execute.EncodeAbi() - require.NoError(t, err) - - executionStateSync := &contractsapi.ExecuteStateReceiverFn{} - require.NoError(t, executionStateSync.DecodeAbi(inputData)) - require.Equal(t, stateSync.ID.Uint64(), executionStateSync.Obj.ID.Uint64()) - require.Equal(t, stateSync.Sender, executionStateSync.Obj.Sender) - require.Equal(t, stateSync.Receiver, executionStateSync.Obj.Receiver) - require.Equal(t, stateSync.Data, executionStateSync.Obj.Data) - require.Equal(t, proof, executionStateSync.Proof) - - err = commitmentSigned.VerifyStateSyncProof(executionStateSync.Proof, - (*contractsapi.StateSyncedEvent)(executionStateSync.Obj)) - require.NoError(t, err) - } -} - -func TestCommitmentMessage_VerifyProof_NoStateSyncsInCommitment(t *testing.T) { - t.Parallel() - - commitment := &CommitmentMessageSigned{Message: &contractsapi.StateSyncCommitment{StartID: big.NewInt(1), EndID: big.NewInt(10)}} - err := commitment.VerifyStateSyncProof([]types.Hash{}, nil) - assert.ErrorContains(t, err, "no state sync event") -} - -func TestCommitmentMessage_VerifyProof_StateSyncHashNotEqualToProof(t *testing.T) { - t.Parallel() - - const ( - fromIndex = 0 - toIndex = 4 - ) - - stateSyncs := generateStateSyncEvents(t, 5, 0) - tree, err := createMerkleTree(stateSyncs) - require.NoError(t, err) - - leaf, err := stateSyncs[0].EncodeAbi() - require.NoError(t, err) - - proof, err := tree.GenerateProof(leaf) - require.NoError(t, err) - - commitment := &CommitmentMessageSigned{ - Message: &contractsapi.StateSyncCommitment{ - StartID: big.NewInt(fromIndex), - EndID: big.NewInt(toIndex), - Root: tree.Hash(), - }, - } - - assert.ErrorContains(t, commitment.VerifyStateSyncProof(proof, stateSyncs[4]), "not a member of merkle tree") -} - -func buildCommitmentAndStateSyncs(t *testing.T, stateSyncsCount int, - epoch, startIdx uint64) (*PendingCommitment, *CommitmentMessageSigned, []*contractsapi.StateSyncedEvent) { - t.Helper() - - stateSyncEvents := generateStateSyncEvents(t, stateSyncsCount, startIdx) - commitment, err := NewPendingCommitment(epoch, stateSyncEvents) - require.NoError(t, err) - - commitmentSigned := &CommitmentMessageSigned{ - Message: commitment.StateSyncCommitment, - AggSignature: Signature{ - AggregatedSignature: []byte{}, - Bitmap: []byte{}, - }, - PublicKeys: [][]byte{}, - } - - return commitment, commitmentSigned, stateSyncEvents -} - func TestStateTransaction_Signature(t *testing.T) { t.Parallel() @@ -186,8 +21,8 @@ func TestStateTransaction_Signature(t *testing.T) { sig string }{ { - contractsapi.ChildValidatorSet.Abi.GetMethod("commitEpoch"), - "410899c9", + contractsapi.ValidatorSet.Abi.GetMethod("commitEpoch"), + "0f50287c", }, } for _, c := range cases { @@ -200,18 +35,13 @@ func TestStateTransaction_Encoding(t *testing.T) { t.Parallel() cases := []contractsapi.StateTransactionInput{ - &contractsapi.CommitEpochChildValidatorSetFn{ + &contractsapi.CommitEpochValidatorSetFn{ ID: big.NewInt(1), Epoch: &contractsapi.Epoch{ StartBlock: big.NewInt(1), EndBlock: big.NewInt(10), EpochRoot: types.Hash{}, }, - Uptime: &contractsapi.Uptime{ - EpochID: big.NewInt(1), - TotalBlocks: big.NewInt(10), - UptimeData: []*contractsapi.UptimeData{}, - }, }, } diff --git a/consensus/polybft/statesyncrelayer/state_sync_relayer.go b/consensus/polybft/statesyncrelayer/state_sync_relayer.go index e1c0cc33b8..26ca56bce2 100644 --- a/consensus/polybft/statesyncrelayer/state_sync_relayer.go +++ b/consensus/polybft/statesyncrelayer/state_sync_relayer.go @@ -38,7 +38,7 @@ func sanitizeRPCEndpoint(rpcEndpoint string) string { if err == nil { rpcEndpoint = fmt.Sprintf("http://%s:%s", "127.0.0.1", port) } else { - rpcEndpoint = "http://127.0.0.1:8545" + rpcEndpoint = txrelayer.DefaultRPCAddress } } @@ -196,11 +196,10 @@ func (r *StateSyncRelayer) executeStateSync(proof *types.Proof) error { // execute the state sync txn := ðgo.Transaction{ - From: r.key.Address(), - To: (*ethgo.Address)(&contracts.StateReceiverContract), - GasPrice: 0, - Gas: types.StateTransactionGasLimit, - Input: input, + From: r.key.Address(), + To: (*ethgo.Address)(&contracts.StateReceiverContract), + Gas: types.StateTransactionGasLimit, + Input: input, } receipt, err := r.txRelayer.SendTransaction(txn, r.key) diff --git a/consensus/polybft/statesyncrelayer/state_sync_relayer_test.go b/consensus/polybft/statesyncrelayer/state_sync_relayer_test.go index e2a2bc26f1..e523bb0b40 100644 --- a/consensus/polybft/statesyncrelayer/state_sync_relayer_test.go +++ b/consensus/polybft/statesyncrelayer/state_sync_relayer_test.go @@ -5,14 +5,18 @@ import ( "testing" "github.com/0xPolygon/polygon-edge/contracts" + "github.com/0xPolygon/polygon-edge/txrelayer" "github.com/0xPolygon/polygon-edge/types" "github.com/hashicorp/go-hclog" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/umbracle/ethgo" + "github.com/umbracle/ethgo/jsonrpc" "github.com/umbracle/ethgo/wallet" ) +var _ txrelayer.TxRelayer = (*txRelayerMock)(nil) + type txRelayerMock struct { mock.Mock } @@ -35,6 +39,10 @@ func (t *txRelayerMock) SendTransactionLocal(txn *ethgo.Transaction) (*ethgo.Rec return nil, args.Error(1) } +func (t *txRelayerMock) Client() *jsonrpc.Client { + return nil +} + func Test_executeStateSync(t *testing.T) { t.Parallel() @@ -93,7 +101,7 @@ func Test_sanitizeRPCEndpoint(t *testing.T) { { "empty endpoint", "", - "http://127.0.0.1:8545", + txrelayer.DefaultRPCAddress, }, } @@ -115,7 +123,7 @@ func TestStateSyncRelayer_Stop(t *testing.T) { key, err := wallet.GenerateKey() require.NoError(t, err) - r := NewRelayer("test-chain-1", "http://127.0.0.1:8545", ethgo.Address(contracts.StateReceiverContract), 0, hclog.NewNullLogger(), key) + r := NewRelayer("test-chain-1", txrelayer.DefaultRPCAddress, ethgo.Address(contracts.StateReceiverContract), 0, hclog.NewNullLogger(), key) require.NotPanics(t, func() { r.Stop() }) } diff --git a/consensus/polybft/system_state.go b/consensus/polybft/system_state.go index f4dfbee5e8..451b13adbd 100644 --- a/consensus/polybft/system_state.go +++ b/consensus/polybft/system_state.go @@ -1,12 +1,10 @@ package polybft import ( - "encoding/json" "fmt" "math/big" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" - bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" "github.com/0xPolygon/polygon-edge/types" "github.com/umbracle/ethgo" "github.com/umbracle/ethgo/contract" @@ -17,16 +15,13 @@ import ( type ValidatorInfo struct { Address ethgo.Address Stake *big.Int - TotalStake *big.Int - Commission *big.Int WithdrawableRewards *big.Int - Active bool + IsActive bool + IsWhitelisted bool } // SystemState is an interface to interact with the consensus system contracts in the chain type SystemState interface { - // GetValidatorSet retrieves current validator set from the smart contract - GetValidatorSet() (AccountSet, error) // GetEpoch retrieves current epoch number from the smart contract GetEpoch() (uint64, error) // GetNextCommittedIndex retrieves next committed bridge state sync index @@ -46,7 +41,7 @@ func NewSystemState(valSetAddr types.Address, stateRcvAddr types.Address, provid s := &SystemStateImpl{} s.validatorContract = contract.NewContract( ethgo.Address(valSetAddr), - contractsapi.ChildValidatorSet.Abi, contract.WithProvider(provider), + contractsapi.ValidatorSet.Abi, contract.WithProvider(provider), ) s.sidechainBridgeContract = contract.NewContract( ethgo.Address(stateRcvAddr), @@ -57,71 +52,6 @@ func NewSystemState(valSetAddr types.Address, stateRcvAddr types.Address, provid return s } -// GetValidatorSet retrieves current validator set from the smart contract -func (s *SystemStateImpl) GetValidatorSet() (AccountSet, error) { - output, err := s.validatorContract.Call("getCurrentValidatorSet", ethgo.Latest) - if err != nil { - return nil, err - } - - res := AccountSet{} - - addresses, isOk := output["0"].([]ethgo.Address) - if !isOk { - return nil, fmt.Errorf("failed to decode addresses of the current validator set") - } - - queryValidator := func(addr ethgo.Address) (*ValidatorMetadata, error) { - output, err := s.validatorContract.Call("getValidator", ethgo.Latest, addr) - if err != nil { - return nil, fmt.Errorf("failed to call getValidator function: %w", err) - } - - blsKey, ok := output["blsKey"].([4]*big.Int) - if !ok { - return nil, fmt.Errorf("failed to decode blskey") - } - - pubKey, err := bls.UnmarshalPublicKeyFromBigInt(blsKey) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal BLS public key: %w", err) - } - - totalStake, ok := output["totalStake"].(*big.Int) - if !ok { - return nil, fmt.Errorf("failed to decode total stake") - } - - isActive, ok := output["active"].(bool) - if !ok { - return nil, fmt.Errorf("failed to decode active field") - } - - return &ValidatorMetadata{ - Address: types.Address(addr), - BlsKey: pubKey, - VotingPower: new(big.Int).Set(totalStake), - IsActive: isActive, - }, nil - } - - for _, addr := range addresses { - val, err := queryValidator(addr) - if err != nil { - return nil, err - } - - // filter out non active validators - if !val.IsActive { - continue - } - - res = append(res, val) - } - - return res, nil -} - // GetEpoch retrieves current epoch number from the smart contract func (s *SystemStateImpl) GetEpoch() (uint64, error) { rawResult, err := s.validatorContract.Call("currentEpochId", ethgo.Latest) @@ -151,23 +81,3 @@ func (s *SystemStateImpl) GetNextCommittedIndex() (uint64, error) { return nextCommittedIndex.Uint64() + 1, nil } - -func buildLogsFromReceipts(entry []*types.Receipt, header *types.Header) []*types.Log { - var logs []*types.Log - - for _, taskReceipt := range entry { - for _, taskLog := range taskReceipt.Logs { - log := new(types.Log) - *log = *taskLog - - data := map[string]interface{}{ - "Hash": header.Hash, - "Number": header.Number, - } - log.Data, _ = json.Marshal(&data) - logs = append(logs, log) - } - } - - return logs -} diff --git a/consensus/polybft/system_state_test.go b/consensus/polybft/system_state_test.go index 46001d1c48..04dc1cd615 100644 --- a/consensus/polybft/system_state_test.go +++ b/consensus/polybft/system_state_test.go @@ -2,7 +2,6 @@ package polybft import ( "encoding/hex" - "encoding/json" "math/big" "testing" @@ -20,71 +19,6 @@ import ( "github.com/umbracle/ethgo/testutil" ) -func TestSystemState_GetValidatorSet(t *testing.T) { - t.Parallel() - - cc := &testutil.Contract{} - cc.AddCallback(func() string { - return ` - - function getCurrentValidatorSet() public returns (address[] memory) { - address[] memory addresses = new address[](1); - addresses[0] = address(1); - return addresses; - } - - function getValidator( - address validator - ) - external - view - returns ( - uint256[4] memory blsKey, - uint256 stake, - uint256 totalStake, - uint256 commission, - uint256 withdrawableRewards, - bool active - ) - { - blsKey = [ - 1708568697487735112380375954529256823287318886168633341382922712646533763844, - 14713639476280042449606484361428781226013866637570951139712205035697871856089, - 16798350082249088544573448433070681576641749462807627179536437108134609634615, - 21427200503135995176566340351867145775962083994845221446131416289459495591422 - ]; - stake = 10; - totalStake = 15; - commission = 20; - withdrawableRewards = 30; - active = true; - } - ` - }) - - solcContract, err := cc.Compile() - assert.NoError(t, err) - - bin, err := hex.DecodeString(solcContract.Bin) - assert.NoError(t, err) - - transition := newTestTransition(t, nil) - - // deploy a contract - result := transition.Create2(types.Address{}, bin, big.NewInt(0), 1000000000) - assert.NoError(t, result.Err) - - provider := &stateProvider{ - transition: transition, - } - - st := NewSystemState(result.Address, contracts.StateReceiverContract, provider) - validators, err := st.GetValidatorSet() - assert.NoError(t, err) - assert.Equal(t, types.Address(ethgo.HexToAddress("1")), validators[0].Address) - assert.Equal(t, new(big.Int).SetUint64(15), validators[0].VotingPower) -} - func TestSystemState_GetNextCommittedIndex(t *testing.T) { t.Parallel() @@ -199,6 +133,9 @@ func newTestTransition(t *testing.T, alloc map[types.Address]*chain.GenesisAccou ex := state.NewExecutor(&chain.Params{ Forks: chain.AllForksEnabled, + BurnContract: map[uint64]types.Address{ + 0: types.ZeroAddress, + }, }, st, hclog.NewNullLogger()) rootHash, err := ex.WriteGenesis(alloc, types.Hash{}) @@ -219,71 +156,3 @@ func newTestTransition(t *testing.T, alloc map[types.Address]*chain.GenesisAccou return transition } - -func Test_buildLogsFromReceipts(t *testing.T) { - t.Parallel() - - defaultHeader := &types.Header{ - Number: 100, - } - - type args struct { - entry []*types.Receipt - header *types.Header - } - - data := map[string]interface{}{ - "Hash": defaultHeader.Hash, - "Number": defaultHeader.Number, - } - - dataArray, err := json.Marshal(&data) - require.NoError(t, err) - - tests := []struct { - name string - args args - want []*types.Log - }{ - { - name: "no entries provided", - }, - { - name: "successfully created logs", - args: args{ - entry: []*types.Receipt{ - { - Logs: []*types.Log{ - { - Address: types.BytesToAddress([]byte{0, 1}), - Topics: nil, - Data: dataArray, - }, - }, - }, - }, - header: defaultHeader, - }, - want: []*types.Log{ - { - Address: types.BytesToAddress([]byte{0, 1}), - Topics: nil, - Data: dataArray, - }, - }, - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - - assert.EqualValuesf(t, - tt.want, - buildLogsFromReceipts(tt.args.entry, tt.args.header), - "buildLogsFromReceipts(%v, %v)", tt.args.entry, tt.args.header, - ) - }) - } -} diff --git a/consensus/polybft/validator/genesis_validator.go b/consensus/polybft/validator/genesis_validator.go new file mode 100644 index 0000000000..1ffa9a41ed --- /dev/null +++ b/consensus/polybft/validator/genesis_validator.go @@ -0,0 +1,97 @@ +package validator + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "math/big" + + bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" + "github.com/0xPolygon/polygon-edge/types" +) + +// GenesisValidator represents public information about validator accounts which are the part of genesis +type GenesisValidator struct { + Address types.Address + BlsPrivateKey *bls.PrivateKey + BlsKey string + Balance *big.Int + Stake *big.Int + MultiAddr string +} + +type genesisValidatorRaw struct { + Address types.Address `json:"address"` + BlsKey string `json:"blsKey"` + Balance *string `json:"balance"` + Stake *string `json:"stake"` + MultiAddr string `json:"multiAddr"` +} + +func (v *GenesisValidator) MarshalJSON() ([]byte, error) { + raw := &genesisValidatorRaw{Address: v.Address, BlsKey: v.BlsKey, MultiAddr: v.MultiAddr} + raw.Balance = types.EncodeBigInt(v.Balance) + raw.Stake = types.EncodeBigInt(v.Stake) + + return json.Marshal(raw) +} + +func (v *GenesisValidator) UnmarshalJSON(data []byte) error { + var ( + raw genesisValidatorRaw + err error + ) + + if err = json.Unmarshal(data, &raw); err != nil { + return err + } + + v.Address = raw.Address + v.BlsKey = raw.BlsKey + v.MultiAddr = raw.MultiAddr + + v.Balance, err = types.ParseUint256orHex(raw.Balance) + if err != nil { + return err + } + + v.Stake, err = types.ParseUint256orHex(raw.Stake) + if err != nil { + return err + } + + return nil +} + +// UnmarshalBLSPublicKey unmarshals the hex encoded BLS public key +func (v *GenesisValidator) UnmarshalBLSPublicKey() (*bls.PublicKey, error) { + decoded, err := hex.DecodeString(v.BlsKey) + if err != nil { + return nil, err + } + + return bls.UnmarshalPublicKey(decoded) +} + +// ToValidatorMetadata creates ValidatorMetadata instance +func (v *GenesisValidator) ToValidatorMetadata() (*ValidatorMetadata, error) { + blsKey, err := v.UnmarshalBLSPublicKey() + if err != nil { + return nil, err + } + + metadata := &ValidatorMetadata{ + Address: v.Address, + BlsKey: blsKey, + VotingPower: new(big.Int).Set(v.Stake), + IsActive: true, + } + + return metadata, nil +} + +// String implements fmt.Stringer interface +func (v *GenesisValidator) String() string { + return fmt.Sprintf("Address=%s; Balance=%d; Stake=%d; P2P Multi addr=%s; BLS Key=%s;", + v.Address, v.Balance, v.Stake, v.MultiAddr, v.BlsKey) +} diff --git a/consensus/polybft/validator/test_helpers.go b/consensus/polybft/validator/test_helpers.go new file mode 100644 index 0000000000..8a6c719d21 --- /dev/null +++ b/consensus/polybft/validator/test_helpers.go @@ -0,0 +1,244 @@ +package validator + +import ( + "encoding/hex" + "fmt" + "math/big" + "sort" + "strconv" + "testing" + + "github.com/0xPolygon/polygon-edge/consensus/polybft/bitmap" + bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" + "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" + "github.com/0xPolygon/polygon-edge/types" + "github.com/hashicorp/go-hclog" + "github.com/stretchr/testify/require" +) + +type TestValidators struct { + Validators map[string]*TestValidator +} + +func NewTestValidators(tb testing.TB, validatorsCount int) *TestValidators { + tb.Helper() + + aliases := make([]string, validatorsCount) + for i := 0; i < validatorsCount; i++ { + aliases[i] = strconv.Itoa(i) + } + + return NewTestValidatorsWithAliases(tb, aliases) +} + +func NewTestValidatorsWithAliases(tb testing.TB, aliases []string, votingPowers ...[]uint64) *TestValidators { + tb.Helper() + + validators := map[string]*TestValidator{} + + for i, alias := range aliases { + votingPower := uint64(1) + if len(votingPowers) == 1 { + votingPower = votingPowers[0][i] + } + + validators[alias] = NewTestValidator(tb, alias, votingPower) + } + + return &TestValidators{Validators: validators} +} + +func (v *TestValidators) Create(t *testing.T, alias string, votingPower uint64) { + t.Helper() + + if _, ok := v.Validators[alias]; !ok { + v.Validators[alias] = NewTestValidator(t, alias, votingPower) + } +} + +func (v *TestValidators) IterAcct(aliases []string, handle func(t *TestValidator)) { + if len(aliases) == 0 { + // loop over the whole set + for k := range v.Validators { + aliases = append(aliases, k) + } + // sort the names since they get queried randomly + sort.Strings(aliases) + } + + for _, alias := range aliases { + handle(v.GetValidator(alias)) + } +} + +func (v *TestValidators) GetParamValidators(aliases ...string) (res []*GenesisValidator) { + v.IterAcct(aliases, func(t *TestValidator) { + res = append(res, t.ParamsValidator()) + }) + + return +} + +func (v *TestValidators) GetValidators(aliases ...string) (res []*TestValidator) { + v.IterAcct(aliases, func(t *TestValidator) { + res = append(res, t) + }) + + return +} + +func (v *TestValidators) GetPublicIdentities(aliases ...string) (res AccountSet) { + v.IterAcct(aliases, func(t *TestValidator) { + res = append(res, t.ValidatorMetadata()) + }) + + return +} + +func (v *TestValidators) GetPrivateIdentities(aliases ...string) (res []*wallet.Account) { + v.IterAcct(aliases, func(t *TestValidator) { + res = append(res, t.Account) + }) + + return +} + +func (v *TestValidators) GetValidator(alias string) *TestValidator { + vv, ok := v.Validators[alias] + if !ok { + panic(fmt.Sprintf("Validator %s does not exist", alias)) //nolint:gocritic + } + + return vv +} + +func (v *TestValidators) ToValidatorSet() ValidatorSet { + return NewValidatorSet(v.GetPublicIdentities(), hclog.NewNullLogger()) +} + +func (v *TestValidators) UpdateVotingPowers(votingPowersMap map[string]uint64) AccountSet { + if len(votingPowersMap) == 0 { + return AccountSet{} + } + + aliases := []string{} + for alias := range votingPowersMap { + aliases = append(aliases, alias) + } + + v.IterAcct(aliases, func(t *TestValidator) { + t.VotingPower = votingPowersMap[t.Alias] + }) + + return v.GetPublicIdentities(aliases...) +} + +type TestValidator struct { + Alias string + Account *wallet.Account + VotingPower uint64 +} + +func NewTestValidator(tb testing.TB, alias string, votingPower uint64) *TestValidator { + tb.Helper() + + return &TestValidator{ + Alias: alias, + VotingPower: votingPower, + Account: generateTestAccount(tb), + } +} + +func (v *TestValidator) Address() types.Address { + return types.Address(v.Account.Ecdsa.Address()) +} + +func (v *TestValidator) Key() *wallet.Key { + return wallet.NewKey(v.Account) +} + +func (v *TestValidator) ParamsValidator() *GenesisValidator { + bls := v.Account.Bls.PublicKey().Marshal() + + return &GenesisValidator{ + Address: v.Address(), + BlsKey: hex.EncodeToString(bls), + Balance: big.NewInt(1000), + Stake: big.NewInt(1000), + } +} + +func (v *TestValidator) ValidatorMetadata() *ValidatorMetadata { + return &ValidatorMetadata{ + Address: types.Address(v.Account.Ecdsa.Address()), + BlsKey: v.Account.Bls.PublicKey(), + VotingPower: new(big.Int).SetUint64(v.VotingPower), + } +} + +func (v *TestValidator) MustSign(hash, domain []byte) *bls.Signature { + signature, err := v.Account.Bls.Sign(hash, domain) + if err != nil { + panic(fmt.Sprintf("BUG: failed to sign: %v", err)) //nolint:gocritic + } + + return signature +} + +func generateTestAccount(tb testing.TB) *wallet.Account { + tb.Helper() + + acc, err := wallet.GenerateAccount() + require.NoError(tb, err) + + return acc +} + +// CreateValidatorSetDelta calculates ValidatorSetDelta based on the provided old and new validator sets +func CreateValidatorSetDelta(oldValidatorSet, newValidatorSet AccountSet) (*ValidatorSetDelta, error) { + var addedValidators, updatedValidators AccountSet + + oldValidatorSetMap := make(map[types.Address]*ValidatorMetadata) + removedValidators := map[types.Address]int{} + + for i, validator := range oldValidatorSet { + if (validator.Address != types.Address{}) { + removedValidators[validator.Address] = i + oldValidatorSetMap[validator.Address] = validator + } + } + + for _, newValidator := range newValidatorSet { + // Check if the validator is among both old and new validator set + oldValidator, validatorExists := oldValidatorSetMap[newValidator.Address] + if validatorExists { + if !oldValidator.EqualAddressAndBlsKey(newValidator) { + return nil, fmt.Errorf("validator '%s' found in both old and new validator set, but its BLS keys differ", + newValidator.Address.String()) + } + + // If it is, then discard it from removed validators... + delete(removedValidators, newValidator.Address) + + if !oldValidator.Equals(newValidator) { + updatedValidators = append(updatedValidators, newValidator) + } + } else { + // ...otherwise it is added + addedValidators = append(addedValidators, newValidator) + } + } + + removedValsBitmap := bitmap.Bitmap{} + for _, i := range removedValidators { + removedValsBitmap.Set(uint64(i)) + } + + delta := &ValidatorSetDelta{ + Added: addedValidators, + Updated: updatedValidators, + Removed: removedValsBitmap, + } + + return delta, nil +} diff --git a/consensus/polybft/validator_metadata.go b/consensus/polybft/validator/validator_metadata.go similarity index 99% rename from consensus/polybft/validator_metadata.go rename to consensus/polybft/validator/validator_metadata.go index 3b207a31cf..8baf12f8f9 100644 --- a/consensus/polybft/validator_metadata.go +++ b/consensus/polybft/validator/validator_metadata.go @@ -1,4 +1,4 @@ -package polybft +package validator import ( "bytes" diff --git a/consensus/polybft/validator_metadata_test.go b/consensus/polybft/validator/validator_metadata_test.go similarity index 87% rename from consensus/polybft/validator_metadata_test.go rename to consensus/polybft/validator/validator_metadata_test.go index 164a60958f..e6999a87f6 100644 --- a/consensus/polybft/validator_metadata_test.go +++ b/consensus/polybft/validator/validator_metadata_test.go @@ -1,6 +1,7 @@ -package polybft +package validator import ( + "crypto/rand" "math/big" "testing" @@ -11,10 +12,21 @@ import ( "github.com/stretchr/testify/require" ) +// generateRandomBytes generates byte array with random data of 32 bytes length +func generateRandomBytes(t *testing.T) (result []byte) { + t.Helper() + + result = make([]byte, types.HashLength) + _, err := rand.Reader.Read(result) + require.NoError(t, err, "Cannot generate random byte array content.") + + return +} + func TestValidatorMetadata_Equals(t *testing.T) { t.Parallel() - v := newTestValidator(t, "A", 10) + v := NewTestValidator(t, "A", 10) validatorAcc := v.ValidatorMetadata() // proper validator metadata instance doesn't equal to nil require.False(t, validatorAcc.Equals(nil)) @@ -29,7 +41,7 @@ func TestValidatorMetadata_Equals(t *testing.T) { func TestValidatorMetadata_EqualAddressAndBlsKey(t *testing.T) { t.Parallel() - v := newTestValidator(t, "A", 10) + v := NewTestValidator(t, "A", 10) validatorAcc := v.ValidatorMetadata() // proper validator metadata instance doesn't equal to nil require.False(t, validatorAcc.EqualAddressAndBlsKey(nil)) @@ -82,7 +94,7 @@ func TestAccountSet_IndexContainsAddressesAndContainsNodeId(t *testing.T) { const count = 10 dummy := types.Address{2, 3, 4} - validators := newTestValidators(t, count).getPublicIdentities() + validators := NewTestValidators(t, count).GetPublicIdentities() addresses := [count]types.Address{} for i, validator := range validators { @@ -195,12 +207,12 @@ func TestAccountSet_ApplyDelta(t *testing.T) { snapshot := AccountSet{} // Add a couple of validators to the snapshot => validators are present in the snapshot after applying such delta - vals := newTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) + vals := NewTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) for _, step := range cc.steps { addedValidators := AccountSet{} if step.added != nil { - addedValidators = vals.getPublicIdentities(step.added...) + addedValidators = vals.GetPublicIdentities(step.added...) } delta := &ValidatorSetDelta{ Added: addedValidators, @@ -211,7 +223,7 @@ func TestAccountSet_ApplyDelta(t *testing.T) { } // update voting powers - delta.Updated = vals.updateVotingPowers(step.updated) + delta.Updated = vals.UpdateVotingPowers(step.updated) // apply delta var err error @@ -227,7 +239,7 @@ func TestAccountSet_ApplyDelta(t *testing.T) { // validate validator set require.Equal(t, len(step.expected), snapshot.Len()) for validatorAlias, votingPower := range step.expected { - v := vals.getValidator(validatorAlias).ValidatorMetadata() + v := vals.GetValidator(validatorAlias).ValidatorMetadata() require.True(t, snapshot.ContainsAddress(v.Address), "validator '%s' not found in snapshot", validatorAlias) require.Equal(t, new(big.Int).SetUint64(votingPower), v.VotingPower) } @@ -239,8 +251,8 @@ func TestAccountSet_ApplyDelta(t *testing.T) { func TestAccountSet_ApplyEmptyDelta(t *testing.T) { t.Parallel() - v := newTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) - validatorAccs := v.getPublicIdentities() + v := NewTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) + validatorAccs := v.GetPublicIdentities() validators, err := validatorAccs.ApplyDelta(nil) require.NoError(t, err) require.Equal(t, validatorAccs, validators) @@ -252,8 +264,8 @@ func TestAccountSet_Hash(t *testing.T) { t.Run("Hash non-empty account set", func(t *testing.T) { t.Parallel() - v := newTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) - hash, err := v.getPublicIdentities().Hash() + v := NewTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) + hash, err := v.GetPublicIdentities().Hash() require.NoError(t, err) require.NotEqual(t, types.ZeroHash, hash) }) diff --git a/consensus/polybft/validator_set.go b/consensus/polybft/validator/validator_set.go similarity index 84% rename from consensus/polybft/validator_set.go rename to consensus/polybft/validator/validator_set.go index ff8d893ab4..f552966729 100644 --- a/consensus/polybft/validator_set.go +++ b/consensus/polybft/validator/validator_set.go @@ -1,4 +1,4 @@ -package polybft +package validator import ( "math/big" @@ -19,8 +19,11 @@ type ValidatorSet interface { // Accounts returns the list of the ValidatorMetadata Accounts() AccountSet - // checks if submitted signers have reached quorum + // HasQuorum checks if submitted signers have reached quorum HasQuorum(signers map[types.Address]struct{}) bool + + // GetVotingPowers retrieves map: string(address) -> vp + GetVotingPowers() map[string]*big.Int } type validatorSet struct { @@ -80,6 +83,16 @@ func (vs validatorSet) HasQuorum(signers map[types.Address]struct{}) bool { return hasQuorum } +func (vs validatorSet) GetVotingPowers() map[string]*big.Int { + result := make(map[string]*big.Int, vs.Len()) + + for address, vp := range vs.votingPowerMap { + result[types.AddressToString(address)] = vp + } + + return result +} + func (vs validatorSet) Accounts() AccountSet { return vs.validators } @@ -92,6 +105,10 @@ func (vs validatorSet) Len() int { return vs.validators.Len() } +func (vs validatorSet) TotalVotingPower() big.Int { + return *vs.totalVotingPower +} + // getQuorumSize calculates quorum size as 2/3 super-majority of provided total voting power func getQuorumSize(totalVotingPower *big.Int) *big.Int { quorum := new(big.Int) diff --git a/consensus/polybft/validator/validator_set_delta.go b/consensus/polybft/validator/validator_set_delta.go new file mode 100644 index 0000000000..23e6f31a12 --- /dev/null +++ b/consensus/polybft/validator/validator_set_delta.go @@ -0,0 +1,144 @@ +package validator + +import ( + "bytes" + "fmt" + + "github.com/0xPolygon/polygon-edge/consensus/polybft/bitmap" + "github.com/umbracle/fastrlp" +) + +// ValidatorSetDelta holds information about added and removed validators compared to the previous epoch +type ValidatorSetDelta struct { + // Added is the slice of added validators + Added AccountSet + // Updated is the slice of updated valiadtors + Updated AccountSet + // Removed is a bitmap of the validators removed from the set + Removed bitmap.Bitmap +} + +// Equals checks validator set delta equality +func (d *ValidatorSetDelta) Equals(other *ValidatorSetDelta) bool { + if other == nil { + return false + } + + return d.Added.Equals(other.Added) && + d.Updated.Equals(other.Updated) && + bytes.Equal(d.Removed, other.Removed) +} + +// MarshalRLPWith marshals ValidatorSetDelta to RLP format +func (d *ValidatorSetDelta) MarshalRLPWith(ar *fastrlp.Arena) *fastrlp.Value { + vv := ar.NewArray() + addedValidatorsRaw := ar.NewArray() + updatedValidatorsRaw := ar.NewArray() + + for _, validatorAccount := range d.Added { + addedValidatorsRaw.Set(validatorAccount.MarshalRLPWith(ar)) + } + + for _, validatorAccount := range d.Updated { + updatedValidatorsRaw.Set(validatorAccount.MarshalRLPWith(ar)) + } + + vv.Set(addedValidatorsRaw) // added + vv.Set(updatedValidatorsRaw) // updated + vv.Set(ar.NewCopyBytes(d.Removed)) // removed + + return vv +} + +// UnmarshalRLPWith unmarshals ValidatorSetDelta from RLP format +func (d *ValidatorSetDelta) UnmarshalRLPWith(v *fastrlp.Value) error { + elems, err := v.GetElems() + if err != nil { + return err + } + + if len(elems) == 0 { + return nil + } else if num := len(elems); num != 3 { + return fmt.Errorf("incorrect elements count to decode validator set delta, expected 3 but found %d", num) + } + + // Validators (added) + { + validatorsRaw, err := elems[0].GetElems() + if err != nil { + return fmt.Errorf("array expected for added validators") + } + + d.Added, err = unmarshalValidators(validatorsRaw) + if err != nil { + return err + } + } + + // Validators (updated) + { + validatorsRaw, err := elems[1].GetElems() + if err != nil { + return fmt.Errorf("array expected for updated validators") + } + + d.Updated, err = unmarshalValidators(validatorsRaw) + if err != nil { + return err + } + } + + // Bitmap (removed) + { + dst, err := elems[2].GetBytes(nil) + if err != nil { + return err + } + + d.Removed = bitmap.Bitmap(dst) + } + + return nil +} + +// unmarshalValidators unmarshals RLP encoded validators and returns AccountSet instance +func unmarshalValidators(validatorsRaw []*fastrlp.Value) (AccountSet, error) { + if len(validatorsRaw) == 0 { + return nil, nil + } + + validators := make(AccountSet, len(validatorsRaw)) + + for i, validatorRaw := range validatorsRaw { + acc := &ValidatorMetadata{} + if err := acc.UnmarshalRLPWith(validatorRaw); err != nil { + return nil, err + } + + validators[i] = acc + } + + return validators, nil +} + +// IsEmpty returns indication whether delta is empty (namely added, updated slices and removed bitmap are empty) +func (d *ValidatorSetDelta) IsEmpty() bool { + return len(d.Added) == 0 && + len(d.Updated) == 0 && + d.Removed.Len() == 0 +} + +// Copy creates deep copy of ValidatorSetDelta +func (d *ValidatorSetDelta) Copy() *ValidatorSetDelta { + added := d.Added.Copy() + removed := make([]byte, len(d.Removed)) + copy(removed, d.Removed) + + return &ValidatorSetDelta{Added: added, Removed: removed} +} + +// fmt.Stringer interface implementation +func (d *ValidatorSetDelta) String() string { + return fmt.Sprintf("Added: \n%v Removed: %v\n Updated: \n%v", d.Added, d.Removed, d.Updated) +} diff --git a/consensus/polybft/validator/validator_set_delta_test.go b/consensus/polybft/validator/validator_set_delta_test.go new file mode 100644 index 0000000000..ca1911dc45 --- /dev/null +++ b/consensus/polybft/validator/validator_set_delta_test.go @@ -0,0 +1,237 @@ +package validator + +import ( + "crypto/rand" + "math/big" + "testing" + + bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" + "github.com/stretchr/testify/require" + "github.com/umbracle/fastrlp" +) + +func TestExtra_CreateValidatorSetDelta_BlsDiffer(t *testing.T) { + t.Parallel() + + vals := NewTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F"}) + oldValidatorSet := vals.GetPublicIdentities("A", "B", "C", "D") + + // change the public bls key of 'B' + newValidatorSet := vals.GetPublicIdentities("B", "E", "F") + privateKey, err := bls.GenerateBlsKey() + require.NoError(t, err) + + newValidatorSet[0].BlsKey = privateKey.PublicKey() + + _, err = CreateValidatorSetDelta(oldValidatorSet, newValidatorSet) + require.Error(t, err) +} + +func TestValidatorSetDelta_Copy(t *testing.T) { + t.Parallel() + + const ( + originalValidatorsCount = 10 + addedValidatorsCount = 2 + ) + + oldValidatorSet := NewTestValidators(t, originalValidatorsCount).GetPublicIdentities() + newValidatorSet := oldValidatorSet[:len(oldValidatorSet)-2] + originalDelta, err := CreateValidatorSetDelta(oldValidatorSet, newValidatorSet) + require.NoError(t, err) + require.NotNil(t, originalDelta) + require.Empty(t, originalDelta.Added) + + copiedDelta := originalDelta.Copy() + require.NotNil(t, copiedDelta) + require.NotSame(t, originalDelta, copiedDelta) + require.NotEqual(t, originalDelta, copiedDelta) + require.Empty(t, copiedDelta.Added) + require.Equal(t, copiedDelta.Removed.Len(), originalDelta.Removed.Len()) + + newValidators := NewTestValidators(t, addedValidatorsCount).GetPublicIdentities() + copiedDelta.Added = append(copiedDelta.Added, newValidators...) + require.Empty(t, originalDelta.Added) + require.Len(t, copiedDelta.Added, addedValidatorsCount) + require.Equal(t, copiedDelta.Removed.Len(), originalDelta.Removed.Len()) +} + +func TestValidatorSetDelta_UnmarshalRLPWith_NegativeCases(t *testing.T) { + t.Parallel() + + t.Run("Incorrect RLP value type provided", func(t *testing.T) { + t.Parallel() + + ar := &fastrlp.Arena{} + delta := &ValidatorSetDelta{} + require.ErrorContains(t, delta.UnmarshalRLPWith(ar.NewNull()), "value is not of type array") + }) + + t.Run("Empty RLP array provided", func(t *testing.T) { + t.Parallel() + + ar := &fastrlp.Arena{} + delta := &ValidatorSetDelta{} + require.NoError(t, delta.UnmarshalRLPWith(ar.NewArray())) + }) + + t.Run("Incorrect RLP array size", func(t *testing.T) { + t.Parallel() + + ar := &fastrlp.Arena{} + deltaMarshalled := ar.NewArray() + deltaMarshalled.Set(ar.NewBytes([]byte{0x59})) + deltaMarshalled.Set(ar.NewBytes([]byte{0x33})) + deltaMarshalled.Set(ar.NewBytes([]byte{0x26})) + deltaMarshalled.Set(ar.NewBytes([]byte{0x74})) + delta := &ValidatorSetDelta{} + require.ErrorContains(t, delta.UnmarshalRLPWith(deltaMarshalled), "incorrect elements count to decode validator set delta, expected 3 but found 4") + }) + + t.Run("Incorrect RLP value type for Added field", func(t *testing.T) { + t.Parallel() + + ar := &fastrlp.Arena{} + deltaMarshalled := ar.NewArray() + deltaMarshalled.Set(ar.NewBytes([]byte{0x59})) + deltaMarshalled.Set(ar.NewBytes([]byte{0x33})) + deltaMarshalled.Set(ar.NewBytes([]byte{0x27})) + delta := &ValidatorSetDelta{} + require.ErrorContains(t, delta.UnmarshalRLPWith(deltaMarshalled), "array expected for added validators") + }) + + t.Run("Incorrect RLP value type for ValidatorMetadata in Added field", func(t *testing.T) { + t.Parallel() + + ar := &fastrlp.Arena{} + deltaMarshalled := ar.NewArray() + addedArray := ar.NewArray() + addedArray.Set(ar.NewNull()) + deltaMarshalled.Set(addedArray) + deltaMarshalled.Set(ar.NewNullArray()) + deltaMarshalled.Set(ar.NewNull()) + delta := &ValidatorSetDelta{} + require.ErrorContains(t, delta.UnmarshalRLPWith(deltaMarshalled), "value is not of type array") + }) + + t.Run("Incorrect RLP value type for Removed field", func(t *testing.T) { + t.Parallel() + + ar := &fastrlp.Arena{} + deltaMarshalled := ar.NewArray() + addedValidators := NewTestValidators(t, 3).GetPublicIdentities() + addedArray := ar.NewArray() + updatedArray := ar.NewArray() + for _, validator := range addedValidators { + addedArray.Set(validator.MarshalRLPWith(ar)) + } + for _, validator := range addedValidators { + votingPower, err := rand.Int(rand.Reader, big.NewInt(100)) + require.NoError(t, err) + + validator.VotingPower = new(big.Int).Set(votingPower) + updatedArray.Set(validator.MarshalRLPWith(ar)) + } + deltaMarshalled.Set(addedArray) + deltaMarshalled.Set(updatedArray) + deltaMarshalled.Set(ar.NewNull()) + delta := &ValidatorSetDelta{} + require.ErrorContains(t, delta.UnmarshalRLPWith(deltaMarshalled), "value is not of type bytes") + }) + + t.Run("Incorrect RLP value type for Updated field", func(t *testing.T) { + t.Parallel() + + ar := &fastrlp.Arena{} + deltaMarshalled := ar.NewArray() + deltaMarshalled.Set(ar.NewArray()) + deltaMarshalled.Set(ar.NewBytes([]byte{0x33})) + deltaMarshalled.Set(ar.NewNull()) + delta := &ValidatorSetDelta{} + require.ErrorContains(t, delta.UnmarshalRLPWith(deltaMarshalled), "array expected for updated validators") + }) + + t.Run("Incorrect RLP value type for ValidatorMetadata in Updated field", func(t *testing.T) { + t.Parallel() + + ar := &fastrlp.Arena{} + deltaMarshalled := ar.NewArray() + updatedArray := ar.NewArray() + updatedArray.Set(ar.NewNull()) + deltaMarshalled.Set(ar.NewArray()) + deltaMarshalled.Set(updatedArray) + deltaMarshalled.Set(ar.NewNull()) + delta := &ValidatorSetDelta{} + require.ErrorContains(t, delta.UnmarshalRLPWith(deltaMarshalled), "value is not of type array") + }) +} + +func TestExtra_CreateValidatorSetDelta_Cases(t *testing.T) { + t.Parallel() + + cases := []struct { + name string + oldSet []string + newSet []string + added []string + updated []string + removed []uint64 + }{ + { + "Simple", + []string{"A", "B", "C", "E", "F"}, + []string{"B", "E", "H"}, + []string{"H"}, + []string{"B", "E"}, + []uint64{0, 2, 4}, + }, + } + + for _, c := range cases { + c := c + t.Run(c.name, func(t *testing.T) { + t.Parallel() + + vals := NewTestValidatorsWithAliases(t, []string{}) + + for _, name := range c.oldSet { + vals.Create(t, name, 1) + } + for _, name := range c.newSet { + vals.Create(t, name, 1) + } + + oldValidatorSet := vals.GetPublicIdentities(c.oldSet...) + // update voting power to random value + maxVotingPower := big.NewInt(100) + for _, name := range c.updated { + v := vals.GetValidator(name) + vp, err := rand.Int(rand.Reader, maxVotingPower) + require.NoError(t, err) + // make sure generated voting power is different than the original one + v.VotingPower += vp.Uint64() + 1 + } + newValidatorSet := vals.GetPublicIdentities(c.newSet...) + + delta, err := CreateValidatorSetDelta(oldValidatorSet, newValidatorSet) + require.NoError(t, err) + + // added validators + require.Len(t, delta.Added, len(c.added)) + for i, name := range c.added { + require.Equal(t, delta.Added[i].Address, vals.GetValidator(name).Address()) + } + + // removed validators + for _, i := range c.removed { + require.True(t, delta.Removed.IsSet(i)) + } + + // updated validators + require.Len(t, delta.Updated, len(c.updated)) + for i, name := range c.updated { + require.Equal(t, delta.Updated[i].Address, vals.GetValidator(name).Address()) + } + }) + } +} diff --git a/consensus/polybft/validator_set_test.go b/consensus/polybft/validator/validator_set_test.go similarity index 79% rename from consensus/polybft/validator_set_test.go rename to consensus/polybft/validator/validator_set_test.go index f7faa5a678..01778e7e29 100644 --- a/consensus/polybft/validator_set_test.go +++ b/consensus/polybft/validator/validator_set_test.go @@ -1,4 +1,4 @@ -package polybft +package validator import ( "math/big" @@ -12,12 +12,12 @@ func TestValidatorSet_HasQuorum(t *testing.T) { t.Parallel() // enough signers for quorum (2/3 super-majority of validators are signers) - validators := newTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F", "G"}) - vs := validators.toValidatorSet() + validators := NewTestValidatorsWithAliases(t, []string{"A", "B", "C", "D", "E", "F", "G"}) + vs := validators.ToValidatorSet() signers := make(map[types.Address]struct{}) - validators.iterAcct([]string{"A", "B", "C", "D", "E"}, func(v *testValidator) { + validators.IterAcct([]string{"A", "B", "C", "D", "E"}, func(v *TestValidator) { signers[v.Address()] = struct{}{} }) @@ -26,7 +26,7 @@ func TestValidatorSet_HasQuorum(t *testing.T) { // not enough signers for quorum (less than 2/3 super-majority of validators are signers) signers = make(map[types.Address]struct{}) - validators.iterAcct([]string{"A", "B", "C", "D"}, func(v *testValidator) { + validators.IterAcct([]string{"A", "B", "C", "D"}, func(v *TestValidator) { signers[v.Address()] = struct{}{} }) require.False(t, vs.HasQuorum(signers)) diff --git a/consensus/polybft/validators_snapshot.go b/consensus/polybft/validators_snapshot.go index 84295e4ddf..d4ba539920 100644 --- a/consensus/polybft/validators_snapshot.go +++ b/consensus/polybft/validators_snapshot.go @@ -6,14 +6,15 @@ import ( "sync" "github.com/0xPolygon/polygon-edge/blockchain" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/types" "github.com/hashicorp/go-hclog" ) type validatorSnapshot struct { - Epoch uint64 `json:"epoch"` - EpochEndingBlock uint64 `json:"epochEndingBlock"` - Snapshot AccountSet `json:"snapshot"` + Epoch uint64 `json:"epoch"` + EpochEndingBlock uint64 `json:"epochEndingBlock"` + Snapshot validator.AccountSet `json:"snapshot"` } func (vs *validatorSnapshot) copy() *validatorSnapshot { @@ -49,7 +50,8 @@ func newValidatorsSnapshotCache( // GetSnapshot tries to retrieve the most recent cached snapshot (if any) and // applies pending validator set deltas to it. // Otherwise, it builds a snapshot from scratch and applies pending validator set deltas. -func (v *validatorsSnapshotCache) GetSnapshot(blockNumber uint64, parents []*types.Header) (AccountSet, error) { +func (v *validatorsSnapshotCache) GetSnapshot( + blockNumber uint64, parents []*types.Header) (validator.AccountSet, error) { v.lock.Lock() defer v.lock.Unlock() @@ -178,12 +180,12 @@ func (v *validatorsSnapshotCache) computeSnapshot( } var ( - snapshot AccountSet + snapshot validator.AccountSet snapshotEpoch uint64 ) if existingSnapshot == nil { - snapshot = AccountSet{} + snapshot = validator.AccountSet{} } else { snapshot = existingSnapshot.Snapshot snapshotEpoch = existingSnapshot.Epoch + 1 diff --git a/consensus/polybft/validators_snapshot_test.go b/consensus/polybft/validators_snapshot_test.go index f22b633d9d..e74d82c6b3 100644 --- a/consensus/polybft/validators_snapshot_test.go +++ b/consensus/polybft/validators_snapshot_test.go @@ -4,6 +4,7 @@ import ( "fmt" "testing" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" "github.com/0xPolygon/polygon-edge/types" "github.com/hashicorp/go-hclog" "github.com/stretchr/testify/assert" @@ -21,9 +22,9 @@ func TestValidatorsSnapshotCache_GetSnapshot_Build(t *testing.T) { epochSize = uint64(10) ) - allValidators := newTestValidators(t, totalValidators).getPublicIdentities() + allValidators := validator.NewTestValidators(t, totalValidators).GetPublicIdentities() - var oddValidators, evenValidators AccountSet + var oddValidators, evenValidators validator.AccountSet for i := 0; i < totalValidators; i++ { if i%2 == 0 { @@ -42,7 +43,7 @@ func TestValidatorsSnapshotCache_GetSnapshot_Build(t *testing.T) { var cases = []struct { blockNumber uint64 - expectedSnapshot AccountSet + expectedSnapshot validator.AccountSet validatorsOverlap bool parents []*types.Header }{ @@ -98,8 +99,8 @@ func TestValidatorsSnapshotCache_GetSnapshot_FetchFromCache(t *testing.T) { validatorSetSize = 5 ) - allValidators := newTestValidators(t, totalValidators).getPublicIdentities() - epochOneValidators := AccountSet{allValidators[0], allValidators[len(allValidators)-1]} + allValidators := validator.NewTestValidators(t, totalValidators).GetPublicIdentities() + epochOneValidators := validator.AccountSet{allValidators[0], allValidators[len(allValidators)-1]} epochTwoValidators := allValidators[1 : len(allValidators)-2] headersMap := &testHeadersMap{headersByNumber: make(map[uint64]*types.Header)} @@ -143,7 +144,7 @@ func TestValidatorsSnapshotCache_Cleanup(t *testing.T) { cache := &testValidatorsCache{ validatorsSnapshotCache: newValidatorsSnapshotCache(hclog.NewNullLogger(), newTestState(t), blockchainMock), } - snapshot := newTestValidators(t, 3).getPublicIdentities() + snapshot := validator.NewTestValidators(t, 3).GetPublicIdentities() maxEpoch := uint64(0) for i := uint64(0); i < validatorSnapshotLimit; i++ { @@ -191,7 +192,7 @@ func TestValidatorsSnapshotCache_ComputeSnapshot_UnknownBlock(t *testing.T) { epochSize = uint64(10) ) - allValidators := newTestValidators(t, totalValidators).getPublicIdentities() + allValidators := validator.NewTestValidators(t, totalValidators).GetPublicIdentities() headersMap := &testHeadersMap{} headersMap.addHeader(createValidatorDeltaHeader(t, 0, 0, nil, allValidators[:validatorSetSize])) headersMap.addHeader(createValidatorDeltaHeader(t, 1*epochSize, 1, allValidators[:validatorSetSize], allValidators[validatorSetSize:])) @@ -218,7 +219,7 @@ func TestValidatorsSnapshotCache_ComputeSnapshot_IncorrectExtra(t *testing.T) { epochSize = uint64(10) ) - allValidators := newTestValidators(t, totalValidators).getPublicIdentities() + allValidators := validator.NewTestValidators(t, totalValidators).GetPublicIdentities() headersMap := &testHeadersMap{} invalidHeader := createValidatorDeltaHeader(t, 1*epochSize, 1, allValidators[:validatorSetSize], allValidators[validatorSetSize:]) invalidHeader.ExtraData = []byte{0x2, 0x7} @@ -246,7 +247,7 @@ func TestValidatorsSnapshotCache_ComputeSnapshot_ApplyDeltaFail(t *testing.T) { epochSize = uint64(10) ) - allValidators := newTestValidators(t, totalValidators).getPublicIdentities() + allValidators := validator.NewTestValidators(t, totalValidators).GetPublicIdentities() headersMap := &testHeadersMap{} headersMap.addHeader(createValidatorDeltaHeader(t, 0, 0, nil, allValidators[:validatorSetSize])) headersMap.addHeader(createValidatorDeltaHeader(t, 1*epochSize, 1, nil, allValidators[:validatorSetSize])) @@ -264,7 +265,7 @@ func TestValidatorsSnapshotCache_ComputeSnapshot_ApplyDeltaFail(t *testing.T) { } func createHeaders(t *testing.T, headersMap *testHeadersMap, - fromBlock, toBlock, epoch uint64, oldValidators, newValidators AccountSet) { + fromBlock, toBlock, epoch uint64, oldValidators, newValidators validator.AccountSet) { t.Helper() headersMap.addHeader(createValidatorDeltaHeader(t, fromBlock, epoch-1, oldValidators, newValidators)) @@ -274,15 +275,15 @@ func createHeaders(t *testing.T, headersMap *testHeadersMap, } } -func createValidatorDeltaHeader(t *testing.T, blockNumber, epoch uint64, oldValidatorSet, newValidatorSet AccountSet) *types.Header { +func createValidatorDeltaHeader(t *testing.T, blockNumber, epoch uint64, oldValidatorSet, newValidatorSet validator.AccountSet) *types.Header { t.Helper() - delta, _ := createValidatorSetDelta(oldValidatorSet, newValidatorSet) + delta, _ := validator.CreateValidatorSetDelta(oldValidatorSet, newValidatorSet) extra := &Extra{Validators: delta, Checkpoint: &CheckpointData{EpochNumber: epoch}} return &types.Header{ Number: blockNumber, - ExtraData: append(make([]byte, ExtraVanity), extra.MarshalRLPTo(nil)...), + ExtraData: extra.MarshalRLPTo(nil), } } diff --git a/consensus/polybft/wallet/account.go b/consensus/polybft/wallet/account.go index 751bfb4938..b6c8600221 100644 --- a/consensus/polybft/wallet/account.go +++ b/consensus/polybft/wallet/account.go @@ -7,6 +7,7 @@ import ( bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" "github.com/0xPolygon/polygon-edge/secrets" + "github.com/0xPolygon/polygon-edge/types" "github.com/umbracle/ethgo/wallet" ) @@ -36,37 +37,52 @@ func GenerateAccount() (*Account, error) { // NewAccountFromSecret creates new account by using provided secretsManager func NewAccountFromSecret(secretsManager secrets.SecretsManager) (*Account, error) { - var ( - encodedKey []byte - err error - ) + ecdsaKey, err := GetEcdsaFromSecret(secretsManager) + if err != nil { + return nil, err + } + + blsKey, err := GetBlsFromSecret(secretsManager) + if err != nil { + return nil, err + } + + return &Account{Ecdsa: ecdsaKey, Bls: blsKey}, nil +} - // ECDSA - if encodedKey, err = secretsManager.GetSecret(secrets.ValidatorKey); err != nil { - return nil, fmt.Errorf("failed to read account data: %w", err) +// GetEcdsaFromSecret retrieves validator(ECDSA) key by using provided secretsManager +func GetEcdsaFromSecret(secretsManager secrets.SecretsManager) (*wallet.Key, error) { + encodedKey, err := secretsManager.GetSecret(secrets.ValidatorKey) + if err != nil { + return nil, fmt.Errorf("failed to retrieve ecdsa key: %w", err) } ecdsaRaw, err := hex.DecodeString(string(encodedKey)) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to retrieve ecdsa key: %w", err) } - ecdsaKey, err := wallet.NewWalletFromPrivKey(ecdsaRaw) + key, err := wallet.NewWalletFromPrivKey(ecdsaRaw) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to retrieve ecdsa key: %w", err) } - // BLS - if encodedKey, err = secretsManager.GetSecret(secrets.ValidatorBLSKey); err != nil { - return nil, fmt.Errorf("failed to read account data: %w", err) + return key, nil +} + +// GetBlsFromSecret retrieves BLS key by using provided secretsManager +func GetBlsFromSecret(secretsManager secrets.SecretsManager) (*bls.PrivateKey, error) { + encodedKey, err := secretsManager.GetSecret(secrets.ValidatorBLSKey) + if err != nil { + return nil, fmt.Errorf("failed to retrieve bls key: %w", err) } blsKey, err := bls.UnmarshalPrivateKey(encodedKey) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to retrieve bls key: %w", err) } - return &Account{Ecdsa: ecdsaKey, Bls: blsKey}, nil + return blsKey, nil } // Save persists ECDSA and BLS private keys to the SecretsManager @@ -101,3 +117,7 @@ func (a *Account) GetEcdsaPrivateKey() (*ecdsa.PrivateKey, error) { return wallet.ParsePrivateKey(ecdsaRaw) } + +func (a Account) Address() types.Address { + return types.Address(a.Ecdsa.Address()) +} diff --git a/contracts/system_addresses.go b/contracts/system_addresses.go index abd14886dd..1c6da159cf 100644 --- a/contracts/system_addresses.go +++ b/contracts/system_addresses.go @@ -9,16 +9,36 @@ var ( BLSContract = types.StringToAddress("0x102") // MerkleContract is an address of Merkle contract on the child chain MerkleContract = types.StringToAddress("0x103") + // RewardTokenContract is an address of reward token on child chain + RewardTokenContract = types.StringToAddress("0x104") + // RewardPoolContract is an address of RewardPoolContract contract on the child chain + RewardPoolContract = types.StringToAddress("0x105") // StateReceiverContract is an address of bridge contract on the child chain StateReceiverContract = types.StringToAddress("0x1001") // NativeERC20TokenContract is an address of bridge contract (used for transferring ERC20 native tokens on child chain) NativeERC20TokenContract = types.StringToAddress("0x1010") // L2StateSenderContract is an address of bridge contract to the rootchain L2StateSenderContract = types.StringToAddress("0x1002") + // ChildERC20Contract is an address of bridgable ERC20 token contract on the child chain ChildERC20Contract = types.StringToAddress("0x1003") // ChildERC20PredicateContract is an address of child ERC20 predicate contract on the child chain ChildERC20PredicateContract = types.StringToAddress("0x1004") + // ChildERC721Contract is an address of bridgable ERC721 token contract on the child chain + ChildERC721Contract = types.StringToAddress("0x1005") + // ChildERC721PredicateContract is an address of child ERC721 predicate contract on the child chain + ChildERC721PredicateContract = types.StringToAddress("0x1006") + // ChildERC1155Contract is an address of bridgable ERC1155 token contract on the child chain + ChildERC1155Contract = types.StringToAddress("0x1007") + // ChildERC1155PredicateContract is an address of child ERC1155 predicate contract on the child chain + ChildERC1155PredicateContract = types.StringToAddress("0x1008") + // RootMintableERC20PredicateContract is an address of mintable ERC20 predicate on the child chain + RootMintableERC20PredicateContract = types.StringToAddress("0x1009") + // RootMintableERC721PredicateContract is an address of mintable ERC721 predicate on the child chain + RootMintableERC721PredicateContract = types.StringToAddress("0x100a") + // RootMintableERC1155PredicateContract is an address of mintable ERC1155 predicate on the child chain + RootMintableERC1155PredicateContract = types.StringToAddress("0x100b") + // SystemCaller is address of account, used for system calls to smart contracts SystemCaller = types.StringToAddress("0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE") @@ -30,4 +50,14 @@ var ( ConsolePrecompile = types.StringToAddress("0x000000000000000000636F6e736F6c652e6c6f67") // AllowListContractsAddr is the address of the contract deployer allow list AllowListContractsAddr = types.StringToAddress("0x0200000000000000000000000000000000000000") + // BlockListContractsAddr is the address of the contract deployer block list + BlockListContractsAddr = types.StringToAddress("0x0300000000000000000000000000000000000000") + // AllowListTransactionsAddr is the address of the transactions allow list + AllowListTransactionsAddr = types.StringToAddress("0x0200000000000000000000000000000000000002") + // BlockListTransactionsAddr is the address of the transactions block list + BlockListTransactionsAddr = types.StringToAddress("0x0300000000000000000000000000000000000002") + // AllowListBridgeAddr is the address of the bridge allow list + AllowListBridgeAddr = types.StringToAddress("0x0200000000000000000000000000000000000004") + // BlockListBridgeAddr is the address of the bridge block list + BlockListBridgeAddr = types.StringToAddress("0x0300000000000000000000000000000000000004") ) diff --git a/core-contracts b/core-contracts index 622a936ffb..5a68054893 160000 --- a/core-contracts +++ b/core-contracts @@ -1 +1 @@ -Subproject commit 622a936ffb0539d21cb1519f20a8cea8ab9b28de +Subproject commit 5a68054893e8a9755645b11528221e3c68c2af29 diff --git a/crypto/crypto.go b/crypto/crypto.go index 30ecd13fa5..95421f13bc 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -147,10 +147,6 @@ func RecoverPubkey(signature, hash []byte) (*ecdsa.PublicKey, error) { return nil, errHashOfInvalidLength } - if types.BytesToHash(hash) == types.ZeroHash { - return nil, errZeroHash - } - size := len(signature) term := byte(27) diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go index c9b53d4d80..ab38b04848 100644 --- a/crypto/crypto_test.go +++ b/crypto/crypto_test.go @@ -456,13 +456,6 @@ func TestRecoverPublicKey(t *testing.T) { require.ErrorIs(t, err, errHashOfInvalidLength) }) - t.Run("Zero hash", func(t *testing.T) { - t.Parallel() - - _, err := RecoverPubkey(testSignature, types.ZeroHash[:]) - require.ErrorIs(t, err, errZeroHash) - }) - t.Run("Ok signature and hash", func(t *testing.T) { t.Parallel() diff --git a/crypto/txsigner.go b/crypto/txsigner.go index c35f0b3581..f0c7e203b4 100644 --- a/crypto/txsigner.go +++ b/crypto/txsigner.go @@ -4,12 +4,16 @@ import ( "crypto/ecdsa" "fmt" "math/big" - "math/bits" "github.com/0xPolygon/polygon-edge/chain" "github.com/0xPolygon/polygon-edge/helper/keccak" "github.com/0xPolygon/polygon-edge/types" - "github.com/umbracle/fastrlp" +) + +// Magic numbers from Ethereum, used in v calculation +var ( + big27 = big.NewInt(27) + big35 = big.NewInt(35) ) // TxSigner is a utility interface used to recover data from a transaction @@ -22,9 +26,6 @@ type TxSigner interface { // SignTx signs a transaction SignTx(tx *types.Transaction, priv *ecdsa.PrivateKey) (*types.Transaction, error) - - // CalculateV calculates the V value based on the type of signer used - CalculateV(parity byte) []byte } // NewSigner creates a new signer object (EIP155 or FrontierSigner) @@ -32,27 +33,54 @@ func NewSigner(forks chain.ForksInTime, chainID uint64) TxSigner { var signer TxSigner if forks.EIP155 { - signer = &EIP155Signer{chainID: chainID, isHomestead: forks.Homestead} + signer = NewEIP155Signer(chainID, forks.Homestead) } else { - signer = &FrontierSigner{forks.Homestead} + signer = NewFrontierSigner(forks.Homestead) + } + + // London signer requires a fallback signer that is defined above. + // This is the reason why the london signer check is separated. + if forks.London { + return NewLondonSigner(chainID, forks.Homestead, signer) } return signer } -type FrontierSigner struct { - isHomestead bool -} +// encodeSignature generates a signature value based on the R, S and V value +func encodeSignature(R, S, V *big.Int, isHomestead bool) ([]byte, error) { + if !ValidateSignatureValues(V, R, S, isHomestead) { + return nil, fmt.Errorf("invalid txn signature") + } -var signerPool fastrlp.ArenaPool + sig := make([]byte, 65) + copy(sig[32-len(R.Bytes()):32], R.Bytes()) + copy(sig[64-len(S.Bytes()):64], S.Bytes()) + sig[64] = byte(V.Int64()) // here is safe to convert it since ValidateSignatureValues will validate the v value + + return sig, nil +} // calcTxHash calculates the transaction hash (keccak256 hash of the RLP value) func calcTxHash(tx *types.Transaction, chainID uint64) types.Hash { a := signerPool.Get() + isDynamicFeeTx := tx.Type == types.DynamicFeeTx v := a.NewArray() + + if isDynamicFeeTx { + v.Set(a.NewUint(chainID)) + } + v.Set(a.NewUint(tx.Nonce)) - v.Set(a.NewBigInt(tx.GasPrice)) + + if isDynamicFeeTx { + v.Set(a.NewBigInt(tx.GasTipCap)) + v.Set(a.NewBigInt(tx.GasFeeCap)) + } else { + v.Set(a.NewBigInt(tx.GasPrice)) + } + v.Set(a.NewUint(tx.Gas)) if tx.To == nil { @@ -62,183 +90,28 @@ func calcTxHash(tx *types.Transaction, chainID uint64) types.Hash { } v.Set(a.NewBigInt(tx.Value)) + v.Set(a.NewCopyBytes(tx.Input)) - // EIP155 - if chainID != 0 { - v.Set(a.NewUint(chainID)) - v.Set(a.NewUint(0)) - v.Set(a.NewUint(0)) + if isDynamicFeeTx { + v.Set(a.NewArray()) + } else { + // EIP155 + if chainID != 0 { + v.Set(a.NewUint(chainID)) + v.Set(a.NewUint(0)) + v.Set(a.NewUint(0)) + } } - hash := keccak.Keccak256Rlp(nil, v) + var hash []byte + if isDynamicFeeTx { + hash = keccak.PrefixedKeccak256Rlp([]byte{byte(tx.Type)}, nil, v) + } else { + hash = keccak.Keccak256Rlp(nil, v) + } signerPool.Put(a) return types.BytesToHash(hash) } - -// Hash is a wrapper function for the calcTxHash, with chainID 0 -func (f *FrontierSigner) Hash(tx *types.Transaction) types.Hash { - return calcTxHash(tx, 0) -} - -// Magic numbers from Ethereum, used in v calculation -var ( - big27 = big.NewInt(27) - big35 = big.NewInt(35) -) - -// Sender decodes the signature and returns the sender of the transaction -func (f *FrontierSigner) Sender(tx *types.Transaction) (types.Address, error) { - refV := big.NewInt(0) - if tx.V != nil { - refV.SetBytes(tx.V.Bytes()) - } - - refV.Sub(refV, big27) - - sig, err := encodeSignature(tx.R, tx.S, refV, f.isHomestead) - if err != nil { - return types.Address{}, err - } - - pub, err := Ecrecover(f.Hash(tx).Bytes(), sig) - if err != nil { - return types.Address{}, err - } - - buf := Keccak256(pub[1:])[12:] - - return types.BytesToAddress(buf), nil -} - -// SignTx signs the transaction using the passed in private key -func (f *FrontierSigner) SignTx( - tx *types.Transaction, - privateKey *ecdsa.PrivateKey, -) (*types.Transaction, error) { - tx = tx.Copy() - - h := f.Hash(tx) - - sig, err := Sign(privateKey, h[:]) - if err != nil { - return nil, err - } - - tx.R = new(big.Int).SetBytes(sig[:32]) - tx.S = new(big.Int).SetBytes(sig[32:64]) - tx.V = new(big.Int).SetBytes(f.CalculateV(sig[64])) - - return tx, nil -} - -// calculateV returns the V value for transactions pre EIP155 -func (f *FrontierSigner) CalculateV(parity byte) []byte { - reference := big.NewInt(int64(parity)) - reference.Add(reference, big27) - - return reference.Bytes() -} - -// NewEIP155Signer returns a new EIP155Signer object -func NewEIP155Signer(forks chain.ForksInTime, chainID uint64) *EIP155Signer { - return &EIP155Signer{chainID: chainID, isHomestead: forks.Homestead} -} - -type EIP155Signer struct { - chainID uint64 - isHomestead bool -} - -// Hash is a wrapper function that calls calcTxHash with the EIP155Signer's chainID -func (e *EIP155Signer) Hash(tx *types.Transaction) types.Hash { - return calcTxHash(tx, e.chainID) -} - -// Sender returns the transaction sender -func (e *EIP155Signer) Sender(tx *types.Transaction) (types.Address, error) { - protected := true - - // Check if v value conforms to an earlier standard (before EIP155) - bigV := big.NewInt(0) - if tx.V != nil { - bigV.SetBytes(tx.V.Bytes()) - } - - if vv := bigV.Uint64(); bits.Len(uint(vv)) <= 8 { - protected = vv != 27 && vv != 28 - } - - if !protected { - return (&FrontierSigner{}).Sender(tx) - } - - // Reverse the V calculation to find the original V in the range [0, 1] - // v = CHAIN_ID * 2 + 35 + {0, 1} - mulOperand := big.NewInt(0).Mul(big.NewInt(int64(e.chainID)), big.NewInt(2)) - bigV.Sub(bigV, mulOperand) - bigV.Sub(bigV, big35) - - sig, err := encodeSignature(tx.R, tx.S, bigV, e.isHomestead) - if err != nil { - return types.Address{}, err - } - - pub, err := Ecrecover(e.Hash(tx).Bytes(), sig) - if err != nil { - return types.Address{}, err - } - - buf := Keccak256(pub[1:])[12:] - - return types.BytesToAddress(buf), nil -} - -// SignTx signs the transaction using the passed in private key -func (e *EIP155Signer) SignTx( - tx *types.Transaction, - privateKey *ecdsa.PrivateKey, -) (*types.Transaction, error) { - tx = tx.Copy() - - h := e.Hash(tx) - - sig, err := Sign(privateKey, h[:]) - if err != nil { - return nil, err - } - - tx.R = new(big.Int).SetBytes(sig[:32]) - tx.S = new(big.Int).SetBytes(sig[32:64]) - tx.V = new(big.Int).SetBytes(e.CalculateV(sig[64])) - - return tx, nil -} - -// calculateV returns the V value for transaction signatures. Based on EIP155 -func (e *EIP155Signer) CalculateV(parity byte) []byte { - reference := big.NewInt(int64(parity)) - reference.Add(reference, big35) - - mulOperand := big.NewInt(0).Mul(big.NewInt(int64(e.chainID)), big.NewInt(2)) - - reference.Add(reference, mulOperand) - - return reference.Bytes() -} - -// encodeSignature generates a signature value based on the R, S and V value -func encodeSignature(R, S, V *big.Int, isHomestead bool) ([]byte, error) { - if !ValidateSignatureValues(V, R, S, isHomestead) { - return nil, fmt.Errorf("invalid txn signature") - } - - sig := make([]byte, 65) - copy(sig[32-len(R.Bytes()):32], R.Bytes()) - copy(sig[64-len(S.Bytes()):64], S.Bytes()) - sig[64] = byte(V.Int64()) // here is safe to convert it since ValidateSignatureValues will validate the v value - - return sig, nil -} diff --git a/crypto/txsigner_eip155.go b/crypto/txsigner_eip155.go new file mode 100644 index 0000000000..faa394347b --- /dev/null +++ b/crypto/txsigner_eip155.go @@ -0,0 +1,99 @@ +package crypto + +import ( + "crypto/ecdsa" + "math/big" + "math/bits" + + "github.com/0xPolygon/polygon-edge/types" +) + +type EIP155Signer struct { + chainID uint64 + isHomestead bool +} + +// NewEIP155Signer returns a new EIP155Signer object +func NewEIP155Signer(chainID uint64, isHomestead bool) *EIP155Signer { + return &EIP155Signer{ + chainID: chainID, + isHomestead: isHomestead, + } +} + +// Hash is a wrapper function that calls calcTxHash with the EIP155Signer's chainID +func (e *EIP155Signer) Hash(tx *types.Transaction) types.Hash { + return calcTxHash(tx, e.chainID) +} + +// Sender returns the transaction sender +func (e *EIP155Signer) Sender(tx *types.Transaction) (types.Address, error) { + protected := true + + // Check if v value conforms to an earlier standard (before EIP155) + bigV := big.NewInt(0) + if tx.V != nil { + bigV.SetBytes(tx.V.Bytes()) + } + + if vv := bigV.Uint64(); bits.Len(uint(vv)) <= 8 { + protected = vv != 27 && vv != 28 + } + + if !protected { + return (&FrontierSigner{}).Sender(tx) + } + + // Reverse the V calculation to find the original V in the range [0, 1] + // v = CHAIN_ID * 2 + 35 + {0, 1} + mulOperand := big.NewInt(0).Mul(big.NewInt(int64(e.chainID)), big.NewInt(2)) + bigV.Sub(bigV, mulOperand) + bigV.Sub(bigV, big35) + + sig, err := encodeSignature(tx.R, tx.S, bigV, e.isHomestead) + if err != nil { + return types.Address{}, err + } + + pub, err := Ecrecover(e.Hash(tx).Bytes(), sig) + if err != nil { + return types.Address{}, err + } + + buf := Keccak256(pub[1:])[12:] + + return types.BytesToAddress(buf), nil +} + +// SignTx signs the transaction using the passed in private key +func (e *EIP155Signer) SignTx( + tx *types.Transaction, + privateKey *ecdsa.PrivateKey, +) (*types.Transaction, error) { + tx = tx.Copy() + + h := e.Hash(tx) + + sig, err := Sign(privateKey, h[:]) + if err != nil { + return nil, err + } + + tx.R = new(big.Int).SetBytes(sig[:32]) + tx.S = new(big.Int).SetBytes(sig[32:64]) + tx.V = new(big.Int).SetBytes(e.calculateV(sig[64])) + + return tx, nil +} + +// calculateV returns the V value for transaction signatures. Based on EIP155 +func (e *EIP155Signer) calculateV(parity byte) []byte { + reference := big.NewInt(int64(parity)) + reference.Add(reference, big35) + + mulOperand := big.NewInt(0).Mul(big.NewInt(int64(e.chainID)), big.NewInt(2)) + + reference.Add(reference, mulOperand) + + return reference.Bytes() +} diff --git a/crypto/txsigner_test.go b/crypto/txsigner_eip155_test.go similarity index 74% rename from crypto/txsigner_test.go rename to crypto/txsigner_eip155_test.go index f53cb5f694..a312b4023f 100644 --- a/crypto/txsigner_test.go +++ b/crypto/txsigner_eip155_test.go @@ -4,71 +4,59 @@ import ( "math/big" "testing" - "github.com/0xPolygon/polygon-edge/chain" "github.com/0xPolygon/polygon-edge/types" "github.com/stretchr/testify/assert" ) -func TestFrontierSigner(t *testing.T) { - signer := &FrontierSigner{} - - toAddress := types.StringToAddress("1") - key, err := GenerateECDSAKey() - assert.NoError(t, err) - - txn := &types.Transaction{ - To: &toAddress, - Value: big.NewInt(10), - GasPrice: big.NewInt(0), - } - signedTx, err := signer.SignTx(txn, key) - assert.NoError(t, err) - - from, err := signer.Sender(signedTx) - assert.NoError(t, err) - assert.Equal(t, from, PubKeyToAddress(&key.PublicKey)) -} - func TestEIP155Signer_Sender(t *testing.T) { t.Parallel() toAddress := types.StringToAddress("1") testTable := []struct { - name string - chainID *big.Int + name string + chainID *big.Int + isHomestead bool }{ { "mainnet", big.NewInt(1), + true, }, { "expanse mainnet", big.NewInt(2), + true, }, { "ropsten", big.NewInt(3), + true, }, { "rinkeby", big.NewInt(4), + true, }, { "goerli", big.NewInt(5), + true, }, { "kovan", big.NewInt(42), + true, }, { "geth private", big.NewInt(1337), + true, }, { "mega large", big.NewInt(0).Exp(big.NewInt(2), big.NewInt(20), nil), // 2**20 + true, }, } @@ -88,7 +76,10 @@ func TestEIP155Signer_Sender(t *testing.T) { GasPrice: big.NewInt(0), } - signer := NewEIP155Signer(chain.AllForksEnabled.At(0), testCase.chainID.Uint64()) + signer := NewEIP155Signer( + testCase.chainID.Uint64(), + testCase.isHomestead, + ) signedTx, signErr := signer.SignTx(txn, key) if signErr != nil { @@ -121,7 +112,7 @@ func TestEIP155Signer_ChainIDMismatch(t *testing.T) { GasPrice: big.NewInt(0), } - signer := NewEIP155Signer(chain.AllForksEnabled.At(0), chainIDTop) + signer := NewEIP155Signer(chainIDTop, true) signedTx, signErr := signer.SignTx(txn, key) if signErr != nil { @@ -129,7 +120,7 @@ func TestEIP155Signer_ChainIDMismatch(t *testing.T) { } for _, chainIDBottom := range chainIDS { - signerBottom := NewEIP155Signer(chain.AllForksEnabled.At(0), chainIDBottom) + signerBottom := NewEIP155Signer(chainIDBottom, true) recoveredSender, recoverErr := signerBottom.Sender(signedTx) if chainIDTop == chainIDBottom { diff --git a/crypto/txsigner_frontier.go b/crypto/txsigner_frontier.go new file mode 100644 index 0000000000..f2d2297d75 --- /dev/null +++ b/crypto/txsigner_frontier.go @@ -0,0 +1,82 @@ +package crypto + +import ( + "crypto/ecdsa" + "math/big" + + "github.com/umbracle/fastrlp" + + "github.com/0xPolygon/polygon-edge/types" +) + +var signerPool fastrlp.ArenaPool + +// FrontierSigner implements tx signer interface +type FrontierSigner struct { + isHomestead bool +} + +// NewFrontierSigner is the constructor of FrontierSigner +func NewFrontierSigner(isHomestead bool) *FrontierSigner { + return &FrontierSigner{ + isHomestead: isHomestead, + } +} + +// Hash is a wrapper function for the calcTxHash, with chainID 0 +func (f *FrontierSigner) Hash(tx *types.Transaction) types.Hash { + return calcTxHash(tx, 0) +} + +// Sender decodes the signature and returns the sender of the transaction +func (f *FrontierSigner) Sender(tx *types.Transaction) (types.Address, error) { + refV := big.NewInt(0) + if tx.V != nil { + refV.SetBytes(tx.V.Bytes()) + } + + refV.Sub(refV, big27) + + sig, err := encodeSignature(tx.R, tx.S, refV, f.isHomestead) + if err != nil { + return types.Address{}, err + } + + pub, err := Ecrecover(f.Hash(tx).Bytes(), sig) + if err != nil { + return types.Address{}, err + } + + buf := Keccak256(pub[1:])[12:] + + return types.BytesToAddress(buf), nil +} + +// SignTx signs the transaction using the passed in private key +func (f *FrontierSigner) SignTx( + tx *types.Transaction, + privateKey *ecdsa.PrivateKey, +) (*types.Transaction, error) { + tx = tx.Copy() + + h := f.Hash(tx) + + sig, err := Sign(privateKey, h[:]) + if err != nil { + return nil, err + } + + tx.R = new(big.Int).SetBytes(sig[:32]) + tx.S = new(big.Int).SetBytes(sig[32:64]) + tx.V = new(big.Int).SetBytes(f.calculateV(sig[64])) + + return tx, nil +} + +// calculateV returns the V value for transactions pre EIP155 +func (f *FrontierSigner) calculateV(parity byte) []byte { + reference := big.NewInt(int64(parity)) + reference.Add(reference, big27) + + return reference.Bytes() +} diff --git a/crypto/txsigner_frontier_test.go b/crypto/txsigner_frontier_test.go new file mode 100644 index 0000000000..e0d9c3ddfb --- /dev/null +++ b/crypto/txsigner_frontier_test.go @@ -0,0 +1,29 @@ +package crypto + +import ( + "math/big" + "testing" + + "github.com/0xPolygon/polygon-edge/types" + "github.com/stretchr/testify/assert" +) + +func TestFrontierSigner(t *testing.T) { + signer := &FrontierSigner{} + + toAddress := types.StringToAddress("1") + key, err := GenerateECDSAKey() + assert.NoError(t, err) + + txn := &types.Transaction{ + To: &toAddress, + Value: big.NewInt(10), + GasPrice: big.NewInt(0), + } + signedTx, err := signer.SignTx(txn, key) + assert.NoError(t, err) + + from, err := signer.Sender(signedTx) + assert.NoError(t, err) + assert.Equal(t, from, PubKeyToAddress(&key.PublicKey)) +} diff --git a/crypto/txsigner_london.go b/crypto/txsigner_london.go new file mode 100644 index 0000000000..727368b28b --- /dev/null +++ b/crypto/txsigner_london.go @@ -0,0 +1,79 @@ +package crypto + +import ( + "crypto/ecdsa" + "math/big" + + "github.com/0xPolygon/polygon-edge/types" +) + +// LondonSigner implements signer for EIP-1559 +type LondonSigner struct { + chainID uint64 + isHomestead bool + fallbackSigner TxSigner +} + +// NewLondonSigner returns a new LondonSigner object +func NewLondonSigner(chainID uint64, isHomestead bool, fallbackSigner TxSigner) *LondonSigner { + return &LondonSigner{ + chainID: chainID, + isHomestead: isHomestead, + fallbackSigner: fallbackSigner, + } +} + +// Hash is a wrapper function that calls calcTxHash with the LondonSigner's fields +func (e *LondonSigner) Hash(tx *types.Transaction) types.Hash { + return calcTxHash(tx, e.chainID) +} + +// Sender returns the transaction sender +func (e *LondonSigner) Sender(tx *types.Transaction) (types.Address, error) { + // Apply fallback signer for non-dynamic-fee-txs + if tx.Type != types.DynamicFeeTx { + return e.fallbackSigner.Sender(tx) + } + + sig, err := encodeSignature(tx.R, tx.S, tx.V, e.isHomestead) + if err != nil { + return types.Address{}, err + } + + pub, err := Ecrecover(e.Hash(tx).Bytes(), sig) + if err != nil { + return types.Address{}, err + } + + buf := Keccak256(pub[1:])[12:] + + return types.BytesToAddress(buf), nil +} + +// SignTx signs the transaction using the passed in private key +func (e *LondonSigner) SignTx(tx *types.Transaction, pk *ecdsa.PrivateKey) (*types.Transaction, error) { + // Apply fallback signer for non-dynamic-fee-txs + if tx.Type != types.DynamicFeeTx { + return e.fallbackSigner.SignTx(tx, pk) + } + + tx = tx.Copy() + + h := e.Hash(tx) + + sig, err := Sign(pk, h[:]) + if err != nil { + return nil, err + } + + tx.R = new(big.Int).SetBytes(sig[:32]) + tx.S = new(big.Int).SetBytes(sig[32:64]) + tx.V = new(big.Int).SetBytes(e.calculateV(sig[64])) + + return tx, nil +} + +// calculateV returns the V value for transaction signatures. Based on EIP155 +func (e *LondonSigner) calculateV(parity byte) []byte { + return big.NewInt(int64(parity)).Bytes() +} diff --git a/crypto/txsigner_london_test.go b/crypto/txsigner_london_test.go new file mode 100644 index 0000000000..f27997dd43 --- /dev/null +++ b/crypto/txsigner_london_test.go @@ -0,0 +1,145 @@ +package crypto + +import ( + "math/big" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/0xPolygon/polygon-edge/types" +) + +func TestLondonSignerSender(t *testing.T) { + t.Parallel() + + toAddress := types.StringToAddress("1") + + testTable := []struct { + name string + chainID *big.Int + isGomestead bool + }{ + { + "mainnet", + big.NewInt(1), + true, + }, + { + "expanse mainnet", + big.NewInt(2), + true, + }, + { + "ropsten", + big.NewInt(3), + true, + }, + { + "rinkeby", + big.NewInt(4), + true, + }, + { + "goerli", + big.NewInt(5), + true, + }, + { + "kovan", + big.NewInt(42), + true, + }, + { + "geth private", + big.NewInt(1337), + true, + }, + { + "mega large", + big.NewInt(0).Exp(big.NewInt(2), big.NewInt(20), nil), // 2**20 + true, + }, + } + + for _, testCase := range testTable { + testCase := testCase + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + + key, keyGenError := GenerateECDSAKey() + if keyGenError != nil { + t.Fatalf("Unable to generate key") + } + + txn := &types.Transaction{ + To: &toAddress, + Value: big.NewInt(1), + GasPrice: big.NewInt(0), + } + + chainID := testCase.chainID.Uint64() + signer := NewLondonSigner(chainID, true, NewEIP155Signer(chainID, true)) + + signedTx, signErr := signer.SignTx(txn, key) + if signErr != nil { + t.Fatalf("Unable to sign transaction") + } + + recoveredSender, recoverErr := signer.Sender(signedTx) + if recoverErr != nil { + t.Fatalf("Unable to recover sender") + } + + assert.Equal(t, recoveredSender.String(), PubKeyToAddress(&key.PublicKey).String()) + }) + } +} + +func Test_LondonSigner_Sender(t *testing.T) { + t.Parallel() + + signer := NewLondonSigner(100, true, NewEIP155Signer(100, true)) + to := types.StringToAddress("0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF") + + r, ok := big.NewInt(0).SetString("102623819621514684481463796449525884981685455700611671612296611353030973716382", 10) + require.True(t, ok) + + s, ok := big.NewInt(0).SetString("52694559292202008915948760944211702951173212957828665318138448463580296965840", 10) + require.True(t, ok) + + testTable := []struct { + name string + tx *types.Transaction + sender types.Address + }{ + { + name: "sender is 0x85dA99c8a7C2C95964c8EfD687E95E632Fc533D6", + tx: &types.Transaction{ + Type: types.DynamicFeeTx, + GasPrice: big.NewInt(1000000402), + GasTipCap: big.NewInt(1000000000), + GasFeeCap: big.NewInt(10000000000), + Gas: 21000, + To: &to, + Value: big.NewInt(100000000000000), + V: big.NewInt(0), + R: r, + S: s, + }, + sender: types.StringToAddress("0x85dA99c8a7C2C95964c8EfD687E95E632Fc533D6"), + }, + } + + for _, tt := range testTable { + tt := tt + + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + sender, err := signer.Sender(tt.tx) + require.NoError(t, err) + require.Equal(t, tt.sender, sender) + }) + } +} diff --git a/docker/README.md b/docker/README.md index f4a5cba036..39a7dc23fe 100644 --- a/docker/README.md +++ b/docker/README.md @@ -7,7 +7,7 @@ ### `polybft` consensus When deploying with `polybft` consensus, there are some additional dependencies: * [npm](https://nodejs.org/en/) -* [go 1.18.x](https://go.dev/dl/) +* [go 1.20.x](https://go.dev/dl/) ## Local development Running `polygon-edge` local cluster with docker can be done very easily by using provided `scripts` folder @@ -50,10 +50,10 @@ Primarily, the `--premine` parameter needs to be edited to include the accounts ### Submodules Before deploying `polybft` environment, `core-contracts` submodule needs to be downloaded. -To do that simply run `make download-submodules`. +To do that, simply run `make download-submodules`. ### Build times -When building containers for the first time (or after purging docker build cache) +When building containers for the first time (or after purging docker build cache), it might take a while to complete, depending on the hardware that the build operation is running on. ### Production diff --git a/docker/local/Dockerfile b/docker/local/Dockerfile index afffcbc864..05c9cf6659 100644 --- a/docker/local/Dockerfile +++ b/docker/local/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.18-alpine AS builder +FROM golang:1.20-alpine AS builder WORKDIR /polygon-edge diff --git a/docker/local/docker-compose.yml b/docker/local/docker-compose.yml index 425b95bd36..00e99800e2 100644 --- a/docker/local/docker-compose.yml +++ b/docker/local/docker-compose.yml @@ -1,14 +1,40 @@ version: '3.9' services: - ## INITIALIZE GENESIS AND SECRETS + ## RUN ROOTCHAIN + rootchain: + image: ghcr.io/0xpolygon/go-ethereum-console:latest + container_name: polygon-edge-rootchain + command: [ + "--dev", + "--dev.period", "2", + "--datadir", "/eth1data", + "--ipcpath", "/eth1data/geth.ipc", + "--http", + "--http.addr", "0.0.0.0", + "--http.vhosts", "*", + "--http.api", "eth,net,web3,debug", + "--ws", + "--ws.addr", "0.0.0.0" + ] + ports: + - '8545:8545' + volumes: + - eth1data:/eth1data + networks: + - polygon-edge-docker + + ## INITIALIZE GENESIS AND SECRETS, ETC. init: build: context: ../../ dockerfile: docker/local/Dockerfile image: local/polygon-edge container_name: polygon-edge-bootstrapper - command: [ "init", "${EDGE_CONSENSUS:-ibft}" ] + command: [ "init", "${EDGE_CONSENSUS:-polybft}" ] + depends_on: + rootchain: + condition: service_started volumes: - data:/data networks: @@ -18,10 +44,21 @@ services: node-1: image: local/polygon-edge container_name: polygon-edge-validator-1 - command: ["server", "--data-dir", "/data/data-1", "--chain", "/data/genesis.json", "--grpc-address", "0.0.0.0:9632", "--libp2p", "0.0.0.0:1478", "--jsonrpc", "0.0.0.0:8545", "--prometheus", "0.0.0.0:5001", "--seal"] + command: [ + "server", + "--data-dir", "/data/data-1", + "--chain", "/data/genesis.json", + "--grpc-address", "0.0.0.0:9632", + "--libp2p", "0.0.0.0:1478", + "--jsonrpc", "0.0.0.0:8545", + "--prometheus", "0.0.0.0:5001", + "--seal" + ] depends_on: init: condition: service_completed_successfully + rootchain: + condition: service_started ports: - '10000:9632' - '10002:8545' @@ -35,10 +72,22 @@ services: node-2: image: local/polygon-edge container_name: polygon-edge-validator-2 - command: ["server", "--data-dir", "/data/data-2", "--chain", "/data/genesis.json", "--grpc-address", "0.0.0.0:9632", "--libp2p", "0.0.0.0:1478", "--jsonrpc", "0.0.0.0:8545", "--prometheus", "0.0.0.0:5001", "--seal"] + command: [ + "server", + "--data-dir", + "/data/data-2", + "--chain", "/data/genesis.json", + "--grpc-address", "0.0.0.0:9632", + "--libp2p", "0.0.0.0:1478", + "--jsonrpc", "0.0.0.0:8545", + "--prometheus", "0.0.0.0:5001", + "--seal" + ] depends_on: init: condition: service_completed_successfully + rootchain: + condition: service_started ports: - '20000:9632' - '20002:8545' @@ -52,10 +101,21 @@ services: node-3: image: local/polygon-edge container_name: polygon-edge-validator-3 - command: ["server", "--data-dir", "/data/data-3", "--chain", "/data/genesis.json", "--grpc-address", "0.0.0.0:9632", "--libp2p", "0.0.0.0:1478", "--jsonrpc", "0.0.0.0:8545", "--prometheus", "0.0.0.0:5001", "--seal"] + command: [ + "server", + "--data-dir", "/data/data-3", + "--chain", "/data/genesis.json", + "--grpc-address", "0.0.0.0:9632", + "--libp2p", "0.0.0.0:1478", + "--jsonrpc", "0.0.0.0:8545", + "--prometheus", "0.0.0.0:5001", + "--seal" + ] depends_on: init: condition: service_completed_successfully + rootchain: + condition: service_started ports: - '30000:9632' - '30002:8545' @@ -69,10 +129,21 @@ services: node-4: image: local/polygon-edge container_name: polygon-edge-validator-4 - command: ["server", "--data-dir", "/data/data-4", "--chain", "/data/genesis.json", "--grpc-address", "0.0.0.0:9632", "--libp2p", "0.0.0.0:1478", "--jsonrpc", "0.0.0.0:8545", "--prometheus", "0.0.0.0:5001", "--seal"] + command: [ + "server", + "--data-dir", "/data/data-4", + "--chain", "/data/genesis.json", + "--grpc-address", "0.0.0.0:9632", + "--libp2p", "0.0.0.0:1478", + "--jsonrpc", "0.0.0.0:8545", + "--prometheus", "0.0.0.0:5001", + "--seal" + ] depends_on: init: condition: service_completed_successfully + rootchain: + condition: service_started ports: - '40000:9632' - '40002:8545' @@ -90,4 +161,5 @@ networks: volumes: data: + eth1data: genesis: diff --git a/docker/local/polygon-edge.sh b/docker/local/polygon-edge.sh index cbb813c501..29db8d7bc3 100755 --- a/docker/local/polygon-edge.sh +++ b/docker/local/polygon-edge.sh @@ -14,49 +14,115 @@ EOL ) case "$1" in - "init") case "$2" in - "ibft") - if [ -f "$GENESIS_PATH" ]; then - echo "Secrets have already been generated." - else - echo "Generating secrets..." - secrets=$("$POLYGON_EDGE_BIN" secrets init --insecure --num 4 --data-dir /data/data- --json) - echo "Secrets have been successfully generated" - echo "Generating IBFT Genesis file..." - cd /data && /polygon-edge/polygon-edge genesis $CHAIN_CUSTOM_OPTIONS \ - --dir genesis.json \ - --consensus ibft \ - --ibft-validators-prefix-path data- \ - --validator-set-size=4 \ - --bootnode "/dns4/node-1/tcp/1478/p2p/$(echo "$secrets" | jq -r '.[0] | .node_id')" \ - --bootnode "/dns4/node-2/tcp/1478/p2p/$(echo "$secrets" | jq -r '.[1] | .node_id')" - fi + "ibft") + if [ -f "$GENESIS_PATH" ]; then + echo "Secrets have already been generated." + else + echo "Generating IBFT secrets..." + secrets=$("$POLYGON_EDGE_BIN" secrets init --insecure --num 4 --data-dir /data/data- --json) + echo "Secrets have been successfully generated" + + rm -f /data/genesis.json + + echo "Generating IBFT Genesis file..." + "$POLYGON_EDGE_BIN" genesis $CHAIN_CUSTOM_OPTIONS \ + --dir /data/genesis.json \ + --consensus ibft \ + --ibft-validators-prefix-path data- \ + --bootnode "/dns4/node-1/tcp/1478/p2p/$(echo "$secrets" | jq -r '.[0] | .node_id')" \ + --bootnode "/dns4/node-2/tcp/1478/p2p/$(echo "$secrets" | jq -r '.[1] | .node_id')" \ + --bootnode "/dns4/node-3/tcp/1478/p2p/$(echo "$secrets" | jq -r '.[2] | .node_id')" \ + --bootnode "/dns4/node-4/tcp/1478/p2p/$(echo "$secrets" | jq -r '.[3] | .node_id')" + fi ;; "polybft") echo "Generating PolyBFT secrets..." secrets=$("$POLYGON_EDGE_BIN" polybft-secrets init --insecure --num 4 --data-dir /data/data- --json) echo "Secrets have been successfully generated" - echo "Generating manifest..." - "$POLYGON_EDGE_BIN" manifest --path /data/manifest.json --validators-path /data --validators-prefix data- + rm -f /data/genesis.json - echo "Generating PolyBFT Genesis file..." + echo "Generating PolyBFT genesis file..." "$POLYGON_EDGE_BIN" genesis $CHAIN_CUSTOM_OPTIONS \ --dir /data/genesis.json \ --consensus polybft \ - --manifest /data/manifest.json \ - --validator-set-size=4 \ + --validators-path /data \ + --validators-prefix data- \ + --reward-wallet 0xDEADBEEF:1000000 \ + --native-token-config "Polygon:MATIC:18:true:$(echo "$secrets" | jq -r '.[0] | .address')" \ --bootnode "/dns4/node-1/tcp/1478/p2p/$(echo "$secrets" | jq -r '.[0] | .node_id')" \ - --bootnode "/dns4/node-2/tcp/1478/p2p/$(echo "$secrets" | jq -r '.[1] | .node_id')" + --bootnode "/dns4/node-2/tcp/1478/p2p/$(echo "$secrets" | jq -r '.[1] | .node_id')" \ + --bootnode "/dns4/node-3/tcp/1478/p2p/$(echo "$secrets" | jq -r '.[2] | .node_id')" \ + --bootnode "/dns4/node-4/tcp/1478/p2p/$(echo "$secrets" | jq -r '.[3] | .node_id')" + + echo "Deploying stake manager..." + "$POLYGON_EDGE_BIN" polybft stake-manager-deploy \ + --jsonrpc http://rootchain:8545 \ + --genesis /data/genesis.json \ + --test + + stakeManagerAddr=$(cat /data/genesis.json | jq -r '.params.engine.polybft.bridge.stakeManagerAddr') + stakeToken=$(cat /data/genesis.json | jq -r '.params.engine.polybft.bridge.stakeTokenAddr') + + "$POLYGON_EDGE_BIN" rootchain deploy \ + --stake-manager ${stakeManagerAddr} \ + --stake-token ${stakeToken} \ + --json-rpc http://rootchain:8545 \ + --genesis /data/genesis.json \ + --test + + customSupernetManagerAddr=$(cat /data/genesis.json | jq -r '.params.engine.polybft.bridge.customSupernetManagerAddr') + supernetID=$(cat /data/genesis.json | jq -r '.params.engine.polybft.supernetID') + addresses="$(echo "$secrets" | jq -r '.[0] | .address'),$(echo "$secrets" | jq -r '.[1] | .address'),$(echo "$secrets" | jq -r '.[2] | .address'),$(echo "$secrets" | jq -r '.[3] | .address')" + + "$POLYGON_EDGE_BIN" rootchain fund \ + --json-rpc http://rootchain:8545 \ + --stake-token ${stakeToken} \ + --mint \ + --addresses ${addresses} \ + --amounts 1000000000000000000000000,1000000000000000000000000,1000000000000000000000000,1000000000000000000000000 + + "$POLYGON_EDGE_BIN" polybft whitelist-validators \ + --addresses ${addresses} \ + --supernet-manager ${customSupernetManagerAddr} \ + --private-key aa75e9a7d427efc732f8e4f1a5b7646adcc61fd5bae40f80d13c8419c9f43d6d \ + --jsonrpc http://rootchain:8545 + + counter=1 + while [ $counter -le 4 ]; do + echo "Registering validator: ${counter}" + + "$POLYGON_EDGE_BIN" polybft register-validator \ + --supernet-manager ${customSupernetManagerAddr} \ + --data-dir /data/data-${counter} \ + --jsonrpc http://rootchain:8545 + + "$POLYGON_EDGE_BIN" polybft stake \ + --data-dir /data/data-${counter} \ + --amount 1000000000000000000000000 \ + --supernet-id ${supernetID} \ + --stake-manager ${stakeManagerAddr} \ + --stake-token ${stakeToken} \ + --jsonrpc http://rootchain:8545 + + counter=$((counter + 1)) + done + + "$POLYGON_EDGE_BIN" polybft supernet \ + --private-key aa75e9a7d427efc732f8e4f1a5b7646adcc61fd5bae40f80d13c8419c9f43d6d \ + --supernet-manager ${customSupernetManagerAddr} \ + --stake-manager ${stakeManagerAddr} \ + --finalize-genesis-set \ + --enable-staking \ + --genesis /data/genesis.json \ + --jsonrpc http://rootchain:8545 ;; esac ;; - *) echo "Executing polygon-edge..." exec "$POLYGON_EDGE_BIN" "$@" ;; - esac diff --git a/docs/bridge/sequences.md b/docs/bridge/sequences.md new file mode 100644 index 0000000000..7134412653 --- /dev/null +++ b/docs/bridge/sequences.md @@ -0,0 +1,64 @@ +## Deposit + +Bridge ERC 20 tokens from rootchain to childchain via deposit. + +```mermaid +sequenceDiagram + User->>Edge: deposit + Edge->>RootERC20.sol: approve(RootERC20Predicate) + Edge->>RootERC20Predicate.sol: deposit() + RootERC20Predicate.sol->>RootERC20Predicate.sol: mapToken() + RootERC20Predicate.sol->>StateSender.sol: syncState(MAP_TOKEN_SIG), recv=ChildERC20Predicate + RootERC20Predicate.sol-->>Edge: TokenMapped Event + StateSender.sol-->>Edge: StateSynced Event to map tokens on child predicate + RootERC20Predicate.sol->>StateSender.sol: syncState(DEPOSIT_SIG), recv=ChildERC20Predicate + StateSender.sol-->>Edge: StateSynced Event to deposit on child chain + Edge->>User: ok + Edge->>StateReceiver.sol:commit() + StateReceiver.sol-->>Edge: NewCommitment Event + Edge->>StateReceiver.sol:execute() + StateReceiver.sol->>ChildERC20Predicate.sol:onStateReceive() + ChildERC20Predicate.sol->>ChildERC20.sol: mint() + StateReceiver.sol-->>Edge:StateSyncResult Event +``` + +## Withdraw + +Bridge ERC 20 tokens from childchain to rootchain via withdrawal. + +```mermaid +sequenceDiagram + User->>Edge: withdraw + Edge->>ChildERC20Predicate.sol: withdrawTo() + ChildERC20Predicate.sol->>ChildERC20: burn() + ChildERC20Predicate.sol->>L2StateSender.sol: syncState(WITHDRAW_SIG), recv=RootERC20Predicate + Edge->>User: tx hash + User->>Edge: get tx receipt + Edge->>User: exit event id + ChildERC20Predicate.sol-->>Edge: L2ERC20Withdraw Event + L2StateSender.sol-->>Edge: StateSynced Event + Edge->>Edge: Seal block + Edge->>CheckpointManager.sol: submit() +``` +## Exit + +Finalize withdrawal of ERC 20 tokens from childchain to rootchain. + +```mermaid +sequenceDiagram + User->>Edge: exit, event id:X + Edge->>Edge: bridge_generateExitProof() + Edge->>CheckpointManager.sol: getCheckpointBlock() + CheckpointManager.sol->>Edge: blockNum + Edge->>Edge: getExitEventsForProof(epochNum, blockNum) + Edge->>Edge: createExitTree(exitEvents) + Edge->>Edge: generateProof() + Edge->>ExitHelper.sol: exit() + ExitHelper.sol->>CheckpointManager.sol: getEventMembershipByBlockNumber() + ExitHelper.sol->>RootERC20Predicate.sol:onL2StateReceive() + RootERC20Predicate.sol->>RootERC20: transfer() + Edge->>User: ok + RootERC20Predicate.sol-->>Edge: ERC20Withdraw Event + ExitHelper.sol-->>Edge: ExitProcessed Event +``` + diff --git a/e2e-polybft/e2e/acls_test.go b/e2e-polybft/e2e/acls_test.go new file mode 100644 index 0000000000..deb72c2a27 --- /dev/null +++ b/e2e-polybft/e2e/acls_test.go @@ -0,0 +1,415 @@ +package e2e + +import ( + "fmt" + "math/big" + "testing" + + "github.com/0xPolygon/polygon-edge/contracts" + "github.com/0xPolygon/polygon-edge/e2e-polybft/framework" + "github.com/0xPolygon/polygon-edge/helper/hex" + "github.com/0xPolygon/polygon-edge/state/runtime/addresslist" + "github.com/0xPolygon/polygon-edge/types" + "github.com/stretchr/testify/require" + "github.com/umbracle/ethgo/wallet" +) + +// Contract used as bytecode + +/* +pragma solidity ^0.8; +pragma experimental ABIEncoderV2; + +contract Sample { + address public constant allowListContractsAddr = 0x0200000000000000000000000000000000000000; + + function readAddressList(address addr) public returns (uint256) { + (bool success, bytes memory returnData) = allowListContractsAddr.call(abi.encodeWithSignature("readAddressList(address)", addr)); + (uint256 val) = abi.decode(returnData, (uint256)); + return val; + } +} +*/ + +func TestE2E_AllowList_ContractDeployment(t *testing.T) { + // create two accounts, one for an admin sender and a second + // one for a non-enabled account that will switch on-off between + // both enabled and non-enabled roles. + admin, _ := wallet.GenerateKey() + target, _ := wallet.GenerateKey() + + adminAddr := types.Address(admin.Address()) + targetAddr := types.Address(target.Address()) + + otherAddr := types.Address{0x1} + + cluster := framework.NewTestCluster(t, 5, + framework.WithNativeTokenConfig(fmt.Sprintf(nativeTokenMintableTestCfg, adminAddr)), + framework.WithPremine(adminAddr, targetAddr), + framework.WithContractDeployerAllowListAdmin(adminAddr), + framework.WithContractDeployerAllowListEnabled(otherAddr), + ) + defer cluster.Stop() + + cluster.WaitForReady(t) + + // bytecode for an empty smart contract + bytecode, err := hex.DecodeString("608060405234801561001057600080fd5b506103db806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80635e9f13f81461003b578063d78bca6914610059575b600080fd5b610043610089565b6040516100509190610217565b60405180910390f35b610073600480360381019061006e9190610263565b6100a1565b60405161008091906102a9565b60405180910390f35b73020000000000000000000000000000000000000081565b600080600073020000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16846040516024016100e29190610217565b6040516020818303038152906040527fd78bca69000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161016c9190610335565b6000604051808303816000865af19150503d80600081146101a9576040519150601f19603f3d011682016040523d82523d6000602084013e6101ae565b606091505b50915091506000818060200190518101906101c99190610378565b9050809350505050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610201826101d6565b9050919050565b610211816101f6565b82525050565b600060208201905061022c6000830184610208565b92915050565b600080fd5b610240816101f6565b811461024b57600080fd5b50565b60008135905061025d81610237565b92915050565b60006020828403121561027957610278610232565b5b60006102878482850161024e565b91505092915050565b6000819050919050565b6102a381610290565b82525050565b60006020820190506102be600083018461029a565b92915050565b600081519050919050565b600081905092915050565b60005b838110156102f85780820151818401526020810190506102dd565b60008484015250505050565b600061030f826102c4565b61031981856102cf565b93506103298185602086016102da565b80840191505092915050565b60006103418284610304565b915081905092915050565b61035581610290565b811461036057600080fd5b50565b6000815190506103728161034c565b92915050565b60006020828403121561038e5761038d610232565b5b600061039c84828501610363565b9150509291505056fea264697066735822122035f391b5c3dbf9a5e31072167a4ada71e9ba762650849f6320bc6150fa45aa9564736f6c63430008110033") + require.NoError(t, err) + + { + // Step 0. Check the role of both accounts + expectRole(t, cluster, contracts.AllowListContractsAddr, adminAddr, addresslist.AdminRole) + expectRole(t, cluster, contracts.AllowListContractsAddr, targetAddr, addresslist.NoRole) + expectRole(t, cluster, contracts.AllowListContractsAddr, otherAddr, addresslist.EnabledRole) + } + + { + // Step 1. 'targetAddr' can send a normal transaction (non-contract creation). + err := cluster.Transfer(t, target, types.ZeroAddress, big.NewInt(1)).Wait() + require.NoError(t, err) + } + + var proxyContract types.Address + + { + // Step 2. 'targetAddr' **cannot** deploy a contract because it is not whitelisted. + // (The transaction does not fail but the contract is not deployed and all gas + // for the transaction is consumed) + deployTxn := cluster.Deploy(t, target, bytecode) + require.NoError(t, deployTxn.Wait()) + require.True(t, deployTxn.Reverted()) + require.False(t, cluster.ExistsCode(t, deployTxn.Receipt().ContractAddress)) + } + + { + // Step 3. 'adminAddr' can create contracts + deployTxn := cluster.Deploy(t, admin, bytecode) + require.NoError(t, deployTxn.Wait()) + require.True(t, deployTxn.Succeed()) + require.True(t, cluster.ExistsCode(t, deployTxn.Receipt().ContractAddress)) + + proxyContract = types.Address(deployTxn.Receipt().ContractAddress) + } + + { + // Step 4. 'adminAddr' sends a transaction to enable 'targetAddr'. + input, _ := addresslist.SetEnabledFunc.Encode([]interface{}{targetAddr}) + + adminSetTxn := cluster.MethodTxn(t, admin, contracts.AllowListContractsAddr, input) + require.NoError(t, adminSetTxn.Wait()) + expectRole(t, cluster, contracts.AllowListContractsAddr, targetAddr, addresslist.EnabledRole) + } + + { + // Step 5. 'targetAddr' can create contracts now. + deployTxn := cluster.Deploy(t, target, bytecode) + require.NoError(t, deployTxn.Wait()) + require.True(t, deployTxn.Succeed()) + require.True(t, cluster.ExistsCode(t, deployTxn.Receipt().ContractAddress)) + } + + { + // Step 6. 'targetAddr' cannot enable other accounts since it is not an admin + // (The transaction fails) + input, _ := addresslist.SetEnabledFunc.Encode([]interface{}{types.ZeroAddress}) + + adminSetFailTxn := cluster.MethodTxn(t, target, contracts.AllowListContractsAddr, input) + require.NoError(t, adminSetFailTxn.Wait()) + require.True(t, adminSetFailTxn.Failed()) + expectRole(t, cluster, contracts.AllowListContractsAddr, types.ZeroAddress, addresslist.NoRole) + } + + { + // Step 7. Call a proxy contract that can call the allow list + resp := cluster.Call(t, proxyContract, addresslist.ReadAddressListFunc, adminAddr) + + role, ok := resp["0"].(*big.Int) + require.True(t, ok) + require.Equal(t, role.Uint64(), addresslist.AdminRole.Uint64()) + } +} + +func TestE2E_BlockList_ContractDeployment(t *testing.T) { + // create two accounts, one for an admin sender and a second + // one for a non-enabled account that will switch on-off between + // both enabled and non-enabled roles. + admin, _ := wallet.GenerateKey() + target, _ := wallet.GenerateKey() + + adminAddr := types.Address(admin.Address()) + targetAddr := types.Address(target.Address()) + + otherAddr := types.Address{0x1} + + cluster := framework.NewTestCluster(t, 5, + framework.WithNativeTokenConfig(fmt.Sprintf(nativeTokenMintableTestCfg, adminAddr)), + framework.WithPremine(adminAddr, targetAddr), + framework.WithContractDeployerBlockListAdmin(adminAddr), + framework.WithContractDeployerBlockListEnabled(otherAddr), + ) + defer cluster.Stop() + + cluster.WaitForReady(t) + + // bytecode for an empty smart contract + bytecode, err := hex.DecodeString("608060405234801561001057600080fd5b506103db806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80635e9f13f81461003b578063d78bca6914610059575b600080fd5b610043610089565b6040516100509190610217565b60405180910390f35b610073600480360381019061006e9190610263565b6100a1565b60405161008091906102a9565b60405180910390f35b73020000000000000000000000000000000000000081565b600080600073020000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16846040516024016100e29190610217565b6040516020818303038152906040527fd78bca69000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161016c9190610335565b6000604051808303816000865af19150503d80600081146101a9576040519150601f19603f3d011682016040523d82523d6000602084013e6101ae565b606091505b50915091506000818060200190518101906101c99190610378565b9050809350505050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610201826101d6565b9050919050565b610211816101f6565b82525050565b600060208201905061022c6000830184610208565b92915050565b600080fd5b610240816101f6565b811461024b57600080fd5b50565b60008135905061025d81610237565b92915050565b60006020828403121561027957610278610232565b5b60006102878482850161024e565b91505092915050565b6000819050919050565b6102a381610290565b82525050565b60006020820190506102be600083018461029a565b92915050565b600081519050919050565b600081905092915050565b60005b838110156102f85780820151818401526020810190506102dd565b60008484015250505050565b600061030f826102c4565b61031981856102cf565b93506103298185602086016102da565b80840191505092915050565b60006103418284610304565b915081905092915050565b61035581610290565b811461036057600080fd5b50565b6000815190506103728161034c565b92915050565b60006020828403121561038e5761038d610232565b5b600061039c84828501610363565b9150509291505056fea264697066735822122035f391b5c3dbf9a5e31072167a4ada71e9ba762650849f6320bc6150fa45aa9564736f6c63430008110033") + require.NoError(t, err) + + { + // Step 0. Check the role of accounts + expectRole(t, cluster, contracts.BlockListContractsAddr, adminAddr, addresslist.AdminRole) + expectRole(t, cluster, contracts.BlockListContractsAddr, targetAddr, addresslist.NoRole) + expectRole(t, cluster, contracts.BlockListContractsAddr, otherAddr, addresslist.EnabledRole) + } + + { + // Step 1. 'targetAddr' can send a normal transaction (non-contract creation). + err := cluster.Transfer(t, target, types.ZeroAddress, big.NewInt(1)).Wait() + require.NoError(t, err) + } + + { + // Step 2. 'targetAddr' **can** deploy a contract because it is not blacklisted. + deployTxn := cluster.Deploy(t, target, bytecode) + require.NoError(t, deployTxn.Wait()) + require.True(t, deployTxn.Succeed()) + require.True(t, cluster.ExistsCode(t, deployTxn.Receipt().ContractAddress)) + } + + { + // Step 3. 'adminAddr' can create contracts + deployTxn := cluster.Deploy(t, admin, bytecode) + require.NoError(t, deployTxn.Wait()) + require.True(t, deployTxn.Succeed()) + require.True(t, cluster.ExistsCode(t, deployTxn.Receipt().ContractAddress)) + } + + { + // Step 4. 'adminAddr' sends a transaction to enable 'targetAddr'. + input, _ := addresslist.SetEnabledFunc.Encode([]interface{}{targetAddr}) + + adminSetTxn := cluster.MethodTxn(t, admin, contracts.BlockListContractsAddr, input) + require.NoError(t, adminSetTxn.Wait()) + expectRole(t, cluster, contracts.BlockListContractsAddr, targetAddr, addresslist.EnabledRole) + } + + { + // Step 5. 'targetAddr' **cannot** create contracts now as it's now blacklisted. + deployTxn := cluster.Deploy(t, target, bytecode) + require.NoError(t, deployTxn.Wait()) + require.True(t, deployTxn.Reverted()) + require.False(t, cluster.ExistsCode(t, deployTxn.Receipt().ContractAddress)) + } + + { + // Step 6. 'targetAddr' cannot enable other accounts since it is not an admin + // (The transaction fails) + input, _ := addresslist.SetEnabledFunc.Encode([]interface{}{types.ZeroAddress}) + + adminSetFailTxn := cluster.MethodTxn(t, target, contracts.BlockListContractsAddr, input) + require.NoError(t, adminSetFailTxn.Wait()) + require.True(t, adminSetFailTxn.Failed()) + expectRole(t, cluster, contracts.BlockListContractsAddr, types.ZeroAddress, addresslist.NoRole) + } +} + +func TestE2E_AllowList_Transactions(t *testing.T) { + // create two accounts, one for an admin sender and a second + // one for a non-enabled account that will switch on-off between + // both enabled and non-enabled roles. + admin, _ := wallet.GenerateKey() + target, _ := wallet.GenerateKey() + other, _ := wallet.GenerateKey() + + adminAddr := types.Address(admin.Address()) + targetAddr := types.Address(target.Address()) + otherAddr := types.Address(other.Address()) + + cluster := framework.NewTestCluster(t, 5, + framework.WithNativeTokenConfig(fmt.Sprintf(nativeTokenMintableTestCfg, adminAddr)), + framework.WithPremine(adminAddr, targetAddr, otherAddr), + framework.WithTransactionsAllowListAdmin(adminAddr), + framework.WithTransactionsAllowListEnabled(otherAddr), + ) + defer cluster.Stop() + + cluster.WaitForReady(t) + + // bytecode for an empty smart contract + bytecode, _ := hex.DecodeString("608060405234801561001057600080fd5b506103db806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80635e9f13f81461003b578063d78bca6914610059575b600080fd5b610043610089565b6040516100509190610217565b60405180910390f35b610073600480360381019061006e9190610263565b6100a1565b60405161008091906102a9565b60405180910390f35b73020000000000000000000000000000000000000081565b600080600073020000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16846040516024016100e29190610217565b6040516020818303038152906040527fd78bca69000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161016c9190610335565b6000604051808303816000865af19150503d80600081146101a9576040519150601f19603f3d011682016040523d82523d6000602084013e6101ae565b606091505b50915091506000818060200190518101906101c99190610378565b9050809350505050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610201826101d6565b9050919050565b610211816101f6565b82525050565b600060208201905061022c6000830184610208565b92915050565b600080fd5b610240816101f6565b811461024b57600080fd5b50565b60008135905061025d81610237565b92915050565b60006020828403121561027957610278610232565b5b60006102878482850161024e565b91505092915050565b6000819050919050565b6102a381610290565b82525050565b60006020820190506102be600083018461029a565b92915050565b600081519050919050565b600081905092915050565b60005b838110156102f85780820151818401526020810190506102dd565b60008484015250505050565b600061030f826102c4565b61031981856102cf565b93506103298185602086016102da565b80840191505092915050565b60006103418284610304565b915081905092915050565b61035581610290565b811461036057600080fd5b50565b6000815190506103728161034c565b92915050565b60006020828403121561038e5761038d610232565b5b600061039c84828501610363565b9150509291505056fea264697066735822122035f391b5c3dbf9a5e31072167a4ada71e9ba762650849f6320bc6150fa45aa9564736f6c63430008110033") + + { + // Step 0. Check the role of both accounts + expectRole(t, cluster, contracts.AllowListTransactionsAddr, adminAddr, addresslist.AdminRole) + expectRole(t, cluster, contracts.AllowListTransactionsAddr, targetAddr, addresslist.NoRole) + expectRole(t, cluster, contracts.AllowListTransactionsAddr, otherAddr, addresslist.EnabledRole) + } + + { + // Step 1. 'otherAddr' can send a normal transaction (non-contract creation). + otherTxn := cluster.Transfer(t, other, types.ZeroAddress, big.NewInt(1)) + require.NoError(t, otherTxn.Wait()) + require.True(t, otherTxn.Succeed()) + } + + { + // Step 2. 'targetAddr' **cannot** send a normal transaction because it is not whitelisted. + targetTxn := cluster.Transfer(t, target, types.ZeroAddress, big.NewInt(1)) + require.NoError(t, targetTxn.Wait()) + require.True(t, targetTxn.Reverted()) + } + + { + // Step 2.5. 'targetAddr' **cannot** deploy a contract because it is not whitelisted. + // (The transaction does not fail but the contract is not deployed and all gas + // for the transaction is consumed) + deployTxn := cluster.Deploy(t, target, bytecode) + require.NoError(t, deployTxn.Wait()) + require.True(t, deployTxn.Reverted()) + require.False(t, cluster.ExistsCode(t, deployTxn.Receipt().ContractAddress)) + } + + { + // Step 3. 'adminAddr' sends a transaction to enable 'targetAddr'. + input, _ := addresslist.SetEnabledFunc.Encode([]interface{}{targetAddr}) + + adminSetTxn := cluster.MethodTxn(t, admin, contracts.AllowListTransactionsAddr, input) + require.NoError(t, adminSetTxn.Wait()) + expectRole(t, cluster, contracts.AllowListTransactionsAddr, targetAddr, addresslist.EnabledRole) + } + + { + // Step 4. 'targetAddr' **can** send a normal transaction because it is whitelisted. + targetTxn := cluster.Transfer(t, target, types.ZeroAddress, big.NewInt(1)) + require.NoError(t, targetTxn.Wait()) + require.True(t, targetTxn.Succeed()) + } + + { + // Step 5. 'targetAddr' cannot enable other accounts since it is not an admin + // (The transaction fails) + input, _ := addresslist.SetEnabledFunc.Encode([]interface{}{types.ZeroAddress}) + + adminSetFailTxn := cluster.MethodTxn(t, target, contracts.AllowListTransactionsAddr, input) + require.NoError(t, adminSetFailTxn.Wait()) + require.True(t, adminSetFailTxn.Failed()) + expectRole(t, cluster, contracts.AllowListTransactionsAddr, types.ZeroAddress, addresslist.NoRole) + } + + { + // Step 6. 'adminAddr' sends a transaction to disable himself. + input, _ := addresslist.SetNoneFunc.Encode([]interface{}{adminAddr}) + + noneSetTxn := cluster.MethodTxn(t, admin, contracts.AllowListTransactionsAddr, input) + require.NoError(t, noneSetTxn.Wait()) + require.True(t, noneSetTxn.Failed()) + expectRole(t, cluster, contracts.AllowListTransactionsAddr, adminAddr, addresslist.AdminRole) + } +} + +func TestE2E_BlockList_Transactions(t *testing.T) { + // create two accounts, one for an admin sender and a second + // one for a non-enabled account that will switch on-off between + // both enabled and non-enabled roles. + admin, _ := wallet.GenerateKey() + target, _ := wallet.GenerateKey() + other, _ := wallet.GenerateKey() + + adminAddr := types.Address(admin.Address()) + targetAddr := types.Address(target.Address()) + otherAddr := types.Address(other.Address()) + + cluster := framework.NewTestCluster(t, 5, + framework.WithNativeTokenConfig(fmt.Sprintf(nativeTokenMintableTestCfg, adminAddr)), + framework.WithPremine(adminAddr, targetAddr, otherAddr), + framework.WithTransactionsBlockListAdmin(adminAddr), + framework.WithTransactionsBlockListEnabled(otherAddr), + ) + defer cluster.Stop() + + cluster.WaitForReady(t) + + { + // Step 0. Check the role of both accounts + expectRole(t, cluster, contracts.BlockListTransactionsAddr, adminAddr, addresslist.AdminRole) + expectRole(t, cluster, contracts.BlockListTransactionsAddr, targetAddr, addresslist.NoRole) + expectRole(t, cluster, contracts.BlockListTransactionsAddr, otherAddr, addresslist.EnabledRole) + } + + { + // Step 1. 'otherAddr' **cannot** send a normal transaction (non-contract creation) because it is blacklisted. + otherTxn := cluster.Transfer(t, other, types.ZeroAddress, big.NewInt(1)) + require.NoError(t, otherTxn.Wait()) + require.True(t, otherTxn.Reverted()) + } + + { + // Step 2. 'targetAddr' **can** send a normal transaction because it is not blacklisted. + targetTxn := cluster.Transfer(t, target, types.ZeroAddress, big.NewInt(1)) + require.NoError(t, targetTxn.Wait()) + require.True(t, targetTxn.Succeed()) + } + + { + // Step 3. 'targetAddr' cannot enable other accounts since it is not an admin + // (The transaction fails) + input, _ := addresslist.SetEnabledFunc.Encode([]interface{}{types.ZeroAddress}) + + adminSetFailTxn := cluster.MethodTxn(t, target, contracts.BlockListTransactionsAddr, input) + require.NoError(t, adminSetFailTxn.Wait()) + require.True(t, adminSetFailTxn.Failed()) + expectRole(t, cluster, contracts.BlockListTransactionsAddr, types.ZeroAddress, addresslist.NoRole) + } + + { + // Step 4. 'adminAddr' sends a transaction to enable 'targetAddr'. + input, _ := addresslist.SetEnabledFunc.Encode([]interface{}{targetAddr}) + + adminSetTxn := cluster.MethodTxn(t, admin, contracts.BlockListTransactionsAddr, input) + require.NoError(t, adminSetTxn.Wait()) + expectRole(t, cluster, contracts.BlockListTransactionsAddr, targetAddr, addresslist.EnabledRole) + } + + { + // Step 5. 'targetAddr' **cannot** send a normal transaction because it is blacklisted. + targetTxn := cluster.Transfer(t, target, types.ZeroAddress, big.NewInt(1)) + require.NoError(t, targetTxn.Wait()) + require.True(t, targetTxn.Reverted()) + } +} + +func TestE2E_AddressLists_Bridge(t *testing.T) { + // create two accounts, one for an admin sender and a second + // one for a non-enabled account that will switch on-off between + // both enabled and non-enabled roles. + admin, _ := wallet.GenerateKey() + target, _ := wallet.GenerateKey() + other, _ := wallet.GenerateKey() + + adminAddr := types.Address(admin.Address()) + targetAddr := types.Address(target.Address()) + otherAddr := types.Address(other.Address()) + + cluster := framework.NewTestCluster(t, 5, + framework.WithNativeTokenConfig(fmt.Sprintf(nativeTokenMintableTestCfg, adminAddr)), + framework.WithPremine(adminAddr, targetAddr, otherAddr), + framework.WithBridgeAllowListAdmin(adminAddr), + framework.WithBridgeAllowListEnabled(otherAddr), + framework.WithBridgeBlockListAdmin(adminAddr), + framework.WithBridgeBlockListEnabled(otherAddr), + ) + defer cluster.Stop() + + cluster.WaitForReady(t) + + { + // Step 0. Check the role of both accounts + expectRole(t, cluster, contracts.AllowListBridgeAddr, adminAddr, addresslist.AdminRole) + expectRole(t, cluster, contracts.AllowListBridgeAddr, targetAddr, addresslist.NoRole) + expectRole(t, cluster, contracts.AllowListBridgeAddr, otherAddr, addresslist.EnabledRole) + expectRole(t, cluster, contracts.BlockListBridgeAddr, adminAddr, addresslist.AdminRole) + expectRole(t, cluster, contracts.BlockListBridgeAddr, targetAddr, addresslist.NoRole) + expectRole(t, cluster, contracts.BlockListBridgeAddr, otherAddr, addresslist.EnabledRole) + } +} diff --git a/e2e-polybft/e2e/allowlist_test.go b/e2e-polybft/e2e/allowlist_test.go deleted file mode 100644 index 5978612354..0000000000 --- a/e2e-polybft/e2e/allowlist_test.go +++ /dev/null @@ -1,109 +0,0 @@ -package e2e - -import ( - "math/big" - "testing" - - "github.com/0xPolygon/polygon-edge/contracts" - "github.com/0xPolygon/polygon-edge/e2e-polybft/framework" - "github.com/0xPolygon/polygon-edge/helper/hex" - "github.com/0xPolygon/polygon-edge/state/runtime/allowlist" - "github.com/0xPolygon/polygon-edge/types" - "github.com/stretchr/testify/require" - "github.com/umbracle/ethgo/wallet" -) - -func TestAllowList_ContractDeployment(t *testing.T) { - // create two accounts, one for an admin sender and a second - // one for a non-enabled account that will switch on-off between - // both enabled and non-enabled roles. - admin, _ := wallet.GenerateKey() - target, _ := wallet.GenerateKey() - - adminAddr := types.Address(admin.Address()) - targetAddr := types.Address(target.Address()) - - otherAddr := types.Address{0x1} - - cluster := framework.NewTestCluster(t, 3, - framework.WithPremine(adminAddr, targetAddr), - framework.WithContractDeployerAllowListAdmin(adminAddr), - framework.WithContractDeployerAllowListEnabled(otherAddr), - ) - defer cluster.Stop() - - cluster.WaitForReady(t) - - // bytecode for an empty smart contract - bytecode, _ := hex.DecodeString("6080604052348015600f57600080fd5b50603e80601d6000396000f3fe6080604052600080fdfea265627a7a7231582027748e4afe5ee282a786005d286f4427f13dac1b62e03f9aed311c2db7e8245364736f6c63430005110032") - - expectRole := func(addr types.Address, role allowlist.Role) { - out := cluster.Call(t, contracts.AllowListContractsAddr, allowlist.ReadAllowListFunc, addr) - - num, ok := out["0"].(*big.Int) - if !ok { - t.Fatal("unexpected") - } - - require.Equal(t, role.Uint64(), num.Uint64()) - } - - { - // Step 0. Check the role of both accounts - expectRole(adminAddr, allowlist.AdminRole) - expectRole(targetAddr, allowlist.NoRole) - expectRole(otherAddr, allowlist.EnabledRole) - } - - { - // Step 1. 'targetAddr' can send a normal transaction (non-contract creation). - err := cluster.Transfer(t, target, types.ZeroAddress, big.NewInt(1)).Wait() - require.NoError(t, err) - } - - { - // Step 2. 'targetAddr' **cannot** deploy a contract because it is not whitelisted. - // (The transaction does not fail but the contract is not deployed and all gas - // for the transaction is consumed) - deployTxn := cluster.Deploy(t, target, bytecode) - require.NoError(t, deployTxn.Wait()) - require.True(t, deployTxn.Reverted()) - require.False(t, cluster.ExistsCode(t, deployTxn.Receipt().ContractAddress)) - } - - { - // Step 3. 'adminAddr' can create contracts - deployTxn := cluster.Deploy(t, admin, bytecode) - require.NoError(t, deployTxn.Wait()) - require.True(t, deployTxn.Succeed()) - require.True(t, cluster.ExistsCode(t, deployTxn.Receipt().ContractAddress)) - } - - { - // Step 4. 'adminAddr' sends a transaction to enable 'targetAddr'. - input, _ := allowlist.SetEnabledSignatureFunc.Encode([]interface{}{targetAddr}) - - adminSetTxn := cluster.MethodTxn(t, admin, contracts.AllowListContractsAddr, input) - require.NoError(t, adminSetTxn.Wait()) - expectRole(targetAddr, allowlist.EnabledRole) - } - - { - // Step 5. 'targetAddr' can create contracts now. - deployTxn := cluster.Deploy(t, target, bytecode) - require.NoError(t, deployTxn.Wait()) - require.True(t, deployTxn.Succeed()) - require.True(t, cluster.ExistsCode(t, deployTxn.Receipt().ContractAddress)) - } - - { - // Step 6. 'targetAddr' cannot enable other accounts since it is not an admin - // (The transaction fails) - input, _ := allowlist.SetEnabledSignatureFunc.Encode([]interface{}{types.ZeroAddress}) - - adminSetFailTxn := cluster.MethodTxn(t, target, contracts.AllowListContractsAddr, input) - require.NoError(t, adminSetFailTxn.Wait()) - require.True(t, adminSetFailTxn.Failed()) - expectRole(types.ZeroAddress, allowlist.NoRole) - } -} diff --git a/e2e-polybft/e2e/bridge_test.go b/e2e-polybft/e2e/bridge_test.go index fffa24d9d6..e6c33cf376 100644 --- a/e2e-polybft/e2e/bridge_test.go +++ b/e2e-polybft/e2e/bridge_test.go @@ -5,7 +5,6 @@ import ( "fmt" "math/big" "path" - "strconv" "strings" "testing" "time" @@ -14,35 +13,38 @@ import ( "github.com/umbracle/ethgo" ethgow "github.com/umbracle/ethgo/wallet" + "github.com/0xPolygon/polygon-edge/command" + "github.com/0xPolygon/polygon-edge/command/bridge/common" "github.com/0xPolygon/polygon-edge/command/genesis" - rootchainHelper "github.com/0xPolygon/polygon-edge/command/rootchain/helper" + rootHelper "github.com/0xPolygon/polygon-edge/command/rootchain/helper" "github.com/0xPolygon/polygon-edge/command/sidechain" "github.com/0xPolygon/polygon-edge/consensus/polybft" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" "github.com/0xPolygon/polygon-edge/contracts" "github.com/0xPolygon/polygon-edge/e2e-polybft/framework" - + "github.com/0xPolygon/polygon-edge/state/runtime/addresslist" "github.com/0xPolygon/polygon-edge/txrelayer" "github.com/0xPolygon/polygon-edge/types" ) const ( - manifestFileName = "manifest.json" + chainConfigFileName = "genesis.json" ) -func TestE2E_Bridge_DepositAndWithdrawERC20(t *testing.T) { +func TestE2E_Bridge_Transfers(t *testing.T) { const ( - num = 10 + transfersCount = 5 amount = 100 numBlockConfirmations = 2 // make epoch size long enough, so that all exit events are processed within the same epoch - epochSize = 30 + epochSize = 30 + sprintSize = uint64(5) ) - receivers := make([]string, num) - amounts := make([]string, num) + receivers := make([]string, transfersCount) + amounts := make([]string, transfersCount) - for i := 0; i < num; i++ { + for i := 0; i < transfersCount; i++ { key, err := ethgow.GenerateKey() require.NoError(t, err) @@ -53,532 +55,969 @@ func TestE2E_Bridge_DepositAndWithdrawERC20(t *testing.T) { } cluster := framework.NewTestCluster(t, 5, - framework.WithBridge(), framework.WithNumBlockConfirmations(numBlockConfirmations), framework.WithEpochSize(epochSize)) defer cluster.Stop() cluster.WaitForReady(t) - manifest, err := polybft.LoadManifest(path.Join(cluster.Config.TmpDir, manifestFileName)) + polybftCfg, err := polybft.LoadPolyBFTConfig(path.Join(cluster.Config.TmpDir, chainConfigFileName)) require.NoError(t, err) - // DEPOSIT ERC20 TOKENS - // send a few transactions to the bridge - require.NoError( - t, - cluster.Bridge.DepositERC20( - manifest.RootchainConfig.RootNativeERC20Address, - manifest.RootchainConfig.RootERC20PredicateAddress, - strings.Join(receivers[:], ","), - strings.Join(amounts[:], ","), - ), - ) + validatorSrv := cluster.Servers[0] + senderAccount, err := sidechain.GetAccountFromDir(validatorSrv.DataDir()) + require.NoError(t, err) - // wait for a few more sprints - require.NoError(t, cluster.WaitForBlock(35, 2*time.Minute)) + childEthEndpoint := validatorSrv.JSONRPC().Eth() - // the transactions are processed and there should be a success events - var stateSyncedResult contractsapi.StateSyncResultEvent + // bridge some tokens for first validator to child chain + tokensToDeposit := ethgo.Ether(10) - id := stateSyncedResult.Sig() - filter := ðgo.LogFilter{ - Topics: [][]*ethgo.Hash{ - {&id}, - }, - } + require.NoError( + t, cluster.Bridge.Deposit( + common.ERC20, + polybftCfg.Bridge.RootNativeERC20Addr, + polybftCfg.Bridge.RootERC20PredicateAddr, + rootHelper.TestAccountPrivKey, + senderAccount.Address().String(), + tokensToDeposit.String(), + "", + cluster.Bridge.JSONRPCAddr(), + rootHelper.TestAccountPrivKey, + false), + ) - filter.SetFromUint64(0) - filter.SetToUint64(100) + // wait for a couple of sprints + finalBlockNum := 5 * sprintSize + require.NoError(t, cluster.WaitForBlock(finalBlockNum, 2*time.Minute)) - childEthEndpoint := cluster.Servers[0].JSONRPC().Eth() + // the transaction is processed and there should be a success event + var stateSyncedResult contractsapi.StateSyncResultEvent - logs, err := childEthEndpoint.GetLogs(filter) + logs, err := getFilteredLogs(stateSyncedResult.Sig(), 0, finalBlockNum, childEthEndpoint) require.NoError(t, err) // assert that all deposits are executed successfully - checkStateSyncResultLogs(t, logs, num) - - // check receivers balances got increased by deposited amount - for _, receiver := range receivers { - balance, err := childEthEndpoint.GetBalance(ethgo.Address(types.StringToAddress(receiver)), ethgo.Latest) - require.NoError(t, err) - require.Equal(t, big.NewInt(amount), balance) - } + checkStateSyncResultLogs(t, logs, 1) - t.Log("Deposits were successfully processed") - - // WITHDRAW ERC20 TOKENS - rootchainTxRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Bridge.JSONRPCAddr())) + // check validator balance got increased by deposited amount + balance, err := childEthEndpoint.GetBalance(ethgo.Address(senderAccount.Address()), ethgo.Latest) require.NoError(t, err) + require.Equal(t, tokensToDeposit, balance) + + t.Run("bridge ERC 20 tokens", func(t *testing.T) { + // DEPOSIT ERC20 TOKENS + // send a few transactions to the bridge + require.NoError( + t, + cluster.Bridge.Deposit( + common.ERC20, + polybftCfg.Bridge.RootNativeERC20Addr, + polybftCfg.Bridge.RootERC20PredicateAddr, + rootHelper.TestAccountPrivKey, + strings.Join(receivers[:], ","), + strings.Join(amounts[:], ","), + "", + cluster.Bridge.JSONRPCAddr(), + rootHelper.TestAccountPrivKey, + false), + ) + + finalBlockNum := 10 * sprintSize + // wait for a couple of sprints + require.NoError(t, cluster.WaitForBlock(finalBlockNum, 2*time.Minute)) + + // the transactions are processed and there should be a success events + var stateSyncedResult contractsapi.StateSyncResultEvent + + logs, err := getFilteredLogs(stateSyncedResult.Sig(), 0, finalBlockNum, childEthEndpoint) + require.NoError(t, err) - senderAccount, err := sidechain.GetAccountFromDir(cluster.Servers[0].DataDir()) - require.NoError(t, err) + // assert that all deposits are executed successfully + checkStateSyncResultLogs(t, logs, transfersCount+1) // because of the first deposit for the first validator - t.Logf("Withdraw sender: %s\n", senderAccount.Ecdsa.Address()) + // check receivers balances got increased by deposited amount + for _, receiver := range receivers { + balance, err := childEthEndpoint.GetBalance(ethgo.Address(types.StringToAddress(receiver)), ethgo.Latest) + require.NoError(t, err) + require.Equal(t, big.NewInt(amount), balance) + } - rawKey, err := senderAccount.Ecdsa.MarshallPrivateKey() - require.NoError(t, err) + t.Log("Deposits were successfully processed") - // send withdraw transaction - err = cluster.Bridge.WithdrawERC20( - hex.EncodeToString(rawKey), - strings.Join(receivers[:], ","), - strings.Join(amounts[:], ","), - cluster.Servers[0].JSONRPCAddr()) - require.NoError(t, err) + // WITHDRAW ERC20 TOKENS + rootchainTxRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Bridge.JSONRPCAddr())) + require.NoError(t, err) - currentBlock, err := childEthEndpoint.GetBlockByNumber(ethgo.Latest, false) - require.NoError(t, err) + senderAccount, err := sidechain.GetAccountFromDir(validatorSrv.DataDir()) + require.NoError(t, err) - currentExtra, err := polybft.GetIbftExtra(currentBlock.ExtraData) - require.NoError(t, err) + t.Logf("Withdraw sender: %s\n", senderAccount.Ecdsa.Address()) - t.Logf("Latest block number: %d, epoch number: %d\n", currentBlock.Number, currentExtra.Checkpoint.EpochNumber) + rawKey, err := senderAccount.Ecdsa.MarshallPrivateKey() + require.NoError(t, err) - currentEpoch := currentExtra.Checkpoint.EpochNumber - fail := 0 + // send withdraw transaction + err = cluster.Bridge.Withdraw( + common.ERC20, + hex.EncodeToString(rawKey), + strings.Join(receivers[:], ","), + strings.Join(amounts[:], ","), + "", + validatorSrv.JSONRPCAddr(), + contracts.ChildERC20PredicateContract, + contracts.NativeERC20TokenContract, + false) + require.NoError(t, err) - // make sure we have progressed to the next epoch on the root chain - // before sending exit transaction to the root chain - // (it means that checkpoint was submitted) - for range time.Tick(time.Second) { - currentEpochString, err := ABICall(rootchainTxRelayer, contractsapi.CheckpointManager, - ethgo.Address(manifest.RootchainConfig.CheckpointManagerAddress), ethgo.ZeroAddress, "currentEpoch") + currentBlock, err := childEthEndpoint.GetBlockByNumber(ethgo.Latest, false) require.NoError(t, err) - rootchainEpoch, err := types.ParseUint64orHex(¤tEpochString) + currentExtra, err := polybft.GetIbftExtra(currentBlock.ExtraData) require.NoError(t, err) - if rootchainEpoch >= currentEpoch { - break + t.Logf("Latest block number: %d, epoch number: %d\n", currentBlock.Number, currentExtra.Checkpoint.EpochNumber) + + currentEpoch := currentExtra.Checkpoint.EpochNumber + + require.NoError(t, waitForRootchainEpoch(currentEpoch, 3*time.Minute, + rootchainTxRelayer, polybftCfg.Bridge.CheckpointManagerAddr)) + + exitHelper := polybftCfg.Bridge.ExitHelperAddr + childJSONRPC := validatorSrv.JSONRPCAddr() + + for exitEventID := uint64(1); exitEventID <= transfersCount; exitEventID++ { + // send exit transaction to exit helper + err = cluster.Bridge.SendExitTransaction(exitHelper, exitEventID, childJSONRPC) + require.NoError(t, err) } - if fail > 300 { - t.Fatal("root chain hasn't progressed to the next epoch") + // assert that receiver's balances on RootERC20 smart contract are expected + for _, receiver := range receivers { + balance := erc20BalanceOf(t, types.StringToAddress(receiver), + polybftCfg.Bridge.RootNativeERC20Addr, rootchainTxRelayer) + require.Equal(t, big.NewInt(amount), balance) } - fail++ - } + }) - exitHelper := manifest.RootchainConfig.ExitHelperAddress - rootJSONRPC := cluster.Bridge.JSONRPCAddr() - childJSONRPC := cluster.Servers[0].JSONRPCAddr() + t.Run("multiple deposit batches per epoch", func(t *testing.T) { + const ( + depositsSubset = 1 + ) - for i := uint64(0); i < num; i++ { - exitEventID := i + 1 + txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithClient(validatorSrv.JSONRPC())) + require.NoError(t, err) - // send exit transaction to exit helper - err = cluster.Bridge.SendExitTransaction(exitHelper, exitEventID, rootJSONRPC, childJSONRPC) + lastCommittedIDMethod := contractsapi.StateReceiver.Abi.GetMethod("lastCommittedId") + lastCommittedIDInput, err := lastCommittedIDMethod.Encode([]interface{}{}) require.NoError(t, err) - // make sure exit event is processed successfully - isProcessed, err := isExitEventProcessed(exitEventID, ethgo.Address(exitHelper), rootchainTxRelayer) + // check that we submitted the minimal commitment to smart contract + commitmentIDRaw, err := txRelayer.Call(ethgo.ZeroAddress, ethgo.Address(contracts.StateReceiverContract), lastCommittedIDInput) require.NoError(t, err) - require.True(t, isProcessed, fmt.Sprintf("exit event with ID %d was not processed", exitEventID)) - } - // assert that receiver's balances on RootERC20 smart contract are expected - for _, receiver := range receivers { - balanceInput, err := contractsapi.RootERC20.Abi.Methods["balanceOf"].Encode([]interface{}{receiver}) + initialCommittedID, err := types.ParseUint64orHex(&commitmentIDRaw) require.NoError(t, err) - balanceRaw, err := rootchainTxRelayer.Call(ethgo.ZeroAddress, - ethgo.Address(manifest.RootchainConfig.RootNativeERC20Address), balanceInput) + initialBlockNum, err := childEthEndpoint.BlockNumber() require.NoError(t, err) - balance, err := types.ParseUint256orHex(&balanceRaw) + // wait for next sprint block as the starting point, + // in order to be able to make assertions against blocks offseted by sprints + initialBlockNum = initialBlockNum + sprintSize - (initialBlockNum % sprintSize) + require.NoError(t, cluster.WaitForBlock(initialBlockNum, 1*time.Minute)) + + // send two transactions to the bridge so that we have a minimal commitment + require.NoError( + t, + cluster.Bridge.Deposit( + common.ERC20, + polybftCfg.Bridge.RootNativeERC20Addr, + polybftCfg.Bridge.RootERC20PredicateAddr, + rootHelper.TestAccountPrivKey, + strings.Join(receivers[:depositsSubset], ","), + strings.Join(amounts[:depositsSubset], ","), + "", + cluster.Bridge.JSONRPCAddr(), + rootHelper.TestAccountPrivKey, + false), + ) + + // wait for a few more sprints + midBlockNumber := initialBlockNum + 2*sprintSize + require.NoError(t, cluster.WaitForBlock(midBlockNumber, 2*time.Minute)) + + // check that we submitted the minimal commitment to smart contract + commitmentIDRaw, err = txRelayer.Call(ethgo.ZeroAddress, + ethgo.Address(contracts.StateReceiverContract), lastCommittedIDInput) require.NoError(t, err) - require.Equal(t, big.NewInt(amount), balance) - } + + lastCommittedID, err := types.ParseUint64orHex(&commitmentIDRaw) + require.NoError(t, err) + require.Equal(t, initialCommittedID+depositsSubset, lastCommittedID) + + // send some more transactions to the bridge to build another commitment in epoch + require.NoError( + t, + cluster.Bridge.Deposit( + common.ERC20, + polybftCfg.Bridge.RootNativeERC20Addr, + polybftCfg.Bridge.RootERC20PredicateAddr, + rootHelper.TestAccountPrivKey, + strings.Join(receivers[depositsSubset:], ","), + strings.Join(amounts[depositsSubset:], ","), + "", + cluster.Bridge.JSONRPCAddr(), + rootHelper.TestAccountPrivKey, + false), + ) + + finalBlockNum := midBlockNumber + 5*sprintSize + // wait for a few more sprints + require.NoError(t, cluster.WaitForBlock(midBlockNumber+5*sprintSize, 3*time.Minute)) + + // check that we submitted the minimal commitment to smart contract + commitmentIDRaw, err = txRelayer.Call(ethgo.ZeroAddress, ethgo.Address(contracts.StateReceiverContract), lastCommittedIDInput) + require.NoError(t, err) + + // check that the second (larger commitment) was also submitted in epoch + lastCommittedID, err = types.ParseUint64orHex(&commitmentIDRaw) + require.NoError(t, err) + require.Equal(t, initialCommittedID+uint64(transfersCount), lastCommittedID) + + // the transactions are mined and state syncs should be executed by the relayer + // and there should be a success events + var stateSyncedResult contractsapi.StateSyncResultEvent + + logs, err := getFilteredLogs(stateSyncedResult.Sig(), initialBlockNum, finalBlockNum, childEthEndpoint) + require.NoError(t, err) + + // assert that all state syncs are executed successfully + checkStateSyncResultLogs(t, logs, transfersCount) + }) } -func TestE2E_Bridge_MultipleCommitmentsPerEpoch(t *testing.T) { - const depositsCount = 10 +func TestE2E_Bridge_ERC721Transfer(t *testing.T) { + const ( + transfersCount = 4 + epochSize = 5 + ) + + minter, err := ethgow.GenerateKey() + require.NoError(t, err) - receivers := make([]string, depositsCount) - amounts := make([]string, depositsCount) + receiverKeys := make([]string, transfersCount) + receivers := make([]string, transfersCount) + receiversAddrs := make([]types.Address, transfersCount) + tokenIDs := make([]string, transfersCount) - for i := 0; i < depositsCount; i++ { + for i := 0; i < transfersCount; i++ { key, err := ethgow.GenerateKey() require.NoError(t, err) + rawKey, err := key.MarshallPrivateKey() + require.NoError(t, err) + + receiverKeys[i] = hex.EncodeToString(rawKey) receivers[i] = types.Address(key.Address()).String() - amounts[i] = fmt.Sprintf("%d", 100) + receiversAddrs[i] = types.Address(key.Address()) + tokenIDs[i] = fmt.Sprintf("%d", i) + + t.Logf("Receiver#%d=%s\n", i+1, receivers[i]) } cluster := framework.NewTestCluster(t, 5, - framework.WithBridge(), - framework.WithEpochSize(30)) + framework.WithEpochSize(epochSize), + framework.WithNativeTokenConfig(fmt.Sprintf(nativeTokenMintableTestCfg, minter.Address())), + framework.WithPremine(types.Address(minter.Address())), + framework.WithPremine(receiversAddrs...)) defer cluster.Stop() - manifest, err := polybft.LoadManifest(path.Join(cluster.Config.TmpDir, manifestFileName)) - require.NoError(t, err) - cluster.WaitForReady(t) - // send two transactions to the bridge so that we have a minimal commitment - require.NoError( - t, - cluster.Bridge.DepositERC20( - manifest.RootchainConfig.RootNativeERC20Address, - manifest.RootchainConfig.RootERC20PredicateAddress, - strings.Join(receivers[:2], ","), - strings.Join(amounts[:2], ","), - ), - ) - - // wait for a few more sprints - require.NoError(t, cluster.WaitForBlock(10, 2*time.Minute)) - - txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithClient(cluster.Servers[0].JSONRPC())) + polybftCfg, err := polybft.LoadPolyBFTConfig(path.Join(cluster.Config.TmpDir, chainConfigFileName)) require.NoError(t, err) - lastCommittedIDMethod := contractsapi.StateReceiver.Abi.GetMethod("lastCommittedId") - encode, err := lastCommittedIDMethod.Encode([]interface{}{}) + rootchainTxRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Bridge.JSONRPCAddr())) require.NoError(t, err) - // check that we submitted the minimal commitment to smart contract - result, err := txRelayer.Call(ethgo.ZeroAddress, ethgo.Address(contracts.StateReceiverContract), encode) + rootchainDeployer, err := rootHelper.DecodePrivateKey("") require.NoError(t, err) - lastCommittedID, err := strconv.ParseUint(result, 0, 64) + // deploy root ERC 721 token + deployTxn := ðgo.Transaction{To: nil, Input: contractsapi.RootERC721.Bytecode} + receipt, err := rootchainTxRelayer.SendTransaction(deployTxn, rootchainDeployer) require.NoError(t, err) - require.Equal(t, uint64(2), lastCommittedID) - // send some more transactions to the bridge to build another commitment in epoch + rootERC721Addr := receipt.ContractAddress + + // DEPOSIT ERC721 TOKENS + // send a few transactions to the bridge require.NoError( t, - cluster.Bridge.DepositERC20( - manifest.RootchainConfig.RootNativeERC20Address, - manifest.RootchainConfig.RootERC20PredicateAddress, - strings.Join(receivers[2:], ","), - strings.Join(amounts[2:], ","), - ), + cluster.Bridge.Deposit( + common.ERC721, + types.Address(rootERC721Addr), + polybftCfg.Bridge.RootERC721PredicateAddr, + rootHelper.TestAccountPrivKey, + strings.Join(receivers[:], ","), + "", + strings.Join(tokenIDs[:], ","), + cluster.Bridge.JSONRPCAddr(), + rootHelper.TestAccountPrivKey, + false), ) // wait for a few more sprints - require.NoError(t, cluster.WaitForBlock(40, 3*time.Minute)) + require.NoError(t, cluster.WaitForBlock(50, 4*time.Minute)) - // check that we submitted the minimal commitment to smart contract - result, err = txRelayer.Call(ethgo.ZeroAddress, ethgo.Address(contracts.StateReceiverContract), encode) - require.NoError(t, err) + validatorSrv := cluster.Servers[0] + childEthEndpoint := validatorSrv.JSONRPC().Eth() - // check that the second (larger commitment) was also submitted in epoch - lastCommittedID, err = strconv.ParseUint(result, 0, 64) - require.NoError(t, err) - require.Equal(t, uint64(depositsCount), lastCommittedID) - - // the transactions are mined and state syncs should be executed by the relayer - // and there should be a success events + // the transactions are processed and there should be a success events var stateSyncedResult contractsapi.StateSyncResultEvent - id := stateSyncedResult.Sig() - filter := ðgo.LogFilter{ - Topics: [][]*ethgo.Hash{ - {&id}, - }, - } - - filter.SetFromUint64(0) - filter.SetToUint64(100) - - logs, err := cluster.Servers[0].JSONRPC().Eth().GetLogs(filter) + logs, err := getFilteredLogs(stateSyncedResult.Sig(), 0, 50, childEthEndpoint) require.NoError(t, err) - // assert that all state syncs are executed successfully - checkStateSyncResultLogs(t, logs, depositsCount) -} - -func TestE2E_CheckpointSubmission(t *testing.T) { - // spin up a cluster with epoch size set to 5 blocks - cluster := framework.NewTestCluster(t, 5, framework.WithBridge(), framework.WithEpochSize(5)) - defer cluster.Stop() - - // initialize tx relayer used to query CheckpointManager smart contract - l1Relayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Bridge.JSONRPCAddr())) + txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithClient(validatorSrv.JSONRPC())) require.NoError(t, err) - manifest, err := polybft.LoadManifest(path.Join(cluster.Config.TmpDir, manifestFileName)) - require.NoError(t, err) + // assert that all deposits are executed successfully. + // All deposits are sent using a single transaction, so arbitrary message bridge emits two state sync events: + // MAP_TOKEN_SIG and DEPOSIT_BATCH_SIG state sync events + checkStateSyncResultLogs(t, logs, 2) - checkpointManagerAddr := ethgo.Address(manifest.RootchainConfig.CheckpointManagerAddress) + // retrieve child token address (from both chains, and assert they are the same) + l1ChildTokenAddr := getChildToken(t, contractsapi.RootERC721Predicate.Abi, polybftCfg.Bridge.RootERC721PredicateAddr, + types.Address(rootERC721Addr), rootchainTxRelayer) + l2ChildTokenAddr := getChildToken(t, contractsapi.ChildERC721Predicate.Abi, contracts.ChildERC721PredicateContract, + types.Address(rootERC721Addr), txRelayer) - testCheckpointBlockNumber := func(expectedCheckpointBlock uint64) (bool, error) { - actualCheckpointBlock, err := getCheckpointBlockNumber(l1Relayer, checkpointManagerAddr) - if err != nil { - return false, err - } - - t.Logf("Checkpoint block: %d\n", actualCheckpointBlock) + t.Log("L1 child token", l1ChildTokenAddr) + t.Log("L2 child token", l2ChildTokenAddr) + require.Equal(t, l1ChildTokenAddr, l2ChildTokenAddr) - return actualCheckpointBlock == expectedCheckpointBlock, nil + for i, receiver := range receiversAddrs { + owner := erc721OwnerOf(t, big.NewInt(int64(i)), l2ChildTokenAddr, txRelayer) + require.Equal(t, receiver, owner) } - // wait for a single epoch to be checkpointed - require.NoError(t, cluster.WaitForBlock(7, 30*time.Second)) + t.Log("Deposits were successfully processed") - // checking last checkpoint block before rootchain server stop - err = cluster.Bridge.WaitUntil(2*time.Second, 30*time.Second, func() (bool, error) { - return testCheckpointBlockNumber(5) - }) + // WITHDRAW ERC721 TOKENS + for i, receiverKey := range receiverKeys { + // send withdraw transactions + err = cluster.Bridge.Withdraw( + common.ERC721, + receiverKey, + receivers[i], + "", + tokenIDs[i], + validatorSrv.JSONRPCAddr(), + contracts.ChildERC721PredicateContract, + l2ChildTokenAddr, + false) + require.NoError(t, err) + } + + currentBlock, err := childEthEndpoint.GetBlockByNumber(ethgo.Latest, false) require.NoError(t, err) - // stop rootchain server - cluster.Bridge.Stop() + currentExtra, err := polybft.GetIbftExtra(currentBlock.ExtraData) + require.NoError(t, err) - // wait for a couple of epochs so that there are pending checkpoint (epoch-ending) blocks - require.NoError(t, cluster.WaitForBlock(21, 2*time.Minute)) + t.Logf("Latest block number: %d, epoch number: %d\n", currentBlock.Number, currentExtra.Checkpoint.EpochNumber) - // restart rootchain server - require.NoError(t, cluster.Bridge.Start()) + currentEpoch := currentExtra.Checkpoint.EpochNumber + require.NoError(t, waitForRootchainEpoch(currentEpoch, 3*time.Minute, rootchainTxRelayer, polybftCfg.Bridge.CheckpointManagerAddr)) - // check if pending checkpoint blocks were submitted (namely the last checkpointed block must be block 20) - err = cluster.Bridge.WaitUntil(2*time.Second, 50*time.Second, func() (bool, error) { - return testCheckpointBlockNumber(20) - }) - require.NoError(t, err) -} + exitHelper := polybftCfg.Bridge.ExitHelperAddr + childJSONRPC := validatorSrv.JSONRPCAddr() -// getCheckpointBlockNumber gets current checkpoint block number from checkpoint manager smart contract -func getCheckpointBlockNumber(l1Relayer txrelayer.TxRelayer, checkpointManagerAddr ethgo.Address) (uint64, error) { - checkpointBlockNumRaw, err := ABICall(l1Relayer, contractsapi.CheckpointManager, - checkpointManagerAddr, ethgo.ZeroAddress, "currentCheckpointBlockNumber") - if err != nil { - return 0, err + for exitEventID := uint64(1); exitEventID <= transfersCount; exitEventID++ { + // send exit transaction to exit helper + err = cluster.Bridge.SendExitTransaction(exitHelper, exitEventID, childJSONRPC) + require.NoError(t, err) } - actualCheckpointBlock, err := types.ParseUint64orHex(&checkpointBlockNumRaw) - if err != nil { - return 0, err + // assert that owners of given token ids are the accounts on the root chain ERC 721 token + for i, receiver := range receiversAddrs { + owner := erc721OwnerOf(t, big.NewInt(int64(i)), types.Address(rootERC721Addr), rootchainTxRelayer) + require.Equal(t, receiver, owner) } - - return actualCheckpointBlock, nil } -func TestE2E_Bridge_L2toL1Exit(t *testing.T) { +func TestE2E_Bridge_ERC1155Transfer(t *testing.T) { const ( - userNumber = 10 - epochSize = 30 - checkpointBlock = uint64(epochSize) - checkpointEpoch = uint64(1) + transfersCount = 5 + amount = 100 + epochSize = 5 ) - sidechainKeys := make([]*ethgow.Key, userNumber) - accountAddress := make([]types.Address, userNumber) + minter, err := ethgow.GenerateKey() + require.NoError(t, err) + + receiverKeys := make([]string, transfersCount) + receivers := make([]string, transfersCount) + receiversAddrs := make([]types.Address, transfersCount) + amounts := make([]string, transfersCount) + tokenIDs := make([]string, transfersCount) - for i := 0; i < userNumber; i++ { + for i := 0; i < transfersCount; i++ { key, err := ethgow.GenerateKey() require.NoError(t, err) - sidechainKeys[i] = key - accountAddress[i] = types.Address(key.Address()) - } + rawKey, err := key.MarshallPrivateKey() + require.NoError(t, err) - // use test account for rootchain - rootchainKey, err := rootchainHelper.GetRootchainPrivateKey("") - require.NoError(t, err) + receiverKeys[i] = hex.EncodeToString(rawKey) + receivers[i] = types.Address(key.Address()).String() + receiversAddrs[i] = types.Address(key.Address()) + amounts[i] = fmt.Sprintf("%d", amount) + tokenIDs[i] = fmt.Sprintf("%d", i+1) + + t.Logf("Receiver#%d=%s\n", i+1, receivers[i]) + } cluster := framework.NewTestCluster(t, 5, - framework.WithBridge(), - framework.WithPremine(accountAddress...), + framework.WithNumBlockConfirmations(0), framework.WithEpochSize(epochSize), - ) - + framework.WithNativeTokenConfig(fmt.Sprintf(nativeTokenMintableTestCfg, minter.Address())), + framework.WithPremine(types.Address(minter.Address())), + framework.WithPremine(receiversAddrs...)) defer cluster.Stop() - manifest, err := polybft.LoadManifest(path.Join(cluster.Config.TmpDir, manifestFileName)) + cluster.WaitForReady(t) + + polybftCfg, err := polybft.LoadPolyBFTConfig(path.Join(cluster.Config.TmpDir, chainConfigFileName)) require.NoError(t, err) - checkpointManagerAddr := ethgo.Address(manifest.RootchainConfig.CheckpointManagerAddress) - exitHelperAddr := ethgo.Address(manifest.RootchainConfig.ExitHelperAddress) + rootchainTxRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Bridge.JSONRPCAddr())) + require.NoError(t, err) - cluster.WaitForReady(t) + rootchainDeployer, err := rootHelper.DecodePrivateKey("") + require.NoError(t, err) - // init rpc clients - l1TxRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(txrelayer.DefaultRPCAddress)) + // deploy root ERC 1155 token + deployTxn := ðgo.Transaction{To: nil, Input: contractsapi.RootERC1155.Bytecode} + receipt, err := rootchainTxRelayer.SendTransaction(deployTxn, rootchainDeployer) require.NoError(t, err) - l2TxRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Servers[0].JSONRPCAddr())) + + rootERC1155Addr := receipt.ContractAddress + + // DEPOSIT ERC1155 TOKENS + // send a few transactions to the bridge + require.NoError( + t, + cluster.Bridge.Deposit( + common.ERC1155, + types.Address(rootERC1155Addr), + polybftCfg.Bridge.RootERC1155PredicateAddr, + rootHelper.TestAccountPrivKey, + strings.Join(receivers[:], ","), + strings.Join(amounts[:], ","), + strings.Join(tokenIDs[:], ","), + cluster.Bridge.JSONRPCAddr(), + rootHelper.TestAccountPrivKey, + false), + ) + + // wait for a few more sprints + require.NoError(t, cluster.WaitForBlock(50, 4*time.Minute)) + + validatorSrv := cluster.Servers[0] + childEthEndpoint := validatorSrv.JSONRPC().Eth() + + // the transactions are processed and there should be a success events + var stateSyncedResult contractsapi.StateSyncResultEvent + + logs, err := getFilteredLogs(stateSyncedResult.Sig(), 0, 50, childEthEndpoint) require.NoError(t, err) - // deploy L1ExitTest contract - receipt, err := l1TxRelayer.SendTransaction(ðgo.Transaction{Input: contractsapi.TestL1StateReceiver.Bytecode}, - rootchainKey) + txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithClient(validatorSrv.JSONRPC())) require.NoError(t, err) - require.Equal(t, receipt.Status, uint64(types.ReceiptSuccess)) - l1ExitTestAddr := receipt.ContractAddress - l2StateSenderAddress := ethgo.Address(contracts.L2StateSenderContract) + // assert that all deposits are executed successfully. + // All deposits are sent using a single transaction, so arbitrary message bridge emits two state sync events: + // MAP_TOKEN_SIG and DEPOSIT_BATCH_SIG state sync events + checkStateSyncResultLogs(t, logs, 2) + + // retrieve child token address + l1ChildTokenAddr := getChildToken(t, contractsapi.RootERC1155Predicate.Abi, polybftCfg.Bridge.RootERC1155PredicateAddr, + types.Address(rootERC1155Addr), rootchainTxRelayer) + l2ChildTokenAddr := getChildToken(t, contractsapi.ChildERC1155Predicate.Abi, contracts.ChildERC1155PredicateContract, + types.Address(rootERC1155Addr), txRelayer) + + t.Log("L1 child token", l1ChildTokenAddr) + t.Log("L2 child token", l2ChildTokenAddr) + require.Equal(t, l1ChildTokenAddr, l2ChildTokenAddr) + + // check receivers balances got increased by deposited amount + for i, receiver := range receivers { + balanceOfFn := &contractsapi.BalanceOfChildERC1155Fn{ + Account: types.StringToAddress(receiver), + ID: big.NewInt(int64(i + 1)), + } + + balanceInput, err := balanceOfFn.EncodeAbi() + require.NoError(t, err) - // Start test - // send crosschain transaction on l2 and get exit id - stateSenderData := []byte{123} - for i := 0; i < userNumber; i++ { - receipt, err := ABITransaction(l2TxRelayer, sidechainKeys[i], contractsapi.L2StateSender, l2StateSenderAddress, "syncState", l1ExitTestAddr, stateSenderData) + balanceRaw, err := txRelayer.Call(ethgo.ZeroAddress, ethgo.Address(l2ChildTokenAddr), balanceInput) require.NoError(t, err) - require.Equal(t, receipt.Status, uint64(types.ReceiptSuccess)) + + balance, err := types.ParseUint256orHex(&balanceRaw) + require.NoError(t, err) + require.Equal(t, big.NewInt(int64(amount)), balance) } - require.NoError(t, cluster.WaitForBlock(epochSize, 2*time.Minute)) + t.Log("Deposits were successfully processed") - fail := 0 + // WITHDRAW ERC1155 TOKENS + senderAccount, err := sidechain.GetAccountFromDir(cluster.Servers[0].DataDir()) + require.NoError(t, err) - for range time.Tick(time.Second) { - currentEpochString, err := ABICall(l1TxRelayer, contractsapi.CheckpointManager, checkpointManagerAddr, ethgo.ZeroAddress, "currentEpoch") - require.NoError(t, err) + t.Logf("Withdraw sender: %s\n", senderAccount.Ecdsa.Address()) - currentEpoch, err := types.ParseUint64orHex(¤tEpochString) + for i, receiverKey := range receiverKeys { + // send withdraw transactions + err = cluster.Bridge.Withdraw( + common.ERC1155, + receiverKey, + receivers[i], + amounts[i], + tokenIDs[i], + validatorSrv.JSONRPCAddr(), + contracts.ChildERC1155PredicateContract, + l2ChildTokenAddr, + false) require.NoError(t, err) + } - if currentEpoch >= checkpointEpoch { - break - } + currentBlock, err := childEthEndpoint.GetBlockByNumber(ethgo.Latest, false) + require.NoError(t, err) - if fail > 300 { - t.Fatal("epoch havent achieved") - } - fail++ + currentExtra, err := polybft.GetIbftExtra(currentBlock.ExtraData) + require.NoError(t, err) + + currentEpoch := currentExtra.Checkpoint.EpochNumber + t.Logf("Latest block number: %d, epoch number: %d\n", currentBlock.Number, currentExtra.Checkpoint.EpochNumber) + + require.NoError(t, waitForRootchainEpoch(currentEpoch, 3*time.Minute, + rootchainTxRelayer, polybftCfg.Bridge.CheckpointManagerAddr)) + + exitHelper := polybftCfg.Bridge.ExitHelperAddr + childJSONRPC := validatorSrv.JSONRPCAddr() + + for exitEventID := uint64(1); exitEventID <= transfersCount; exitEventID++ { + // send exit transaction to exit helper + err = cluster.Bridge.SendExitTransaction(exitHelper, exitEventID, childJSONRPC) + require.NoError(t, err) } - var proof types.Proof + // assert that receiver's balances on RootERC1155 smart contract are expected + for i, receiver := range receivers { + balanceOfFn := &contractsapi.BalanceOfRootERC1155Fn{ + Account: types.StringToAddress(receiver), + ID: big.NewInt(int64(i + 1)), + } - for i := 0; i < userNumber; i++ { - exitID := uint64(i + 1) // because exit events start from ID = 1 - proof, err = getExitProof(cluster.Servers[0].JSONRPCAddr(), exitID) + balanceInput, err := balanceOfFn.EncodeAbi() require.NoError(t, err) - isProcessed, err := sendExitTransaction(sidechainKeys[i], rootchainKey, proof, checkpointBlock, stateSenderData, l1ExitTestAddr, exitHelperAddr, l1TxRelayer, exitID) + balanceRaw, err := rootchainTxRelayer.Call(ethgo.ZeroAddress, rootERC1155Addr, balanceInput) require.NoError(t, err) - require.True(t, isProcessed) + + balance, err := types.ParseUint256orHex(&balanceRaw) + require.NoError(t, err) + require.Equal(t, big.NewInt(amount), balance) } } -func TestE2E_Bridge_L2toL1ExitMultiple(t *testing.T) { +func TestE2E_Bridge_ChildChainMintableTokensTransfer(t *testing.T) { const ( - userNumber = 6 - epochSize = 10 - roundNumber = 3 - checkpointBlock = uint64(epochSize) - checkpointEpoch = uint64(1) + transfersCount = uint64(4) + amount = 100 + // make epoch size long enough, so that all exit events are processed within the same epoch + epochSize = 30 + sprintSize = uint64(5) ) - exitEventIds := make([]uint64, userNumber*roundNumber) - sidechainKeys := make([]*ethgow.Key, userNumber) - accountAddress := make([]types.Address, userNumber) + // init private keys and amounts + depositorKeys := make([]string, transfersCount) + depositors := make([]types.Address, transfersCount) + amounts := make([]string, transfersCount) + funds := make([]*big.Int, transfersCount) + singleToken := ethgo.Ether(1) - for i := 0; i < userNumber; i++ { + admin, err := ethgow.GenerateKey() + require.NoError(t, err) + + adminAddr := types.Address(admin.Address()) + + for i := uint64(0); i < transfersCount; i++ { key, err := ethgow.GenerateKey() require.NoError(t, err) - sidechainKeys[i] = key - accountAddress[i] = types.Address(key.Address()) - } + rawKey, err := key.MarshallPrivateKey() + require.NoError(t, err) - // use test account for rootchain - rootchainKey, err := rootchainHelper.GetRootchainPrivateKey("") - require.NoError(t, err) + depositorKeys[i] = hex.EncodeToString(rawKey) + depositors[i] = types.Address(key.Address()) + funds[i] = singleToken + amounts[i] = fmt.Sprintf("%d", amount) + + t.Logf("Depositor#%d=%s\n", i+1, depositors[i]) + } + // setup cluster cluster := framework.NewTestCluster(t, 5, - framework.WithBridge(), - framework.WithPremine(accountAddress...), + framework.WithNumBlockConfirmations(0), framework.WithEpochSize(epochSize), - ) + framework.WithNativeTokenConfig(fmt.Sprintf(nativeTokenMintableTestCfg, adminAddr)), + framework.WithBridgeAllowListAdmin(adminAddr), + framework.WithBridgeBlockListAdmin(adminAddr), + framework.WithPremine(append(depositors, adminAddr)...)) //nolint:makezero defer cluster.Stop() - manifest, err := polybft.LoadManifest(path.Join(cluster.Config.TmpDir, manifestFileName)) + polybftCfg, err := polybft.LoadPolyBFTConfig(path.Join(cluster.Config.TmpDir, chainConfigFileName)) require.NoError(t, err) - checkpointManagerAddr := ethgo.Address(manifest.RootchainConfig.CheckpointManagerAddress) - exitHelperAddr := ethgo.Address(manifest.RootchainConfig.ExitHelperAddress) + validatorSrv := cluster.Servers[0] + childEthEndpoint := validatorSrv.JSONRPC().Eth() + + // fund accounts on rootchain + require.NoError(t, validatorSrv.RootchainFundFor(depositors, funds, polybftCfg.Bridge.StakeTokenAddr)) cluster.WaitForReady(t) - // init rpc clients - l1TxRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(txrelayer.DefaultRPCAddress)) - require.NoError(t, err) - l2TxRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Servers[0].JSONRPCAddr())) + rootchainTxRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Bridge.JSONRPCAddr())) require.NoError(t, err) - // deploy L1ExitTest contract - receipt, err := l1TxRelayer.SendTransaction( - ðgo.Transaction{Input: contractsapi.TestL1StateReceiver.Bytecode}, - rootchainKey) + childchainTxRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithClient(validatorSrv.JSONRPC())) require.NoError(t, err) - require.Equal(t, receipt.Status, uint64(types.ReceiptSuccess)) - l1ExitTestAddr := receipt.ContractAddress - l2StateSenderAddress := ethgo.Address(contracts.L2StateSenderContract) + var mintableTokenMapped contractsapi.MintableTokenMappedEvent + + t.Run("bridge native tokens", func(t *testing.T) { + // rootToken represents deposit token (basically native mintable token from the Supernets) + rootToken := contracts.NativeERC20TokenContract + + // try sending a single native token deposit transaction + // it should fail, because depositors are not allow listed for bridge transactions + err = cluster.Bridge.Deposit( + common.ERC20, + rootToken, + contracts.RootMintableERC20PredicateContract, + depositorKeys[0], + depositors[0].String(), + amounts[0], + "", + validatorSrv.JSONRPCAddr(), + "", + true) + require.Error(t, err) + + // allow list each depositor and make sure deposit is successfully executed + for i, key := range depositorKeys { + // add all depositors to bridge allow list + setAccessListRole(t, cluster, contracts.AllowListBridgeAddr, depositors[i], addresslist.EnabledRole, admin) + + // make sure deposit is successfully executed + err = cluster.Bridge.Deposit( + common.ERC20, + rootToken, + contracts.RootMintableERC20PredicateContract, + key, + depositors[i].String(), + amounts[i], + "", + validatorSrv.JSONRPCAddr(), + "", + true) + require.NoError(t, err) + } - // Start test - // send crosschain transaction on l2 and get exit id - stateSenderData := []byte{123} - addTransaction := func(j, i uint64) { - receipt, err := ABITransaction(l2TxRelayer, sidechainKeys[j], contractsapi.L2StateSender, l2StateSenderAddress, "syncState", l1ExitTestAddr, stateSenderData) + latestBlock, err := childEthEndpoint.GetBlockByNumber(ethgo.Latest, false) require.NoError(t, err) - require.Equal(t, receipt.Status, uint64(types.ReceiptSuccess)) - eventData, err := contractsapi.L2StateSender.Abi.Events["L2StateSynced"].ParseLog(receipt.Logs[0]) + extra, err := polybft.GetIbftExtra(latestBlock.ExtraData) require.NoError(t, err) - exitEventIds[j+(i-1)*userNumber] = eventData["id"].(*big.Int).Uint64() //nolint:forcetypeassert - } + // wait for checkpoint to get submitted before invoking exit transactions + require.NoError(t, + waitForRootchainEpoch(extra.Checkpoint.EpochNumber, 2*time.Minute, rootchainTxRelayer, polybftCfg.Bridge.CheckpointManagerAddr)) - for i := 1; i <= roundNumber; i++ { - for j := 0; j < userNumber; j++ { - go addTransaction(uint64(j), uint64(i)) + // first exit event is mapping child token on a rootchain + // remaining ones are deposits + for exitEventID := uint64(1); exitEventID <= transfersCount+1; exitEventID++ { + require.NoError(t, + cluster.Bridge.SendExitTransaction(polybftCfg.Bridge.ExitHelperAddr, exitEventID, validatorSrv.JSONRPCAddr())) } - require.NoError(t, cluster.WaitForBlock(uint64((i)*epochSize), 2*time.Minute)) - fail := 0 + rootchainLatestBlock, err := rootchainTxRelayer.Client().Eth().BlockNumber() + require.NoError(t, err) + + // retrieve child mintable token address from both chains and make sure they are the same + l1ChildToken := getChildToken(t, contractsapi.ChildMintableERC20Predicate.Abi, polybftCfg.Bridge.ChildMintableERC20PredicateAddr, + rootToken, rootchainTxRelayer) + l2ChildToken := getChildToken(t, contractsapi.RootMintableERC20Predicate.Abi, contracts.RootMintableERC20PredicateContract, + rootToken, childchainTxRelayer) + + t.Log("L1 child token", l1ChildToken) + t.Log("L2 child token", l2ChildToken) + require.Equal(t, l1ChildToken, l2ChildToken) - for range time.Tick(time.Second) { - currentEpochString, err := ABICall(l1TxRelayer, contractsapi.CheckpointManager, checkpointManagerAddr, ethgo.ZeroAddress, "currentEpoch") + logs, err := getFilteredLogs(mintableTokenMapped.Sig(), 0, rootchainLatestBlock, rootchainTxRelayer.Client().Eth()) + require.NoError(t, err) + require.Len(t, logs, 1) + + // check that balances on rootchain have increased by deposited amounts + for _, depositor := range depositors { + balance := erc20BalanceOf(t, depositor, l1ChildToken, rootchainTxRelayer) + require.Equal(t, big.NewInt(amount), balance) + } + + balancesBefore := make([]*big.Int, transfersCount) + for i := uint64(0); i < transfersCount; i++ { + balancesBefore[i], err = childEthEndpoint.GetBalance(ethgo.Address(depositors[i]), ethgo.Latest) require.NoError(t, err) + } - currentEpoch, err := types.ParseUint64orHex(¤tEpochString) + // withdraw child token on the rootchain + for i, depositorKey := range depositorKeys { + err = cluster.Bridge.Withdraw( + common.ERC20, + depositorKey, + depositors[i].String(), + amounts[i], + "", + cluster.Bridge.JSONRPCAddr(), + polybftCfg.Bridge.ChildMintableERC20PredicateAddr, + l1ChildToken, + true) require.NoError(t, err) + } - if currentEpoch >= uint64(i)*checkpointEpoch { - break - } + blockNum, err := childEthEndpoint.BlockNumber() + require.NoError(t, err) - if fail > 300 { - t.Fatal("epoch havent achieved") - } - fail++ + // wait a couple of sprints to finalize state sync events + require.NoError(t, cluster.WaitForBlock(blockNum+3*sprintSize, 2*time.Minute)) + + // check that balances on the child chain are correct + for i, receiver := range depositors { + balance := erc20BalanceOf(t, receiver, contracts.NativeERC20TokenContract, childchainTxRelayer) + t.Log("Balance before", balancesBefore[i], "Balance after", balance) + require.Equal(t, balance, balancesBefore[i].Add(balancesBefore[i], big.NewInt(amount))) } - } + }) - var proof types.Proof + t.Run("bridge ERC 721 tokens", func(t *testing.T) { + rootchainInitialBlock, err := rootchainTxRelayer.Client().Eth().BlockNumber() + require.NoError(t, err) - for i := 0; i < roundNumber; i++ { - for j := 0; j < userNumber; j++ { - proof, err = getExitProof(cluster.Servers[0].JSONRPCAddr(), exitEventIds[j+i*userNumber]) + exitEventsCounterFn := contractsapi.L2StateSender.Abi.Methods["counter"] + input, err := exitEventsCounterFn.Encode([]interface{}{}) + require.NoError(t, err) + initialExitEventIDRaw, err := childchainTxRelayer.Call(ethgo.ZeroAddress, ethgo.Address(contracts.L2StateSenderContract), input) + require.NoError(t, err) + initialExitEventID, err := types.ParseUint64orHex(&initialExitEventIDRaw) + require.NoError(t, err) + + erc721DeployTxn := cluster.Deploy(t, admin, contractsapi.RootERC721.Bytecode) + require.NoError(t, erc721DeployTxn.Wait()) + require.True(t, erc721DeployTxn.Succeed()) + rootERC721Token := erc721DeployTxn.Receipt().ContractAddress + + for _, depositor := range depositors { + // mint all the depositors in advance + mintFn := &contractsapi.MintRootERC721Fn{To: depositor} + mintInput, err := mintFn.EncodeAbi() require.NoError(t, err) - isProcessed, err := sendExitTransaction(sidechainKeys[j], rootchainKey, proof, uint64(i+1)*checkpointBlock, stateSenderData, l1ExitTestAddr, exitHelperAddr, l1TxRelayer, exitEventIds[j+i*userNumber]) + + mintTxn := cluster.MethodTxn(t, admin, types.Address(rootERC721Token), mintInput) + require.NoError(t, mintTxn.Wait()) + require.True(t, mintTxn.Succeed()) + + // add all depositors to bride block list + setAccessListRole(t, cluster, contracts.BlockListBridgeAddr, depositor, addresslist.EnabledRole, admin) + } + + // deposit should fail because depositors are in bridge block list + err = cluster.Bridge.Deposit( + common.ERC721, + types.Address(rootERC721Token), + contracts.RootMintableERC721PredicateContract, + depositorKeys[0], + depositors[0].String(), + "", + fmt.Sprintf("%d", 0), + validatorSrv.JSONRPCAddr(), + "", + true) + require.Error(t, err) + + for i, depositorKey := range depositorKeys { + // add all depositors to the bridge allow list + setAccessListRole(t, cluster, contracts.AllowListBridgeAddr, depositors[i], addresslist.EnabledRole, admin) + + // remove all depositors from the bridge block list + setAccessListRole(t, cluster, contracts.BlockListBridgeAddr, depositors[i], addresslist.NoRole, admin) + + // deposit (without minting, as it was already done beforehand) + err = cluster.Bridge.Deposit( + common.ERC721, + types.Address(rootERC721Token), + contracts.RootMintableERC721PredicateContract, + depositorKey, + depositors[i].String(), + "", + fmt.Sprintf("%d", i), + validatorSrv.JSONRPCAddr(), + "", + true) require.NoError(t, err) - require.True(t, isProcessed) } + + childChainBlock, err := childEthEndpoint.GetBlockByNumber(ethgo.Latest, false) + require.NoError(t, err) + + childChainBlockExtra, err := polybft.GetIbftExtra(childChainBlock.ExtraData) + require.NoError(t, err) + + // wait for checkpoint to be submitted + require.NoError(t, + waitForRootchainEpoch(childChainBlockExtra.Checkpoint.EpochNumber, 2*time.Minute, rootchainTxRelayer, polybftCfg.Bridge.CheckpointManagerAddr)) + + // first exit event is mapping child token on a rootchain + // remaining ones are the deposits + initialExitEventID++ + for i := initialExitEventID; i <= initialExitEventID+transfersCount; i++ { + require.NoError(t, + cluster.Bridge.SendExitTransaction(polybftCfg.Bridge.ExitHelperAddr, i, validatorSrv.JSONRPCAddr())) + } + + latestRootchainBlock, err := rootchainTxRelayer.Client().Eth().BlockNumber() + require.NoError(t, err) + + // retrieve child token addresses on both chains and make sure they are the same + l1ChildToken := getChildToken(t, contractsapi.ChildMintableERC721Predicate.Abi, polybftCfg.Bridge.ChildMintableERC721PredicateAddr, + types.Address(rootERC721Token), rootchainTxRelayer) + l2ChildToken := getChildToken(t, contractsapi.RootMintableERC721Predicate.Abi, contracts.RootMintableERC721PredicateContract, + types.Address(rootERC721Token), childchainTxRelayer) + + t.Log("L1 child token", l1ChildToken) + t.Log("L2 child token", l2ChildToken) + require.Equal(t, l1ChildToken, l2ChildToken) + + logs, err := getFilteredLogs(mintableTokenMapped.Sig(), rootchainInitialBlock, latestRootchainBlock, + rootchainTxRelayer.Client().Eth()) + require.NoError(t, err) + require.Len(t, logs, 1) + + // check owner on the rootchain + for i := uint64(0); i < transfersCount; i++ { + owner := erc721OwnerOf(t, new(big.Int).SetUint64(i), l1ChildToken, rootchainTxRelayer) + t.Log("ChildERC721 owner", owner) + require.Equal(t, depositors[i], owner) + } + + // withdraw tokens + for i, depositorKey := range depositorKeys { + err = cluster.Bridge.Withdraw( + common.ERC721, + depositorKey, + depositors[i].String(), + "", + fmt.Sprintf("%d", i), + cluster.Bridge.JSONRPCAddr(), + polybftCfg.Bridge.ChildMintableERC721PredicateAddr, + l1ChildToken, + true) + require.NoError(t, err) + } + + childChainBlockNum, err := childEthEndpoint.BlockNumber() + require.NoError(t, err) + + // wait for commitment execution + require.NoError(t, cluster.WaitForBlock(childChainBlockNum+3*sprintSize, 2*time.Minute)) + + // check owners on the child chain + for i, receiver := range depositors { + owner := erc721OwnerOf(t, big.NewInt(int64(i)), types.Address(rootERC721Token), childchainTxRelayer) + t.Log("RootERC721 owner", owner) + require.Equal(t, receiver, owner) + } + }) +} + +func TestE2E_CheckpointSubmission(t *testing.T) { + // spin up a cluster with epoch size set to 5 blocks + cluster := framework.NewTestCluster(t, 5, framework.WithEpochSize(5)) + defer cluster.Stop() + + // initialize tx relayer used to query CheckpointManager smart contract + rootChainRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Bridge.JSONRPCAddr())) + require.NoError(t, err) + + polybftCfg, err := polybft.LoadPolyBFTConfig(path.Join(cluster.Config.TmpDir, chainConfigFileName)) + require.NoError(t, err) + + checkpointManagerAddr := ethgo.Address(polybftCfg.Bridge.CheckpointManagerAddr) + + testCheckpointBlockNumber := func(expectedCheckpointBlock uint64) (bool, error) { + actualCheckpointBlock, err := getCheckpointBlockNumber(rootChainRelayer, checkpointManagerAddr) + if err != nil { + return false, err + } + + t.Logf("Checkpoint block: %d\n", actualCheckpointBlock) + + return actualCheckpointBlock == expectedCheckpointBlock, nil } + + // wait for a single epoch to be checkpointed + require.NoError(t, cluster.WaitForBlock(7, 30*time.Second)) + + // checking last checkpoint block before rootchain server stop + err = cluster.Bridge.WaitUntil(2*time.Second, 30*time.Second, func() (bool, error) { + return testCheckpointBlockNumber(5) + }) + require.NoError(t, err) + + // stop rootchain server + cluster.Bridge.Stop() + + // wait for a couple of epochs so that there are pending checkpoint (epoch-ending) blocks + require.NoError(t, cluster.WaitForBlock(21, 2*time.Minute)) + + // restart rootchain server + require.NoError(t, cluster.Bridge.Start()) + + // check if pending checkpoint blocks were submitted (namely the last checkpointed block must be block 20) + err = cluster.Bridge.WaitUntil(2*time.Second, 50*time.Second, func() (bool, error) { + return testCheckpointBlockNumber(20) + }) + require.NoError(t, err) } func TestE2E_Bridge_ChangeVotingPower(t *testing.T) { const ( - finalBlockNumber = 20 - votingPowerChanges = 3 + votingPowerChanges = 2 + epochSize = 5 ) cluster := framework.NewTestCluster(t, 5, - framework.WithBridge(), - framework.WithEpochSize(5), - framework.WithEpochReward(1000)) + framework.WithEpochSize(epochSize), + framework.WithEpochReward(1000000)) defer cluster.Stop() - // load manifest file - manifest, err := polybft.LoadManifest(path.Join(cluster.Config.TmpDir, manifestFileName)) + // load polybft config + polybftCfg, err := polybft.LoadPolyBFTConfig(path.Join(cluster.Config.TmpDir, chainConfigFileName)) require.NoError(t, err) - checkpointManagerAddr := ethgo.Address(manifest.RootchainConfig.CheckpointManagerAddress) - validatorSecretFiles, err := genesis.GetValidatorKeyFiles(cluster.Config.TmpDir, cluster.Config.ValidatorPrefix) require.NoError(t, err) @@ -591,61 +1030,306 @@ func TestE2E_Bridge_ChangeVotingPower(t *testing.T) { votingPowerChangeValidators[i] = validator.Ecdsa.Address() } - // L2 Tx relayer (for sending stake transaction and querying validator) - l2Relayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Servers[0].JSONRPCAddr())) + // child chain tx relayer + childRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Servers[0].JSONRPCAddr())) require.NoError(t, err) - // L1 Tx relayer (for querying checkpoints) - l1Relayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Bridge.JSONRPCAddr())) + // root chain tx relayer + rootRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Bridge.JSONRPCAddr())) require.NoError(t, err) // waiting two epochs, so that some rewards get accumulated - require.NoError(t, cluster.WaitForBlock(10, 1*time.Minute)) + require.NoError(t, cluster.WaitForBlock(2*epochSize, 1*time.Minute)) queryValidators := func(handler func(idx int, validatorInfo *polybft.ValidatorInfo)) { for i, validatorAddr := range votingPowerChangeValidators { // query validator info - validatorInfo, err := sidechain.GetValidatorInfo(validatorAddr, l2Relayer) + validatorInfo, err := sidechain.GetValidatorInfo( + validatorAddr, + polybftCfg.Bridge.CustomSupernetManagerAddr, + polybftCfg.Bridge.StakeManagerAddr, + polybftCfg.SupernetID, + rootRelayer, + childRelayer) require.NoError(t, err) handler(i, validatorInfo) } } - originalValidatorStorage := make(map[ethgo.Address]*polybft.ValidatorInfo, votingPowerChanges) + // validatorsMap holds only changed validators + validatorsMap := make(map[ethgo.Address]*polybft.ValidatorInfo, votingPowerChanges) queryValidators(func(idx int, validator *polybft.ValidatorInfo) { t.Logf("[Validator#%d] Voting power (original)=%d, rewards=%d\n", - idx+1, validator.TotalStake, validator.WithdrawableRewards) + idx+1, validator.Stake, validator.WithdrawableRewards) - originalValidatorStorage[validator.Address] = validator + validatorsMap[validator.Address] = validator + validatorSrv := cluster.Servers[idx] - // stake rewards - require.NoError(t, cluster.Servers[idx].Stake(validator.WithdrawableRewards.Uint64())) - }) + // fund validators (send accumulated rewards amount) + require.NoError(t, validatorSrv.RootchainFund(polybftCfg.Bridge.StakeTokenAddr, validator.WithdrawableRewards)) - // wait a two more epochs, so that stake is registered and two more checkpoints are sent. - // Blocks are still produced, although voting power is slightly changed. - require.NoError(t, cluster.WaitForBlock(finalBlockNumber, 1*time.Minute)) + // stake previously funded amount + require.NoError(t, validatorSrv.Stake(polybftCfg, validator.WithdrawableRewards)) + }) queryValidators(func(idx int, validator *polybft.ValidatorInfo) { - t.Logf("[Validator#%d] Voting power (after stake)=%d\n", idx+1, validator.TotalStake) + t.Logf("[Validator#%d] Voting power (after stake)=%d\n", idx+1, validator.Stake) - previousValidatorInfo := originalValidatorStorage[validator.Address] - stakedAmount := new(big.Int).Add(previousValidatorInfo.WithdrawableRewards, previousValidatorInfo.TotalStake) + previousValidatorInfo := validatorsMap[validator.Address] + stakedAmount := new(big.Int).Add(previousValidatorInfo.WithdrawableRewards, previousValidatorInfo.Stake) // assert that total stake has increased by staked amount - require.Equal(t, stakedAmount, validator.TotalStake) + require.Equal(t, stakedAmount, validator.Stake) + + validatorsMap[validator.Address] = validator }) - require.NoError(t, cluster.Bridge.WaitUntil(time.Second, time.Minute, func() (bool, error) { - actualCheckpointBlock, err := getCheckpointBlockNumber(l1Relayer, checkpointManagerAddr) - if err != nil { - return false, err + currentBlockNum, err := childRelayer.Client().Eth().BlockNumber() + require.NoError(t, err) + + // wait for next epoch-ending block as the starting point, + // in order to be able to easier track checkpoints submission + endOfEpochBlockNum := currentBlockNum + epochSize - (currentBlockNum % epochSize) + require.NoError(t, cluster.WaitForBlock(endOfEpochBlockNum, 1*time.Minute)) + + currentBlock, err := childRelayer.Client().Eth().GetBlockByNumber(ethgo.Latest, false) + require.NoError(t, err) + + currentExtra, err := polybft.GetIbftExtra(currentBlock.ExtraData) + require.NoError(t, err) + + targetEpoch := currentExtra.Checkpoint.EpochNumber + 2 + require.NoError(t, waitForRootchainEpoch(targetEpoch, 2*time.Minute, + rootRelayer, polybftCfg.Bridge.CheckpointManagerAddr)) + + // make sure that correct validator set is submitted to the checkpoint manager + checkpointValidators, err := getCheckpointManagerValidators(rootRelayer, ethgo.Address(polybftCfg.Bridge.CheckpointManagerAddr)) + require.NoError(t, err) + + for _, checkpointValidator := range checkpointValidators { + if validator, ok := validatorsMap[checkpointValidator.Address]; ok { + require.Equal(t, validator.Stake, checkpointValidator.Stake) + } else { + require.Equal(t, command.DefaultPremineBalance, checkpointValidator.Stake) } + } +} - t.Logf("Checkpoint block: %d\n", actualCheckpointBlock) +func TestE2E_Bridge_Transfers_AccessLists(t *testing.T) { + var ( + transfersCount = 5 + depositAmount = ethgo.Ether(5) + withdrawAmount = ethgo.Ether(1) + // make epoch size long enough, so that all exit events are processed within the same epoch + epochSize = 30 + sprintSize = uint64(5) + ) + + receivers := make([]string, transfersCount) + depositAmounts := make([]string, transfersCount) + withdrawAmounts := make([]string, transfersCount) + + admin, _ := ethgow.GenerateKey() + adminAddr := types.Address(admin.Address()) + + cluster := framework.NewTestCluster(t, 5, + framework.WithNumBlockConfirmations(0), + framework.WithEpochSize(epochSize), + framework.WithBridgeAllowListAdmin(adminAddr), + framework.WithBridgeBlockListAdmin(adminAddr), + framework.WithSecretsCallback(func(a []types.Address, tcc *framework.TestClusterConfig) { + for i := 0; i < len(a); i++ { + receivers[i] = a[i].String() + depositAmounts[i] = fmt.Sprintf("%d", depositAmount) + withdrawAmounts[i] = fmt.Sprintf("%d", withdrawAmount) + + t.Logf("Receiver#%d=%s\n", i+1, receivers[i]) + } + }), + ) + defer cluster.Stop() + + cluster.WaitForReady(t) + + polybftCfg, err := polybft.LoadPolyBFTConfig(path.Join(cluster.Config.TmpDir, chainConfigFileName)) + require.NoError(t, err) - return actualCheckpointBlock == finalBlockNumber, nil - })) + validatorSrv := cluster.Servers[0] + childEthEndpoint := validatorSrv.JSONRPC().Eth() + + var stateSyncedResult contractsapi.StateSyncResultEvent + + // fund admin on rootchain + require.NoError(t, cluster.Servers[0].RootchainFundFor([]types.Address{adminAddr}, []*big.Int{ethgo.Ether(10)}, + polybftCfg.Bridge.StakeTokenAddr)) + + adminBalanceOnChild := ethgo.Ether(5) + + // bridge some tokens for admin to child chain + require.NoError( + t, cluster.Bridge.Deposit( + common.ERC20, + polybftCfg.Bridge.RootNativeERC20Addr, + polybftCfg.Bridge.RootERC20PredicateAddr, + rootHelper.TestAccountPrivKey, + adminAddr.String(), + adminBalanceOnChild.String(), + "", + cluster.Bridge.JSONRPCAddr(), + rootHelper.TestAccountPrivKey, + false), + ) + + // wait for a couple of sprints + finalBlockNum := 5 * sprintSize + require.NoError(t, cluster.WaitForBlock(finalBlockNum, 2*time.Minute)) + + // the transaction is processed and there should be a success events + logs, err := getFilteredLogs(stateSyncedResult.Sig(), 0, finalBlockNum, childEthEndpoint) + require.NoError(t, err) + + // assert that all deposits are executed successfully + checkStateSyncResultLogs(t, logs, 1) + + // check admin balance got increased by deposited amount + balance, err := childEthEndpoint.GetBalance(ethgo.Address(adminAddr), ethgo.Latest) + require.NoError(t, err) + require.Equal(t, adminBalanceOnChild, balance) + + t.Run("bridge native (ERC 20) tokens", func(t *testing.T) { + // DEPOSIT ERC20 TOKENS + // send a few transactions to the bridge + require.NoError( + t, + cluster.Bridge.Deposit( + common.ERC20, + polybftCfg.Bridge.RootNativeERC20Addr, + polybftCfg.Bridge.RootERC20PredicateAddr, + rootHelper.TestAccountPrivKey, + strings.Join(receivers[:], ","), + strings.Join(depositAmounts[:], ","), + "", + cluster.Bridge.JSONRPCAddr(), + rootHelper.TestAccountPrivKey, + false), + ) + + finalBlockNum := 10 * sprintSize + // wait for a couple of sprints + require.NoError(t, cluster.WaitForBlock(finalBlockNum, 2*time.Minute)) + + // the transactions are processed and there should be a success events + logs, err := getFilteredLogs(stateSyncedResult.Sig(), 0, finalBlockNum, childEthEndpoint) + require.NoError(t, err) + + // because of the admin deposit on child chain at the beginning + totalTransfers := transfersCount + 1 + + // assert that all deposits are executed successfully + checkStateSyncResultLogs(t, logs, totalTransfers) + + // check receivers balances got increased by deposited amount + for _, receiver := range receivers { + balance, err := childEthEndpoint.GetBalance(ethgo.Address(types.StringToAddress(receiver)), ethgo.Latest) + require.NoError(t, err) + require.Equal(t, depositAmount, balance) + } + + t.Log("Deposits were successfully processed") + + // WITHDRAW ERC20 TOKENS + rootchainTxRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Bridge.JSONRPCAddr())) + require.NoError(t, err) + + senderAccount, err := sidechain.GetAccountFromDir(validatorSrv.DataDir()) + require.NoError(t, err) + + t.Logf("Withdraw sender: %s\n", senderAccount.Ecdsa.Address()) + + rawKey, err := senderAccount.Ecdsa.MarshallPrivateKey() + require.NoError(t, err) + + // send withdraw transaction. + // It should fail because sender is not allow-listed. + err = cluster.Bridge.Withdraw( + common.ERC20, + hex.EncodeToString(rawKey), + strings.Join(receivers[:], ","), + strings.Join(withdrawAmounts[:], ","), + "", + validatorSrv.JSONRPCAddr(), + contracts.ChildERC20PredicateContract, + contracts.NativeERC20TokenContract, + false) + require.Error(t, err) + + // add account to bridge allow list + setAccessListRole(t, cluster, contracts.AllowListBridgeAddr, senderAccount.Address(), addresslist.EnabledRole, admin) + + // try to withdraw again + err = cluster.Bridge.Withdraw( + common.ERC20, + hex.EncodeToString(rawKey), + strings.Join(receivers[:], ","), + strings.Join(withdrawAmounts[:], ","), + "", + validatorSrv.JSONRPCAddr(), + contracts.ChildERC20PredicateContract, + contracts.NativeERC20TokenContract, + false) + require.NoError(t, err) + + // add account to bridge block list + setAccessListRole(t, cluster, contracts.BlockListBridgeAddr, senderAccount.Address(), addresslist.EnabledRole, admin) + + // it should fail now because in block list + err = cluster.Bridge.Withdraw( + common.ERC20, + hex.EncodeToString(rawKey), + strings.Join(receivers[:], ","), + strings.Join(withdrawAmounts[:], ","), + "", + validatorSrv.JSONRPCAddr(), + contracts.ChildERC20PredicateContract, + contracts.NativeERC20TokenContract, + false) + require.ErrorContains(t, err, "failed to send withdraw transaction") + + currentBlock, err := childEthEndpoint.GetBlockByNumber(ethgo.Latest, false) + require.NoError(t, err) + + currentExtra, err := polybft.GetIbftExtra(currentBlock.ExtraData) + require.NoError(t, err) + + t.Logf("Latest block number: %d, epoch number: %d\n", currentBlock.Number, currentExtra.Checkpoint.EpochNumber) + + currentEpoch := currentExtra.Checkpoint.EpochNumber + + require.NoError(t, waitForRootchainEpoch(currentEpoch, 3*time.Minute, + rootchainTxRelayer, polybftCfg.Bridge.CheckpointManagerAddr)) + + exitHelper := polybftCfg.Bridge.ExitHelperAddr + childJSONRPC := validatorSrv.JSONRPCAddr() + + oldBalances := map[types.Address]*big.Int{} + for _, receiver := range receivers { + balance := erc20BalanceOf(t, types.StringToAddress(receiver), polybftCfg.Bridge.RootNativeERC20Addr, rootchainTxRelayer) + oldBalances[types.StringToAddress(receiver)] = balance + } + + for exitEventID := uint64(1); exitEventID <= uint64(transfersCount); exitEventID++ { + // send exit transaction to exit helper + err = cluster.Bridge.SendExitTransaction(exitHelper, exitEventID, childJSONRPC) + require.NoError(t, err) + } + + // assert that receiver's balances on RootERC20 smart contract are expected + for _, receiver := range receivers { + balance := erc20BalanceOf(t, types.StringToAddress(receiver), polybftCfg.Bridge.RootNativeERC20Addr, rootchainTxRelayer) + require.Equal(t, oldBalances[types.StringToAddress(receiver)].Add( + oldBalances[types.StringToAddress(receiver)], withdrawAmount), balance) + } + }) } diff --git a/e2e-polybft/e2e/burn_contract_test.go b/e2e-polybft/e2e/burn_contract_test.go new file mode 100644 index 0000000000..9a592397ea --- /dev/null +++ b/e2e-polybft/e2e/burn_contract_test.go @@ -0,0 +1,37 @@ +package e2e + +import ( + "testing" + + "github.com/stretchr/testify/require" + "github.com/umbracle/ethgo" + "github.com/umbracle/ethgo/wallet" + + "github.com/0xPolygon/polygon-edge/consensus/polybft" + "github.com/0xPolygon/polygon-edge/e2e-polybft/framework" + "github.com/0xPolygon/polygon-edge/types" +) + +func TestE2E_BurnContract_Deployed(t *testing.T) { + contractKey, _ := wallet.GenerateKey() + destinationKey, _ := wallet.GenerateKey() + + contractAddr := types.Address(contractKey.Address()) + destinationAddr := types.Address(destinationKey.Address()) + + cluster := framework.NewTestCluster(t, 5, + framework.WithBurnContract(&polybft.BurnContractInfo{ + Address: contractAddr, + DestinationAddress: destinationAddr, + }), + ) + defer cluster.Stop() + + cluster.WaitForReady(t) + client := cluster.Servers[0].JSONRPC().Eth() + + // Get the code for the default deployed burn contract + code, err := client.GetCode(ethgo.Address(contractAddr), ethgo.Latest) + require.NoError(t, err) + require.NotEqual(t, code, "0x") +} diff --git a/e2e-polybft/e2e/consensus_test.go b/e2e-polybft/e2e/consensus_test.go index 79f5912399..45355401f2 100644 --- a/e2e-polybft/e2e/consensus_test.go +++ b/e2e-polybft/e2e/consensus_test.go @@ -1,88 +1,110 @@ package e2e import ( + "context" + "encoding/json" "fmt" "math/big" "path" + "strconv" "testing" "time" + "github.com/stretchr/testify/require" + "github.com/umbracle/ethgo" + "github.com/umbracle/ethgo/abi" + "github.com/umbracle/ethgo/wallet" + + "github.com/0xPolygon/polygon-edge/command" "github.com/0xPolygon/polygon-edge/command/genesis" "github.com/0xPolygon/polygon-edge/command/sidechain" "github.com/0xPolygon/polygon-edge/consensus/polybft" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" "github.com/0xPolygon/polygon-edge/contracts" "github.com/0xPolygon/polygon-edge/e2e-polybft/framework" + "github.com/0xPolygon/polygon-edge/server/proto" "github.com/0xPolygon/polygon-edge/txrelayer" "github.com/0xPolygon/polygon-edge/types" - "github.com/stretchr/testify/require" - "github.com/umbracle/ethgo" ) +var uint256ABIType = abi.MustNewType("tuple(uint256)") + func TestE2E_Consensus_Basic_WithNonValidators(t *testing.T) { - cluster := framework.NewTestCluster(t, 7, - framework.WithNonValidators(2), framework.WithValidatorSnapshot(5)) + const epochSize = 4 + + cluster := framework.NewTestCluster(t, 5, + framework.WithEpochSize(epochSize), framework.WithNonValidators(2)) defer cluster.Stop() - require.NoError(t, cluster.WaitForBlock(22, 1*time.Minute)) -} + cluster.WaitForReady(t) -func TestE2E_Consensus_Sync_WithNonValidators(t *testing.T) { - // one non-validator node from the ensemble gets disconnected and connected again. - // It should be able to pick up from the synchronization protocol again. - cluster := framework.NewTestCluster(t, 7, - framework.WithNonValidators(2), framework.WithValidatorSnapshot(5)) - defer cluster.Stop() + // initialize tx relayer + relayer, err := txrelayer.NewTxRelayer(txrelayer.WithClient(cluster.Servers[0].JSONRPC())) + require.NoError(t, err) - // wait for the start - require.NoError(t, cluster.WaitForBlock(20, 1*time.Minute)) + // because we are using native token as reward wallet, and it has default premine balance + initialTotalSupply := new(big.Int).Set(command.DefaultPremineBalance) - // stop one non-validator node - node := cluster.Servers[6] - node.Stop() + // check if initial total supply of native ERC20 token is the same as expected + totalSupply := queryNativeERC20Metadata(t, "totalSupply", uint256ABIType, relayer) + require.True(t, initialTotalSupply.Cmp(totalSupply.(*big.Int)) == 0) //nolint:forcetypeassert - // wait for at least 15 more blocks before starting again - require.NoError(t, cluster.WaitForBlock(35, 2*time.Minute)) + t.Run("consensus protocol", func(t *testing.T) { + require.NoError(t, cluster.WaitForBlock(2*epochSize+1, 1*time.Minute)) + }) - // start the node again - node.Start() + t.Run("sync protocol, drop single validator node", func(t *testing.T) { + // query the current block number, as it is a starting point for the test + currentBlockNum, err := cluster.Servers[0].JSONRPC().Eth().BlockNumber() + require.NoError(t, err) - // wait for block 55 - require.NoError(t, cluster.WaitForBlock(55, 2*time.Minute)) -} + // stop one node + node := cluster.Servers[0] + node.Stop() -func TestE2E_Consensus_Sync(t *testing.T) { - // one node from the ensemble gets disconnected and connected again. - // It should be able to pick up from the synchronization protocol again. - cluster := framework.NewTestCluster(t, 6, framework.WithValidatorSnapshot(6)) - defer cluster.Stop() + // wait for 2 epochs to elapse, so that rest of the network progresses + require.NoError(t, cluster.WaitForBlock(currentBlockNum+2*epochSize, 2*time.Minute)) - // wait for the start - require.NoError(t, cluster.WaitForBlock(5, 1*time.Minute)) + // start the node again + node.Start() - // stop one node - node := cluster.Servers[0] - node.Stop() + // wait 2 more epochs to elapse and make sure that stopped node managed to catch up + require.NoError(t, cluster.WaitForBlock(currentBlockNum+4*epochSize, 2*time.Minute)) + }) - // wait for at least 15 more blocks before starting again - require.NoError(t, cluster.WaitForBlock(20, 2*time.Minute)) + t.Run("sync protocol, drop single non-validator node", func(t *testing.T) { + // query the current block number, as it is a starting point for the test + currentBlockNum, err := cluster.Servers[0].JSONRPC().Eth().BlockNumber() + require.NoError(t, err) + + // stop one non-validator node + node := cluster.Servers[6] + node.Stop() - // start the node again - node.Start() + // wait for 2 epochs to elapse, so that rest of the network progresses + require.NoError(t, cluster.WaitForBlock(currentBlockNum+2*epochSize, 2*time.Minute)) + + // start the node again + node.Start() - // wait for block 35 - require.NoError(t, cluster.WaitForBlock(35, 2*time.Minute)) + // wait 2 more epochs to elapse and make sure that stopped node managed to catch up + require.NoError(t, cluster.WaitForBlock(currentBlockNum+4*epochSize, 2*time.Minute)) + }) } -func TestE2E_Consensus_Bulk_Drop(t *testing.T) { - clusterSize := 5 - bulkToDrop := 3 +func TestE2E_Consensus_BulkDrop(t *testing.T) { + const ( + clusterSize = 5 + bulkToDrop = 3 + epochSize = 5 + ) - cluster := framework.NewTestCluster(t, clusterSize) + cluster := framework.NewTestCluster(t, clusterSize, + framework.WithEpochSize(epochSize)) defer cluster.Stop() // wait for cluster to start - require.NoError(t, cluster.WaitForBlock(5, 1*time.Minute)) + cluster.WaitForReady(t) // drop bulk of nodes from cluster for i := 0; i < bulkToDrop; i++ { @@ -96,45 +118,53 @@ func TestE2E_Consensus_Bulk_Drop(t *testing.T) { node.Start() } - // wait for block 10 - require.NoError(t, cluster.WaitForBlock(10, 2*time.Minute)) + // wait to proceed to the 2nd epoch + require.NoError(t, cluster.WaitForBlock(epochSize+1, 2*time.Minute)) } func TestE2E_Consensus_RegisterValidator(t *testing.T) { const ( - validatorSize = 5 - epochSize = 5 - epochReward = 1000000000 + validatorSetSize = 5 + epochSize = 5 ) var ( - firstValidatorDataDir = fmt.Sprintf("test-chain-%d", validatorSize+1) // directory where the first validator secrets will be stored - secondValidatorDataDir = fmt.Sprintf("test-chain-%d", validatorSize+2) // directory where the second validator secrets will be stored + firstValidatorDataDir = fmt.Sprintf("test-chain-%d", validatorSetSize+1) // directory where the first validator secrets will be stored + secondValidatorDataDir = fmt.Sprintf("test-chain-%d", validatorSetSize+2) // directory where the second validator secrets will be stored - premineBalance = ethgo.Ether(2e6) // 2M native tokens (so that we have enough balance to fund new validator) + initMinterBalance = ethgo.Ether(4e6) + premineBalance = ethgo.Ether(2e6) // 2M native tokens (so that we have enough balance to fund new validator) ) + minter, err := wallet.GenerateKey() + require.NoError(t, err) + // start cluster with 'validatorSize' validators - cluster := framework.NewTestCluster(t, validatorSize, + cluster := framework.NewTestCluster(t, validatorSetSize, framework.WithEpochSize(epochSize), - framework.WithEpochReward(epochReward), + framework.WithEpochReward(int(ethgo.Ether(1).Uint64())), + framework.WithNativeTokenConfig(fmt.Sprintf(nativeTokenMintableTestCfg, minter.Address())), framework.WithSecretsCallback(func(addresses []types.Address, config *framework.TestClusterConfig) { + config.Premine = append(config.Premine, fmt.Sprintf("%s:%s", minter.Address(), initMinterBalance)) for _, a := range addresses { - config.PremineValidators = append(config.PremineValidators, fmt.Sprintf("%s:%s", a, premineBalance)) + config.Premine = append(config.Premine, fmt.Sprintf("%s:%s", a, premineBalance)) } }), ) defer cluster.Stop() + cluster.WaitForReady(t) + // first validator is the owner of ChildValidator set smart contract owner := cluster.Servers[0] - txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(owner.JSONRPCAddr())) + childChainRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(owner.JSONRPCAddr())) + require.NoError(t, err) + + rootChainRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Bridge.JSONRPCAddr())) require.NoError(t, err) - systemState := polybft.NewSystemState( - contracts.ValidatorSetContract, - contracts.StateReceiverContract, - &e2eStateProvider{txRelayer: txRelayer}) + polybftConfig, err := polybft.LoadPolyBFTConfig(path.Join(cluster.Config.TmpDir, chainConfigFileName)) + require.NoError(t, err) // create the first account and extract the address addrs, err := cluster.InitSecrets(firstValidatorDataDir, 1) @@ -151,371 +181,266 @@ func TestE2E_Consensus_RegisterValidator(t *testing.T) { // assert that accounts are created validatorSecrets, err := genesis.GetValidatorKeyFiles(cluster.Config.TmpDir, cluster.Config.ValidatorPrefix) require.NoError(t, err) - require.Equal(t, validatorSize+2, len(validatorSecrets)) + require.Equal(t, validatorSetSize+2, len(validatorSecrets)) // collect owners validator secrets - ownerSecrets := validatorSecrets[0] - - // wait for consensus to start - require.NoError(t, cluster.WaitForBlock(1, 10*time.Second)) + firstValidatorSecrets := validatorSecrets[validatorSetSize] + secondValidatorSecrets := validatorSecrets[validatorSetSize+1] genesisBlock, err := owner.JSONRPC().Eth().GetBlockByNumber(0, false) require.NoError(t, err) - extra, err := polybft.GetIbftExtra(genesisBlock.ExtraData) + _, err = polybft.GetIbftExtra(genesisBlock.ExtraData) require.NoError(t, err) - // on genesis block all validators are marked as added, which makes initial validator set - initialValidators := extra.Validators.Added - // owner whitelists both new validators - require.NoError(t, owner.WhitelistValidator(firstValidatorAddr.String(), ownerSecrets)) - require.NoError(t, owner.WhitelistValidator(secondValidatorAddr.String(), ownerSecrets)) + require.NoError(t, owner.WhitelistValidators([]string{ + firstValidatorAddr.String(), + secondValidatorAddr.String(), + }, polybftConfig.Bridge.CustomSupernetManagerAddr)) - // start the first and the second validator - cluster.InitTestServer(t, validatorSize+1, true, false) - cluster.InitTestServer(t, validatorSize+2, true, false) + // set the initial balance of the new validators at the rootchain + initialBalance := ethgo.Ether(500) - ownerAcc, err := sidechain.GetAccountFromDir(path.Join(cluster.Config.TmpDir, ownerSecrets)) + // fund first new validator + err = cluster.Bridge.FundValidators(polybftConfig.Bridge.StakeTokenAddr, + []string{path.Join(cluster.Config.TmpDir, firstValidatorSecrets)}, []*big.Int{initialBalance}) require.NoError(t, err) - // get the initial balance of the new validator - initialBalance := ethgo.Ether(500000) - - // send some tokens from the owner to the first validator so that the first validator can register and stake - receipt, err := txRelayer.SendTransaction(ðgo.Transaction{ - From: ownerAcc.Ecdsa.Address(), - To: &firstValidatorAddr, - Value: initialBalance, - }, ownerAcc.Ecdsa) + // fund second new validator + err = cluster.Bridge.FundValidators(polybftConfig.Bridge.StakeTokenAddr, + []string{path.Join(cluster.Config.TmpDir, secondValidatorSecrets)}, []*big.Int{initialBalance}) require.NoError(t, err) - require.Equal(t, uint64(types.ReceiptSuccess), receipt.Status) - - // send some tokens from the owner to the second validator so that the second validator can register and stake - receipt, err = txRelayer.SendTransaction(ðgo.Transaction{ - From: ownerAcc.Ecdsa.Address(), - To: &secondValidatorAddr, - Value: initialBalance, - }, ownerAcc.Ecdsa) - require.NoError(t, err) - require.Equal(t, uint64(types.ReceiptSuccess), receipt.Status) - // collect the first and the second validator from the cluster - firstValidator := cluster.Servers[validatorSize] - secondValidator := cluster.Servers[validatorSize+1] - - // wait for the first validator's balance to be received - firstBalance, err := firstValidator.WaitForNonZeroBalance(firstValidatorAddr, 5*time.Second) + // first validator's balance to be received + firstBalance, err := rootChainRelayer.Client().Eth().GetBalance(firstValidatorAddr, ethgo.Latest) require.NoError(t, err) t.Logf("First validator balance=%d\n", firstBalance) - // wait for the first validator's balance to be received - secondBalance, err := secondValidator.WaitForNonZeroBalance(secondValidatorAddr, 5*time.Second) + // second validator's balance to be received + secondBalance, err := rootChainRelayer.Client().Eth().GetBalance(secondValidatorAddr, ethgo.Latest) require.NoError(t, err) t.Logf("Second validator balance=%d\n", secondBalance) - newValidatorStake := ethgo.Ether(10) + // start the first and the second validator + cluster.InitTestServer(t, cluster.Config.ValidatorPrefix+strconv.Itoa(validatorSetSize+1), + cluster.Bridge.JSONRPCAddr(), true, false) + + cluster.InitTestServer(t, cluster.Config.ValidatorPrefix+strconv.Itoa(validatorSetSize+2), + cluster.Bridge.JSONRPCAddr(), true, false) + + // collect the first and the second validator from the cluster + firstValidator := cluster.Servers[validatorSetSize] + secondValidator := cluster.Servers[validatorSetSize+1] + + initialStake := ethgo.Ether(499) // register the first validator with stake - require.NoError(t, firstValidator.RegisterValidator(firstValidatorDataDir, newValidatorStake.String())) + require.NoError(t, firstValidator.RegisterValidator(polybftConfig.Bridge.CustomSupernetManagerAddr)) // register the second validator without stake - require.NoError(t, secondValidator.RegisterValidator(secondValidatorDataDir, "")) - - // stake manually for the second validator - require.NoError(t, secondValidator.Stake(newValidatorStake.Uint64())) + require.NoError(t, secondValidator.RegisterValidator(polybftConfig.Bridge.CustomSupernetManagerAddr)) - validators := polybft.AccountSet{} - // assert that new validator is among validator set - require.NoError(t, cluster.WaitUntil(20*time.Second, 1*time.Second, func() bool { - // query validators - validators, err = systemState.GetValidatorSet() - require.NoError(t, err) + // stake manually for the first validator + require.NoError(t, firstValidator.Stake(polybftConfig, initialStake)) - return validators.ContainsAddress((types.Address(firstValidatorAddr))) && - validators.ContainsAddress((types.Address(secondValidatorAddr))) - })) + // stake manually for the second validator + require.NoError(t, secondValidator.Stake(polybftConfig, initialStake)) - // assert that next validators hash is correct - block, err := owner.JSONRPC().Eth().GetBlockByNumber(ethgo.Latest, false) + firstValidatorInfo, err := sidechain.GetValidatorInfo(firstValidatorAddr, + polybftConfig.Bridge.CustomSupernetManagerAddr, polybftConfig.Bridge.StakeManagerAddr, + polybftConfig.SupernetID, rootChainRelayer, childChainRelayer) require.NoError(t, err) - t.Logf("Block Number=%d\n", block.Number) + require.True(t, firstValidatorInfo.IsActive) + require.True(t, firstValidatorInfo.Stake.Cmp(initialStake) == 0) - // apply all deltas from epoch ending blocks - nextValidators := initialValidators + secondValidatorInfo, err := sidechain.GetValidatorInfo(secondValidatorAddr, + polybftConfig.Bridge.CustomSupernetManagerAddr, polybftConfig.Bridge.StakeManagerAddr, + polybftConfig.SupernetID, rootChainRelayer, childChainRelayer) + require.NoError(t, err) + require.True(t, secondValidatorInfo.IsActive) + require.True(t, secondValidatorInfo.Stake.Cmp(initialStake) == 0) - // apply all the deltas to the initial validator set - latestEpochEndBlock := block.Number - (block.Number % epochSize) - for blockNum := uint64(epochSize); blockNum <= latestEpochEndBlock; blockNum += epochSize { - block, err = owner.JSONRPC().Eth().GetBlockByNumber(ethgo.BlockNumber(blockNum), false) - require.NoError(t, err) + // wait for the stake to be bridged + require.NoError(t, cluster.WaitForBlock(polybftConfig.EpochSize*4, time.Minute)) - extra, err = polybft.GetIbftExtra(block.ExtraData) - require.NoError(t, err) - require.NotNil(t, extra.Checkpoint) + checkpointManagerAddr := ethgo.Address(polybftConfig.Bridge.CheckpointManagerAddr) - t.Logf("Block Number: %d, Delta: %v\n", blockNum, extra.Validators) - - nextValidators, err = nextValidators.ApplyDelta(extra.Validators) - require.NoError(t, err) - } + // check if the validators are added to active validator set + rootchainValidators := []*polybft.ValidatorInfo{} + err = cluster.Bridge.WaitUntil(time.Second, time.Minute, func() (bool, error) { + rootchainValidators, err = getCheckpointManagerValidators(rootChainRelayer, checkpointManagerAddr) + if err != nil { + return true, err + } - // assert that correct validators hash gets submitted - nextValidatorsHash, err := nextValidators.Hash() - require.NoError(t, err) - require.Equal(t, extra.Checkpoint.NextValidatorsHash, nextValidatorsHash) + return len(rootchainValidators) == validatorSetSize+2, nil + }) - // query the first validator - firstValidatorInfo, err := sidechain.GetValidatorInfo(firstValidatorAddr, txRelayer) require.NoError(t, err) + require.Equal(t, validatorSetSize+2, len(rootchainValidators)) - // assert the first validator's stake - t.Logf("First validator stake=%d\n", firstValidatorInfo.TotalStake) - require.Equal(t, newValidatorStake, firstValidatorInfo.TotalStake) - - // query the second validatorr - secondValidatorInfo, err := sidechain.GetValidatorInfo(secondValidatorAddr, txRelayer) - require.NoError(t, err) + var ( + isFirstValidatorFound bool + isSecondValidatorFound bool + ) - // assert the second validator's stake - t.Logf("Second validator stake=%d\n", secondValidatorInfo.TotalStake) - require.Equal(t, newValidatorStake, secondValidatorInfo.TotalStake) + for _, v := range rootchainValidators { + if v.Address == firstValidatorAddr { + isFirstValidatorFound = true + } else if v.Address == secondValidatorAddr { + isSecondValidatorFound = true + } + } - // wait 3 more epochs, so that rewards get accumulated to the registered validator account - currentBlock, err := owner.JSONRPC().Eth().BlockNumber() - require.NoError(t, err) - require.NoError(t, cluster.WaitForBlock(currentBlock+3*epochSize, 2*time.Minute)) + // new validators should be in the active validator set + require.True(t, isFirstValidatorFound) + require.True(t, isSecondValidatorFound) - // query the first validator info again - firstValidatorInfo, err = sidechain.GetValidatorInfo(firstValidatorAddr, txRelayer) + currentBlock, err := owner.JSONRPC().Eth().GetBlockByNumber(ethgo.Latest, false) require.NoError(t, err) - // check if the first validator has signed any prposals - firstSealed, err := firstValidator.HasValidatorSealed(currentBlock, currentBlock+3*epochSize, nextValidators, firstValidatorAddr) - require.NoError(t, err) + // wait for couple of epochs to have some rewards accumulated + require.NoError(t, cluster.WaitForBlock(currentBlock.Number+(polybftConfig.EpochSize*2), time.Minute)) - if firstSealed { - // assert registered validator's rewards) - t.Logf("First validator rewards (block %d)=%d\n", currentBlock, firstValidatorInfo.WithdrawableRewards) - require.True(t, firstValidatorInfo.WithdrawableRewards.Cmp(big.NewInt(0)) > 0) - } + bigZero := big.NewInt(0) - // query the second validator info again - secondValidatorInfo, err = sidechain.GetValidatorInfo(secondValidatorAddr, txRelayer) + firstValidatorInfo, err = sidechain.GetValidatorInfo(firstValidatorAddr, + polybftConfig.Bridge.CustomSupernetManagerAddr, polybftConfig.Bridge.StakeManagerAddr, + polybftConfig.SupernetID, rootChainRelayer, childChainRelayer) require.NoError(t, err) + require.True(t, firstValidatorInfo.IsActive) + require.True(t, firstValidatorInfo.WithdrawableRewards.Cmp(bigZero) > 0) - // check if the second validator has signed any prposals - secondSealed, err := secondValidator.HasValidatorSealed(currentBlock, currentBlock+3*epochSize, nextValidators, secondValidatorAddr) + secondValidatorInfo, err = sidechain.GetValidatorInfo(secondValidatorAddr, + polybftConfig.Bridge.CustomSupernetManagerAddr, polybftConfig.Bridge.StakeManagerAddr, + polybftConfig.SupernetID, rootChainRelayer, childChainRelayer) require.NoError(t, err) - - if secondSealed { - // assert registered validator's rewards - t.Logf("Second validator rewards (block %d)=%d\n", currentBlock, secondValidatorInfo.WithdrawableRewards) - require.True(t, secondValidatorInfo.WithdrawableRewards.Cmp(big.NewInt(0)) > 0) - } + require.True(t, secondValidatorInfo.IsActive) + require.True(t, secondValidatorInfo.WithdrawableRewards.Cmp(bigZero) > 0) } -func TestE2E_Consensus_Delegation_Undelegation(t *testing.T) { - const ( - validatorSecrets = "test-chain-1" - delegatorSecrets = "test-chain-6" - epochSize = 5 +func TestE2E_Consensus_Validator_Unstake(t *testing.T) { + var ( + premineAmount = ethgo.Ether(10) + minterBalance = ethgo.Ether(1e6) ) - premineBalance := ethgo.Ether(500) // 500 native tokens (so that we have enough funds to fund delegator) - fundAmount := ethgo.Ether(250) + minter, err := wallet.GenerateKey() + require.NoError(t, err) cluster := framework.NewTestCluster(t, 5, - framework.WithEpochReward(100000), - framework.WithEpochSize(epochSize), + framework.WithEpochReward(int(ethgo.Ether(1).Uint64())), + framework.WithEpochSize(5), + framework.WithNativeTokenConfig(fmt.Sprintf(nativeTokenMintableTestCfg, minter.Address())), framework.WithSecretsCallback(func(addresses []types.Address, config *framework.TestClusterConfig) { + config.Premine = append(config.Premine, fmt.Sprintf("%s:%d", minter.Address(), minterBalance)) for _, a := range addresses { - config.PremineValidators = append(config.PremineValidators, fmt.Sprintf("%s:%s", a, premineBalance)) - config.StakeAmounts = append(config.StakeAmounts, fmt.Sprintf("%s:%s", a, premineBalance)) + config.Premine = append(config.Premine, fmt.Sprintf("%s:%d", a, premineAmount)) + config.StakeAmounts = append(config.StakeAmounts, new(big.Int).Set(premineAmount)) } }), ) - defer cluster.Stop() - // init delegator account - _, err := cluster.InitSecrets(delegatorSecrets, 1) + polybftCfg, err := polybft.LoadPolyBFTConfig(path.Join(cluster.Config.TmpDir, chainConfigFileName)) require.NoError(t, err) srv := cluster.Servers[0] - txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(srv.JSONRPCAddr())) - require.NoError(t, err) - - cluster.WaitForReady(t) - - // extract delegator's secrets - delegatorSecretsPath := path.Join(cluster.Config.TmpDir, delegatorSecrets) - delegatorAcc, err := sidechain.GetAccountFromDir(delegatorSecretsPath) + childChainRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(srv.JSONRPCAddr())) require.NoError(t, err) - delegatorAddr := delegatorAcc.Ecdsa.Address() - - // extract validator's secrets - validatorSecretsPath := path.Join(cluster.Config.TmpDir, validatorSecrets) - - validatorAcc, err := sidechain.GetAccountFromDir(validatorSecretsPath) + rootChainRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Bridge.JSONRPCAddr())) require.NoError(t, err) - validatorAddr := validatorAcc.Ecdsa.Address() - - // fund delegator - receipt, err := txRelayer.SendTransaction(ðgo.Transaction{ - From: validatorAddr, - To: &delegatorAddr, - Value: fundAmount, - }, validatorAcc.Ecdsa) + validatorAcc, err := sidechain.GetAccountFromDir(srv.DataDir()) require.NoError(t, err) - require.Equal(t, uint64(types.ReceiptSuccess), receipt.Status) - - // getDelegatorInfo queries delegator's balance and its rewards - getDelegatorInfo := func() (balance *big.Int, reward *big.Int) { - currentBlockNum, err := srv.JSONRPC().Eth().BlockNumber() - require.NoError(t, err) - - balance, err = srv.JSONRPC().Eth().GetBalance(delegatorAddr, ethgo.Latest) - require.NoError(t, err) - t.Logf("Delegator balance (block %d)=%s\n", currentBlockNum, balance) - - reward, err = sidechain.GetDelegatorReward(validatorAddr, delegatorAddr, txRelayer) - require.NoError(t, err) - t.Logf("Delegator reward (block %d)=%s\n", currentBlockNum, reward) - - return - } - // assert that delegator received fund amount from validator - delegatorBalance, _ := getDelegatorInfo() - require.Equal(t, fundAmount, delegatorBalance) - - // delegate 1 native token - delegationAmount := uint64(1e18) - require.NoError(t, srv.Delegate(delegationAmount, delegatorSecretsPath, validatorAddr)) + cluster.WaitForReady(t) - // wait for 2 epochs to accumulate delegator rewards - currentBlockNum, err := srv.JSONRPC().Eth().BlockNumber() + initialValidatorBalance, err := srv.JSONRPC().Eth().GetBalance(validatorAcc.Ecdsa.Address(), ethgo.Latest) require.NoError(t, err) - require.NoError(t, cluster.WaitForBlock(currentBlockNum+2*epochSize, 1*time.Minute)) + t.Logf("Balance (before unstake)=%d\n", initialValidatorBalance) - // query delegator rewards - _, delegatorReward := getDelegatorInfo() - // if validator signed at leased 1 block per epoch, this will be the minimal reward for the delegator - require.Greater(t, delegatorReward.Uint64(), uint64(16)) + validatorAddr := validatorAcc.Ecdsa.Address() - // undelegate rewards - require.NoError(t, srv.Undelegate(delegationAmount, delegatorSecretsPath, validatorAddr)) - t.Logf("Rewards are undelegated\n") + // wait for some rewards to get accumulated + require.NoError(t, cluster.WaitForBlock(polybftCfg.EpochSize*3, time.Minute)) - // wait for one epoch to be able to withdraw undelegated funds - currentBlockNum, err = srv.JSONRPC().Eth().BlockNumber() + validatorInfo, err := sidechain.GetValidatorInfo(validatorAddr, + polybftCfg.Bridge.CustomSupernetManagerAddr, polybftCfg.Bridge.StakeManagerAddr, + polybftCfg.SupernetID, rootChainRelayer, childChainRelayer) require.NoError(t, err) - require.NoError(t, cluster.WaitForBlock(currentBlockNum+epochSize, time.Minute)) - - balanceBeforeWithdraw, _ := getDelegatorInfo() + require.True(t, validatorInfo.IsActive) - // withdraw available rewards - require.NoError(t, srv.Withdraw(delegatorSecretsPath, delegatorAddr)) - t.Logf("Funds are withdrawn\n") + initialStake := validatorInfo.Stake + t.Logf("Stake (before unstake)=%d\n", initialStake) - // wait for single epoch to process withdrawal - currentBlockNum, err = srv.JSONRPC().Eth().BlockNumber() - require.NoError(t, err) - require.NoError(t, cluster.WaitForBlock(currentBlockNum+epochSize, time.Minute)) + reward := validatorInfo.WithdrawableRewards + t.Logf("Rewards=%d\n", reward) + require.Greater(t, reward.Uint64(), uint64(0)) - // assert that delegator doesn't receive any rewards - delegatorBalance, delegatorReward = getDelegatorInfo() - require.True(t, delegatorReward.Cmp(big.NewInt(0)) == 0) - require.True(t, balanceBeforeWithdraw.Cmp(delegatorBalance) == -1) -} + // unstake entire balance (which should remove validator from the validator set in next epoch) + require.NoError(t, srv.Unstake(initialStake)) -func TestE2E_Consensus_Validator_Unstake(t *testing.T) { - premineAmount := ethgo.Ether(10) + // wait for one epoch to withdraw from child + require.NoError(t, cluster.WaitForBlock(polybftCfg.EpochSize*4, time.Minute)) - cluster := framework.NewTestCluster(t, 5, - framework.WithBridge(), - framework.WithEpochReward(10000), - framework.WithEpochSize(5), - framework.WithSecretsCallback(func(addresses []types.Address, config *framework.TestClusterConfig) { - for _, a := range addresses { - config.PremineValidators = append(config.PremineValidators, fmt.Sprintf("%s:%d", a, premineAmount)) - config.StakeAmounts = append(config.StakeAmounts, fmt.Sprintf("%s:%d", a, premineAmount)) - } - }), - ) - validatorSecrets := path.Join(cluster.Config.TmpDir, "test-chain-1") - srv := cluster.Servers[0] + // withdraw from child + require.NoError(t, srv.WithdrawChildChain()) - txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(srv.JSONRPCAddr())) + currentBlock, err := srv.JSONRPC().Eth().GetBlockByNumber(ethgo.Latest, false) require.NoError(t, err) - systemState := polybft.NewSystemState( - contracts.ValidatorSetContract, - contracts.StateReceiverContract, - &e2eStateProvider{txRelayer: txRelayer}) - - validatorAcc, err := sidechain.GetAccountFromDir(validatorSecrets) + currentExtra, err := polybft.GetIbftExtra(currentBlock.ExtraData) require.NoError(t, err) - validatorAddr := validatorAcc.Ecdsa.Address() - - // wait for one epoch to accumulate validator rewards - require.NoError(t, cluster.WaitForBlock(5, 20*time.Second)) - - validatorInfo, err := sidechain.GetValidatorInfo(validatorAddr, txRelayer) - require.NoError(t, err) + t.Logf("Latest block number: %d, epoch number: %d\n", currentBlock.Number, currentExtra.Checkpoint.EpochNumber) - initialStake := validatorInfo.TotalStake - t.Logf("Stake (before unstake)=%d\n", initialStake) + currentEpoch := currentExtra.Checkpoint.EpochNumber - // unstake entire balance (which should remove validator from the validator set in next epoch) - require.NoError(t, srv.Unstake(initialStake.Uint64())) + // wait for checkpoint to be submitted + require.NoError(t, waitForRootchainEpoch(currentEpoch, time.Minute, + rootChainRelayer, polybftCfg.Bridge.CheckpointManagerAddr)) - // wait end of epoch - require.NoError(t, cluster.WaitForBlock(10, 20*time.Second)) + exitEventID := uint64(1) - validatorSet, err := systemState.GetValidatorSet() + // send exit transaction to exit helper + err = cluster.Bridge.SendExitTransaction(polybftCfg.Bridge.ExitHelperAddr, exitEventID, srv.JSONRPCAddr()) require.NoError(t, err) - // assert that validator isn't present in new validator set - require.Equal(t, 4, validatorSet.Len()) - - validatorInfo, err = sidechain.GetValidatorInfo(validatorAddr, txRelayer) + // check that validator is no longer active (out of validator set) + validatorInfo, err = sidechain.GetValidatorInfo(validatorAddr, + polybftCfg.Bridge.CustomSupernetManagerAddr, polybftCfg.Bridge.StakeManagerAddr, + polybftCfg.SupernetID, rootChainRelayer, childChainRelayer) require.NoError(t, err) + require.False(t, validatorInfo.IsActive) + require.True(t, validatorInfo.Stake.Cmp(big.NewInt(0)) == 0) - reward := validatorInfo.WithdrawableRewards - t.Logf("Rewards=%d\n", reward) - t.Logf("Stake (after unstake)=%d\n", validatorInfo.TotalStake) - require.Greater(t, reward.Uint64(), uint64(0)) + t.Logf("Stake (after unstake)=%d\n", validatorInfo.Stake) - oldValidatorBalance, err := srv.JSONRPC().Eth().GetBalance(validatorAcc.Ecdsa.Address(), ethgo.Latest) + balanceBeforeRewardsWithdraw, err := srv.JSONRPC().Eth().GetBalance(validatorAcc.Ecdsa.Address(), ethgo.Latest) require.NoError(t, err) - t.Logf("Balance (before withdrawal)=%s\n", oldValidatorBalance) + t.Logf("Balance (before withdraw rewards)=%d\n", balanceBeforeRewardsWithdraw) - // withdraw (stake + rewards) - require.NoError(t, srv.Withdraw(validatorSecrets, validatorAddr)) + // withdraw pending rewards + require.NoError(t, srv.WithdrawRewards()) newValidatorBalance, err := srv.JSONRPC().Eth().GetBalance(validatorAcc.Ecdsa.Address(), ethgo.Latest) require.NoError(t, err) - t.Logf("Balance (after withdrawal)=%s\n", newValidatorBalance) - require.True(t, newValidatorBalance.Cmp(oldValidatorBalance) > 0) + t.Logf("Balance (after withdrawal of rewards)=%s\n", newValidatorBalance) + require.True(t, newValidatorBalance.Cmp(balanceBeforeRewardsWithdraw) > 0) l1Relayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Bridge.JSONRPCAddr())) require.NoError(t, err) - manifest, err := polybft.LoadManifest(path.Join(cluster.Config.TmpDir, manifestFileName)) - require.NoError(t, err) - - checkpointManagerAddr := ethgo.Address(manifest.RootchainConfig.CheckpointManagerAddress) + checkpointManagerAddr := ethgo.Address(polybftCfg.Bridge.CheckpointManagerAddr) // query rootchain validator set and make sure that validator which unstaked all the funds isn't present in validator set anymore // (execute it multiple times if needed, because it is unknown in advance how much time it is going to take until checkpoint is submitted) rootchainValidators := []*polybft.ValidatorInfo{} err = cluster.Bridge.WaitUntil(time.Second, 10*time.Second, func() (bool, error) { - rootchainValidators, err = getRootchainValidators(l1Relayer, checkpointManagerAddr) + rootchainValidators, err = getCheckpointManagerValidators(l1Relayer, checkpointManagerAddr) if err != nil { return true, err } @@ -532,132 +457,78 @@ func TestE2E_Consensus_Validator_Unstake(t *testing.T) { } } -func TestE2E_Consensus_CorrectnessOfExtraValidatorsShouldNotDependOnDelegate(t *testing.T) { - const ( - validatorSecrets = "test-chain-1" - delegatorSecrets = "test-chain-delegator" - epochSize = 5 - validatorCount = 4 - blockTime = 2 * time.Second - ) - - cluster := framework.NewTestCluster(t, validatorCount, - framework.WithEpochReward(100000), - framework.WithEpochSize(epochSize)) - defer cluster.Stop() - - txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Servers[0].JSONRPCAddr())) - require.NoError(t, err) - - // init delegator account - _, err = cluster.InitSecrets(delegatorSecrets, 1) - require.NoError(t, err) - - cluster.WaitForReady(t) - - // extract delegator's secrets - delegatorSecretsPath := path.Join(cluster.Config.TmpDir, delegatorSecrets) - delegatorAcc, err := sidechain.GetAccountFromDir(delegatorSecretsPath) - require.NoError(t, err) - - delegatorAddr := delegatorAcc.Ecdsa.Address() - - // extract validator's secrets - validatorSecretsPath := path.Join(cluster.Config.TmpDir, validatorSecrets) - - validatorAcc, err := sidechain.GetAccountFromDir(validatorSecretsPath) - require.NoError(t, err) - - validatorAddr := validatorAcc.Ecdsa.Address() - - fundAmount := ethgo.Ether(250) - - // fund delegator - receipt, err := txRelayer.SendTransaction(ðgo.Transaction{ - From: validatorAddr, - To: &delegatorAddr, - Value: fundAmount, - }, validatorAcc.Ecdsa) - require.NoError(t, err) - require.Equal(t, uint64(types.ReceiptSuccess), receipt.Status) - - endCh, waitCh := make(chan struct{}), make(chan struct{}) - - // delegate tokens to validator in the loop to be sure that the stake of validator will be changed at end of epoch block - go func() { - for { - delegationAmount := uint64(1e18) - - err = cluster.Servers[0].Delegate(delegationAmount, validatorSecretsPath, validatorAddr) - require.NoError(t, err) - - select { - case <-endCh: - close(waitCh) - - return - case <-time.After(blockTime / 2): - } - } - }() - - require.NoError(t, cluster.WaitForBlock(6, 30*time.Second)) - - close(endCh) - <-waitCh -} - func TestE2E_Consensus_MintableERC20NativeToken(t *testing.T) { const ( validatorCount = 5 epochSize = 5 - minterPath = "test-chain-1" + + tokenName = "Edge Coin" + tokenSymbol = "EDGE" + decimals = uint8(5) ) validatorsAddrs := make([]types.Address, validatorCount) - initialStake := ethgo.Gwei(1) - initialBalance := int64(0) + initValidatorsBalance := ethgo.Ether(1) + initMinterBalance := ethgo.Ether(100000) + + minter, err := wallet.GenerateKey() + require.NoError(t, err) + + // because we are using native token as reward wallet, and it has default premine balance + initialTotalSupply := new(big.Int).Set(command.DefaultPremineBalance) cluster := framework.NewTestCluster(t, validatorCount, - framework.WithMintableNativeToken(true), + framework.WithNativeTokenConfig( + fmt.Sprintf("%s:%s:%d:true:%s", tokenName, tokenSymbol, decimals, minter.Address())), framework.WithEpochSize(epochSize), framework.WithSecretsCallback(func(addrs []types.Address, config *framework.TestClusterConfig) { + config.Premine = append(config.Premine, fmt.Sprintf("%s:%d", minter.Address(), initMinterBalance)) + initialTotalSupply.Add(initialTotalSupply, initMinterBalance) + for i, addr := range addrs { - // first one is the owner of the NativeERC20Mintable SC - // and it should have premine set to default 1M tokens - // (it is going to send mint transactions to all the other validators) - if i > 0 { - // premine other validators with as minimum stake as possible just to ensure liveness of consensus protocol - config.StakeAmounts = append(config.StakeAmounts, fmt.Sprintf("%s:%d", addr, initialStake)) - config.PremineValidators = append(config.PremineValidators, fmt.Sprintf("%s:%d", addr, initialBalance)) - } + config.Premine = append(config.Premine, fmt.Sprintf("%s:%d", addr, initValidatorsBalance)) + config.StakeAmounts = append(config.StakeAmounts, new(big.Int).Set(initValidatorsBalance)) validatorsAddrs[i] = addr + initialTotalSupply.Add(initialTotalSupply, initValidatorsBalance) } })) defer cluster.Stop() - minterSrv := cluster.Servers[0] - targetJSONRPC := minterSrv.JSONRPC() - - minterAcc, err := sidechain.GetAccountFromDir(minterSrv.DataDir()) - require.NoError(t, err) + targetJSONRPC := cluster.Servers[0].JSONRPC() cluster.WaitForReady(t) - // send mint transactions + // initialize tx relayer relayer, err := txrelayer.NewTxRelayer(txrelayer.WithClient(targetJSONRPC)) require.NoError(t, err) + // check are native token metadata correctly initialized + stringABIType := abi.MustNewType("tuple(string)") + uint8ABIType := abi.MustNewType("tuple(uint8)") + + totalSupply := queryNativeERC20Metadata(t, "totalSupply", uint256ABIType, relayer) + require.True(t, initialTotalSupply.Cmp(totalSupply.(*big.Int)) == 0) //nolint:forcetypeassert + + // check if initial total supply of native ERC20 token is the same as expected + name := queryNativeERC20Metadata(t, "name", stringABIType, relayer) + require.Equal(t, tokenName, name) + + symbol := queryNativeERC20Metadata(t, "symbol", stringABIType, relayer) + require.Equal(t, tokenSymbol, symbol) + + decimalsCount := queryNativeERC20Metadata(t, "decimals", uint8ABIType, relayer) + require.Equal(t, decimals, decimalsCount) + + // send mint transactions mintFn, exists := contractsapi.NativeERC20Mintable.Abi.Methods["mint"] require.True(t, exists) - nativeTokenAddr := ethgo.Address(contracts.NativeERC20TokenContract) mintAmount := ethgo.Ether(10) + nativeTokenAddr := ethgo.Address(contracts.NativeERC20TokenContract) // make sure minter account can mint tokens - // (first account, which is minter sends mint transactions to all the other validators) - for _, addr := range validatorsAddrs[1:] { + for _, addr := range validatorsAddrs { balance, err := targetJSONRPC.Eth().GetBalance(ethgo.Address(addr), ethgo.Latest) require.NoError(t, err) t.Logf("Pre-mint balance: %v=%d\n", addr, balance) @@ -669,7 +540,7 @@ func TestE2E_Consensus_MintableERC20NativeToken(t *testing.T) { ðgo.Transaction{ To: &nativeTokenAddr, Input: mintInput, - }, minterAcc.Ecdsa) + }, minter) require.NoError(t, err) require.Equal(t, uint64(types.ReceiptSuccess), receipt.Status) @@ -677,18 +548,19 @@ func TestE2E_Consensus_MintableERC20NativeToken(t *testing.T) { require.NoError(t, err) t.Logf("Post-mint balance: %v=%d\n", addr, balance) - require.Equal(t, new(big.Int).Add(mintAmount, big.NewInt(initialBalance)), balance) + require.Equal(t, new(big.Int).Add(initValidatorsBalance, mintAmount), balance) } - minterBalance, err := targetJSONRPC.Eth().GetBalance(minterAcc.Ecdsa.Address(), ethgo.Latest) + // assert that minter balance remained the same + minterBalance, err := targetJSONRPC.Eth().GetBalance(minter.Address(), ethgo.Latest) require.NoError(t, err) - require.Equal(t, ethgo.Ether(1e6), minterBalance) + require.Equal(t, initMinterBalance, minterBalance) // try sending mint transaction from non minter account and make sure it would fail nonMinterAcc, err := sidechain.GetAccountFromDir(cluster.Servers[1].DataDir()) require.NoError(t, err) - mintInput, err := mintFn.Encode([]interface{}{validatorsAddrs[2], ethgo.Ether(1)}) + mintInput, err := mintFn.Encode([]interface{}{validatorsAddrs[0], ethgo.Ether(1)}) require.NoError(t, err) receipt, err := relayer.SendTransaction( @@ -696,6 +568,158 @@ func TestE2E_Consensus_MintableERC20NativeToken(t *testing.T) { To: &nativeTokenAddr, Input: mintInput, }, nonMinterAcc.Ecdsa) + require.Error(t, err) + require.Nil(t, receipt) +} + +func TestE2E_Consensus_CustomRewardToken(t *testing.T) { + const epochSize = 5 + + cluster := framework.NewTestCluster(t, 5, + framework.WithEpochSize(epochSize), + framework.WithEpochReward(1000000), + framework.WithTestRewardToken(), + ) + defer cluster.Stop() + + cluster.WaitForReady(t) + + // initialize tx relayer + relayer, err := txrelayer.NewTxRelayer(txrelayer.WithClient(cluster.Servers[0].JSONRPC())) require.NoError(t, err) - require.Equal(t, uint64(types.ReceiptFailed), receipt.Status) + + // because we are not using native token as reward wallet, and have no premine + // initial token supply should be 0 + initialTotalSupply := big.NewInt(0) + + // check if initial total supply of native ERC20 token is the same as expected + totalSupply := queryNativeERC20Metadata(t, "totalSupply", uint256ABIType, relayer) + require.True(t, initialTotalSupply.Cmp(totalSupply.(*big.Int)) == 0) //nolint:forcetypeassert + + // wait for couple of epochs to accumulate some rewards + require.NoError(t, cluster.WaitForBlock(epochSize*3, 3*time.Minute)) + + // first validator is the owner of ChildValidator set smart contract + owner := cluster.Servers[0] + childChainRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(owner.JSONRPCAddr())) + require.NoError(t, err) + + rootChainRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Bridge.JSONRPCAddr())) + require.NoError(t, err) + + polybftConfig, err := polybft.LoadPolyBFTConfig(path.Join(cluster.Config.TmpDir, chainConfigFileName)) + require.NoError(t, err) + + validatorAcc, err := sidechain.GetAccountFromDir(owner.DataDir()) + require.NoError(t, err) + + validatorInfo, err := sidechain.GetValidatorInfo(validatorAcc.Ecdsa.Address(), + polybftConfig.Bridge.CustomSupernetManagerAddr, polybftConfig.Bridge.StakeManagerAddr, + polybftConfig.SupernetID, rootChainRelayer, childChainRelayer) + t.Logf("[Validator#%v] Witdhrawable rewards=%d\n", validatorInfo.Address, validatorInfo.WithdrawableRewards) + + require.NoError(t, err) + require.True(t, validatorInfo.WithdrawableRewards.Cmp(big.NewInt(0)) > 0) +} + +func TestE2E_Consensus_Trace(t *testing.T) { + const ( + validatorSecrets = "test-chain-1" + newAccSecrets = "test-chain-newAcc" + epochSize = 5 + validatorCount = 5 + ) + + var ( + premineAmount = ethgo.Ether(10) + minterBalance = ethgo.Ether(1e6) + ) + + minter, err := wallet.GenerateKey() + require.NoError(t, err) + + cluster := framework.NewTestCluster(t, 5, + framework.WithEpochReward(int(ethgo.Ether(1).Uint64())), + framework.WithEpochSize(epochSize), + framework.WithNativeTokenConfig(fmt.Sprintf(nativeTokenMintableTestCfg, minter.Address())), + framework.WithSecretsCallback(func(addresses []types.Address, config *framework.TestClusterConfig) { + config.Premine = append(config.Premine, fmt.Sprintf("%s:%d", minter.Address(), minterBalance)) + for _, a := range addresses { + config.Premine = append(config.Premine, fmt.Sprintf("%s:%d", a, premineAmount)) + config.StakeAmounts = append(config.StakeAmounts, new(big.Int).Set(premineAmount)) + } + }), + ) + defer cluster.Stop() + + // init new account + _, err = cluster.InitSecrets(newAccSecrets, 1) + require.NoError(t, err) + + cluster.WaitForReady(t) + + // extract new acc secrets + newAccSecretsPath := path.Join(cluster.Config.TmpDir, newAccSecrets) + newAcc, err := sidechain.GetAccountFromDir(newAccSecretsPath) + require.NoError(t, err) + + newAccAddr := newAcc.Ecdsa.Address() + + // extract validator's secrets + validatorSecretsPath := path.Join(cluster.Config.TmpDir, validatorSecrets) + + validatorAcc, err := sidechain.GetAccountFromDir(validatorSecretsPath) + require.NoError(t, err) + + validatorAddr := validatorAcc.Ecdsa.Address() + + // transfer funds to the new account + txRelayer, err := txrelayer.NewTxRelayer(txrelayer.WithIPAddress(cluster.Servers[0].JSONRPCAddr())) + require.NoError(t, err) + + receipt, err := txRelayer.SendTransaction(ðgo.Transaction{ + From: validatorAddr, + To: &newAccAddr, + Value: ethgo.Ether(2), + }, validatorAcc.Ecdsa) + require.NoError(t, err) + require.Equal(t, uint64(types.ReceiptSuccess), receipt.Status) + require.NotNil(t, receipt.TransactionHash) + + // verify trace existence on all validators + for i := 0; i < validatorCount; i++ { + ethEndpoint := cluster.Servers[i].JSONRPC().Eth() + + blockResponse, err := ethEndpoint.GetBlockByNumber(ethgo.BlockNumber(receipt.BlockNumber), false) + require.NoError(t, err) + require.NotEqual(t, blockResponse.Miner, ethgo.ZeroAddress) + + parentBlock, err := ethEndpoint.GetBlockByHash(blockResponse.ParentHash, false) + require.NoError(t, err) + + sysClient := cluster.Servers[i].Conn() + traceResp, err := sysClient.GetTrace(context.Background(), &proto.GetTraceRequest{Number: receipt.BlockNumber}) + require.NoError(t, err) + + var trace *types.Trace + err = json.Unmarshal(traceResp.Trace, &trace) + require.NoError(t, err) + require.Equal(t, parentBlock.StateRoot.Bytes(), trace.ParentStateRoot.Bytes()) + + containsCoinbaseAddr, containsSenderAddr, containsReceiverAddr := false, false, false + + var journalEntry *types.JournalEntry + + for _, tr := range trace.TxnTraces { + _, containsCoinbaseAddr = tr.Delta[types.Address(blockResponse.Miner)] + _, containsSenderAddr = tr.Delta[types.Address(validatorAddr)] + + journalEntry, containsReceiverAddr = tr.Delta[types.Address(newAccAddr)] + require.True(t, journalEntry.Balance.Cmp(ethgo.Ether(2)) == 0) + } + + require.True(t, containsCoinbaseAddr) + require.True(t, containsSenderAddr) + require.True(t, containsReceiverAddr) + } } diff --git a/e2e-polybft/e2e/helpers_test.go b/e2e-polybft/e2e/helpers_test.go index 5065eec593..2db66a2502 100644 --- a/e2e-polybft/e2e/helpers_test.go +++ b/e2e-polybft/e2e/helpers_test.go @@ -9,19 +9,28 @@ import ( "math/big" "net/http" "testing" + "time" + + "github.com/stretchr/testify/require" + "github.com/umbracle/ethgo" + "github.com/umbracle/ethgo/abi" + "github.com/umbracle/ethgo/contract" + "github.com/umbracle/ethgo/jsonrpc" "github.com/0xPolygon/polygon-edge/consensus/polybft" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi/artifact" + "github.com/0xPolygon/polygon-edge/contracts" + "github.com/0xPolygon/polygon-edge/e2e-polybft/framework" + "github.com/0xPolygon/polygon-edge/helper/common" "github.com/0xPolygon/polygon-edge/helper/hex" + "github.com/0xPolygon/polygon-edge/state/runtime/addresslist" "github.com/0xPolygon/polygon-edge/txrelayer" "github.com/0xPolygon/polygon-edge/types" - "github.com/stretchr/testify/require" - "github.com/umbracle/ethgo" - "github.com/umbracle/ethgo/contract" - ethgow "github.com/umbracle/ethgo/wallet" ) +const nativeTokenMintableTestCfg = "Mintable Edge Coin:MEC:18:true:%s" + type e2eStateProvider struct { txRelayer txrelayer.TxRelayer } @@ -39,36 +48,15 @@ func (s *e2eStateProvider) Txn(ethgo.Address, ethgo.Key, []byte) (contract.Txn, return nil, errors.New("send txn is not supported") } -// isExitEventProcessed queries ExitHelper and as a result returns indication whether given exit event id is processed -func isExitEventProcessed(exitEventID uint64, exitHelper ethgo.Address, rootTxRelayer txrelayer.TxRelayer) (bool, error) { - result, err := ABICall( - rootTxRelayer, - contractsapi.ExitHelper, - exitHelper, - ethgo.ZeroAddress, - "processedExits", - new(big.Int).SetUint64(exitEventID)) - if err != nil { - return false, err - } - - isProcessed, err := types.ParseUint64orHex(&result) - if err != nil { - return false, err - } - - return isProcessed == uint64(1), nil -} - -// getRootchainValidators queries rootchain validator set -func getRootchainValidators(relayer txrelayer.TxRelayer, checkpointManagerAddr ethgo.Address) ([]*polybft.ValidatorInfo, error) { +// getCheckpointManagerValidators queries rootchain validator set on CheckpointManager contract +func getCheckpointManagerValidators(relayer txrelayer.TxRelayer, checkpointManagerAddr ethgo.Address) ([]*polybft.ValidatorInfo, error) { validatorsCountRaw, err := ABICall(relayer, contractsapi.CheckpointManager, checkpointManagerAddr, ethgo.ZeroAddress, "currentValidatorSetLength") if err != nil { return nil, err } - validatorsCount, err := types.ParseUint64orHex(&validatorsCountRaw) + validatorsCount, err := common.ParseUint64orHex(&validatorsCountRaw) if err != nil { return nil, err } @@ -100,8 +88,8 @@ func getRootchainValidators(relayer txrelayer.TxRelayer, checkpointManagerAddr e //nolint:forcetypeassert validators[i] = &polybft.ValidatorInfo{ - Address: results["_address"].(ethgo.Address), - TotalStake: results["votingPower"].(*big.Int), + Address: results["_address"].(ethgo.Address), + Stake: results["votingPower"].(*big.Int), } } @@ -129,52 +117,6 @@ func ABITransaction(relayer txrelayer.TxRelayer, key ethgo.Key, artifact *artifa }, key) } -func sendExitTransaction( - sidechainKey *ethgow.Key, - rootchainKey ethgo.Key, - proof types.Proof, - checkpointBlock uint64, - stateSenderData []byte, - l1ExitTestAddr, - exitHelperAddr ethgo.Address, - l1TxRelayer txrelayer.TxRelayer, - exitEventID uint64) (bool, error) { - var exitEventAPI contractsapi.L2StateSyncedEvent - - proofExitEventEncoded, err := exitEventAPI.Encode(&polybft.ExitEvent{ - ID: exitEventID, - Sender: sidechainKey.Address(), - Receiver: l1ExitTestAddr, - Data: stateSenderData, - }) - if err != nil { - return false, err - } - - leafIndex, ok := proof.Metadata["LeafIndex"].(float64) - if !ok { - return false, fmt.Errorf("could not get leaf index from exit event proof. Leaf from proof: %v", proof.Metadata["LeafIndex"]) - } - - receipt, err := ABITransaction(l1TxRelayer, rootchainKey, contractsapi.ExitHelper, exitHelperAddr, - "exit", - big.NewInt(int64(checkpointBlock)), - uint64(leafIndex), - proofExitEventEncoded, - proof.Data, - ) - - if err != nil { - return false, err - } - - if receipt.Status != uint64(types.ReceiptSuccess) { - return false, errors.New("transaction execution failed") - } - - return isExitEventProcessed(exitEventID, exitHelperAddr, l1TxRelayer) -} - func getExitProof(rpcAddress string, exitID uint64) (types.Proof, error) { query := struct { Jsonrpc string `json:"jsonrpc"` @@ -223,16 +165,186 @@ func checkStateSyncResultLogs( expectedCount int, ) { t.Helper() - require.Len(t, logs, expectedCount) + require.Equal(t, expectedCount, len(logs)) var stateSyncResultEvent contractsapi.StateSyncResultEvent for _, log := range logs { doesMatch, err := stateSyncResultEvent.ParseLog(log) - require.True(t, doesMatch) require.NoError(t, err) + require.True(t, doesMatch) t.Logf("Block Number=%d, Decoded Log=%+v\n", log.BlockNumber, stateSyncResultEvent) require.True(t, stateSyncResultEvent.Status) } } + +// getCheckpointBlockNumber gets current checkpoint block number from checkpoint manager smart contract +func getCheckpointBlockNumber(l1Relayer txrelayer.TxRelayer, checkpointManagerAddr ethgo.Address) (uint64, error) { + checkpointBlockNumRaw, err := ABICall(l1Relayer, contractsapi.CheckpointManager, + checkpointManagerAddr, ethgo.ZeroAddress, "currentCheckpointBlockNumber") + if err != nil { + return 0, err + } + + actualCheckpointBlock, err := types.ParseUint64orHex(&checkpointBlockNumRaw) + if err != nil { + return 0, err + } + + return actualCheckpointBlock, nil +} + +// waitForRootchainEpoch blocks for some predefined timeout to reach target epoch +func waitForRootchainEpoch(targetEpoch uint64, timeout time.Duration, + rootchainTxRelayer txrelayer.TxRelayer, checkpointManager types.Address) error { + timer := time.NewTimer(timeout) + defer timer.Stop() + + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + + for { + select { + case <-timer.C: + return errors.New("root chain hasn't progressed to the desired epoch") + case <-ticker.C: + } + + rootchainEpochRaw, err := ABICall(rootchainTxRelayer, contractsapi.CheckpointManager, + ethgo.Address(checkpointManager), ethgo.ZeroAddress, "currentEpoch") + if err != nil { + return err + } + + rootchainEpoch, err := types.ParseUint64orHex(&rootchainEpochRaw) + if err != nil { + return err + } + + if rootchainEpoch >= targetEpoch { + return nil + } + } +} + +// setAccessListRole sets access list role to appropriate access list precompile +func setAccessListRole(t *testing.T, cluster *framework.TestCluster, precompile, account types.Address, + role addresslist.Role, aclAdmin ethgo.Key) { + t.Helper() + + var updateRoleFn *abi.Method + + switch role { + case addresslist.AdminRole: + updateRoleFn = addresslist.SetAdminFunc + + break + case addresslist.EnabledRole: + updateRoleFn = addresslist.SetEnabledFunc + + break + case addresslist.NoRole: + updateRoleFn = addresslist.SetNoneFunc + + break + } + + input, err := updateRoleFn.Encode([]interface{}{account}) + require.NoError(t, err) + + enableSetTxn := cluster.MethodTxn(t, aclAdmin, precompile, input) + require.NoError(t, enableSetTxn.Wait()) + + expectRole(t, cluster, precompile, account, role) +} + +func expectRole(t *testing.T, cluster *framework.TestCluster, contract types.Address, addr types.Address, role addresslist.Role) { + t.Helper() + out := cluster.Call(t, contract, addresslist.ReadAddressListFunc, addr) + + num, ok := out["0"].(*big.Int) + if !ok { + t.Fatal("unexpected") + } + + require.Equal(t, role.Uint64(), num.Uint64()) +} + +// getFilteredLogs retrieves Ethereum logs, described by event signature within the block range +func getFilteredLogs(eventSig ethgo.Hash, startBlock, endBlock uint64, + ethEndpoint *jsonrpc.Eth) ([]*ethgo.Log, error) { + filter := ðgo.LogFilter{Topics: [][]*ethgo.Hash{{&eventSig}}} + + filter.SetFromUint64(startBlock) + filter.SetToUint64(endBlock) + + return ethEndpoint.GetLogs(filter) +} + +// erc20BalanceOf returns balance of given account on ERC 20 token +func erc20BalanceOf(t *testing.T, account types.Address, tokenAddr types.Address, relayer txrelayer.TxRelayer) *big.Int { + t.Helper() + + balanceOfFn := &contractsapi.BalanceOfRootERC20Fn{Account: account} + balanceOfInput, err := balanceOfFn.EncodeAbi() + require.NoError(t, err) + + balanceRaw, err := relayer.Call(ethgo.ZeroAddress, ethgo.Address(tokenAddr), balanceOfInput) + require.NoError(t, err) + balance, err := types.ParseUint256orHex(&balanceRaw) + require.NoError(t, err) + + return balance +} + +// erc721OwnerOf returns owner of given ERC 721 token +func erc721OwnerOf(t *testing.T, tokenID *big.Int, tokenAddr types.Address, relayer txrelayer.TxRelayer) types.Address { + t.Helper() + + ownerOfFn := &contractsapi.OwnerOfChildERC721Fn{TokenID: tokenID} + ownerOfInput, err := ownerOfFn.EncodeAbi() + require.NoError(t, err) + + ownerRaw, err := relayer.Call(ethgo.ZeroAddress, ethgo.Address(tokenAddr), ownerOfInput) + require.NoError(t, err) + + return types.StringToAddress(ownerRaw) +} + +// queryNativeERC20Metadata returns some meta data user requires from native erc20 token +func queryNativeERC20Metadata(t *testing.T, funcName string, abiType *abi.Type, relayer txrelayer.TxRelayer) interface{} { + t.Helper() + + valueHex, err := ABICall(relayer, contractsapi.NativeERC20Mintable, + ethgo.Address(contracts.NativeERC20TokenContract), + ethgo.ZeroAddress, funcName) + require.NoError(t, err) + + valueRaw, err := hex.DecodeHex(valueHex) + require.NoError(t, err) + + var decodedResult map[string]interface{} + + err = abiType.DecodeStruct(valueRaw, &decodedResult) + require.NoError(t, err) + + return decodedResult["0"] +} + +// getChildToken queries child token address for provided root token on the target predicate +func getChildToken(t *testing.T, predicateABI *abi.ABI, predicateAddr types.Address, + rootToken types.Address, relayer txrelayer.TxRelayer) types.Address { + t.Helper() + + rootToChildTokenFn, exists := predicateABI.Methods["rootTokenToChildToken"] + require.True(t, exists, "rootTokenToChildToken function is not found in the provided predicate ABI definition") + + input, err := rootToChildTokenFn.Encode([]interface{}{rootToken}) + require.NoError(t, err) + + childTokenRaw, err := relayer.Call(ethgo.ZeroAddress, ethgo.Address(predicateAddr), input) + require.NoError(t, err) + + return types.StringToAddress(childTokenRaw) +} diff --git a/e2e-polybft/e2e/jsonrpc_test.go b/e2e-polybft/e2e/jsonrpc_test.go new file mode 100644 index 0000000000..03149db753 --- /dev/null +++ b/e2e-polybft/e2e/jsonrpc_test.go @@ -0,0 +1,308 @@ +package e2e + +import ( + "fmt" + "math/big" + "testing" + + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" + "github.com/0xPolygon/polygon-edge/e2e-polybft/framework" + "github.com/0xPolygon/polygon-edge/helper/hex" + "github.com/0xPolygon/polygon-edge/types" + "github.com/stretchr/testify/require" + "github.com/umbracle/ethgo" + "github.com/umbracle/ethgo/abi" + "github.com/umbracle/ethgo/wallet" +) + +var ( + one = big.NewInt(1) +) + +func TestE2E_JsonRPC(t *testing.T) { + acct, err := wallet.GenerateKey() + require.NoError(t, err) + + cluster := framework.NewTestCluster(t, 3, + framework.WithNativeTokenConfig(fmt.Sprintf(nativeTokenMintableTestCfg, acct.Address())), + framework.WithPremine(types.Address(acct.Address())), + ) + defer cluster.Stop() + + cluster.WaitForReady(t) + + client := cluster.Servers[0].JSONRPC().Eth() + + // Test eth_call with override in state diff + t.Run("eth_call state override", func(t *testing.T) { + deployTxn := cluster.Deploy(t, acct, contractsapi.TestSimple.Bytecode) + require.NoError(t, deployTxn.Wait()) + require.True(t, deployTxn.Succeed()) + + target := deployTxn.Receipt().ContractAddress + + input := abi.MustNewMethod("function getValue() public returns (uint256)").ID() + + resp, err := client.Call(ðgo.CallMsg{To: &target, Data: input}, ethgo.Latest) + require.NoError(t, err) + require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000000", resp) + + override := ðgo.StateOverride{ + target: ethgo.OverrideAccount{ + StateDiff: &map[ethgo.Hash]ethgo.Hash{ + // storage slot 0 stores the 'val' uint256 value + {0x0}: {0x3}, + }, + }, + } + + resp, err = client.Call(ðgo.CallMsg{To: &target, Data: input}, ethgo.Latest, override) + require.NoError(t, err) + + require.Equal(t, "0x0300000000000000000000000000000000000000000000000000000000000000", resp) + }) + + t.Run("eth_getBalance", func(t *testing.T) { + key1, err := wallet.GenerateKey() + require.NoError(t, err) + + // Test. return zero if the account does not exists + balance1, err := client.GetBalance(key1.Address(), ethgo.Latest) + require.NoError(t, err) + require.Equal(t, balance1, big.NewInt(0)) + + // Test. return the balance of an account + newBalance := ethgo.Ether(1) + txn := cluster.Transfer(t, acct, types.Address(key1.Address()), newBalance) + require.NoError(t, txn.Wait()) + require.True(t, txn.Succeed()) + + balance1, err = client.GetBalance(key1.Address(), ethgo.Latest) + require.NoError(t, err) + require.Equal(t, balance1, newBalance) + + // Test. return 0 if the balance of an existing account is empty + gasPrice, err := client.GasPrice() + require.NoError(t, err) + + toAddr := key1.Address() + msg := ðgo.CallMsg{ + From: acct.Address(), + To: &toAddr, + Value: newBalance, + } + + estimatedGas, err := client.EstimateGas(msg) + require.NoError(t, err) + txPrice := gasPrice * estimatedGas + // subtract gasPrice * estimatedGas from the balance and transfer the rest to the other account + // in order to leave no funds on the account + amountToSend := new(big.Int).Sub(newBalance, big.NewInt(int64(txPrice))) + targetAddr := acct.Address() + txn = cluster.SendTxn(t, key1, ðgo.Transaction{ + To: &targetAddr, + Value: amountToSend, + Gas: estimatedGas, + }) + require.NoError(t, txn.Wait()) + require.True(t, txn.Succeed()) + + balance1, err = client.GetBalance(key1.Address(), ethgo.Latest) + require.NoError(t, err) + require.Equal(t, big.NewInt(0), balance1) + }) + + t.Run("eth_getTransactionCount", func(t *testing.T) { + key1, err := wallet.GenerateKey() + require.NoError(t, err) + + nonce, err := client.GetNonce(key1.Address(), ethgo.Latest) + require.Equal(t, uint64(0), nonce) + require.NoError(t, err) + + txn := cluster.Transfer(t, acct, types.Address(key1.Address()), big.NewInt(10000000000000000)) + require.NoError(t, txn.Wait()) + require.True(t, txn.Succeed()) + + // Test. increase the nonce with new transactions + txn = cluster.Transfer(t, key1, types.ZeroAddress, big.NewInt(0)) + require.NoError(t, txn.Wait()) + require.True(t, txn.Succeed()) + + nonce1, err := client.GetNonce(key1.Address(), ethgo.Latest) + require.NoError(t, err) + require.Equal(t, nonce1, uint64(1)) + + // Test. you can query the nonce at any block number in time + nonce1, err = client.GetNonce(key1.Address(), ethgo.BlockNumber(txn.Receipt().BlockNumber-1)) + require.NoError(t, err) + require.Equal(t, nonce1, uint64(0)) + + block, err := client.GetBlockByNumber(ethgo.BlockNumber(txn.Receipt().BlockNumber)-1, false) + require.NoError(t, err) + + _, err = client.GetNonce(key1.Address(), ethgo.BlockNumber(block.Number)) + require.NoError(t, err) + }) + + t.Run("eth_getStorageAt", func(t *testing.T) { + key1, err := wallet.GenerateKey() + require.NoError(t, err) + + txn := cluster.Transfer(t, acct, types.Address(key1.Address()), one) + require.NoError(t, txn.Wait()) + require.True(t, txn.Succeed()) + + txn = cluster.Deploy(t, acct, contractsapi.TestSimple.Bytecode) + require.NoError(t, txn.Wait()) + require.True(t, txn.Succeed()) + + target := txn.Receipt().ContractAddress + + resp, err := client.GetStorageAt(target, ethgo.Hash{}, ethgo.Latest) + require.NoError(t, err) + require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000000", resp.String()) + + setValueFn := abi.MustNewMethod("function setValue(uint256 _val) public") + + newVal := big.NewInt(1) + + input, err := setValueFn.Encode([]interface{}{newVal}) + require.NoError(t, err) + + txn = cluster.SendTxn(t, acct, ðgo.Transaction{Input: input, To: &target}) + require.NoError(t, txn.Wait()) + require.True(t, txn.Succeed()) + + resp, err = client.GetStorageAt(target, ethgo.Hash{}, ethgo.Latest) + require.NoError(t, err) + require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000001", resp.String()) + }) + + t.Run("eth_getCode", func(t *testing.T) { + // we use a predefined private key so that the deployed contract address is deterministic. + // Note that in order to work, this private key should only be used for this test. + priv, err := hex.DecodeString("2c15bd0dc992a47ca660983ae4b611f4ffb6178e14e04e2b34d153f3a74ce741") + require.NoError(t, err) + key1, err := wallet.NewWalletFromPrivKey(priv) + require.NoError(t, err) + + // fund the account so that it can deploy a contract + txn := cluster.Transfer(t, acct, types.Address(key1.Address()), big.NewInt(10000000000000000)) + require.NoError(t, txn.Wait()) + require.True(t, txn.Succeed()) + + codeAddr := ethgo.HexToAddress("0xDBfca0c43cA12759256a7Dd587Dc4c6EEC1D89A5") + + // Test. We get empty code from an empty contract + code, err := client.GetCode(codeAddr, ethgo.Latest) + require.NoError(t, err) + require.Equal(t, code, "0x") + + txn = cluster.Deploy(t, key1, contractsapi.TestSimple.Bytecode) + require.NoError(t, txn.Wait()) + require.True(t, txn.Succeed()) + + receipt := txn.Receipt() + + // Test. The deployed address is the one expected + require.Equal(t, codeAddr, receipt.ContractAddress) + + // Test. We can retrieve the code by address on latest, block number and block hash + cases := []ethgo.BlockNumberOrHash{ + ethgo.Latest, + ethgo.BlockNumber(receipt.BlockNumber), + } + for _, c := range cases { + code, err = client.GetCode(codeAddr, c) + require.NoError(t, err) + require.NotEqual(t, code, "0x") + } + + // Test. We can query in past state (when the code was empty) + code, err = client.GetCode(codeAddr, ethgo.BlockNumber(receipt.BlockNumber-1)) + require.NoError(t, err) + require.Equal(t, code, "0x") + + // Test. Query by pending should default to latest + code, err = client.GetCode(codeAddr, ethgo.Pending) + require.NoError(t, err) + require.NotEqual(t, code, "0x") + }) + + t.Run("eth_getBlockByHash", func(t *testing.T) { + key1, err := wallet.GenerateKey() + require.NoError(t, err) + txn := cluster.Transfer(t, acct, types.Address(key1.Address()), one) + require.NoError(t, txn.Wait()) + require.True(t, txn.Succeed()) + txReceipt := txn.Receipt() + + block, err := client.GetBlockByHash(txReceipt.BlockHash, false) + require.NoError(t, err) + require.Equal(t, txReceipt.BlockNumber, block.Number) + require.Equal(t, txReceipt.BlockHash, block.Hash) + }) + + t.Run("eth_getBlockByNumber", func(t *testing.T) { + key1, err := wallet.GenerateKey() + require.NoError(t, err) + txn := cluster.Transfer(t, acct, types.Address(key1.Address()), one) + require.NoError(t, txn.Wait()) + require.True(t, txn.Succeed()) + txReceipt := txn.Receipt() + + block, err := client.GetBlockByNumber(ethgo.BlockNumber(txReceipt.BlockNumber), false) + require.NoError(t, err) + require.Equal(t, txReceipt.BlockNumber, block.Number) + require.Equal(t, txReceipt.BlockHash, block.Hash) + }) + + t.Run("eth_getTransactionReceipt", func(t *testing.T) { + key1, err := wallet.GenerateKey() + require.NoError(t, err) + txn := cluster.Transfer(t, acct, types.Address(key1.Address()), one) + require.NoError(t, txn.Wait()) + require.True(t, txn.Succeed()) + + // Test. We cannot retrieve a receipt of an empty hash + emptyReceipt, err := client.GetTransactionReceipt(ethgo.ZeroHash) + require.NoError(t, err) // Note that ethgo does not return an error when the item does not exists + require.Nil(t, emptyReceipt) + + // Test. We can retrieve the receipt by the hash + receipt, err := client.GetTransactionReceipt(txn.Receipt().TransactionHash) + require.NoError(t, err) + + // Test. The populated fields match with the block + block, err := client.GetBlockByHash(receipt.BlockHash, false) + require.NoError(t, err) + + require.Equal(t, receipt.TransactionHash, txn.Receipt().TransactionHash) + require.Equal(t, receipt.BlockNumber, block.Number) + require.Equal(t, receipt.BlockHash, block.Hash) + + // Test. The receipt of a deployed contract has the 'ContractAddress' field. + txn = cluster.Deploy(t, acct, contractsapi.TestSimple.Bytecode) + require.NoError(t, txn.Wait()) + require.True(t, txn.Succeed()) + + require.NotEqual(t, txn.Receipt().ContractAddress, ethgo.ZeroAddress) + }) + + t.Run("eth_getTransactionByHash", func(t *testing.T) { + key1, err := wallet.GenerateKey() + require.NoError(t, err) + + // Test. We should be able to query the transaction by its hash + txn := cluster.Transfer(t, acct, types.Address(key1.Address()), one) + require.NoError(t, txn.Wait()) + require.True(t, txn.Succeed()) + + ethTxn, err := client.GetTransactionByHash(txn.Receipt().TransactionHash) + require.NoError(t, err) + + // Test. The dynamic 'from' field is populated + require.NotEqual(t, ethTxn.From, ethgo.ZeroAddress) + }) +} diff --git a/e2e-polybft/e2e/migration_test.go b/e2e-polybft/e2e/migration_test.go index dd7ba4ce9e..50b91f7d32 100644 --- a/e2e-polybft/e2e/migration_test.go +++ b/e2e-polybft/e2e/migration_test.go @@ -21,7 +21,7 @@ import ( "github.com/umbracle/ethgo/wallet" ) -func TestMigration(t *testing.T) { +func TestE2E_Migration(t *testing.T) { userKey, _ := wallet.GenerateKey() userAddr := userKey.Address() userKey2, _ := wallet.GenerateKey() @@ -60,20 +60,18 @@ func TestMigration(t *testing.T) { //send transaction to user2 sendAmount := ethgo.Gwei(10000) receipt, err := relayer.SendTransaction(ðgo.Transaction{ - From: userAddr, - To: &userAddr2, - GasPrice: 1048576, - Gas: 1000000, - Value: sendAmount, + From: userAddr, + To: &userAddr2, + Gas: 1000000, + Value: sendAmount, }, userKey) assert.NoError(t, err) assert.NotNil(t, receipt) receipt, err = relayer.SendTransaction(ðgo.Transaction{ - From: userAddr, - GasPrice: 1048576, - Gas: 1000000, - Input: contractsapi.TestWriteBlockMetadata.Bytecode, + From: userAddr, + Gas: 1000000, + Input: contractsapi.TestWriteBlockMetadata.Bytecode, }, userKey) require.NoError(t, err) require.NotNil(t, receipt) @@ -204,6 +202,6 @@ func TestMigration(t *testing.T) { _, err = cluster.InitSecrets("test-chain-8", 1) require.NoError(t, err) - cluster.InitTestServer(t, 8, false, false) + cluster.InitTestServer(t, "test-chain-8", cluster.Bridge.JSONRPCAddr(), false, false) require.NoError(t, cluster.WaitForBlock(33, time.Minute)) } diff --git a/e2e-polybft/e2e/network_test.go b/e2e-polybft/e2e/network_test.go index e1f5128ac3..c04a1320c1 100644 --- a/e2e-polybft/e2e/network_test.go +++ b/e2e-polybft/e2e/network_test.go @@ -20,8 +20,7 @@ func TestE2E_NetworkDiscoveryProtocol(t *testing.T) { ) // create cluster - cluster := framework.NewTestCluster(t, 10, - framework.WithValidatorSnapshot(validatorCount), + cluster := framework.NewTestCluster(t, validatorCount, framework.WithNonValidators(nonValidatorCount), framework.WithBootnodeCount(1)) defer cluster.Stop() diff --git a/e2e-polybft/e2e/txpool_test.go b/e2e-polybft/e2e/txpool_test.go index 91cb52384a..d8b5017cd4 100644 --- a/e2e-polybft/e2e/txpool_test.go +++ b/e2e-polybft/e2e/txpool_test.go @@ -1,20 +1,23 @@ package e2e import ( + "fmt" "math/big" "sync" "testing" "time" - "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" - "github.com/0xPolygon/polygon-edge/e2e-polybft/framework" - "github.com/0xPolygon/polygon-edge/txrelayer" - "github.com/0xPolygon/polygon-edge/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/umbracle/ethgo" "github.com/umbracle/ethgo/jsonrpc" "github.com/umbracle/ethgo/wallet" + + "github.com/0xPolygon/polygon-edge/consensus/polybft" + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" + "github.com/0xPolygon/polygon-edge/e2e-polybft/framework" + "github.com/0xPolygon/polygon-edge/txrelayer" + "github.com/0xPolygon/polygon-edge/types" ) func TestE2E_TxPool_Transfer(t *testing.T) { @@ -22,7 +25,10 @@ func TestE2E_TxPool_Transfer(t *testing.T) { sender, err := wallet.GenerateKey() require.NoError(t, err) - cluster := framework.NewTestCluster(t, 5, framework.WithPremine(types.Address(sender.Address()))) + cluster := framework.NewTestCluster(t, 5, + framework.WithNativeTokenConfig(fmt.Sprintf(nativeTokenMintableTestCfg, sender.Address())), + framework.WithPremine(types.Address(sender.Address())), + framework.WithBurnContract(&polybft.BurnContractInfo{BlockNumber: 0, Address: types.ZeroAddress})) defer cluster.Stop() cluster.WaitForReady(t) @@ -48,17 +54,27 @@ func TestE2E_TxPool_Transfer(t *testing.T) { go func(i int, to ethgo.Address) { defer wg.Done() - gasPrice, err := client.GasPrice() - require.NoError(t, err) - txn := ðgo.Transaction{ - From: sender.Address(), - To: &to, - GasPrice: gasPrice, - Gas: 30000, // enough to send a transfer - Value: big.NewInt(int64(sendAmount)), - Nonce: uint64(i), + From: sender.Address(), + To: &to, + Gas: 30000, // enough to send a transfer + Value: big.NewInt(int64(sendAmount)), + Nonce: uint64(i), + } + + // Send every second transaction as a dynamic fees one + if i%2 == 0 { + txn.Type = ethgo.TransactionDynamicFee + txn.MaxFeePerGas = big.NewInt(1000000000) + txn.MaxPriorityFeePerGas = big.NewInt(100000000) + } else { + gasPrice, err := client.GasPrice() + require.NoError(t, err) + + txn.Type = ethgo.TransactionLegacy + txn.GasPrice = gasPrice } + sendTransaction(t, client, sender, txn) }(i, receivers[i]) } @@ -88,7 +104,11 @@ func TestE2E_TxPool_Transfer_Linear(t *testing.T) { require.NoError(t, err) // first account should have some matics premined - cluster := framework.NewTestCluster(t, 5, framework.WithPremine(types.Address(premine.Address()))) + cluster := framework.NewTestCluster(t, 5, + framework.WithNativeTokenConfig(fmt.Sprintf(nativeTokenMintableTestCfg, premine.Address())), + framework.WithPremine(types.Address(premine.Address())), + framework.WithBurnContract(&polybft.BurnContractInfo{BlockNumber: 0, Address: types.ZeroAddress}), + ) defer cluster.Stop() cluster.WaitForReady(t) @@ -112,6 +132,17 @@ func TestE2E_TxPool_Transfer_Linear(t *testing.T) { return err } + populateTxFees := func(txn *ethgo.Transaction, i int) { + if i%2 == 0 { + txn.Type = ethgo.TransactionDynamicFee + txn.MaxFeePerGas = big.NewInt(1000000000) + txn.MaxPriorityFeePerGas = big.NewInt(100000000) + } else { + txn.Type = ethgo.TransactionLegacy + txn.GasPrice = gasPrice + } + } + num := 4 receivers := []*wallet.Key{ premine, @@ -124,11 +155,7 @@ func TestE2E_TxPool_Transfer_Linear(t *testing.T) { receivers = append(receivers, key) } - // Gas cost is always the same since value transfers are deterministic (21k gas). - // Then, the total gas cost required to make a transfer is 21k multiplied by - // the selected gas price. - gasCost := int(21000 * gasPrice) - sendAmount := 3000000 + const sendAmount = 3000000 // We are going to fund the accounts in linear fashion: // A (premined account) -> B -> C -> D -> E @@ -139,15 +166,23 @@ func TestE2E_TxPool_Transfer_Linear(t *testing.T) { // its child i+1 (cover costs + send amounts). // This means that since gasCost and sendAmount are fixed, account C must receive gasCost * 2 // (to cover two more transfers C->D and D->E) + sendAmount * 3 (one bundle for each C,D and E). - amount := gasCost*(num-i-1) + sendAmount*(num-i) recipient := receivers[i].Address() txn := ðgo.Transaction{ - Value: big.NewInt(int64(amount)), - To: &recipient, - GasPrice: gasPrice, - Gas: 21000, - Nonce: 0, + Value: big.NewInt(int64(sendAmount * (num - i))), + To: &recipient, + Gas: 21000, + } + + // Populate fees fields for the current transaction + populateTxFees(txn, i-1) + + // Add remaining fees to finish the cycle + for j := i; j < num; j++ { + copyTxn := txn.Copy() + populateTxFees(copyTxn, j) + txn.Value = txn.Value.Add(txn.Value, txCost(copyTxn)) } + sendTransaction(t, client, receivers[i-1], txn) err := waitUntilBalancesChanged(receivers[i].Address()) @@ -161,11 +196,12 @@ func TestE2E_TxPool_Transfer_Linear(t *testing.T) { } } -func TestE2E_TxPool_TransactionWithHeaderInstuctions(t *testing.T) { +func TestE2E_TxPool_TransactionWithHeaderInstructions(t *testing.T) { sidechainKey, err := wallet.GenerateKey() require.NoError(t, err) cluster := framework.NewTestCluster(t, 4, + framework.WithNativeTokenConfig(fmt.Sprintf(nativeTokenMintableTestCfg, sidechainKey.Address())), framework.WithPremine(types.Address(sidechainKey.Address())), ) defer cluster.Stop() @@ -186,6 +222,87 @@ func TestE2E_TxPool_TransactionWithHeaderInstuctions(t *testing.T) { require.NoError(t, cluster.WaitForBlock(10, 1*time.Minute)) } +// TestE2E_TxPool_BroadcastTransactions sends several transactions (legacy and dynamic fees) to the cluster +// with the 1 amount of eth and checks that all cluster nodes have the recipient balance updated. +func TestE2E_TxPool_BroadcastTransactions(t *testing.T) { + var ( + sendAmount = ethgo.Ether(1) + ) + + const ( + txNum = 10 + ) + + // Create recipient key + key, err := wallet.GenerateKey() + assert.NoError(t, err) + + recipient := key.Address() + + t.Logf("Recipient %s\n", recipient) + + // Create pre-mined balance for sender + sender, err := wallet.GenerateKey() + require.NoError(t, err) + + // First account should have some matics premined + cluster := framework.NewTestCluster(t, 5, + framework.WithNativeTokenConfig(fmt.Sprintf(nativeTokenMintableTestCfg, sender.Address())), + framework.WithPremine(types.Address(sender.Address())), + framework.WithBurnContract(&polybft.BurnContractInfo{BlockNumber: 0, Address: types.ZeroAddress}), + ) + defer cluster.Stop() + + // Wait until the cluster is up and running + cluster.WaitForReady(t) + + client := cluster.Servers[0].JSONRPC().Eth() + + sentAmount := new(big.Int) + nonce := uint64(0) + + for i := 0; i < txNum; i++ { + txn := ðgo.Transaction{ + Value: sendAmount, + To: &recipient, + Gas: 21000, + Nonce: nonce, + } + + if i%2 == 0 { + txn.Type = ethgo.TransactionDynamicFee + txn.MaxFeePerGas = big.NewInt(1000000000) + txn.MaxPriorityFeePerGas = big.NewInt(100000000) + } else { + gasPrice, err := client.GasPrice() + require.NoError(t, err) + + txn.Type = ethgo.TransactionLegacy + txn.GasPrice = gasPrice + } + + sendTransaction(t, client, sender, txn) + sentAmount = sentAmount.Add(sentAmount, txn.Value) + nonce++ + } + + // Wait until the balance has changed on all nodes in the cluster + err = cluster.WaitUntil(time.Minute, time.Second*3, func() bool { + for _, srv := range cluster.Servers { + balance, err := srv.WaitForNonZeroBalance(recipient, time.Second*10) + assert.NoError(t, err) + if balance != nil && balance.BitLen() > 0 { + assert.Equal(t, sentAmount, balance) + } else { + return false + } + } + + return true + }) + assert.NoError(t, err) +} + // sendTransaction is a helper function which signs transaction with provided private key and sends it func sendTransaction(t *testing.T, client *jsonrpc.Eth, sender *wallet.Key, txn *ethgo.Transaction) { t.Helper() @@ -193,6 +310,10 @@ func sendTransaction(t *testing.T, client *jsonrpc.Eth, sender *wallet.Key, txn chainID, err := client.ChainID() require.NoError(t, err) + if txn.Type == ethgo.TransactionDynamicFee { + txn.ChainID = chainID + } + signer := wallet.NewEIP155Signer(chainID.Uint64()) signedTxn, err := signer.SignTx(txn, sender) require.NoError(t, err) @@ -203,3 +324,15 @@ func sendTransaction(t *testing.T, client *jsonrpc.Eth, sender *wallet.Key, txn _, err = client.SendRawTransaction(txnRaw) require.NoError(t, err) } + +func txCost(t *ethgo.Transaction) *big.Int { + var factor *big.Int + + if t.Type == ethgo.TransactionDynamicFee { + factor = new(big.Int).Set(t.MaxFeePerGas) + } else { + factor = new(big.Int).SetUint64(t.GasPrice) + } + + return new(big.Int).Mul(factor, new(big.Int).SetUint64(t.Gas)) +} diff --git a/e2e-polybft/framework/node.go b/e2e-polybft/framework/node.go index 8cac0d299b..37241dfebb 100644 --- a/e2e-polybft/framework/node.go +++ b/e2e-polybft/framework/node.go @@ -8,7 +8,7 @@ import ( ) type node struct { - shuttingDown uint64 + shuttingDown atomic.Bool cmd *exec.Cmd doneCh chan struct{} exitResult *exitResult @@ -52,7 +52,7 @@ func (n *node) run() { } func (n *node) IsShuttingDown() bool { - return atomic.LoadUint64(&n.shuttingDown) == 1 + return n.shuttingDown.Load() } func (n *node) Stop() error { @@ -65,7 +65,7 @@ func (n *node) Stop() error { return err } - atomic.StoreUint64(&n.shuttingDown, 1) + n.shuttingDown.Store(true) <-n.Wait() return nil diff --git a/e2e-polybft/framework/test-bridge.go b/e2e-polybft/framework/test-bridge.go index 162b704dc3..927ba1ec35 100644 --- a/e2e-polybft/framework/test-bridge.go +++ b/e2e-polybft/framework/test-bridge.go @@ -1,14 +1,26 @@ package framework import ( + "context" "errors" "fmt" + "math/big" "path" "strconv" + "strings" "testing" "time" + "golang.org/x/sync/errgroup" + + "github.com/0xPolygon/polygon-edge/command" + bridgeCommon "github.com/0xPolygon/polygon-edge/command/bridge/common" + "github.com/0xPolygon/polygon-edge/command/genesis" + "github.com/0xPolygon/polygon-edge/command/polybftsecrets" + rootHelper "github.com/0xPolygon/polygon-edge/command/rootchain/helper" "github.com/0xPolygon/polygon-edge/command/rootchain/server" + "github.com/0xPolygon/polygon-edge/consensus/polybft" + "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" "github.com/0xPolygon/polygon-edge/types" ) @@ -92,65 +104,188 @@ func (t *TestBridge) WaitUntil(pollFrequency, timeout time.Duration, handler fun } } -// DepositERC20 function invokes bridge deposit ERC20 tokens (from the root to the child chain) -// with given receivers and amounts -func (t *TestBridge) DepositERC20(rootTokenAddr, rootPredicateAddr types.Address, receivers, amounts string) error { +// Deposit function invokes bridge deposit of ERC tokens (from the root to the child chain) +// with given receivers, amounts and/or token ids +func (t *TestBridge) Deposit(token bridgeCommon.TokenType, rootTokenAddr, rootPredicateAddr types.Address, + senderKey, receivers, amounts, tokenIDs, jsonRPCAddr, minterKey string, childChainMintable bool) error { + args := []string{} + if receivers == "" { return errors.New("provide at least one receiver address value") } - if amounts == "" { - return errors.New("provide at least one amount value") + if jsonRPCAddr == "" { + return errors.New("provide a JSON RPC endpoint URL") } - return t.cmdRun( - "bridge", - "deposit-erc20", - "--test", - "--root-token", rootTokenAddr.String(), - "--root-predicate", rootPredicateAddr.String(), - "--receivers", receivers, - "--amounts", amounts) + switch token { + case bridgeCommon.ERC20: + if amounts == "" { + return errors.New("provide at least one amount value") + } + + if tokenIDs != "" { + return errors.New("not expected to provide token ids for ERC 20 deposits") + } + + args = append(args, + "bridge", + "deposit-erc20", + "--root-token", rootTokenAddr.String(), + "--root-predicate", rootPredicateAddr.String(), + "--receivers", receivers, + "--amounts", amounts, + "--sender-key", senderKey, + "--minter-key", minterKey, + "--json-rpc", jsonRPCAddr) + + if childChainMintable { + args = append(args, "--child-chain-mintable") + } + + case bridgeCommon.ERC721: + if tokenIDs == "" { + return errors.New("provide at least one token id value") + } + + args = append(args, + "bridge", + "deposit-erc721", + "--root-token", rootTokenAddr.String(), + "--root-predicate", rootPredicateAddr.String(), + "--receivers", receivers, + "--token-ids", tokenIDs, + "--sender-key", senderKey, + "--minter-key", minterKey, + "--json-rpc", jsonRPCAddr) + + if childChainMintable { + args = append(args, "--child-chain-mintable") + } + + case bridgeCommon.ERC1155: + if amounts == "" { + return errors.New("provide at least one amount value") + } + + if tokenIDs == "" { + return errors.New("provide at least one token id value") + } + + args = append(args, + "bridge", + "deposit-erc1155", + "--root-token", rootTokenAddr.String(), + "--root-predicate", rootPredicateAddr.String(), + "--receivers", receivers, + "--amounts", amounts, + "--token-ids", tokenIDs, + "--sender-key", senderKey, + "--minter-key", minterKey, + "--json-rpc", jsonRPCAddr) + + if childChainMintable { + args = append(args, "--child-chain-mintable") + } + } + + return t.cmdRun(args...) } -// WithdrawERC20 function is used to invoke bridge withdraw ERC20 tokens (from the child to the root chain) -// with given receivers and amounts -func (t *TestBridge) WithdrawERC20(senderKey, receivers, amounts, jsonRPCEndpoint string) error { +// Withdraw function is used to invoke bridge withdrawals for any kind of ERC tokens (from the child to the root chain) +// with given receivers, amounts and/or token ids +func (t *TestBridge) Withdraw(token bridgeCommon.TokenType, + senderKey, receivers, amounts, tokenIDs, jsonRPCAddr string, + childPredicate, childToken types.Address, childChainMintable bool) error { if senderKey == "" { - return errors.New("provide hex encoded sender private key") + return errors.New("provide hex-encoded sender private key") } if receivers == "" { return errors.New("provide at least one receiver address value") } - if amounts == "" { - return errors.New("provide at least one amount value") + if jsonRPCAddr == "" { + return errors.New("provide a JSON RPC endpoint URL") } - if jsonRPCEndpoint == "" { - return errors.New("provide a JSON RPC endpoint URL") + args := []string{} + + switch token { + case bridgeCommon.ERC20: + if amounts == "" { + return errors.New("provide at least one amount value") + } + + if tokenIDs != "" { + return errors.New("not expected to provide token ids for ERC 20 withdrawals") + } + + args = append(args, + "bridge", + "withdraw-erc20", + "--child-predicate", childPredicate.String(), + "--child-token", childToken.String(), + "--sender-key", senderKey, + "--receivers", receivers, + "--amounts", amounts, + "--json-rpc", jsonRPCAddr) + + if childChainMintable { + args = append(args, "--child-chain-mintable") + } + + case bridgeCommon.ERC721: + if tokenIDs == "" { + return errors.New("provide at least one token id value") + } + + args = append(args, + "bridge", + "withdraw-erc721", + "--child-predicate", childPredicate.String(), + "--child-token", childToken.String(), + "--sender-key", senderKey, + "--receivers", receivers, + "--token-ids", tokenIDs, + "--json-rpc", jsonRPCAddr) + + if childChainMintable { + args = append(args, "--child-chain-mintable") + } + + case bridgeCommon.ERC1155: + if amounts == "" { + return errors.New("provide at least one amount value") + } + + if tokenIDs == "" { + return errors.New("provide at least one token id value") + } + + args = append(args, + "bridge", + "withdraw-erc1155", + "--child-predicate", childPredicate.String(), + "--child-token", childToken.String(), + "--sender-key", senderKey, + "--receivers", receivers, + "--amounts", amounts, + "--token-ids", tokenIDs, + "--json-rpc", jsonRPCAddr) + + if childChainMintable { + args = append(args, "--child-chain-mintable") + } } - return t.cmdRun( - "bridge", - "withdraw-erc20", - "--sender-key", senderKey, - "--receivers", receivers, - "--amounts", amounts, - "--json-rpc", jsonRPCEndpoint, - ) + return t.cmdRun(args...) } // SendExitTransaction sends exit transaction to the root chain -func (t *TestBridge) SendExitTransaction(exitHelper types.Address, exitID uint64, - rootJSONRPCAddr, childJSONRPCAddr string) error { - if rootJSONRPCAddr == "" { - return errors.New("provide a root JSON RPC endpoint URL") - } - +func (t *TestBridge) SendExitTransaction(exitHelper types.Address, exitID uint64, childJSONRPCAddr string) error { if childJSONRPCAddr == "" { - return errors.New("provide a child JSON RPC endpoint URL") + return errors.New("provide a child chain JSON RPC endpoint URL") } return t.cmdRun( @@ -158,7 +293,7 @@ func (t *TestBridge) SendExitTransaction(exitHelper types.Address, exitID uint64 "exit", "--exit-helper", exitHelper.String(), "--exit-id", strconv.FormatUint(exitID, 10), - "--root-json-rpc", rootJSONRPCAddr, + "--root-json-rpc", t.JSONRPCAddr(), "--child-json-rpc", childJSONRPCAddr, "--test", ) @@ -170,11 +305,18 @@ func (t *TestBridge) cmdRun(args ...string) error { } // deployRootchainContracts deploys and initializes rootchain contracts -func (t *TestBridge) deployRootchainContracts(manifestPath string) error { +func (t *TestBridge) deployRootchainContracts(genesisPath string) error { + polybftConfig, err := polybft.LoadPolyBFTConfig(genesisPath) + if err != nil { + return err + } + args := []string{ "rootchain", - "init-contracts", - "--manifest", manifestPath, + "deploy", + "--stake-manager", polybftConfig.Bridge.StakeManagerAddr.String(), + "--stake-token", polybftConfig.Bridge.StakeTokenAddr.String(), + "--genesis", genesisPath, "--test", } @@ -186,16 +328,202 @@ func (t *TestBridge) deployRootchainContracts(manifestPath string) error { } // fundRootchainValidators sends predefined amount of tokens to rootchain validators -func (t *TestBridge) fundRootchainValidators() error { +func (t *TestBridge) fundRootchainValidators(polybftConfig polybft.PolyBFTConfig) error { + validatorSecrets, err := genesis.GetValidatorKeyFiles(t.clusterConfig.TmpDir, t.clusterConfig.ValidatorPrefix) + if err != nil { + return fmt.Errorf("could not get validator secrets on initial rootchain funding of genesis validators: %w", err) + } + + balances := make([]*big.Int, len(polybftConfig.InitialValidatorSet)) + secrets := make([]string, len(validatorSecrets)) + + for i, secret := range validatorSecrets { + secrets[i] = path.Join(t.clusterConfig.TmpDir, secret) + balances[i] = command.DefaultPremineBalance + } + + if err := t.FundValidators(polybftConfig.Bridge.StakeTokenAddr, + secrets, balances); err != nil { + return fmt.Errorf("failed to fund validators on the rootchain: %w", err) + } + + return nil +} + +func (t *TestBridge) whitelistValidators(validatorAddresses []types.Address, + polybftConfig polybft.PolyBFTConfig) error { + addressesAsString := make([]string, len(validatorAddresses)) + for i := 0; i < len(validatorAddresses); i++ { + addressesAsString[i] = validatorAddresses[i].String() + } + + args := []string{ + "polybft", + "whitelist-validators", + "--addresses", strings.Join(addressesAsString, ","), + "--jsonrpc", t.JSONRPCAddr(), + "--supernet-manager", polybftConfig.Bridge.CustomSupernetManagerAddr.String(), + "--private-key", rootHelper.TestAccountPrivKey, + } + + if err := t.cmdRun(args...); err != nil { + return fmt.Errorf("failed to whitelist genesis validators on supernet manager: %w", err) + } + + return nil +} + +func (t *TestBridge) registerGenesisValidators(polybftConfig polybft.PolyBFTConfig) error { + validatorSecrets, err := genesis.GetValidatorKeyFiles(t.clusterConfig.TmpDir, t.clusterConfig.ValidatorPrefix) + if err != nil { + return fmt.Errorf("could not get validator secrets on whitelist of genesis validators: %w", err) + } + + g, ctx := errgroup.WithContext(context.Background()) + + for _, secret := range validatorSecrets { + secret := secret + + g.Go(func() error { + select { + case <-ctx.Done(): + return ctx.Err() + default: + args := []string{ + "polybft", + "register-validator", + "--jsonrpc", t.JSONRPCAddr(), + "--supernet-manager", polybftConfig.Bridge.CustomSupernetManagerAddr.String(), + "--" + polybftsecrets.AccountDirFlag, path.Join(t.clusterConfig.TmpDir, secret), + } + + if err := t.cmdRun(args...); err != nil { + return fmt.Errorf("failed to register genesis validator on supernet manager: %w", err) + } + + return nil + } + }) + } + + return g.Wait() +} + +func (t *TestBridge) initialStakingOfGenesisValidators(polybftConfig polybft.PolyBFTConfig) error { + validatorSecrets, err := genesis.GetValidatorKeyFiles(t.clusterConfig.TmpDir, t.clusterConfig.ValidatorPrefix) + if err != nil { + return fmt.Errorf("could not get validator secrets on initial staking of genesis validators: %w", err) + } + + g, ctx := errgroup.WithContext(context.Background()) + + for i, secret := range validatorSecrets { + secret := secret + i := i + + g.Go(func() error { + select { + case <-ctx.Done(): + return ctx.Err() + default: + args := []string{ + "polybft", + "stake", + "--jsonrpc", t.JSONRPCAddr(), + "--stake-manager", polybftConfig.Bridge.StakeManagerAddr.String(), + "--" + polybftsecrets.AccountDirFlag, path.Join(t.clusterConfig.TmpDir, secret), + "--amount", t.getStakeAmount(i).String(), + "--supernet-id", strconv.FormatInt(polybftConfig.SupernetID, 10), + "--stake-token", polybftConfig.Bridge.StakeTokenAddr.String(), + } + + if err := t.cmdRun(args...); err != nil { + return fmt.Errorf("failed to do initial staking for genesis validator on stake manager: %w", err) + } + + return nil + } + }) + } + + return g.Wait() +} + +func (t *TestBridge) getStakeAmount(validatorIndex int) *big.Int { + l := len(t.clusterConfig.StakeAmounts) + if l == 0 || l <= validatorIndex { + return command.DefaultStake + } + + return t.clusterConfig.StakeAmounts[validatorIndex] +} + +func (t *TestBridge) finalizeGenesis(genesisPath string, polybftConfig polybft.PolyBFTConfig) error { + args := []string{ + "polybft", + "supernet", + "--jsonrpc", t.JSONRPCAddr(), + "--private-key", rootHelper.TestAccountPrivKey, + "--genesis", genesisPath, + "--supernet-manager", polybftConfig.Bridge.CustomSupernetManagerAddr.String(), + "--stake-manager", polybftConfig.Bridge.StakeManagerAddr.String(), + "--finalize-genesis-set", + "--enable-staking", + } + + if err := t.cmdRun(args...); err != nil { + return fmt.Errorf("failed to finalize genesis validators on supernet manager: %w", err) + } + + return nil +} + +// FundValidators sends tokens to a rootchain validators +func (t *TestBridge) FundValidators(tokenAddress types.Address, secretsPaths []string, amounts []*big.Int) error { + if len(secretsPaths) != len(amounts) { + return errors.New("expected the same length of secrets paths and amounts") + } + args := []string{ "rootchain", "fund", - "--data-dir", path.Join(t.clusterConfig.TmpDir, t.clusterConfig.ValidatorPrefix), - "--num", strconv.Itoa(int(t.clusterConfig.ValidatorSetSize) + t.clusterConfig.NonValidatorCount), + "--stake-token", tokenAddress.String(), + "--mint", + } + + for i := 0; i < len(secretsPaths); i++ { + secretsManager, err := polybftsecrets.GetSecretsManager(secretsPaths[i], "", true) + if err != nil { + return err + } + + key, err := wallet.GetEcdsaFromSecret(secretsManager) + if err != nil { + return err + } + + args = append(args, "--addresses", key.Address().String()) + args = append(args, "--amounts", amounts[i].String()) + } + + if err := t.cmdRun(args...); err != nil { + return err + } + + return nil +} + +func (t *TestBridge) deployStakeManager(genesisPath string) error { + args := []string{ + "polybft", + "stake-manager-deploy", + "--jsonrpc", t.JSONRPCAddr(), + "--genesis", genesisPath, + "--test", } if err := t.cmdRun(args...); err != nil { - return fmt.Errorf("failed to deploy fund validators: %w", err) + return fmt.Errorf("failed to deploy stake manager contract: %w", err) } return nil diff --git a/e2e-polybft/framework/test-cluster.go b/e2e-polybft/framework/test-cluster.go index bd83e3e351..eb57b9c321 100644 --- a/e2e-polybft/framework/test-cluster.go +++ b/e2e-polybft/framework/test-cluster.go @@ -19,7 +19,8 @@ import ( "time" "github.com/0xPolygon/polygon-edge/command/genesis" - "github.com/0xPolygon/polygon-edge/command/rootchain/helper" + "github.com/0xPolygon/polygon-edge/consensus/polybft" + "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" "github.com/0xPolygon/polygon-edge/helper/common" "github.com/0xPolygon/polygon-edge/txrelayer" "github.com/0xPolygon/polygon-edge/types" @@ -43,16 +44,17 @@ const ( // envStdoutEnabled signal whether the output of the nodes get piped to stdout envStdoutEnabled = "E2E_STDOUT" - // envE2ETestsType used just to display type of test if skipped - envE2ETestsType = "E2E_TESTS_TYPE" -) - -const ( // prefix for validator directory defaultValidatorPrefix = "test-chain-" + + // prefix for non validators directory + nonValidatorPrefix = "test-non-validator-" ) -var startTime int64 +var ( + startTime int64 + testRewardWalletAddr = types.StringToAddress("0xFFFFFFFF") +) func init() { startTime = time.Now().UTC().UnixMilli() @@ -70,34 +72,48 @@ func resolveBinary() string { type TestClusterConfig struct { t *testing.T - Name string - Premine []string // address[:amount] - PremineValidators []string // address:[amount] - StakeAmounts []string // address[:amount] - MintableNativeToken bool - HasBridge bool - BootnodeCount int - NonValidatorCount int - WithLogs bool - WithStdout bool - LogsDir string - TmpDir string - BlockGasLimit uint64 - ValidatorPrefix string - Binary string - ValidatorSetSize uint64 - EpochSize int - EpochReward int - SecretsCallback func([]types.Address, *TestClusterConfig) + Name string + Premine []string // address[:amount] + PremineValidators []string // address[:amount] + StakeAmounts []*big.Int + WithoutBridge bool + BootnodeCount int + NonValidatorCount int + WithLogs bool + WithStdout bool + LogsDir string + TmpDir string + BlockGasLimit uint64 + BurnContract *polybft.BurnContractInfo + ValidatorPrefix string + Binary string + ValidatorSetSize uint64 + EpochSize int + EpochReward int + NativeTokenConfigRaw string + SecretsCallback func([]types.Address, *TestClusterConfig) ContractDeployerAllowListAdmin []types.Address ContractDeployerAllowListEnabled []types.Address + ContractDeployerBlockListAdmin []types.Address + ContractDeployerBlockListEnabled []types.Address + TransactionsAllowListAdmin []types.Address + TransactionsAllowListEnabled []types.Address + TransactionsBlockListAdmin []types.Address + TransactionsBlockListEnabled []types.Address + BridgeAllowListAdmin []types.Address + BridgeAllowListEnabled []types.Address + BridgeBlockListAdmin []types.Address + BridgeBlockListEnabled []types.Address NumBlockConfirmations uint64 InitialTrieDB string InitialStateRoot types.Hash + IsPropertyTest bool + TestRewardToken string + logsDirOnce sync.Once } @@ -145,6 +161,12 @@ func (c *TestClusterConfig) GetStdout(name string, custom ...io.Writer) io.Write func (c *TestClusterConfig) initLogsDir() { logsDir := path.Join("../..", fmt.Sprintf("e2e-logs-%d", startTime), c.t.Name()) + if c.IsPropertyTest { + // property tests run cluster multiple times, so each cluster run will be in the main folder + // e2e-logs-{someNumber}/NameOfPropertyTest/NameOfPropertyTest-{someNumber} + // to have a separation between logs of each cluster run + logsDir = path.Join(logsDir, fmt.Sprintf("%v-%d", c.t.Name(), time.Now().UTC().Unix())) + } if err := common.CreateDirSafe(logsDir, 0750); err != nil { c.t.Fatal(err) @@ -177,21 +199,15 @@ func WithPremine(addresses ...types.Address) ClusterOption { } } -func WithMintableNativeToken(mintableToken bool) ClusterOption { - return func(h *TestClusterConfig) { - h.MintableNativeToken = mintableToken - } -} - func WithSecretsCallback(fn func([]types.Address, *TestClusterConfig)) ClusterOption { return func(h *TestClusterConfig) { h.SecretsCallback = fn } } -func WithBridge() ClusterOption { +func WithoutBridge() ClusterOption { return func(h *TestClusterConfig) { - h.HasBridge = true + h.WithoutBridge = true } } @@ -238,6 +254,12 @@ func WithBlockGasLimit(blockGasLimit uint64) ClusterOption { } } +func WithBurnContract(burnContract *polybft.BurnContractInfo) ClusterOption { + return func(h *TestClusterConfig) { + h.BurnContract = burnContract + } +} + func WithNumBlockConfirmations(numBlockConfirmations uint64) ClusterOption { return func(h *TestClusterConfig) { h.NumBlockConfirmations = numBlockConfirmations @@ -256,25 +278,110 @@ func WithContractDeployerAllowListEnabled(addr types.Address) ClusterOption { } } +func WithContractDeployerBlockListAdmin(addr types.Address) ClusterOption { + return func(h *TestClusterConfig) { + h.ContractDeployerBlockListAdmin = append(h.ContractDeployerBlockListAdmin, addr) + } +} + +func WithContractDeployerBlockListEnabled(addr types.Address) ClusterOption { + return func(h *TestClusterConfig) { + h.ContractDeployerBlockListEnabled = append(h.ContractDeployerBlockListEnabled, addr) + } +} + +func WithTransactionsAllowListAdmin(addr types.Address) ClusterOption { + return func(h *TestClusterConfig) { + h.TransactionsAllowListAdmin = append(h.TransactionsAllowListAdmin, addr) + } +} + +func WithTransactionsAllowListEnabled(addr types.Address) ClusterOption { + return func(h *TestClusterConfig) { + h.TransactionsAllowListEnabled = append(h.TransactionsAllowListEnabled, addr) + } +} + +func WithTransactionsBlockListAdmin(addr types.Address) ClusterOption { + return func(h *TestClusterConfig) { + h.TransactionsBlockListAdmin = append(h.TransactionsBlockListAdmin, addr) + } +} + +func WithTransactionsBlockListEnabled(addr types.Address) ClusterOption { + return func(h *TestClusterConfig) { + h.TransactionsBlockListEnabled = append(h.TransactionsBlockListEnabled, addr) + } +} + +func WithBridgeAllowListAdmin(addr types.Address) ClusterOption { + return func(h *TestClusterConfig) { + h.BridgeAllowListAdmin = append(h.BridgeAllowListAdmin, addr) + } +} + +func WithBridgeAllowListEnabled(addr types.Address) ClusterOption { + return func(h *TestClusterConfig) { + h.BridgeAllowListEnabled = append(h.BridgeAllowListEnabled, addr) + } +} + +func WithBridgeBlockListAdmin(addr types.Address) ClusterOption { + return func(h *TestClusterConfig) { + h.BridgeBlockListAdmin = append(h.BridgeBlockListAdmin, addr) + } +} + +func WithBridgeBlockListEnabled(addr types.Address) ClusterOption { + return func(h *TestClusterConfig) { + h.BridgeBlockListEnabled = append(h.BridgeBlockListEnabled, addr) + } +} + +func WithPropertyTestLogging() ClusterOption { + return func(h *TestClusterConfig) { + h.IsPropertyTest = true + } +} + +func WithNativeTokenConfig(tokenConfigRaw string) ClusterOption { + return func(h *TestClusterConfig) { + h.NativeTokenConfigRaw = tokenConfigRaw + } +} + +func WithTestRewardToken() ClusterOption { + return func(h *TestClusterConfig) { + h.TestRewardToken = hex.EncodeToString(contractsapi.TestRewardToken.DeployedBytecode) + } +} + func isTrueEnv(e string) bool { return strings.ToLower(os.Getenv(e)) == "true" } +func NewPropertyTestCluster(t *testing.T, validatorsCount int, opts ...ClusterOption) *TestCluster { + t.Helper() + + opts = append(opts, WithPropertyTestLogging()) + + return NewTestCluster(t, validatorsCount, opts...) +} + func NewTestCluster(t *testing.T, validatorsCount int, opts ...ClusterOption) *TestCluster { t.Helper() var err error config := &TestClusterConfig{ - t: t, - WithLogs: isTrueEnv(envLogsEnabled), - WithStdout: isTrueEnv(envStdoutEnabled), - Binary: resolveBinary(), - EpochSize: 10, - EpochReward: 1, - BlockGasLimit: 1e7, // 10M - PremineValidators: []string{}, - StakeAmounts: []string{}, + t: t, + WithLogs: isTrueEnv(envLogsEnabled), + WithStdout: isTrueEnv(envStdoutEnabled), + Binary: resolveBinary(), + EpochSize: 10, + EpochReward: 1, + BlockGasLimit: 1e7, // 10M + StakeAmounts: []*big.Int{}, } if config.ValidatorPrefix == "" { @@ -286,8 +393,10 @@ func NewTestCluster(t *testing.T, validatorsCount int, opts ...ClusterOption) *T } if !isTrueEnv(envE2ETestsEnabled) { - testType := os.Getenv(envE2ETestsType) - if testType == "" { + var testType string + if config.IsPropertyTest { + testType = "property" + } else { testType = "integration" } @@ -305,83 +414,64 @@ func NewTestCluster(t *testing.T, validatorsCount int, opts ...ClusterOption) *T once: sync.Once{}, } - { - // run init accounts - addresses, err := cluster.InitSecrets(cluster.Config.ValidatorPrefix, validatorsCount) - require.NoError(t, err) - - if cluster.Config.SecretsCallback != nil { - cluster.Config.SecretsCallback(addresses, cluster.Config) - } - } - - manifestPath := path.Join(config.TmpDir, "manifest.json") - args := []string{ - "manifest", - "--path", manifestPath, - "--validators-path", config.TmpDir, - "--validators-prefix", cluster.Config.ValidatorPrefix, - } - - // premine validators - for _, premineValidator := range cluster.Config.PremineValidators { - args = append(args, "--premine-validators", premineValidator) - } - - for _, validatorStake := range cluster.Config.StakeAmounts { - args = append(args, "--stake", validatorStake) - } - - // run manifest file creation - require.NoError(t, cluster.cmdRun(args...)) - - if cluster.Config.HasBridge { - // start bridge - cluster.Bridge, err = NewTestBridge(t, cluster.Config) - require.NoError(t, err) - } - // in case no validators are specified in opts, all nodes will be validators if cluster.Config.ValidatorSetSize == 0 { cluster.Config.ValidatorSetSize = uint64(validatorsCount) } - if cluster.Config.HasBridge { - err := cluster.Bridge.deployRootchainContracts(manifestPath) - require.NoError(t, err) + // run init accounts for validators + addresses, err := cluster.InitSecrets(cluster.Config.ValidatorPrefix, int(cluster.Config.ValidatorSetSize)) + require.NoError(t, err) + + if cluster.Config.SecretsCallback != nil { + cluster.Config.SecretsCallback(addresses, cluster.Config) + } - err = cluster.Bridge.fundRootchainValidators() + if config.NonValidatorCount > 0 { + // run init accounts for non-validators + // we don't call secrets callback on non-validators, + // since we have nothing to premine nor stake for non validators + _, err = cluster.InitSecrets(nonValidatorPrefix, config.NonValidatorCount) require.NoError(t, err) } + genesisPath := path.Join(config.TmpDir, "genesis.json") + { // run genesis configuration population args := []string{ "genesis", - "--manifest", manifestPath, - "--consensus", "polybft", - "--dir", path.Join(config.TmpDir, "genesis.json"), + "--validators-path", config.TmpDir, + "--validators-prefix", cluster.Config.ValidatorPrefix, + "--dir", genesisPath, "--block-gas-limit", strconv.FormatUint(cluster.Config.BlockGasLimit, 10), "--epoch-size", strconv.Itoa(cluster.Config.EpochSize), "--epoch-reward", strconv.Itoa(cluster.Config.EpochReward), "--premine", "0x0000000000000000000000000000000000000000", + "--reward-wallet", testRewardWalletAddr.String(), "--trieroot", cluster.Config.InitialStateRoot.String(), } + if cluster.Config.TestRewardToken != "" { + args = append(args, "--reward-token-code", cluster.Config.TestRewardToken) + } + + // add optional genesis flags + if cluster.Config.NativeTokenConfigRaw != "" { + args = append(args, "--native-token-config", cluster.Config.NativeTokenConfigRaw) + } + if len(cluster.Config.Premine) != 0 { for _, premine := range cluster.Config.Premine { args = append(args, "--premine", premine) } } - if cluster.Config.MintableNativeToken { - args = append(args, "--mintable-native-token") - } - - if cluster.Config.HasBridge { - rootchainIP, err := helper.ReadRootchainIP() - require.NoError(t, err) - args = append(args, "--bridge-json-rpc", rootchainIP) + burnContract := cluster.Config.BurnContract + if burnContract != nil { + args = append(args, "--burn-contract", + fmt.Sprintf("%d:%s:%s", + burnContract.BlockNumber, burnContract.Address, burnContract.DestinationAddress)) } validators, err := genesis.ReadValidatorsByPrefix( @@ -399,10 +489,6 @@ func NewTestCluster(t *testing.T, validatorsCount int, opts ...ClusterOption) *T } } - if cluster.Config.ValidatorSetSize > 0 { - args = append(args, "--validator-set-size", fmt.Sprint(cluster.Config.ValidatorSetSize)) - } - if len(cluster.Config.ContractDeployerAllowListAdmin) != 0 { args = append(args, "--contract-deployer-allow-list-admin", strings.Join(sliceAddressToSliceString(cluster.Config.ContractDeployerAllowListAdmin), ",")) @@ -413,29 +499,120 @@ func NewTestCluster(t *testing.T, validatorsCount int, opts ...ClusterOption) *T strings.Join(sliceAddressToSliceString(cluster.Config.ContractDeployerAllowListEnabled), ",")) } - // run cmd init-genesis with all the arguments + if len(cluster.Config.ContractDeployerBlockListAdmin) != 0 { + args = append(args, "--contract-deployer-block-list-admin", + strings.Join(sliceAddressToSliceString(cluster.Config.ContractDeployerBlockListAdmin), ",")) + } + + if len(cluster.Config.ContractDeployerBlockListEnabled) != 0 { + args = append(args, "--contract-deployer-block-list-enabled", + strings.Join(sliceAddressToSliceString(cluster.Config.ContractDeployerBlockListEnabled), ",")) + } + + if len(cluster.Config.TransactionsAllowListAdmin) != 0 { + args = append(args, "--transactions-allow-list-admin", + strings.Join(sliceAddressToSliceString(cluster.Config.TransactionsAllowListAdmin), ",")) + } + + if len(cluster.Config.TransactionsAllowListEnabled) != 0 { + args = append(args, "--transactions-allow-list-enabled", + strings.Join(sliceAddressToSliceString(cluster.Config.TransactionsAllowListEnabled), ",")) + } + + if len(cluster.Config.TransactionsBlockListAdmin) != 0 { + args = append(args, "--transactions-block-list-admin", + strings.Join(sliceAddressToSliceString(cluster.Config.TransactionsBlockListAdmin), ",")) + } + + if len(cluster.Config.TransactionsBlockListEnabled) != 0 { + args = append(args, "--transactions-block-list-enabled", + strings.Join(sliceAddressToSliceString(cluster.Config.TransactionsBlockListEnabled), ",")) + } + + if len(cluster.Config.BridgeAllowListAdmin) != 0 { + args = append(args, "--bridge-allow-list-admin", + strings.Join(sliceAddressToSliceString(cluster.Config.BridgeAllowListAdmin), ",")) + } + + if len(cluster.Config.BridgeAllowListEnabled) != 0 { + args = append(args, "--bridge-allow-list-enabled", + strings.Join(sliceAddressToSliceString(cluster.Config.BridgeAllowListEnabled), ",")) + } + + if len(cluster.Config.BridgeBlockListAdmin) != 0 { + args = append(args, "--bridge-block-list-admin", + strings.Join(sliceAddressToSliceString(cluster.Config.BridgeBlockListAdmin), ",")) + } + + if len(cluster.Config.BridgeBlockListEnabled) != 0 { + args = append(args, "--bridge-block-list-enabled", + strings.Join(sliceAddressToSliceString(cluster.Config.BridgeBlockListEnabled), ",")) + } + + // run genesis command with all the arguments err = cluster.cmdRun(args...) require.NoError(t, err) } + if !cluster.Config.WithoutBridge { + // start bridge + cluster.Bridge, err = NewTestBridge(t, cluster.Config) + require.NoError(t, err) + + // deploy stake manager contract + err := cluster.Bridge.deployStakeManager(genesisPath) + require.NoError(t, err) + + // deploy rootchain contracts + err = cluster.Bridge.deployRootchainContracts(genesisPath) + require.NoError(t, err) + + polybftConfig, err := polybft.LoadPolyBFTConfig(genesisPath) + require.NoError(t, err) + + // fund validators on the rootchain + err = cluster.Bridge.fundRootchainValidators(polybftConfig) + require.NoError(t, err) + + // whitelist genesis validators on the rootchain + err = cluster.Bridge.whitelistValidators(addresses, polybftConfig) + require.NoError(t, err) + + // register genesis validators on the rootchain + err = cluster.Bridge.registerGenesisValidators(polybftConfig) + require.NoError(t, err) + + // do initial staking for genesis validators on the rootchain + err = cluster.Bridge.initialStakingOfGenesisValidators(polybftConfig) + require.NoError(t, err) + + // finalize genesis validators on the rootchain + err = cluster.Bridge.finalizeGenesis(genesisPath, polybftConfig) + require.NoError(t, err) + } + for i := 1; i <= int(cluster.Config.ValidatorSetSize); i++ { - cluster.InitTestServer(t, i, true, cluster.Config.HasBridge && i == 1 /* relayer */) + dir := cluster.Config.ValidatorPrefix + strconv.Itoa(i) + cluster.InitTestServer(t, dir, cluster.Bridge.JSONRPCAddr(), + true, !cluster.Config.WithoutBridge && i == 1 /* relayer */) } for i := 1; i <= cluster.Config.NonValidatorCount; i++ { - offsetIndex := i + int(cluster.Config.ValidatorSetSize) - cluster.InitTestServer(t, offsetIndex, false, false /* relayer */) + dir := nonValidatorPrefix + strconv.Itoa(i) + cluster.InitTestServer(t, dir, cluster.Bridge.JSONRPCAddr(), + false, false /* relayer */) } return cluster } -func (c *TestCluster) InitTestServer(t *testing.T, i int, isValidator bool, relayer bool) { +func (c *TestCluster) InitTestServer(t *testing.T, + dataDir string, bridgeJSONRPC string, isValidator bool, relayer bool) { t.Helper() logLevel := os.Getenv(envLogLevel) - dataDir := c.Config.Dir(c.Config.ValidatorPrefix + strconv.Itoa(i)) + dataDir = c.Config.Dir(dataDir) if c.Config.InitialTrieDB != "" { err := CopyDir(c.Config.InitialTrieDB, filepath.Join(dataDir, "trie")) if err != nil { @@ -443,7 +620,7 @@ func (c *TestCluster) InitTestServer(t *testing.T, i int, isValidator bool, rela } } - srv := NewTestServer(t, c.Config, func(config *TestServerConfig) { + srv := NewTestServer(t, c.Config, bridgeJSONRPC, func(config *TestServerConfig) { config.DataDir = dataDir config.Seal = isValidator config.Chain = c.Config.Dir("genesis.json") @@ -451,6 +628,7 @@ func (c *TestCluster) InitTestServer(t *testing.T, i int, isValidator bool, rela config.LogLevel = logLevel config.Relayer = relayer config.NumBlockConfirmations = c.Config.NumBlockConfirmations + config.BridgeJSONRPC = bridgeJSONRPC }) // watch the server for stop signals. It is important to fix the specific @@ -524,7 +702,7 @@ func (c *TestCluster) WaitUntil(timeout, pollFrequency time.Duration, handler fu func (c *TestCluster) WaitForReady(t *testing.T) { t.Helper() - require.NoError(t, c.WaitForBlock(1, 30*time.Second)) + require.NoError(t, c.WaitForBlock(1, time.Minute)) } func (c *TestCluster) WaitForBlock(n uint64, timeout time.Duration) error { @@ -679,7 +857,7 @@ func (c *TestCluster) Call(t *testing.T, to types.Address, method *abi.Method, func (c *TestCluster) Deploy(t *testing.T, sender ethgo.Key, bytecode []byte) *TestTxn { t.Helper() - return c.SendTxn(t, sender, ðgo.Transaction{Input: bytecode}) + return c.SendTxn(t, sender, ðgo.Transaction{From: sender.Address(), Input: bytecode}) } func (c *TestCluster) Transfer(t *testing.T, sender ethgo.Key, target types.Address, value *big.Int) *TestTxn { @@ -687,7 +865,7 @@ func (c *TestCluster) Transfer(t *testing.T, sender ethgo.Key, target types.Addr targetAddr := ethgo.Address(target) - return c.SendTxn(t, sender, ðgo.Transaction{To: &targetAddr, Value: value}) + return c.SendTxn(t, sender, ðgo.Transaction{From: sender.Address(), To: &targetAddr, Value: value}) } func (c *TestCluster) MethodTxn(t *testing.T, sender ethgo.Key, target types.Address, input []byte) *TestTxn { @@ -695,7 +873,7 @@ func (c *TestCluster) MethodTxn(t *testing.T, sender ethgo.Key, target types.Add targetAddr := ethgo.Address(target) - return c.SendTxn(t, sender, ðgo.Transaction{To: &targetAddr, Input: input}) + return c.SendTxn(t, sender, ðgo.Transaction{From: sender.Address(), To: &targetAddr, Input: input}) } // SendTxn sends a transaction @@ -721,11 +899,23 @@ func (c *TestCluster) SendTxn(t *testing.T, sender ethgo.Key, txn *ethgo.Transac } if txn.GasPrice == 0 { - txn.GasPrice = txrelayer.DefaultGasPrice + gasPrice, err := client.Eth().GasPrice() + require.NoError(t, err) + + txn.GasPrice = gasPrice } if txn.Gas == 0 { - txn.Gas = txrelayer.DefaultGasLimit + callMsg := txrelayer.ConvertTxnToCallMsg(txn) + + gasLimit, err := client.Eth().EstimateGas(callMsg) + if err != nil { + // gas estimation can fail in case an account is not allow-listed + // (fallback it to default gas limit in that case) + txn.Gas = txrelayer.DefaultGasLimit + } else { + txn.Gas = gasLimit + } } chainID, err := client.Eth().ChainID() @@ -741,13 +931,11 @@ func (c *TestCluster) SendTxn(t *testing.T, sender ethgo.Key, txn *ethgo.Transac hash, err := client.Eth().SendRawTransaction(txnRaw) require.NoError(t, err) - tTxn := &TestTxn{ + return &TestTxn{ client: client.Eth(), txn: txn, hash: hash, } - - return tTxn } type TestTxn struct { diff --git a/e2e-polybft/framework/test-server.go b/e2e-polybft/framework/test-server.go index b71f4cfc38..1c49b5adba 100644 --- a/e2e-polybft/framework/test-server.go +++ b/e2e-polybft/framework/test-server.go @@ -1,22 +1,26 @@ package framework import ( + "errors" "fmt" "io/ioutil" "math/big" - "path" "strconv" + "strings" "sync/atomic" "testing" "time" "github.com/0xPolygon/polygon-edge/command/polybftsecrets" + rootHelper "github.com/0xPolygon/polygon-edge/command/rootchain/helper" "github.com/0xPolygon/polygon-edge/consensus/polybft" + "github.com/0xPolygon/polygon-edge/consensus/polybft/validator" + "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" "github.com/0xPolygon/polygon-edge/server/proto" txpoolProto "github.com/0xPolygon/polygon-edge/txpool/proto" "github.com/0xPolygon/polygon-edge/types" "github.com/google/uuid" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/umbracle/ethgo" "github.com/umbracle/ethgo/jsonrpc" "google.golang.org/grpc" @@ -33,6 +37,7 @@ type TestServerConfig struct { LogLevel string Relayer bool NumBlockConfirmations uint64 + BridgeJSONRPC string } type TestServerConfigCallback func(*TestServerConfig) @@ -48,6 +53,7 @@ func getOpenPortForServer() int64 { type TestServer struct { t *testing.T + address types.Address clusterConfig *TestClusterConfig config *TestServerConfig node *node @@ -61,6 +67,10 @@ func (t *TestServer) JSONRPCAddr() string { return fmt.Sprintf("http://%s:%d", hostIP, t.config.JSONRPCPort) } +func (t *TestServer) BridgeJSONRPCAddr() string { + return t.config.BridgeJSONRPC +} + func (t *TestServer) JSONRPC() *jsonrpc.Client { clt, err := jsonrpc.NewClient(t.JSONRPCAddr()) if err != nil { @@ -92,14 +102,16 @@ func (t *TestServer) TxnPoolOperator() txpoolProto.TxnPoolOperatorClient { return txpoolProto.NewTxnPoolOperatorClient(conn) } -func NewTestServer(t *testing.T, clusterConfig *TestClusterConfig, callback TestServerConfigCallback) *TestServer { +func NewTestServer(t *testing.T, clusterConfig *TestClusterConfig, + bridgeJSONRPC string, callback TestServerConfigCallback) *TestServer { t.Helper() config := &TestServerConfig{ - Name: uuid.New().String(), - JSONRPCPort: getOpenPortForServer(), - GRPCPort: getOpenPortForServer(), - P2PPort: getOpenPortForServer(), + Name: uuid.New().String(), + JSONRPCPort: getOpenPortForServer(), + GRPCPort: getOpenPortForServer(), + P2PPort: getOpenPortForServer(), + BridgeJSONRPC: bridgeJSONRPC, } if callback != nil { @@ -108,14 +120,21 @@ func NewTestServer(t *testing.T, clusterConfig *TestClusterConfig, callback Test if config.DataDir == "" { dataDir, err := ioutil.TempDir("/tmp", "edge-e2e-") - assert.NoError(t, err) + require.NoError(t, err) config.DataDir = dataDir } + secretsManager, err := polybftsecrets.GetSecretsManager(config.DataDir, "", true) + require.NoError(t, err) + + key, err := wallet.GetEcdsaFromSecret(secretsManager) + require.NoError(t, err) + srv := &TestServer{ t: t, clusterConfig: clusterConfig, + address: types.Address(key.Address()), config: config, } srv.Start() @@ -180,107 +199,143 @@ func (t *TestServer) Stop() { t.node = nil } +// RootchainFund funds given validator account on the rootchain +func (t *TestServer) RootchainFund(stakeToken types.Address, amount *big.Int) error { + return t.RootchainFundFor([]types.Address{t.address}, []*big.Int{amount}, stakeToken) +} + +// RootchainFundFor funds given account on the rootchain +func (t *TestServer) RootchainFundFor(accounts []types.Address, amounts []*big.Int, stakeToken types.Address) error { + if len(accounts) != len(amounts) { + return errors.New("same size for accounts and amounts must be provided to the rootchain funding") + } + + args := []string{ + "rootchain", + "fund", + "--json-rpc", t.BridgeJSONRPCAddr(), + "--stake-token", stakeToken.String(), + "--mint", + } + + for i := 0; i < len(accounts); i++ { + args = append(args, "--addresses", accounts[i].String()) + args = append(args, "--amounts", amounts[i].String()) + } + + if err := runCommand(t.clusterConfig.Binary, args, t.clusterConfig.GetStdout("bridge")); err != nil { + acctAddrs := make([]string, len(accounts)) + for i, acc := range accounts { + acctAddrs[i] = acc.String() + } + + return fmt.Errorf("failed to fund accounts (%s) on the rootchain: %w", strings.Join(acctAddrs, ","), err) + } + + return nil +} + // Stake stakes given amount to validator account encapsulated by given server instance -func (t *TestServer) Stake(amount uint64) error { +func (t *TestServer) Stake(polybftConfig polybft.PolyBFTConfig, amount *big.Int) error { args := []string{ "polybft", "stake", + "--jsonrpc", t.BridgeJSONRPCAddr(), + "--stake-manager", polybftConfig.Bridge.StakeManagerAddr.String(), "--" + polybftsecrets.AccountDirFlag, t.config.DataDir, - "--jsonrpc", t.JSONRPCAddr(), - "--amount", strconv.FormatUint(amount, 10), - "--self", + "--amount", amount.String(), + "--supernet-id", strconv.FormatInt(polybftConfig.SupernetID, 10), + "--stake-token", polybftConfig.Bridge.StakeTokenAddr.String(), } return runCommand(t.clusterConfig.Binary, args, t.clusterConfig.GetStdout("stake")) } // Unstake unstakes given amount from validator account encapsulated by given server instance -func (t *TestServer) Unstake(amount uint64) error { +func (t *TestServer) Unstake(amount *big.Int) error { args := []string{ "polybft", "unstake", "--" + polybftsecrets.AccountDirFlag, t.config.DataDir, "--jsonrpc", t.JSONRPCAddr(), - "--amount", strconv.FormatUint(amount, 10), - "--self", + "--amount", amount.String(), } - return runCommand(t.clusterConfig.Binary, args, t.clusterConfig.GetStdout("stake")) + return runCommand(t.clusterConfig.Binary, args, t.clusterConfig.GetStdout("unstake")) } -// RegisterValidator is a wrapper function which registers new validator with given balance and stake -func (t *TestServer) RegisterValidator(secrets string, stake string) error { +// RegisterValidator is a wrapper function which registers new validator on a root chain +func (t *TestServer) RegisterValidator(supernetManagerAddr types.Address) error { args := []string{ "polybft", "register-validator", - "--" + polybftsecrets.AccountDirFlag, path.Join(t.clusterConfig.TmpDir, secrets), - "--jsonrpc", t.JSONRPCAddr(), - } - - if stake != "" { - args = append(args, "--stake", stake) + "--jsonrpc", t.BridgeJSONRPCAddr(), + "--supernet-manager", supernetManagerAddr.String(), + "--" + polybftsecrets.AccountDirFlag, t.DataDir(), } - return runCommand(t.clusterConfig.Binary, args, t.clusterConfig.GetStdout("register-validator")) + return runCommand(t.clusterConfig.Binary, args, t.clusterConfig.GetStdout("bridge")) } -// WhitelistValidator invokes whitelist-validator helper CLI command, -// which sends whitelist transaction to ChildValidatorSet -func (t *TestServer) WhitelistValidator(address, secrets string) error { +// WhitelistValidators invokes whitelist-validators helper CLI command, +// that whitelists validators on the root chain +func (t *TestServer) WhitelistValidators(addresses []string, supernetManager types.Address) error { args := []string{ "polybft", - "whitelist-validator", - "--" + polybftsecrets.AccountDirFlag, path.Join(t.clusterConfig.TmpDir, secrets), - "--address", address, - "--jsonrpc", t.JSONRPCAddr(), + "whitelist-validators", + "--private-key", rootHelper.TestAccountPrivKey, + "--jsonrpc", t.BridgeJSONRPCAddr(), + "--supernet-manager", supernetManager.String(), + } + for _, addr := range addresses { + args = append(args, "--addresses", addr) } - return runCommand(t.clusterConfig.Binary, args, t.clusterConfig.GetStdout("whitelist-validator")) + return runCommand(t.clusterConfig.Binary, args, t.clusterConfig.GetStdout("bridge")) } -// Delegate delegates given amount by the account in secrets to validatorAddr validator -func (t *TestServer) Delegate(amount uint64, secrets string, validatorAddr ethgo.Address) error { +// WithdrawChildChain withdraws available balance from child chain +func (t *TestServer) WithdrawChildChain() error { args := []string{ "polybft", - "stake", - "--" + polybftsecrets.AccountDirFlag, secrets, + "withdraw-child", + "--" + polybftsecrets.AccountDirFlag, t.config.DataDir, "--jsonrpc", t.JSONRPCAddr(), - "--delegate", validatorAddr.String(), - "--amount", strconv.FormatUint(amount, 10), } - return runCommand(t.clusterConfig.Binary, args, t.clusterConfig.GetStdout("delegation")) + return runCommand(t.clusterConfig.Binary, args, t.clusterConfig.GetStdout("withdraw-child")) } -// Undelegate undelegates given amount by the account in secrets from validatorAddr validator -func (t *TestServer) Undelegate(amount uint64, secrets string, validatorAddr ethgo.Address) error { +// WithdrawRootChain withdraws available balance from root chain +func (t *TestServer) WithdrawRootChain(recipient string, amount *big.Int, + stakeManager ethgo.Address, bridgeJSONRPC string) error { args := []string{ "polybft", - "unstake", - "--" + polybftsecrets.AccountDirFlag, secrets, - "--undelegate", validatorAddr.String(), - "--amount", strconv.FormatUint(amount, 10), - "--jsonrpc", t.JSONRPCAddr(), + "withdraw-root", + "--" + polybftsecrets.AccountDirFlag, t.config.DataDir, + "--to", recipient, + "--amount", amount.String(), + "--stake-manager", stakeManager.String(), + "--jsonrpc", bridgeJSONRPC, } - return runCommand(t.clusterConfig.Binary, args, t.clusterConfig.GetStdout("delegation")) + return runCommand(t.clusterConfig.Binary, args, t.clusterConfig.GetStdout("withdraw-root")) } -// Withdraw withdraws available balance to provided recipient address -func (t *TestServer) Withdraw(secrets string, recipient ethgo.Address) error { +// WithdrawRewards withdraws pending rewards for given validator on RewardPool contract +func (t *TestServer) WithdrawRewards() error { args := []string{ "polybft", - "withdraw", - "--" + polybftsecrets.AccountDirFlag, secrets, - "--to", recipient.String(), + "withdraw-rewards", + "--" + polybftsecrets.AccountDirFlag, t.config.DataDir, "--jsonrpc", t.JSONRPCAddr(), } - return runCommand(t.clusterConfig.Binary, args, t.clusterConfig.GetStdout("withdrawal")) + return runCommand(t.clusterConfig.Binary, args, t.clusterConfig.GetStdout("withdraw-rewards")) } // HasValidatorSealed checks whether given validator has signed at least single block for the given range of blocks -func (t *TestServer) HasValidatorSealed(firstBlock, lastBlock uint64, validators polybft.AccountSet, +func (t *TestServer) HasValidatorSealed(firstBlock, lastBlock uint64, validators validator.AccountSet, validatorAddr ethgo.Address) (bool, error) { rpcClient := t.JSONRPC() for i := firstBlock + 1; i <= lastBlock; i++ { diff --git a/e2e-polybft/property/property_test.go b/e2e-polybft/property/property_test.go index 9231cb829a..d43a179993 100644 --- a/e2e-polybft/property/property_test.go +++ b/e2e-polybft/property/property_test.go @@ -3,46 +3,54 @@ package property import ( "fmt" "math" + "math/big" + "path/filepath" "testing" "time" - "github.com/0xPolygon/polygon-edge/e2e-polybft/framework" - "github.com/0xPolygon/polygon-edge/types" "github.com/stretchr/testify/require" "pgregory.net/rapid" + + "github.com/0xPolygon/polygon-edge/e2e-polybft/framework" + "github.com/0xPolygon/polygon-edge/types" ) func TestProperty_DifferentVotingPower(t *testing.T) { t.Parallel() const ( - blockTime = time.Second * 6 - maxPremine = math.MaxUint64 + blockTime = time.Second * 6 + maxStake = math.MaxUint64 ) rapid.Check(t, func(tt *rapid.T) { var ( - numNodes = rapid.Uint64Range(4, 8).Draw(tt, "number of cluster nodes") + numNodes = rapid.Uint64Range(5, 8).Draw(tt, "number of cluster nodes") epochSize = rapid.OneOf(rapid.Just(4), rapid.Just(10)).Draw(tt, "epoch size") numBlocks = rapid.Uint64Range(2, 5).Draw(tt, "number of blocks the cluster should mine") ) - premine := make([]uint64, numNodes) + stakes := make([]*big.Int, numNodes) - // premined amount will determine validator's stake and therefore voting power - for i := range premine { - premine[i] = rapid.Uint64Range(1, maxPremine).Draw(tt, fmt.Sprintf("stake for node %d", i+1)) + // stake amount will determine validator's stake and therefore voting power + for i := range stakes { + stakes[i] = new(big.Int). + SetUint64(rapid.Uint64Range(1, maxStake). + Draw(tt, fmt.Sprintf("stake for node %d", i+1))) } - cluster := framework.NewTestCluster(t, int(numNodes), + cluster := framework.NewPropertyTestCluster(t, int(numNodes), framework.WithEpochSize(epochSize), framework.WithSecretsCallback(func(adresses []types.Address, config *framework.TestClusterConfig) { - for i, a := range adresses { - config.PremineValidators = append(config.PremineValidators, fmt.Sprintf("%s:%d", a, premine[i])) + for i := range adresses { + config.StakeAmounts = append(config.StakeAmounts, stakes[i]) } })) defer cluster.Stop() + t.Logf("Test %v, run with %d nodes, epoch size: %d. Number of blocks to mine: %d", + filepath.Base(cluster.Config.LogsDir), numNodes, epochSize, numBlocks) + // wait for single epoch to process withdrawal require.NoError(t, cluster.WaitForBlock(numBlocks, blockTime*time.Duration(numBlocks))) }) diff --git a/e2e/framework/config.go b/e2e/framework/config.go index 85ee0eb060..aed0eab16c 100644 --- a/e2e/framework/config.go +++ b/e2e/framework/config.go @@ -50,17 +50,19 @@ type TestServerConfig struct { EpochSize uint64 // The epoch size in blocks for the IBFT layer BlockGasLimit uint64 // Block gas limit BlockGasTarget uint64 // Gas target for new blocks + BaseFee uint64 // Initial base fee ShowsLog bool // Flag specifying if logs are shown Name string // Name of the server SaveLogs bool // Flag specifying if logs are saved LogsDir string // Directory where logs are saved IsPos bool // Specifies the mechanism used for IBFT (PoA / PoS) - Signer *crypto.EIP155Signer // Signer used for transactions + Signer crypto.TxSigner // Signer used for transactions MinValidatorCount uint64 // Min validator count MaxValidatorCount uint64 // Max validator count BlockTime uint64 // Minimum block generation time (in s) IBFTBaseTimeout uint64 // Base Timeout in seconds for IBFT PredeployParams *PredeployParams + BurnContracts map[uint64]types.Address } func (t *TestServerConfig) SetPredeployParams(params *PredeployParams) { @@ -77,7 +79,7 @@ func (t *TestServerConfig) DataDir() string { } } -func (t *TestServerConfig) SetSigner(signer *crypto.EIP155Signer) { +func (t *TestServerConfig) SetSigner(signer crypto.TxSigner) { t.Signer = signer } @@ -118,6 +120,15 @@ func (t *TestServerConfig) SetBlockGasTarget(target uint64) { t.BlockGasTarget = target } +// SetBurnContract sets the given burn contract for the test server +func (t *TestServerConfig) SetBurnContract(block uint64, address types.Address) { + if t.BurnContracts == nil { + t.BurnContracts = map[uint64]types.Address{} + } + + t.BurnContracts[block] = address +} + // SetConsensus callback sets consensus func (t *TestServerConfig) SetConsensus(c ConsensusType) { t.Consensus = c diff --git a/e2e/framework/testserver.go b/e2e/framework/testserver.go index 8fd54c7c5c..442cc41bf9 100644 --- a/e2e/framework/testserver.go +++ b/e2e/framework/testserver.go @@ -21,11 +21,19 @@ import ( "testing" "time" - "github.com/0xPolygon/polygon-edge/chain" - "github.com/0xPolygon/polygon-edge/command/genesis/predeploy" + "github.com/hashicorp/go-hclog" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/umbracle/ethgo" + "github.com/umbracle/ethgo/jsonrpc" + "github.com/umbracle/ethgo/wallet" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + empty "google.golang.org/protobuf/types/known/emptypb" + "github.com/0xPolygon/polygon-edge/chain" "github.com/0xPolygon/polygon-edge/command" "github.com/0xPolygon/polygon-edge/command/genesis" + "github.com/0xPolygon/polygon-edge/command/genesis/predeploy" ibftSwitch "github.com/0xPolygon/polygon-edge/command/ibft/switch" initCmd "github.com/0xPolygon/polygon-edge/command/secrets/init" "github.com/0xPolygon/polygon-edge/command/server" @@ -41,14 +49,6 @@ import ( txpoolProto "github.com/0xPolygon/polygon-edge/txpool/proto" "github.com/0xPolygon/polygon-edge/types" "github.com/0xPolygon/polygon-edge/validators" - "github.com/hashicorp/go-hclog" - "github.com/libp2p/go-libp2p/core/peer" - "github.com/umbracle/ethgo" - "github.com/umbracle/ethgo/jsonrpc" - "github.com/umbracle/ethgo/wallet" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - empty "google.golang.org/protobuf/types/known/emptypb" ) type TestServerConfigCallback func(*TestServerConfig) @@ -83,7 +83,7 @@ func NewTestServer(t *testing.T, rootDir string, callback TestServerConfigCallba LibP2PPort: ports[1].Port(), JSONRPCPort: ports[2].Port(), RootDir: rootDir, - Signer: crypto.NewEIP155Signer(chain.AllForksEnabled.At(0), 100), + Signer: crypto.NewSigner(chain.AllForksEnabled.At(0), 100), ValidatorType: validators.ECDSAValidatorType, } @@ -277,6 +277,13 @@ func (t *TestServer) GenerateGenesis() error { args = append(args, "--premine", acct.Addr.String()+":0x"+acct.Balance.Text(16)) } + // provide block time flag + // (e2e framework expects BlockTime parameter to be provided in seconds) + if t.Config.BlockTime != 0 { + args = append(args, "--block-time", + (time.Duration(t.Config.BlockTime) * time.Second).String()) + } + // add consensus flags switch t.Config.Consensus { case ConsensusIBFT: @@ -339,6 +346,21 @@ func (t *TestServer) GenerateGenesis() error { blockGasLimit := strconv.FormatUint(t.Config.BlockGasLimit, 10) args = append(args, "--block-gas-limit", blockGasLimit) + // add base fee + if t.Config.BaseFee != 0 { + args = append(args, "--base-fee", *types.EncodeUint64(t.Config.BaseFee)) + } + + // add burn contracts + if len(t.Config.BurnContracts) != 0 { + for block, addr := range t.Config.BurnContracts { + args = append(args, "--burn-contract", fmt.Sprintf("%d:%s", block, addr)) + } + } else { + // london hardfork is enabled by default so there must be a default burn contract + args = append(args, "--burn-contract", "0:0x0000000000000000000000000000000000000000") + } + cmd := exec.Command(resolveBinary(), args...) //nolint:gosec cmd.Dir = t.Config.RootDir @@ -429,10 +451,6 @@ func (t *TestServer) Start(ctx context.Context) error { args = append(args, "--block-gas-target", *types.EncodeUint64(t.Config.BlockGasTarget)) } - if t.Config.BlockTime != 0 { - args = append(args, "--block-time", strconv.FormatUint(t.Config.BlockTime, 10)) - } - if t.Config.IBFTBaseTimeout != 0 { args = append(args, "--ibft-base-timeout", strconv.FormatUint(t.Config.IBFTBaseTimeout, 10)) } @@ -608,12 +626,6 @@ func (t *Txn) GasLimit(gas uint64) *Txn { return t } -func (t *Txn) GasPrice(price uint64) *Txn { - t.raw.GasPrice = price - - return t -} - func (t *Txn) Nonce(nonce uint64) *Txn { t.raw.Nonce = nonce @@ -622,8 +634,18 @@ func (t *Txn) Nonce(nonce uint64) *Txn { func (t *Txn) sendImpl() error { // populate default values - t.raw.Gas = 1048576 - t.raw.GasPrice = 1048576 + if t.raw.Gas == 0 { + t.raw.Gas = 1048576 + } + + if t.raw.GasPrice == 0 { + gasPrice, err := t.client.GasPrice() + if err != nil { + return fmt.Errorf("failed to get gas price: %w", err) + } + + t.raw.GasPrice = gasPrice + } if t.raw.Nonce == 0 { nextNonce, err := t.client.GetNonce(t.key.Address(), ethgo.Latest) diff --git a/e2e/ibft_test.go b/e2e/ibft_test.go index 95a3dc94cc..b15d57dca9 100644 --- a/e2e/ibft_test.go +++ b/e2e/ibft_test.go @@ -6,7 +6,6 @@ import ( "testing" "time" - "github.com/0xPolygon/polygon-edge/command/server/config" ibftSigner "github.com/0xPolygon/polygon-edge/consensus/ibft/signer" "github.com/0xPolygon/polygon-edge/e2e/framework" "github.com/0xPolygon/polygon-edge/helper/tests" @@ -19,6 +18,8 @@ import ( // TestIbft_Transfer sends a transfer transaction (EOA -> EOA) // and verifies it was mined func TestIbft_Transfer(t *testing.T) { + const defaultBlockTime uint64 = 2 + testCases := []struct { name string blockTime uint64 @@ -27,7 +28,7 @@ func TestIbft_Transfer(t *testing.T) { }{ { name: "default block time", - blockTime: config.DefaultBlockTime, + blockTime: defaultBlockTime, ibftBaseTimeout: 0, // use default value validatorType: validators.ECDSAValidatorType, }, @@ -39,7 +40,7 @@ func TestIbft_Transfer(t *testing.T) { }, { name: "with BLS", - blockTime: config.DefaultBlockTime, + blockTime: defaultBlockTime, ibftBaseTimeout: 0, // use default value validatorType: validators.BLSValidatorType, }, diff --git a/e2e/jsonrpc_test.go b/e2e/jsonrpc_test.go index 64150ade25..f74eddd52a 100644 --- a/e2e/jsonrpc_test.go +++ b/e2e/jsonrpc_test.go @@ -3,6 +3,7 @@ package e2e import ( "context" "encoding/hex" + "math/big" "testing" @@ -18,19 +19,18 @@ var ( ) func TestJsonRPC(t *testing.T) { - //nolint:godox - // TODO: Reuse the same tests for websockets and IPC. (to be fixed in EVM-521) fund, err := wallet.GenerateKey() require.NoError(t, err) - bytecode, _ := hex.DecodeString(sampleByteCode) + bytecode, err := hex.DecodeString(sampleByteCode) + require.NoError(t, err) ibftManager := framework.NewIBFTServersManager( t, 1, IBFTDirPrefix, func(i int, config *framework.TestServerConfig) { - config.Premine(types.Address(fund.Address()), framework.EthToWei(10)) + config.Premine(types.Address(fund.Address()), ethgo.Ether(10)) config.SetBlockTime(1) }, ) @@ -39,10 +39,12 @@ func TestJsonRPC(t *testing.T) { defer ibftManager.StopServers() srv := ibftManager.GetServer(0) + client := srv.JSONRPC().Eth() t.Run("eth_getBalance", func(t *testing.T) { - key1, _ := wallet.GenerateKey() + key1, err := wallet.GenerateKey() + require.NoError(t, err) // Test. return zero if the account does not exists balance1, err := client.GetBalance(key1.Address(), ethgo.Latest) @@ -50,7 +52,7 @@ func TestJsonRPC(t *testing.T) { require.Equal(t, balance1, big.NewInt(0)) // Test. return the balance of an account - newBalance := big.NewInt(22000) + newBalance := ethgo.Ether(1) txn, err := srv.Txn(fund).Transfer(key1.Address(), newBalance).Send() require.NoError(t, err) txn.NoFail(t) @@ -59,17 +61,41 @@ func TestJsonRPC(t *testing.T) { require.NoError(t, err) require.Equal(t, balance1, newBalance) - //nolint:godox // Test. return 0 if the balance of an existing account is empty - // TODO (to be fixed in EVM-521) + gasPrice, err := client.GasPrice() + require.NoError(t, err) + + toAddr := key1.Address() + msg := ðgo.CallMsg{ + From: fund.Address(), + To: &toAddr, + Value: newBalance, + GasPrice: gasPrice, + } + + estimatedGas, err := client.EstimateGas(msg) + require.NoError(t, err) + txPrice := gasPrice * estimatedGas + // subtract gasPrice * estimatedGas from the balance and transfer the rest to the other account + // in order to leave no funds on the account + amountToSend := new(big.Int).Sub(newBalance, big.NewInt(int64(txPrice))) + txn, err = srv.Txn(key1).Transfer(fund.Address(), amountToSend). + GasLimit(estimatedGas). + Send() + require.NoError(t, err) + txn.NoFail(t) + + balance1, err = client.GetBalance(key1.Address(), ethgo.Latest) + require.NoError(t, err) + require.Equal(t, big.NewInt(0), balance1) }) t.Run("eth_getTransactionCount", func(t *testing.T) { - key1, _ := wallet.GenerateKey() + key1, err := wallet.GenerateKey() + require.NoError(t, err) - //nolint:godox - // TODO. return zero if the account does not exists in the state (Does not work) (to be fixed in EVM-521) - _, err := client.GetNonce(key1.Address(), ethgo.Latest) + nonce, err := client.GetNonce(key1.Address(), ethgo.Latest) + require.Equal(t, uint64(0), nonce) require.NoError(t, err) txn, err := srv.Txn(fund).Transfer(key1.Address(), big.NewInt(10000000000000000)).Send() @@ -91,7 +117,6 @@ func TestJsonRPC(t *testing.T) { require.NoError(t, err) require.Equal(t, nonce1, uint64(0)) - // Test. TODO. you can query the nonce at any block hash in time (to be fixed in EVM-521) //nolint:godox block, err := client.GetBlockByNumber(ethgo.BlockNumber(txn.Receipt().BlockNumber)-1, false) require.NoError(t, err) @@ -100,14 +125,31 @@ func TestJsonRPC(t *testing.T) { }) t.Run("eth_getStorage", func(t *testing.T) { - t.Skip("TODO") + key1, err := wallet.GenerateKey() + require.NoError(t, err) + + txn := srv.Txn(fund) + txn, err = txn.Transfer(key1.Address(), one).Send() + require.NoError(t, err) + txn.NoFail(t) + + txn = srv.Txn(fund) + txn, err = txn.Deploy(bytecode).Send() + require.NoError(t, err) + txn.NoFail(t) + + resp, err := client.GetStorageAt(txn.Receipt().ContractAddress, ethgo.Hash{}, ethgo.Latest) + require.NoError(t, err) + require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000000", resp.String()) }) t.Run("eth_getCode", func(t *testing.T) { // we use a predefined private key so that the deployed contract address is deterministic. // Note that in order to work, this private key should only be used for this test. - priv, _ := hex.DecodeString("2c15bd0dc992a47ca660983ae4b611f4ffb6178e14e04e2b34d153f3a74ce741") - key1, _ := wallet.NewWalletFromPrivKey(priv) + priv, err := hex.DecodeString("2c15bd0dc992a47ca660983ae4b611f4ffb6178e14e04e2b34d153f3a74ce741") + require.NoError(t, err) + key1, err := wallet.NewWalletFromPrivKey(priv) + require.NoError(t, err) // fund the account so that it can deploy a contract txn, err := srv.Txn(fund).Transfer(key1.Address(), big.NewInt(10000000000000000)).Send() @@ -135,7 +177,6 @@ func TestJsonRPC(t *testing.T) { cases := []ethgo.BlockNumberOrHash{ ethgo.Latest, ethgo.BlockNumber(receipt.BlockNumber), - // receipt.BlockHash, TODO: It does not work (to be fixed in EVM-521) //nolint:godox } for _, c := range cases { code, err = client.GetCode(codeAddr, c) @@ -154,15 +195,42 @@ func TestJsonRPC(t *testing.T) { require.NotEqual(t, code, "0x") }) - t.Run("eth_getBlockByX", func(t *testing.T) { - t.Skip("TODO") + t.Run("eth_getBlockByHash", func(t *testing.T) { + key1, err := wallet.GenerateKey() + require.NoError(t, err) + txn := srv.Txn(fund) + txn, err = txn.Transfer(key1.Address(), one).Send() + require.NoError(t, err) + txn.NoFail(t) + txReceipt := txn.Receipt() + + block, err := client.GetBlockByHash(txReceipt.BlockHash, false) + require.NoError(t, err) + require.Equal(t, txReceipt.BlockNumber, block.Number) + require.Equal(t, txReceipt.BlockHash, block.Hash) + }) + + t.Run("eth_getBlockByNumber", func(t *testing.T) { + key1, err := wallet.GenerateKey() + require.NoError(t, err) + txn := srv.Txn(fund) + txn, err = txn.Transfer(key1.Address(), one).Send() + require.NoError(t, err) + txn.NoFail(t) + txReceipt := txn.Receipt() + + block, err := client.GetBlockByNumber(ethgo.BlockNumber(txReceipt.BlockNumber), false) + require.NoError(t, err) + require.Equal(t, txReceipt.BlockNumber, block.Number) + require.Equal(t, txReceipt.BlockHash, block.Hash) }) t.Run("eth_getTransactionReceipt", func(t *testing.T) { - key1, _ := wallet.GenerateKey() + key1, err := wallet.GenerateKey() + require.NoError(t, err) txn := srv.Txn(fund) - txn, err := txn.Transfer(key1.Address(), one).Send() + txn, err = txn.Transfer(key1.Address(), one).Send() require.NoError(t, err) txn.NoFail(t) @@ -193,11 +261,12 @@ func TestJsonRPC(t *testing.T) { }) t.Run("eth_getTransactionByHash", func(t *testing.T) { - key1, _ := wallet.GenerateKey() + key1, err := wallet.GenerateKey() + require.NoError(t, err) // Test. We should be able to query the transaction by its hash txn := srv.Txn(fund) - txn, err := txn.Transfer(key1.Address(), one).Send() + txn, err = txn.Transfer(key1.Address(), one).Send() require.NoError(t, err) txn.NoFail(t) diff --git a/e2e/pos_poa_switch_test.go b/e2e/pos_poa_switch_test.go index be7d78d2dc..e80d0568a3 100644 --- a/e2e/pos_poa_switch_test.go +++ b/e2e/pos_poa_switch_test.go @@ -113,8 +113,8 @@ func TestPoAPoSSwitch(t *testing.T) { } // Stake balance - // 3 genesis validators will stake but 1 gensis validator won't - numStakedValidators := 3 + // 4 genesis validators will stake but 1 gensis validator won't + numStakedValidators := 4 wg = sync.WaitGroup{} for idx := 0; idx < numStakedValidators; idx++ { @@ -143,7 +143,7 @@ func TestPoAPoSSwitch(t *testing.T) { t.Fatalf("Unable to wait for all nodes to seal blocks, %v", waitErrors) } - expectedPoSValidators := genesisValidatorAddrs[:3] + expectedPoSValidators := genesisValidatorAddrs[:4] // Test in PoS wg = sync.WaitGroup{} @@ -159,7 +159,7 @@ func TestPoAPoSSwitch(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), framework.DefaultTimeout) defer cancel() - // every validator should have only 3 validators in validator set + // every validator should have only 4 validators in validator set validateSnapshot(ctx, srv, posStartAt, expectedPoSValidators) }(srv) } diff --git a/e2e/pos_test.go b/e2e/pos_test.go index c8935a3fea..4d8779a184 100644 --- a/e2e/pos_test.go +++ b/e2e/pos_test.go @@ -9,6 +9,11 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/umbracle/ethgo" + "github.com/umbracle/ethgo/jsonrpc" + "github.com/0xPolygon/polygon-edge/chain" ibftOp "github.com/0xPolygon/polygon-edge/consensus/ibft/proto" "github.com/0xPolygon/polygon-edge/contracts/staking" @@ -19,9 +24,6 @@ import ( txpoolOp "github.com/0xPolygon/polygon-edge/txpool/proto" "github.com/0xPolygon/polygon-edge/types" "github.com/golang/protobuf/ptypes/any" - "github.com/stretchr/testify/assert" - "github.com/umbracle/ethgo" - "github.com/umbracle/ethgo/jsonrpc" ) // foundInValidatorSet is a helper function for searching through the passed in set for a specific @@ -358,28 +360,36 @@ func TestPoS_UnstakeExploit(t *testing.T) { // Required default values numTransactions := 5 - signer := crypto.NewEIP155Signer(chain.AllForksEnabled.At(0), 100) + signer := crypto.NewSigner(chain.AllForksEnabled.At(0), 100) currentNonce := 0 // TxPool client clt := srv.TxnPoolOperator() - generateTx := func() *types.Transaction { - signedTx, signErr := signer.SignTx(&types.Transaction{ - Nonce: uint64(currentNonce), - From: types.ZeroAddress, - To: &stakingContractAddr, - GasPrice: bigGasPrice, - Gas: framework.DefaultGasLimit, - Value: big.NewInt(0), - V: big.NewInt(1), // it is necessary to encode in rlp, - Input: framework.MethodSig("unstake"), - }, senderKey) - - if signErr != nil { - t.Fatalf("Unable to sign transaction, %v", signErr) + generateTx := func(i int) *types.Transaction { + unsignedTx := &types.Transaction{ + Nonce: uint64(currentNonce), + From: types.ZeroAddress, + To: &stakingContractAddr, + Gas: framework.DefaultGasLimit, + Value: big.NewInt(0), + V: big.NewInt(1), // it is necessary to encode in rlp, + Input: framework.MethodSig("unstake"), + } + + // Just make very second transaction with dynamic gas fee + if i%2 == 0 { + unsignedTx.Type = types.DynamicFeeTx + unsignedTx.GasFeeCap = bigGasPrice + unsignedTx.GasTipCap = bigGasPrice + } else { + unsignedTx.Type = types.LegacyTx + unsignedTx.GasPrice = bigGasPrice } + signedTx, err := signer.SignTx(unsignedTx, senderKey) + require.NoError(t, err, "Unable to sign transaction") + currentNonce++ return signedTx @@ -390,7 +400,7 @@ func TestPoS_UnstakeExploit(t *testing.T) { for i := 0; i < numTransactions; i++ { var msg *txpoolOp.AddTxnReq - unstakeTxn := generateTx() + unstakeTxn := generateTx(i) msg = &txpoolOp.AddTxnReq{ Raw: &any.Any{ @@ -500,28 +510,36 @@ func TestPoS_StakeUnstakeExploit(t *testing.T) { // Required default values numTransactions := 6 - signer := crypto.NewEIP155Signer(chain.AllForksEnabled.At(0), 100) + signer := crypto.NewSigner(chain.AllForksEnabled.At(0), 100) currentNonce := 0 // TxPool client txpoolClient := srv.TxnPoolOperator() - generateTx := func(value *big.Int, methodName string) *types.Transaction { - signedTx, signErr := signer.SignTx(&types.Transaction{ - Nonce: uint64(currentNonce), - From: types.ZeroAddress, - To: &stakingContractAddr, - GasPrice: bigGasPrice, - Gas: framework.DefaultGasLimit, - Value: value, - V: big.NewInt(1), // it is necessary to encode in rlp - Input: framework.MethodSig(methodName), - }, senderKey) - - if signErr != nil { - t.Fatalf("Unable to sign transaction, %v", signErr) + generateTx := func(i int, value *big.Int, methodName string) *types.Transaction { + unsignedTx := &types.Transaction{ + Nonce: uint64(currentNonce), + From: types.ZeroAddress, + To: &stakingContractAddr, + Gas: framework.DefaultGasLimit, + Value: value, + V: big.NewInt(1), // it is necessary to encode in rlp + Input: framework.MethodSig(methodName), + } + + // Just make very second transaction with dynamic gas fee + if i%2 == 0 { + unsignedTx.Type = types.DynamicFeeTx + unsignedTx.GasFeeCap = bigGasPrice + unsignedTx.GasTipCap = bigGasPrice + } else { + unsignedTx.Type = types.LegacyTx + unsignedTx.GasPrice = bigGasPrice } + signedTx, err := signer.SignTx(unsignedTx, senderKey) + require.NoError(t, err, "Unable to sign transaction") + currentNonce++ return signedTx @@ -535,7 +553,7 @@ func TestPoS_StakeUnstakeExploit(t *testing.T) { var msg *txpoolOp.AddTxnReq if i%2 == 0 { - unstakeTxn := generateTx(zeroEth, "unstake") + unstakeTxn := generateTx(i, zeroEth, "unstake") msg = &txpoolOp.AddTxnReq{ Raw: &any.Any{ Value: unstakeTxn.MarshalRLP(), @@ -543,7 +561,7 @@ func TestPoS_StakeUnstakeExploit(t *testing.T) { From: types.ZeroAddress.String(), } } else { - stakeTxn := generateTx(oneEth, "stake") + stakeTxn := generateTx(i, oneEth, "stake") msg = &txpoolOp.AddTxnReq{ Raw: &any.Any{ Value: stakeTxn.MarshalRLP(), @@ -631,28 +649,35 @@ func TestPoS_StakeUnstakeWithinSameBlock(t *testing.T) { } // Required default values - signer := crypto.NewEIP155Signer(chain.AllForksEnabled.At(0), 100) + signer := crypto.NewSigner(chain.AllForksEnabled.At(0), 100) currentNonce := 0 // TxPool client txpoolClient := srv.TxnPoolOperator() - generateTx := func(value *big.Int, methodName string) *types.Transaction { - signedTx, signErr := signer.SignTx(&types.Transaction{ - Nonce: uint64(currentNonce), - From: types.ZeroAddress, - To: &stakingContractAddr, - GasPrice: bigGasPrice, - Gas: framework.DefaultGasLimit, - Value: value, - V: big.NewInt(1), // it is necessary to encode in rlp - Input: framework.MethodSig(methodName), - }, senderKey) - - if signErr != nil { - t.Fatalf("Unable to sign transaction, %v", signErr) + generateTx := func(dynamicTx bool, value *big.Int, methodName string) *types.Transaction { + unsignedTx := &types.Transaction{ + Nonce: uint64(currentNonce), + From: types.ZeroAddress, + To: &stakingContractAddr, + Gas: framework.DefaultGasLimit, + Value: value, + V: big.NewInt(1), // it is necessary to encode in rlp + Input: framework.MethodSig(methodName), } + if dynamicTx { + unsignedTx.Type = types.DynamicFeeTx + unsignedTx.GasFeeCap = bigGasPrice + unsignedTx.GasTipCap = bigGasPrice + } else { + unsignedTx.Type = types.LegacyTx + unsignedTx.GasPrice = bigGasPrice + } + + signedTx, err := signer.SignTx(unsignedTx, senderKey) + require.NoError(t, err, "Unable to signatransaction") + currentNonce++ return signedTx @@ -663,8 +688,8 @@ func TestPoS_StakeUnstakeWithinSameBlock(t *testing.T) { // addTxn is a helper method for generating and adding a transaction // through the operator command - addTxn := func(value *big.Int, methodName string) { - txn := generateTx(value, methodName) + addTxn := func(dynamicTx bool, value *big.Int, methodName string) { + txn := generateTx(dynamicTx, value, methodName) txnMsg := &txpoolOp.AddTxnReq{ Raw: &any.Any{ Value: txn.MarshalRLP(), @@ -681,10 +706,10 @@ func TestPoS_StakeUnstakeWithinSameBlock(t *testing.T) { } // Stake transaction - addTxn(oneEth, "stake") + addTxn(false, oneEth, "stake") // Unstake transaction - addTxn(zeroEth, "unstake") + addTxn(true, zeroEth, "unstake") // Wait for the transactions to go through totalGasUsed := srv.GetGasTotal(txHashes) diff --git a/e2e/transaction_test.go b/e2e/transaction_test.go index bb5c811771..b088391467 100644 --- a/e2e/transaction_test.go +++ b/e2e/transaction_test.go @@ -12,7 +12,10 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/umbracle/ethgo" + "github.com/umbracle/ethgo/jsonrpc" "github.com/0xPolygon/polygon-edge/chain" "github.com/0xPolygon/polygon-edge/contracts/abis" @@ -21,8 +24,6 @@ import ( "github.com/0xPolygon/polygon-edge/helper/tests" "github.com/0xPolygon/polygon-edge/types" "github.com/0xPolygon/polygon-edge/validators" - "github.com/stretchr/testify/assert" - "github.com/umbracle/ethgo/jsonrpc" ) func TestPreminedBalance(t *testing.T) { @@ -271,6 +272,7 @@ func getCount( // IBFT_Loop and Dev_Loop stress tests func generateStressTestTx( t *testing.T, + txNum int, currentNonce uint64, contractAddr types.Address, senderKey *ecdsa.PrivateKey, @@ -278,7 +280,7 @@ func generateStressTestTx( t.Helper() bigGasPrice := big.NewInt(framework.DefaultGasPrice) - signer := crypto.NewEIP155Signer(chain.AllForksEnabled.At(0), 100) + signer := crypto.NewSigner(chain.AllForksEnabled.At(0), 100) setNameMethod, ok := abis.StressTestABI.Methods["setName"] if !ok { @@ -294,21 +296,28 @@ func generateStressTestTx( t.Fatalf("Unable to encode inputs, %v", encodeErr) } - signedTx, signErr := signer.SignTx(&types.Transaction{ - Nonce: currentNonce, - From: types.ZeroAddress, - To: &contractAddr, - GasPrice: bigGasPrice, - Gas: framework.DefaultGasLimit, - Value: big.NewInt(0), - V: big.NewInt(1), // it is necessary to encode in rlp, - Input: append(setNameMethod.ID(), encodedInput...), - }, senderKey) - - if signErr != nil { - t.Fatalf("Unable to sign transaction, %v", signErr) + unsignedTx := &types.Transaction{ + Nonce: currentNonce, + From: types.ZeroAddress, + To: &contractAddr, + Gas: framework.DefaultGasLimit, + Value: big.NewInt(0), + V: big.NewInt(1), // it is necessary to encode in rlp, + Input: append(setNameMethod.ID(), encodedInput...), } + if txNum%2 == 0 { + unsignedTx.Type = types.DynamicFeeTx + unsignedTx.GasFeeCap = bigGasPrice + unsignedTx.GasTipCap = bigGasPrice + } else { + unsignedTx.Type = types.LegacyTx + unsignedTx.GasPrice = bigGasPrice + } + + signedTx, err := signer.SignTx(unsignedTx, senderKey) + require.NoError(t, err, "Unable to sign transaction") + return signedTx } @@ -331,6 +340,7 @@ func addStressTxnsWithHashes( for i := 0; i < numTransactions; i++ { setNameTxn := generateStressTestTx( t, + i, uint64(currentNonce), contractAddr, senderKey, diff --git a/e2e/txpool_test.go b/e2e/txpool_test.go index e78332e603..5ab6d80f9c 100644 --- a/e2e/txpool_test.go +++ b/e2e/txpool_test.go @@ -9,6 +9,9 @@ import ( "time" "github.com/0xPolygon/polygon-edge/chain" + + "github.com/stretchr/testify/require" + "github.com/0xPolygon/polygon-edge/txpool" "github.com/umbracle/ethgo" @@ -23,7 +26,7 @@ import ( var ( oneEth = framework.EthToWei(1) - signer = crypto.NewEIP155Signer(chain.AllForksEnabled.At(0), 100) + signer = crypto.NewSigner(chain.AllForksEnabled.At(0), 100) ) type generateTxReqParams struct { @@ -32,25 +35,34 @@ type generateTxReqParams struct { referenceKey *ecdsa.PrivateKey toAddress types.Address gasPrice *big.Int + gasFeeCap *big.Int + gasTipCap *big.Int value *big.Int t *testing.T } func generateTx(params generateTxReqParams) *types.Transaction { - signedTx, signErr := signer.SignTx(&types.Transaction{ - Nonce: params.nonce, - From: params.referenceAddr, - To: ¶ms.toAddress, - GasPrice: params.gasPrice, - Gas: 1000000, - Value: params.value, - V: big.NewInt(27), // it is necessary to encode in rlp - }, params.referenceKey) - - if signErr != nil { - params.t.Fatalf("Unable to sign transaction, %v", signErr) + unsignedTx := &types.Transaction{ + Nonce: params.nonce, + From: params.referenceAddr, + To: ¶ms.toAddress, + Gas: 1000000, + Value: params.value, + V: big.NewInt(27), // it is necessary to encode in rlp } + if params.gasPrice != nil { + unsignedTx.Type = types.LegacyTx + unsignedTx.GasPrice = params.gasPrice + } else { + unsignedTx.Type = types.DynamicFeeTx + unsignedTx.GasFeeCap = params.gasFeeCap + unsignedTx.GasTipCap = params.gasTipCap + } + + signedTx, err := signer.SignTx(unsignedTx, params.referenceKey) + require.NoError(params.t, err, "Unable to sign transaction") + return signedTx } @@ -67,33 +79,64 @@ func generateReq(params generateTxReqParams) *txpoolOp.AddTxnReq { func TestTxPool_ErrorCodes(t *testing.T) { gasPrice := big.NewInt(10000) + gasFeeCap := big.NewInt(1000000000) + gasTipCap := big.NewInt(100000000) devInterval := 5 testTable := []struct { name string defaultBalance *big.Int txValue *big.Int + gasPrice *big.Int + gasFeeCap *big.Int + gasTipCap *big.Int expectedError error }{ { // Test scenario: + // Add legacy tx with nonce 0 + // -> Check if tx has been parsed // Add tx with nonce 0 + // -> tx shouldn't be added, since the nonce is too low + name: "ErrNonceTooLow - legacy", + defaultBalance: framework.EthToWei(10), + txValue: oneEth, + gasPrice: gasPrice, + expectedError: txpool.ErrNonceTooLow, + }, + { + // Test scenario: + // Add dynamic fee tx with nonce 0 // -> Check if tx has been parsed // Add tx with nonce 0 // -> tx shouldn't be added, since the nonce is too low - "ErrNonceTooLow", - framework.EthToWei(10), - oneEth, - txpool.ErrNonceTooLow, + name: "ErrNonceTooLow - dynamic fees", + defaultBalance: framework.EthToWei(10), + txValue: oneEth, + gasFeeCap: gasFeeCap, + gasTipCap: gasTipCap, + expectedError: txpool.ErrNonceTooLow, }, { // Test scenario: - // Add tx with insufficient funds + // Add legacy tx with insufficient funds // -> Tx should be discarded because of low funds - "ErrInsufficientFunds", - framework.EthToWei(1), - framework.EthToWei(5), - txpool.ErrInsufficientFunds, + name: "ErrInsufficientFunds - legacy", + defaultBalance: framework.EthToWei(1), + txValue: framework.EthToWei(5), + gasPrice: gasPrice, + expectedError: txpool.ErrInsufficientFunds, + }, + { + // Test scenario: + // Add dynamic fee tx with insufficient funds + // -> Tx should be discarded because of low funds + name: "ErrInsufficientFunds - dynamic fee", + defaultBalance: framework.EthToWei(1), + txValue: framework.EthToWei(5), + gasFeeCap: gasFeeCap, + gasTipCap: gasTipCap, + expectedError: txpool.ErrInsufficientFunds, }, } @@ -119,7 +162,9 @@ func TestTxPool_ErrorCodes(t *testing.T) { referenceAddr: referenceAddr, referenceKey: referenceKey, toAddress: toAddress, - gasPrice: gasPrice, + gasPrice: testCase.gasPrice, + gasFeeCap: testCase.gasFeeCap, + gasTipCap: testCase.gasTipCap, value: testCase.txValue, t: t, }) @@ -188,7 +233,7 @@ func TestTxPool_TransactionCoalescing(t *testing.T) { client := srv.JSONRPC() // Required default values - signer := crypto.NewEIP155Signer(chain.AllForksEnabled.At(0), 100) + signer := crypto.NewEIP155Signer(100, true) // TxPool client clt := srv.TxnPoolOperator() @@ -340,7 +385,7 @@ func TestTxPool_RecoverableError(t *testing.T) { // 1. Send a first valid transaction with gasLimit = block gas limit - 1 // // 2. Send a second transaction with gasLimit = block gas limit / 2. Since there is not enough gas remaining, - // the transaction will be pushed back to the pending queue so that is can be executed in the next block. + // the transaction will be pushed back to the pending queue so that can be executed in the next block. // // 3. Send a third - valid - transaction, both the previous one and this one should be executed. // @@ -367,13 +412,15 @@ func TestTxPool_RecoverableError(t *testing.T) { From: senderAddress, }, { - Nonce: 2, - GasPrice: big.NewInt(framework.DefaultGasPrice), - Gas: 22000, - To: &receiverAddress, - Value: oneEth, - V: big.NewInt(27), - From: senderAddress, + Type: types.DynamicFeeTx, + Nonce: 2, + GasFeeCap: big.NewInt(10000000000), + GasTipCap: big.NewInt(1000000000), + Gas: 22000, + To: &receiverAddress, + Value: oneEth, + V: big.NewInt(27), + From: senderAddress, }, } diff --git a/forkmanager/fork.go b/forkmanager/fork.go new file mode 100644 index 0000000000..51bae5019a --- /dev/null +++ b/forkmanager/fork.go @@ -0,0 +1,87 @@ +package forkmanager + +import ( + "fmt" + + "github.com/0xPolygon/polygon-edge/chain" +) + +const InitialFork = "initialfork" + +// HandlerDesc gives description for the handler +// eq: "extra", "proposer_calculator", etc +type HandlerDesc string + +// Fork structure defines one fork +type Fork struct { + // name of the fork + Name string + // after the fork is activated, `FromBlockNumber` shows from which block is enabled + FromBlockNumber uint64 + // fork consensus parameters + Params *chain.ForkParams + // this value is false if fork is registered but not activated + IsActive bool + // map of all handlers registered for this fork + Handlers map[HandlerDesc]interface{} +} + +// forkHandler defines one custom handler +type forkHandler struct { + // Handler should be active from block `FromBlockNumber`` + FromBlockNumber uint64 + // instance of some structure, function etc + Handler interface{} +} + +// forkParamsBlock encapsulates block and actual fork params +type forkParamsBlock struct { + // Params should be active from block `FromBlockNumber`` + FromBlockNumber uint64 + // pointer to fork params + Params *chain.ForkParams +} + +func ForkManagerInit( + initialParams *chain.ForkParams, + factory func(*chain.Forks) error, + forks *chain.Forks) error { + if factory == nil { + return nil + } + + fm := GetInstance() + fm.Clear() + + // register initial fork + fm.RegisterFork(InitialFork, initialParams) + + // Register forks + for name, f := range *forks { + // check if fork is not supported by current edge version + if _, found := (*chain.AllForksEnabled)[name]; !found { + return fmt.Errorf("fork is not available: %s", name) + } + + fm.RegisterFork(name, f.Params) + } + + // Register handlers and additional forks here + if err := factory(forks); err != nil { + return err + } + + // Activate initial fork + if err := fm.ActivateFork(InitialFork, uint64(0)); err != nil { + return err + } + + // Activate forks + for name, f := range *forks { + if err := fm.ActivateFork(name, f.Block); err != nil { + return err + } + } + + return nil +} diff --git a/forkmanager/fork_manager.go b/forkmanager/fork_manager.go new file mode 100644 index 0000000000..0b7d7e2899 --- /dev/null +++ b/forkmanager/fork_manager.go @@ -0,0 +1,301 @@ +package forkmanager + +import ( + "fmt" + "reflect" + "sort" + "sync" + + "github.com/0xPolygon/polygon-edge/chain" +) + +var ( + forkManagerInstance *forkManager + forkManagerInstanceLock sync.Mutex +) + +type forkManager struct { + lock sync.Mutex + + forkMap map[string]*Fork + handlersMap map[HandlerDesc][]forkHandler + params []*forkParamsBlock +} + +// GeInstance returns fork manager singleton instance. Thread safe +func GetInstance() *forkManager { + forkManagerInstanceLock.Lock() + defer forkManagerInstanceLock.Unlock() + + if forkManagerInstance == nil { + forkManagerInstance = &forkManager{} + forkManagerInstance.Clear() + } + + return forkManagerInstance +} + +func (fm *forkManager) Clear() { + fm.lock.Lock() + defer fm.lock.Unlock() + + fm.forkMap = map[string]*Fork{} + fm.handlersMap = map[HandlerDesc][]forkHandler{} +} + +// RegisterFork registers fork by its name +func (fm *forkManager) RegisterFork(name string, forkParams *chain.ForkParams) { + fm.lock.Lock() + defer fm.lock.Unlock() + + fm.forkMap[name] = &Fork{ + Name: name, + FromBlockNumber: 0, + IsActive: false, + Params: forkParams, + Handlers: map[HandlerDesc]interface{}{}, + } +} + +// RegisterHandler registers handler by its name for specific fork +func (fm *forkManager) RegisterHandler(forkName string, handlerName HandlerDesc, handler interface{}) error { + fm.lock.Lock() + defer fm.lock.Unlock() + + fork, exists := fm.forkMap[forkName] + if !exists { + return fmt.Errorf("fork does not exist: %s", forkName) + } + + fork.Handlers[handlerName] = handler + + return nil +} + +// ActivateFork activates fork from some block number +// All handlers and parameters belonging to this fork are also activated +func (fm *forkManager) ActivateFork(forkName string, blockNumber uint64) error { + fm.lock.Lock() + defer fm.lock.Unlock() + + fork, exists := fm.forkMap[forkName] + if !exists { + return fmt.Errorf("fork does not exist: %s", forkName) + } + + if fork.IsActive { + return nil // already activated + } + + fork.IsActive = true + fork.FromBlockNumber = blockNumber + + for name, handler := range fork.Handlers { + fm.addHandler(name, blockNumber, handler) + } + + fm.addParams(blockNumber, fork.Params) + + return nil +} + +// DeactivateFork de-activates fork +// All handlers and parameters belong to this fork are also de-activated +func (fm *forkManager) DeactivateFork(forkName string) error { + fm.lock.Lock() + defer fm.lock.Unlock() + + fork, exists := fm.forkMap[forkName] + if !exists { + return fmt.Errorf("fork does not exist: %s", forkName) + } + + if !fork.IsActive { + return nil // already deactivated + } + + fork.IsActive = false + + for forkHandlerName := range fork.Handlers { + fm.removeHandler(forkHandlerName, fork.FromBlockNumber) + } + + fm.removeParams(fork.FromBlockNumber) + + return nil +} + +// GetHandler retrieves handler for handler name and for a block number +func (fm *forkManager) GetHandler(name HandlerDesc, blockNumber uint64) interface{} { + fm.lock.Lock() + defer fm.lock.Unlock() + + handlers, exists := fm.handlersMap[name] + if !exists { + return nil + } + + // binary search to find the latest handler defined for a specific block + pos := sort.Search(len(handlers), func(i int) bool { + return handlers[i].FromBlockNumber > blockNumber + }) - 1 + if pos < 0 { + return nil + } + + return handlers[pos].Handler +} + +// GetParams retrieves chain.ForkParams for a block number +func (fm *forkManager) GetParams(blockNumber uint64) *chain.ForkParams { + fm.lock.Lock() + defer fm.lock.Unlock() + + // binary search to find the desired *chain.ForkParams + pos := sort.Search(len(fm.params), func(i int) bool { + return fm.params[i].FromBlockNumber > blockNumber + }) - 1 + if pos < 0 { + return nil + } + + return fm.params[pos].Params +} + +// IsForkRegistered checks if fork is registered +func (fm *forkManager) IsForkRegistered(name string) bool { + fm.lock.Lock() + defer fm.lock.Unlock() + + _, exists := fm.forkMap[name] + + return exists +} + +// IsForkEnabled checks if fork is registered and enabled for specific block +func (fm *forkManager) IsForkEnabled(name string, blockNumber uint64) bool { + fm.lock.Lock() + defer fm.lock.Unlock() + + fork, exists := fm.forkMap[name] + if !exists { + return false + } + + return fork.IsActive && fork.FromBlockNumber <= blockNumber +} + +// GetForkBlock returns fork block if fork is registered and activated +func (fm *forkManager) GetForkBlock(name string) (uint64, error) { + fm.lock.Lock() + defer fm.lock.Unlock() + + fork, exists := fm.forkMap[name] + if !exists { + return 0, fmt.Errorf("fork does not exist: %s", name) + } + + if !fork.IsActive { + return 0, fmt.Errorf("fork is not active: %s", name) + } + + return fork.FromBlockNumber, nil +} + +func (fm *forkManager) addHandler(handlerName HandlerDesc, blockNumber uint64, handler interface{}) { + if handlers, exists := fm.handlersMap[handlerName]; !exists { + fm.handlersMap[handlerName] = []forkHandler{ + { + FromBlockNumber: blockNumber, + Handler: handler, + }, + } + } else { + // keep everything in sorted order + index := sort.Search(len(handlers), func(i int) bool { + return handlers[i].FromBlockNumber >= blockNumber + }) + handlers = append(handlers, forkHandler{}) + copy(handlers[index+1:], handlers[index:]) + handlers[index] = forkHandler{ + FromBlockNumber: blockNumber, + Handler: handler, + } + fm.handlersMap[handlerName] = handlers + } +} + +func (fm *forkManager) removeHandler(handlerName HandlerDesc, blockNumber uint64) { + handlers, exists := fm.handlersMap[handlerName] + if !exists { + return + } + + index := sort.Search(len(handlers), func(i int) bool { + return handlers[i].FromBlockNumber >= blockNumber + }) + + if index < len(handlers) && handlers[index].FromBlockNumber == blockNumber { + copy(handlers[index:], handlers[index+1:]) + handlers[len(handlers)-1] = forkHandler{} + fm.handlersMap[handlerName] = handlers[:len(handlers)-1] + } +} + +func (fm *forkManager) addParams(blockNumber uint64, params *chain.ForkParams) { + if params == nil { + return + } + + item := &forkParamsBlock{FromBlockNumber: blockNumber, Params: params} + + if len(fm.params) == 0 { + fm.params = append(fm.params, item) + } else { + // keep everything in sorted order + index := sort.Search(len(fm.params), func(i int) bool { + return fm.params[i].FromBlockNumber >= blockNumber + }) + + fm.params = append(fm.params, (*forkParamsBlock)(nil)) + copy(fm.params[index+1:], fm.params[index:]) + fm.params[index] = item + + if index > 0 { + // copy all nil parameters from previous + copyParams(item.Params, fm.params[index-1].Params) + } + + // update parameters for next + for i := index; i < len(fm.params)-1; i++ { + copyParams(fm.params[i+1].Params, fm.params[i].Params) + } + } +} + +func (fm *forkManager) removeParams(blockNumber uint64) { + index := sort.Search(len(fm.params), func(i int) bool { + return fm.params[i].FromBlockNumber >= blockNumber + }) + + if index < len(fm.params) && fm.params[index].FromBlockNumber == blockNumber { + copy(fm.params[index:], fm.params[index+1:]) + fm.params[len(fm.params)-1] = nil + fm.params = fm.params[:len(fm.params)-1] + } +} + +func copyParams(dest, src *chain.ForkParams) { + srcValue := reflect.ValueOf(src).Elem() + dstValue := reflect.ValueOf(dest).Elem() + + for i := 0; i < srcValue.NumField(); i++ { + dstField := dstValue.Field(i) + srcField := srcValue.Field(i) + + // copy if dst is nil, but src is not + if dstField.Kind() == reflect.Ptr && dstField.IsNil() && !srcField.IsNil() { + dstField.Set(srcField) + } + } +} diff --git a/forkmanager/fork_manager_test.go b/forkmanager/fork_manager_test.go new file mode 100644 index 0000000000..69a0bad964 --- /dev/null +++ b/forkmanager/fork_manager_test.go @@ -0,0 +1,228 @@ +package forkmanager + +import ( + "testing" + "time" + + "github.com/0xPolygon/polygon-edge/chain" + "github.com/0xPolygon/polygon-edge/helper/common" + "github.com/stretchr/testify/assert" +) + +const ( + HandlerA = HandlerDesc("HA") + HandlerB = HandlerDesc("HB") + HandlerC = HandlerDesc("HC") + HandlerD = HandlerDesc("HD") + + ForkA = "A" + ForkB = "B" + ForkC = "C" + ForkD = "D" + ForkE = "E" +) + +func TestForkManager(t *testing.T) { + t.Parallel() + + es1, es2, es3 := uint64(100), uint64(300), uint64(200) + mss1 := uint64(10002) + bt1, bt2 := common.Duration{Duration: time.Second * 5}, common.Duration{Duration: time.Second * 12} + + forkManager := GetInstance() + + forkManager.RegisterFork(ForkA, &chain.ForkParams{EpochSize: &es1, BlockTime: &bt1}) + forkManager.RegisterFork(ForkB, &chain.ForkParams{EpochSize: &es2, MaxValidatorSetSize: &mss1}) + forkManager.RegisterFork(ForkC, nil) + forkManager.RegisterFork(ForkD, &chain.ForkParams{EpochSize: &es3, BlockTime: &bt2}) + + assert.NoError(t, forkManager.RegisterHandler(ForkA, HandlerA, func() string { return "AAH" })) + assert.NoError(t, forkManager.RegisterHandler(ForkC, HandlerA, func() string { return "ACH" })) + assert.NoError(t, forkManager.RegisterHandler(ForkA, HandlerB, func() string { return "BAH" })) + assert.NoError(t, forkManager.RegisterHandler(ForkB, HandlerB, func() string { return "BBH" })) + assert.NoError(t, forkManager.RegisterHandler(ForkD, HandlerB, func() string { return "BDH" })) + assert.NoError(t, forkManager.RegisterHandler(ForkC, HandlerC, func() string { return "CCH" })) + + assert.NoError(t, forkManager.ActivateFork(ForkD, 300)) + assert.NoError(t, forkManager.ActivateFork(ForkA, 0)) + assert.NoError(t, forkManager.ActivateFork(ForkC, 200)) + assert.NoError(t, forkManager.ActivateFork(ForkB, 100)) + + handlersACnt := len(forkManager.handlersMap[HandlerA]) + handlersBCnt := len(forkManager.handlersMap[HandlerB]) + + assert.Equal(t, 2, handlersACnt) + assert.Equal(t, 3, handlersBCnt) + + t.Run("activate not registered fork", func(t *testing.T) { + t.Parallel() + + assert.Error(t, forkManager.ActivateFork(ForkE, 100)) + }) + + t.Run("activate already activated fork", func(t *testing.T) { + t.Parallel() + + assert.NoError(t, forkManager.ActivateFork(ForkA, 100)) + + // count not changed + assert.Equal(t, handlersACnt, len(forkManager.handlersMap[HandlerA])) + assert.Equal(t, handlersBCnt, len(forkManager.handlersMap[HandlerB])) + }) + + t.Run("is fork enabled", func(t *testing.T) { + t.Parallel() + + assert.True(t, forkManager.IsForkEnabled(ForkA, 0)) + assert.True(t, forkManager.IsForkEnabled(ForkA, 100)) + assert.True(t, forkManager.IsForkEnabled(ForkA, 200)) + + assert.False(t, forkManager.IsForkEnabled(ForkB, 0)) + assert.True(t, forkManager.IsForkEnabled(ForkB, 100)) + assert.True(t, forkManager.IsForkEnabled(ForkB, 200)) + + assert.False(t, forkManager.IsForkEnabled(ForkC, 0)) + assert.False(t, forkManager.IsForkEnabled(ForkC, 100)) + assert.True(t, forkManager.IsForkEnabled(ForkC, 200)) + assert.True(t, forkManager.IsForkEnabled(ForkC, 300)) + + assert.False(t, forkManager.IsForkEnabled(ForkD, 0)) + assert.False(t, forkManager.IsForkEnabled(ForkD, 100)) + assert.False(t, forkManager.IsForkEnabled(ForkD, 200)) + assert.True(t, forkManager.IsForkEnabled(ForkD, 300)) + assert.True(t, forkManager.IsForkEnabled(ForkD, 400)) + + assert.False(t, forkManager.IsForkEnabled(ForkE, 0)) + }) + + t.Run("is fork supported", func(t *testing.T) { + t.Parallel() + + assert.True(t, forkManager.IsForkRegistered(ForkA)) + assert.True(t, forkManager.IsForkRegistered(ForkB)) + assert.True(t, forkManager.IsForkRegistered(ForkC)) + assert.True(t, forkManager.IsForkRegistered(ForkD)) + + assert.False(t, forkManager.IsForkRegistered(ForkE)) + }) + + t.Run("get fork block", func(t *testing.T) { + t.Parallel() + + b, err := forkManager.GetForkBlock(ForkA) + assert.NoError(t, err) + assert.Equal(t, uint64(0), b) + + b, err = forkManager.GetForkBlock(ForkB) + assert.NoError(t, err) + assert.Equal(t, uint64(100), b) + + b, err = forkManager.GetForkBlock(ForkC) + assert.NoError(t, err) + assert.Equal(t, uint64(200), b) + + b, err = forkManager.GetForkBlock(ForkD) + assert.NoError(t, err) + assert.Equal(t, uint64(300), b) + + _, err = forkManager.GetForkBlock(ForkE) + assert.Error(t, err) + }) + + t.Run("register handler not existing fork", func(t *testing.T) { + t.Parallel() + + assert.Error(t, forkManager.RegisterHandler(ForkE, HandlerD, func() {})) + }) + + t.Run("get handler", func(t *testing.T) { + t.Parallel() + + execute := func(name HandlerDesc, block uint64) string { + //nolint:forcetypeassert + return forkManager.GetHandler(name, block).(func() string)() + } + + for i := uint64(0); i < uint64(4); i++ { + assert.Equal(t, "AAH", execute(HandlerA, i)) + assert.Equal(t, "BAH", execute(HandlerB, i)) + assert.Nil(t, forkManager.GetHandler(HandlerC, i)) + + assert.Equal(t, "AAH", execute(HandlerA, 100+i)) + assert.Equal(t, "BBH", execute(HandlerB, 100+i)) + assert.Nil(t, forkManager.GetHandler(HandlerC, 100+i)) + + assert.Equal(t, "ACH", execute(HandlerA, 200+i)) + assert.Equal(t, "BBH", execute(HandlerB, 200+i)) + assert.Equal(t, "CCH", execute(HandlerC, 200+i)) + + assert.Equal(t, "ACH", execute(HandlerA, 300+i)) + assert.Equal(t, "BDH", execute(HandlerB, 300+i)) + assert.Equal(t, "CCH", execute(HandlerC, 300+i)) + } + + assert.Nil(t, forkManager.GetHandler(HandlerD, 0)) + }) + + t.Run("get params", func(t *testing.T) { + t.Parallel() + + for i := uint64(0); i < uint64(4); i++ { + assert.Equal(t, es1, *forkManager.GetParams(i).EpochSize) + assert.Equal(t, es2, *forkManager.GetParams(i + 100).EpochSize) + assert.Equal(t, es2, *forkManager.GetParams(i + 200).EpochSize) + assert.Equal(t, es3, *forkManager.GetParams(i + 300).EpochSize) + + assert.Nil(t, forkManager.GetParams(i).MaxValidatorSetSize) + assert.Equal(t, mss1, *forkManager.GetParams(i + 100).MaxValidatorSetSize) + assert.Equal(t, mss1, *forkManager.GetParams(i + 200).MaxValidatorSetSize) + assert.Equal(t, mss1, *forkManager.GetParams(i + 300).MaxValidatorSetSize) + + assert.Equal(t, bt1, *forkManager.GetParams(i).BlockTime) + assert.Equal(t, bt1, *forkManager.GetParams(i + 100).BlockTime) + assert.Equal(t, bt1, *forkManager.GetParams(i + 200).BlockTime) + assert.Equal(t, bt2, *forkManager.GetParams(i + 300).BlockTime) + } + }) +} + +func TestForkManager_Deactivate(t *testing.T) { + t.Parallel() + + forkManager := &forkManager{ + forkMap: map[string]*Fork{}, + handlersMap: map[HandlerDesc][]forkHandler{}, + } + mvs1, mvs2 := uint64(1), uint64(2) + + forkManager.RegisterFork(ForkA, &chain.ForkParams{MaxValidatorSetSize: &mvs1}) + forkManager.RegisterFork(ForkB, &chain.ForkParams{MaxValidatorSetSize: &mvs2}) + forkManager.RegisterFork(ForkC, &chain.ForkParams{}) + + assert.NoError(t, forkManager.RegisterHandler(ForkA, HandlerA, func() string { return "AAH" })) + assert.NoError(t, forkManager.RegisterHandler(ForkB, HandlerA, func() string { return "ABH" })) + + assert.NoError(t, forkManager.ActivateFork(ForkB, 10)) + assert.NoError(t, forkManager.ActivateFork(ForkC, 20)) + assert.NoError(t, forkManager.ActivateFork(ForkA, 0)) + + assert.Equal(t, 2, len(forkManager.handlersMap[HandlerA])) + assert.Equal(t, 3, len(forkManager.params)) + assert.Equal(t, mvs2, *forkManager.GetParams(30).MaxValidatorSetSize) + + assert.NoError(t, forkManager.DeactivateFork(ForkA)) + + assert.Equal(t, 1, len(forkManager.handlersMap[HandlerA])) + assert.Equal(t, 2, len(forkManager.params)) + assert.Nil(t, forkManager.GetParams(0)) + + assert.NoError(t, forkManager.DeactivateFork(ForkC)) + + assert.Equal(t, 1, len(forkManager.handlersMap[HandlerA])) + assert.Equal(t, 1, len(forkManager.params)) + + assert.NoError(t, forkManager.DeactivateFork(ForkB)) + + assert.Equal(t, 0, len(forkManager.handlersMap[HandlerA])) + assert.Equal(t, 0, len(forkManager.params)) +} diff --git a/gasprice/gasprice.go b/gasprice/gasprice.go new file mode 100644 index 0000000000..a800a26002 --- /dev/null +++ b/gasprice/gasprice.go @@ -0,0 +1,254 @@ +package gasprice + +import ( + "fmt" + "math/big" + "sort" + "sync" + + "github.com/0xPolygon/polygon-edge/chain" + "github.com/0xPolygon/polygon-edge/crypto" + "github.com/0xPolygon/polygon-edge/types" + "github.com/umbracle/ethgo" +) + +const couldNotFoundBlockFormat = "could not find block. Number: %d, Hash: %s" + +// DefaultGasHelperConfig is the default config for gas helper (as per ethereum) +var DefaultGasHelperConfig = &Config{ + NumOfBlocksToCheck: 20, + PricePercentile: 60, + SampleNumber: 3, + MaxPrice: ethgo.Gwei(500), + LastPrice: ethgo.Gwei(1), + IgnorePrice: big.NewInt(2), // 2 wei +} + +// Config is a struct that holds configuration of GasHelper +type Config struct { + // NumOfBlocksToCheck is the number of blocks to sample + NumOfBlocksToCheck uint64 + // PricePercentile is the sample percentile of transactions in a block + PricePercentile uint64 + // SampleNumber is number of transactions sampled in a block + SampleNumber uint64 + // MaxPrice is the tip max price + MaxPrice *big.Int + // LastPrice is the last price returned for maxPriorityFeePerGas + // when starting node it will be some default value + LastPrice *big.Int + // IgnorePrice is the lowest price to take into consideration + // when collecting transactions + IgnorePrice *big.Int +} + +// Blockchain is the interface representing blockchain +type Blockchain interface { + GetBlockByHash(hash types.Hash, full bool) (*types.Block, bool) + Header() *types.Header + Config() *chain.Params +} + +// GasStore interface is providing functions regarding gas and fees +type GasStore interface { + // MaxPriorityFeePerGas calculates the priority fee needed for transaction to be included in a block + MaxPriorityFeePerGas() (*big.Int, error) +} + +var _ GasStore = (*GasHelper)(nil) + +// GasHelper struct implements functions from the GasStore interface +type GasHelper struct { + // numOfBlocksToCheck is the number of blocks to sample + numOfBlocksToCheck uint64 + // pricePercentile is the sample percentile of transactions in a block + pricePercentile uint64 + // sampleNumber is number of transactions sampled in a block + sampleNumber uint64 + // maxPrice is the tip max price + maxPrice *big.Int + // lastPrice is the last price returned for maxPriorityFeePerGas + lastPrice *big.Int + // ignorePrice is the lowest price to take into consideration + // when collecting transactions + ignorePrice *big.Int + // backend is an abstraction of blockchain + backend Blockchain + // lastHeaderHash is the last header for which maxPriorityFeePerGas was returned + lastHeaderHash types.Hash + + lock sync.Mutex +} + +// NewGasHelper is the constructor function for GasHelper struct +func NewGasHelper(config *Config, backend Blockchain) *GasHelper { + pricePercentile := config.PricePercentile + if pricePercentile > 100 { + pricePercentile = 100 + } + + return &GasHelper{ + numOfBlocksToCheck: config.NumOfBlocksToCheck, + pricePercentile: pricePercentile, + sampleNumber: config.SampleNumber, + ignorePrice: config.IgnorePrice, + lastPrice: config.LastPrice, + maxPrice: config.MaxPrice, + backend: backend, + } +} + +// MaxPriorityFeePerGas calculates the priority fee needed for transaction to be included in a block +// The function does following: +// - takes chain header +// - iterates for numOfBlocksToCheck from chain header to previous blocks +// - collects at most the sample number of sorted transactions in block +// - if not enough transactions were collected and their tips, go through some more blocks to get +// more accurate calculation +// - when enough transactions and their tips are collected, take the one that is in pricePercentile +// - if given price is larger then maxPrice then return the maxPrice +func (g *GasHelper) MaxPriorityFeePerGas() (*big.Int, error) { + currentHeader := g.backend.Header() + + currentBlock, found := g.backend.GetBlockByHash(currentHeader.Hash, true) + if !found { + return nil, fmt.Errorf(couldNotFoundBlockFormat, currentHeader.Number, currentHeader.Hash) + } + + g.lock.Lock() + lastPrice := g.lastPrice + lastHeader := g.lastHeaderHash + g.lock.Unlock() + + if currentHeader.Hash == lastHeader { + // small optimization, if we calculated already the price for given block + return new(big.Int).Set(lastPrice), nil + } + + var allPrices []*big.Int + + collectPrices := func(block *types.Block) error { + baseFee := block.Header.BaseFee + txSorter := newTxByEffectiveTipSorter(block.Transactions, baseFee) + sort.Sort(txSorter) + + blockMiner := types.BytesToAddress(block.Header.Miner) + signer := crypto.NewSigner(g.backend.Config().Forks.At(block.Number()), + uint64(g.backend.Config().ChainID)) + blockTxPrices := make([]*big.Int, 0) + + for _, tx := range txSorter.txs { + tip := tx.EffectiveTip(baseFee) + + if tip.Cmp(g.ignorePrice) == -1 { + // ignore transactions with tip lower than ignore price + continue + } + + sender, err := signer.Sender(tx) + if err != nil { + return fmt.Errorf("could not get sender of transaction: %s. Error: %w", tx.Hash, err) + } + + if sender != blockMiner { + blockTxPrices = append(blockTxPrices, tip) + + // if sample number of txs from block is reached, + // don't process any more txs + if len(blockTxPrices) >= int(g.sampleNumber) { + break + } + } + } + + if len(blockTxPrices) == 0 { + // either block is empty or all transactions in block are sent by the miner. + // in this case add the latests calculated price for sampling + blockTxPrices = append(blockTxPrices, lastPrice) + } + + // add the block prices to the slice of all prices + allPrices = append(allPrices, blockTxPrices...) + + return nil + } + + // iterate from current block to previous blocks determined by numOfBlocksToCheck + // if chain doesn't have that many blocks, we need to stop the loop (currentBlock.Number() > 0) + for i := uint64(0); i < g.numOfBlocksToCheck && currentBlock.Number() > 0; i++ { + if err := collectPrices(currentBlock); err != nil { + return nil, err + } + + currentBlock, found = g.backend.GetBlockByHash(currentBlock.ParentHash(), true) + if !found { + return nil, fmt.Errorf(couldNotFoundBlockFormat, currentHeader.Number, currentHeader.Hash) + } + } + + // at least amount of transactions to get + minNumOfTx := int(g.numOfBlocksToCheck) * 2 + // collect some more blocks and transactions if not enough transactions were collected + for len(allPrices) < minNumOfTx && currentBlock.Number() > 0 { + if err := collectPrices(currentBlock); err != nil { + return nil, err + } + } + + price := lastPrice + + if len(allPrices) > 0 { + // sort prices from lowest to highest + sort.Slice(allPrices, func(i, j int) bool { + return allPrices[i].Cmp(allPrices[j]) < 0 + }) + // take the biggest price that is in the configured percentage + // by default it's 60, so it will take the price on that percentage + // of all prices in the array + price = allPrices[(len(allPrices)-1)*int(g.pricePercentile)/100] + } + + if price.Cmp(g.maxPrice) > 0 { + // if price is larger than the configured max price + // return max price + price = new(big.Int).Set(g.maxPrice) + } + + // cache the calculated price and header hash + g.lock.Lock() + g.lastPrice = price + g.lastHeaderHash = currentHeader.Hash + g.lock.Unlock() + + return price, nil +} + +// txSortedByEffectiveTip sorts transactions by effective tip from smallest to largest +type txSortedByEffectiveTip struct { + txs []*types.Transaction + baseFee uint64 +} + +// newTxByEffectiveTipSorter is constructor function for txSortedByEffectiveTip +func newTxByEffectiveTipSorter(txs []*types.Transaction, baseFee uint64) *txSortedByEffectiveTip { + return &txSortedByEffectiveTip{ + txs: txs, + baseFee: baseFee, + } +} + +// Len is implementation of sort.Interface +func (t *txSortedByEffectiveTip) Len() int { return len(t.txs) } + +// Swap is implementation of sort.Interface +func (t *txSortedByEffectiveTip) Swap(i, j int) { + t.txs[i], t.txs[j] = t.txs[j], t.txs[i] +} + +// Less is implementation of sort.Interface +func (t *txSortedByEffectiveTip) Less(i, j int) bool { + tip1 := t.txs[i].EffectiveTip(t.baseFee) + tip2 := t.txs[j].EffectiveTip(t.baseFee) + + return tip1.Cmp(tip2) < 0 +} diff --git a/gasprice/gasprice_test.go b/gasprice/gasprice_test.go new file mode 100644 index 0000000000..f4ff7bbde3 --- /dev/null +++ b/gasprice/gasprice_test.go @@ -0,0 +1,266 @@ +package gasprice + +import ( + "fmt" + "math/big" + "math/rand" + "testing" + "time" + + "github.com/0xPolygon/polygon-edge/chain" + "github.com/0xPolygon/polygon-edge/crypto" + "github.com/0xPolygon/polygon-edge/helper/tests" + "github.com/0xPolygon/polygon-edge/types" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/umbracle/ethgo" +) + +func TestGasHelper_MaxPriorityFeePerGas(t *testing.T) { + t.Parallel() + + var cases = []struct { + Name string + Expected *big.Int + Error bool + GetBackend func() Blockchain + }{ + { + Name: "Chain just started", + Expected: DefaultGasHelperConfig.LastPrice, + GetBackend: func() Blockchain { + genesis := &types.Header{ + Number: 0, + Hash: types.StringToHash("genesis"), + } + backend := new(backendMock) + backend.On("Header").Return(genesis) + backend.On("GetBlockByHash", mock.Anything, true).Return(&types.Block{ + Header: genesis, + Transactions: []*types.Transaction{}, + }, true) + + return backend + }, + }, + { + Name: "Block does not exist", + Error: true, + GetBackend: func() Blockchain { + header := &types.Header{ + Number: 0, + Hash: types.StringToHash("some header"), + } + backend := new(backendMock) + backend.On("Header").Return(header) + backend.On("GetBlockByHash", mock.Anything, true).Return(&types.Block{}, false) + + return backend + }, + }, + { + Name: "Empty blocks", + Expected: DefaultGasHelperConfig.LastPrice, // should return last (default) price + GetBackend: func() Blockchain { + backend := createTestBlocks(t, 10) + + return backend + }, + }, + { + Name: "All transactions by miner", + Expected: DefaultGasHelperConfig.LastPrice, // should return last (default) price + GetBackend: func() Blockchain { + backend := createTestBlocks(t, 10) + rand.Seed(time.Now().UTC().UnixNano()) + + senderKey, sender := tests.GenerateKeyAndAddr(t) + + for _, b := range backend.blocks { + signer := crypto.NewSigner(backend.Config().Forks.At(b.Number()), + uint64(backend.Config().ChainID)) + + b.Transactions = make([]*types.Transaction, 3) + b.Header.Miner = sender.Bytes() + + for i := 0; i < 3; i++ { + tx := &types.Transaction{ + From: sender, + Value: ethgo.Ether(1), + To: &types.ZeroAddress, + Type: types.DynamicFeeTx, + GasTipCap: ethgo.Gwei(uint64(rand.Intn(200))), + GasFeeCap: ethgo.Gwei(uint64(rand.Intn(200) + 200)), + } + + tx, err := signer.SignTx(tx, senderKey) + require.NoError(t, err) + + b.Transactions[i] = tx + } + } + + return backend + }, + }, + { + Name: "All transactions have small effective tip", + Expected: DefaultGasHelperConfig.LastPrice, // should return last (default) price + GetBackend: func() Blockchain { + backend := createTestBlocks(t, 10) + createTestTxs(t, backend, 3, 1) + + return backend + }, + }, + { + Name: "Number of blocks in chain smaller than numOfBlocksToCheck", + Expected: DefaultGasHelperConfig.LastPrice.Mul( + DefaultGasHelperConfig.LastPrice, big.NewInt(2)), // at least two times of default last price + GetBackend: func() Blockchain { + backend := createTestBlocks(t, 10) + createTestTxs(t, backend, 3, 200) + + return backend + }, + }, + { + Name: "Number of blocks in chain higher than numOfBlocksToCheck", + Expected: DefaultGasHelperConfig.LastPrice.Mul( + DefaultGasHelperConfig.LastPrice, big.NewInt(2)), // at least two times of default last price + GetBackend: func() Blockchain { + backend := createTestBlocks(t, 30) + createTestTxs(t, backend, 3, 200) + + return backend + }, + }, + { + Name: "Not enough transactions in first 20 blocks, so read some more blocks", + Expected: DefaultGasHelperConfig.LastPrice.Mul( + DefaultGasHelperConfig.LastPrice, big.NewInt(2)), // at least two times of default last price + GetBackend: func() Blockchain { + backend := createTestBlocks(t, 50) + createTestTxs(t, backend, 1, 200) + + return backend + }, + }, + } + + for _, tc := range cases { + tc := tc + t.Run(tc.Name, func(t *testing.T) { + t.Parallel() + + backend := tc.GetBackend() + gasHelper := NewGasHelper(DefaultGasHelperConfig, backend) + price, err := gasHelper.MaxPriorityFeePerGas() + + if tc.Error { + require.Error(t, err) + } else { + require.NoError(t, err) + require.True(t, price.Cmp(tc.Expected) >= 0) + } + }) + } +} + +func createTestBlocks(t *testing.T, numOfBlocks int) *backendMock { + t.Helper() + + backend := &backendMock{blocks: make(map[types.Hash]*types.Block)} + genesis := &types.Block{ + Header: &types.Header{ + Number: 0, + Hash: types.StringToHash("genesis"), + Miner: types.ZeroAddress.Bytes(), + BaseFee: chain.GenesisBaseFee, + }, + } + backend.blocks[genesis.Hash()] = genesis + + currentBlock := genesis + + for i := 1; i <= numOfBlocks; i++ { + block := &types.Block{ + Header: &types.Header{ + Number: uint64(i), + Hash: types.BytesToHash([]byte(fmt.Sprintf("Block %d", i))), + Miner: types.ZeroAddress.Bytes(), + ParentHash: currentBlock.Hash(), + }, + } + + backend.blocks[block.Hash()] = block + currentBlock = block + } + + backend.On("Header").Return(currentBlock.Header) + + return backend +} + +func createTestTxs(t *testing.T, backend *backendMock, numOfTxsPerBlock, txCap int) { + t.Helper() + + rand.Seed(time.Now().UTC().UnixNano()) + + for _, b := range backend.blocks { + signer := crypto.NewSigner(backend.Config().Forks.At(b.Number()), + uint64(backend.Config().ChainID)) + + b.Transactions = make([]*types.Transaction, numOfTxsPerBlock) + + for i := 0; i < numOfTxsPerBlock; i++ { + senderKey, sender := tests.GenerateKeyAndAddr(t) + + tx := &types.Transaction{ + From: sender, + Value: ethgo.Ether(1), + To: &types.ZeroAddress, + Type: types.DynamicFeeTx, + GasTipCap: ethgo.Gwei(uint64(rand.Intn(txCap))), + GasFeeCap: ethgo.Gwei(uint64(rand.Intn(txCap) + txCap)), + } + + tx, err := signer.SignTx(tx, senderKey) + require.NoError(t, err) + + b.Transactions[i] = tx + } + } +} + +var _ Blockchain = (*backendMock)(nil) + +type backendMock struct { + mock.Mock + blocks map[types.Hash]*types.Block +} + +func (b *backendMock) Header() *types.Header { + args := b.Called() + + return args.Get(0).(*types.Header) //nolint:forcetypeassert +} + +func (b *backendMock) GetBlockByHash(hash types.Hash, full bool) (*types.Block, bool) { + if len(b.blocks) == 0 { + args := b.Called(hash, full) + + return args.Get(0).(*types.Block), args.Get(1).(bool) //nolint:forcetypeassert + } + + block, exists := b.blocks[hash] + + return block, exists +} + +func (b *backendMock) Config() *chain.Params { + return &chain.Params{ + ChainID: 1, + Forks: chain.AllForksEnabled, + } +} diff --git a/go.mod b/go.mod index e0b6d1afe3..dae9a321e4 100644 --- a/go.mod +++ b/go.mod @@ -1,235 +1,232 @@ module github.com/0xPolygon/polygon-edge -go 1.18 +go 1.20 require ( github.com/btcsuite/btcd v0.22.1 - github.com/containerd/cgroups v1.0.4 // indirect + github.com/containerd/cgroups v1.1.0 // indirect github.com/elastic/gosigar v0.14.2 // indirect - github.com/envoyproxy/protoc-gen-validate v0.9.1 - github.com/golang/protobuf v1.5.2 + github.com/envoyproxy/protoc-gen-validate v1.0.2 + github.com/golang/protobuf v1.5.3 github.com/google/uuid v1.3.0 github.com/gorilla/websocket v1.5.0 - github.com/hashicorp/go-hclog v1.3.1 + github.com/hashicorp/go-hclog v1.5.0 github.com/hashicorp/go-immutable-radix v1.3.1 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d github.com/hashicorp/hcl v1.0.0 - github.com/hashicorp/vault/api v1.8.2 - github.com/libp2p/go-libp2p v0.22.0 - github.com/libp2p/go-libp2p-kbucket v0.5.0 - github.com/libp2p/go-libp2p-pubsub v0.8.1 - github.com/miekg/dns v1.1.50 // indirect - github.com/multiformats/go-base32 v0.0.4 // indirect - github.com/multiformats/go-multiaddr v0.7.0 - github.com/multiformats/go-multihash v0.2.1 // indirect - github.com/onsi/ginkgo v1.16.5 // indirect - github.com/prometheus/client_golang v1.13.1 + github.com/hashicorp/vault/api v1.9.2 + github.com/libp2p/go-libp2p v0.27.6 + github.com/libp2p/go-libp2p-kbucket v0.6.0 + github.com/libp2p/go-libp2p-pubsub v0.9.3 + github.com/miekg/dns v1.1.53 // indirect + github.com/multiformats/go-base32 v0.1.0 // indirect + github.com/multiformats/go-multiaddr v0.9.0 + github.com/multiformats/go-multihash v0.2.3 // indirect + github.com/prometheus/client_golang v1.16.0 github.com/ryanuber/columnize v2.1.2+incompatible - github.com/spf13/cobra v1.6.1 - github.com/stretchr/testify v1.8.1 + github.com/spf13/cobra v1.7.0 + github.com/stretchr/testify v1.8.4 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 - github.com/umbracle/fastrlp v0.0.0-20220527094140-59d5dd30e722 + github.com/umbracle/fastrlp v0.1.1-0.20230504065717-58a1b8a9929d github.com/umbracle/go-eth-bn256 v0.0.0-20230125114011-47cb310d9b0b - golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e - google.golang.org/grpc v1.50.1 - google.golang.org/protobuf v1.28.1 + golang.org/x/crypto v0.10.0 + google.golang.org/grpc v1.53.0-dev + google.golang.org/protobuf v1.31.0 gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce ) require ( - cloud.google.com/go/secretmanager v1.8.0 + cloud.google.com/go/secretmanager v1.10.0 github.com/armon/go-metrics v0.4.1 github.com/aws/aws-sdk-go v1.44.61 github.com/benbjohnson/clock v1.3.0 // indirect github.com/coinbase/kryptology v1.8.0 github.com/fatih/color v1.13.0 // indirect - github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect - github.com/ipfs/go-cid v0.2.0 // indirect - github.com/klauspost/compress v1.15.5 // indirect + github.com/ipfs/go-cid v0.4.1 // indirect + github.com/klauspost/compress v1.16.4 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mitchellh/mapstructure v1.5.0 - github.com/umbracle/ethgo v0.1.4-0.20230126112511-6a4d02533af6 + github.com/umbracle/ethgo v0.1.4-0.20230622091706-8230f57578b2 github.com/valyala/fastjson v1.6.3 // indirect - go.uber.org/zap v1.22.0 // indirect - golang.org/x/sys v0.4.0 // indirect - golang.org/x/tools v0.3.0 - google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e + go.uber.org/zap v1.24.0 // indirect + golang.org/x/sys v0.9.0 // indirect + golang.org/x/tools v0.10.0 gopkg.in/yaml.v3 v3.0.1 - lukechampine.com/blake3 v1.1.7 // indirect + lukechampine.com/blake3 v1.2.1 // indirect ) require ( - github.com/0xPolygon/go-ibft v0.4.0 + github.com/0xPolygon/go-ibft v0.4.1-0.20230612114712-fa4235351cbc github.com/docker/docker v20.10.18+incompatible github.com/docker/go-connections v0.4.0 - go.etcd.io/bbolt v1.3.6 + go.etcd.io/bbolt v1.3.7 ) require ( - github.com/dave/jennifer v1.6.0 + github.com/dave/jennifer v1.6.1 github.com/quasilyte/go-ruleguard v0.3.19 github.com/quasilyte/go-ruleguard/dsl v0.3.22 - golang.org/x/sync v0.1.0 - gopkg.in/DataDog/dd-trace-go.v1 v1.43.1 - pgregory.net/rapid v0.5.5 + github.com/sethvargo/go-retry v0.2.4 + golang.org/x/sync v0.3.0 + google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2 + gopkg.in/DataDog/dd-trace-go.v1 v1.51.0 + pgregory.net/rapid v1.0.0 ) require ( - cloud.google.com/go/compute v1.10.0 // indirect - cloud.google.com/go/iam v0.5.0 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + github.com/DataDog/appsec-internal-go v1.0.0 // indirect + github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.45.0 // indirect + github.com/DataDog/go-libddwaf v1.2.0 // indirect + github.com/DataDog/go-tuf v0.3.0--fix-localmeta-fork // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-jose/go-jose/v3 v3.0.0 // indirect + github.com/golang/mock v1.6.0 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.2 // indirect + github.com/ipfs/go-ipfs-util v0.0.2 // indirect + github.com/libp2p/go-yamux/v4 v4.0.0 // indirect + github.com/onsi/ginkgo/v2 v2.9.2 // indirect + github.com/outcaste-io/ristretto v0.2.1 // indirect + github.com/quic-go/qpack v0.4.0 // indirect + github.com/quic-go/qtls-go1-19 v0.3.2 // indirect + github.com/quic-go/qtls-go1-20 v0.2.2 // indirect + github.com/quic-go/quic-go v0.33.0 // indirect + github.com/quic-go/webtransport-go v0.5.2 // indirect + github.com/richardartoul/molecule v1.0.1-0.20221107223329-32cfee06a052 // indirect + github.com/rogpeppe/go-internal v1.10.0 // indirect + github.com/secure-systems-lab/go-securesystemslib v0.6.0 // indirect + go.uber.org/dig v1.16.1 // indirect + go.uber.org/fx v1.19.2 // indirect + golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect + nhooyr.io/websocket v1.8.7 // indirect +) + +require ( + cloud.google.com/go/compute v1.18.0 // indirect + cloud.google.com/go/iam v0.10.0 // indirect filippo.io/edwards25519 v1.0.0-rc.1 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect - github.com/DataDog/datadog-agent/pkg/obfuscate v0.0.0-20211129110424-6491aa3bf583 // indirect - github.com/DataDog/datadog-go v4.8.2+incompatible // indirect - github.com/DataDog/datadog-go/v5 v5.0.2 // indirect + github.com/DataDog/datadog-agent/pkg/obfuscate v0.45.0-rc.1 // indirect + github.com/DataDog/datadog-go/v5 v5.1.1 // indirect github.com/DataDog/gostackparse v0.5.0 // indirect github.com/DataDog/sketches-go v1.2.1 // indirect - github.com/Microsoft/go-winio v0.5.1 // indirect + github.com/Microsoft/go-winio v0.6.0 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/andybalholm/brotli v1.0.4 // indirect - github.com/armon/go-radix v1.0.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce // indirect github.com/bwesterb/go-ristretto v1.2.0 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cenkalti/backoff/v3 v3.2.2 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/cheekybits/genny v1.0.0 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/consensys/gnark-crypto v0.5.3 // indirect - github.com/containerd/continuity v0.0.0-20191214063359-1097c8bae83b // indirect - github.com/coreos/go-systemd/v22 v22.3.2 // indirect + github.com/containerd/continuity v0.3.0 // indirect + github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect - github.com/dgraph-io/ristretto v0.1.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/docker/distribution v2.8.1+incompatible // indirect - github.com/docker/go-units v0.4.0 // indirect + github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.0 // indirect github.com/flynn/noise v1.0.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect - github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/go-toolsmith/astcopy v1.0.2 // indirect github.com/go-toolsmith/astequal v1.0.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect - github.com/googleapis/gax-go/v2 v2.6.0 // indirect + github.com/google/pprof v0.0.0-20230509042627-b1315fad0c5a // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect + github.com/googleapis/gax-go/v2 v2.7.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-plugin v1.4.5 // indirect github.com/hashicorp/go-retryablehttp v0.7.1 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect - github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 // indirect github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect github.com/hashicorp/go-sockaddr v1.0.2 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect - github.com/hashicorp/go-version v1.5.0 // indirect - github.com/hashicorp/vault/sdk v0.6.0 // indirect - github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect - github.com/huin/goupnp v1.0.3 // indirect - github.com/inconshreveable/mousetrap v1.0.1 // indirect - github.com/ipfs/go-ipfs-util v0.0.2 // indirect + github.com/huin/goupnp v1.1.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/ipfs/go-log v1.0.5 // indirect github.com/ipfs/go-log/v2 v2.5.1 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/klauspost/cpuid/v2 v2.1.0 // indirect - github.com/koron/go-ssdp v0.0.3 // indirect + github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/koron/go-ssdp v0.0.4 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect github.com/libp2p/go-flow-metrics v0.1.0 // indirect - github.com/libp2p/go-libp2p-asn-util v0.2.0 // indirect - github.com/libp2p/go-msgio v0.2.0 // indirect + github.com/libp2p/go-libp2p-asn-util v0.3.0 // indirect + github.com/libp2p/go-msgio v0.3.0 // indirect github.com/libp2p/go-nat v0.1.0 // indirect - github.com/libp2p/go-netroute v0.2.0 // indirect - github.com/libp2p/go-openssl v0.1.0 // indirect + github.com/libp2p/go-netroute v0.2.1 // indirect github.com/libp2p/go-reuseport v0.2.0 // indirect - github.com/libp2p/go-yamux/v3 v3.1.2 // indirect - github.com/lucas-clemente/quic-go v0.28.1 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect - github.com/marten-seemann/qtls-go1-17 v0.1.2 // indirect - github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect - github.com/marten-seemann/qtls-go1-19 v0.1.0 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect - github.com/mattn/go-isatty v0.0.16 // indirect - github.com/mattn/go-pointer v0.0.1 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect - github.com/minio/sha256-simd v1.0.0 // indirect - github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/minio/sha256-simd v1.0.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/go-testing-interface v1.14.1 // indirect - github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect - github.com/multiformats/go-base36 v0.1.0 // indirect + github.com/multiformats/go-base36 v0.2.0 // indirect github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect - github.com/multiformats/go-multibase v0.1.1 // indirect - github.com/multiformats/go-multicodec v0.5.0 // indirect - github.com/multiformats/go-multistream v0.3.3 // indirect - github.com/multiformats/go-varint v0.0.6 // indirect - github.com/nxadm/tail v1.4.8 // indirect - github.com/oklog/run v1.1.0 // indirect - github.com/opencontainers/go-digest v1.0.0-rc1 // indirect - github.com/opencontainers/image-spec v1.0.1 // indirect - github.com/opencontainers/runc v0.1.1 // indirect - github.com/opencontainers/runtime-spec v1.0.2 // indirect + github.com/multiformats/go-multibase v0.2.0 // indirect + github.com/multiformats/go-multicodec v0.9.0 // indirect + github.com/multiformats/go-multistream v0.4.1 // indirect + github.com/multiformats/go-varint v0.0.7 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.0.2 // indirect + github.com/opencontainers/runc v1.1.5 // indirect + github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/ory/dockertest v3.3.5+incompatible // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/philhofer/fwd v1.1.1 // indirect - github.com/pierrec/lz4 v2.6.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.42.0 // indirect + github.com/prometheus/procfs v0.10.1 // indirect github.com/quasilyte/gogrep v0.5.0 // indirect github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect github.com/sirupsen/logrus v1.8.1 // indirect - github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.0 // indirect - github.com/tinylib/msgp v1.1.2 // indirect + github.com/tinylib/msgp v1.1.6 // indirect + github.com/trailofbits/go-fuzz-utils v0.0.0-20210901195358-9657fcfd256c github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.37.0 // indirect - github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee // indirect - go.opencensus.io v0.23.0 // indirect - go.uber.org/atomic v1.10.0 // indirect - go.uber.org/multierr v1.8.0 // indirect + go.opencensus.io v0.24.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/multierr v1.11.0 // indirect go4.org/intern v0.0.0-20211027215823-ae77deb06f29 // indirect go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 // indirect golang.org/x/exp/typeparams v0.0.0-20221002003631-540bb7301a08 // indirect - golang.org/x/mod v0.7.0 // indirect - golang.org/x/net v0.2.0 // indirect - golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1 // indirect - golang.org/x/text v0.4.0 // indirect - golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect + golang.org/x/mod v0.11.0 // indirect + golang.org/x/net v0.11.0 // indirect + golang.org/x/oauth2 v0.8.0 // indirect + golang.org/x/text v0.10.0 // indirect + golang.org/x/time v0.3.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/api v0.99.0 // indirect + google.golang.org/api v0.109.0 // indirect google.golang.org/appengine v1.6.7 // indirect - gopkg.in/square/go-jose.v2 v2.6.0 // indirect - gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gotest.tools/v3 v3.0.2 // indirect - inet.af/netaddr v0.0.0-20220617031823-097006376321 // indirect + inet.af/netaddr v0.0.0-20220811202034-502d2d690317 // indirect ) diff --git a/go.sum b/go.sum index 7d517bd6c5..69ab694e0c 100644 --- a/go.sum +++ b/go.sum @@ -1,75 +1,50 @@ -bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.104.0 h1:gSmWO7DY1vOm0MVU6DNXM11BWHHsTUmsC5cv1fuW5X8= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.10.0 h1:aoLIYaA1fX3ywihqpBk2APQKOo20nXsp1GEZQbx5Jk4= -cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/iam v0.5.0 h1:fz9X5zyTWBmamZsqvqZqD7khbifcZF/q+Z1J8pfhIUg= -cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/secretmanager v1.8.0 h1:4wYWL2t10q+xUtFFS0QuWlqwQguMrwC6FDpjtMM6cUI= -cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go v0.107.0 h1:qkj22L7bgkl6vIeZDlOY2po43Mx/TIa2Wsa7VR+PEww= +cloud.google.com/go/compute v1.18.0 h1:FEigFqoDbys2cvFkZ9Fjq4gnHBP55anJ0yQyau2f9oY= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/iam v0.10.0 h1:fpP/gByFs6US1ma53v7VxhvbJpO2Aapng6wabJ99MuI= +cloud.google.com/go/iam v0.10.0/go.mod h1:nXAECrMt2qHpF6RZUZseteD6QyanL68reN4OXPw0UWM= +cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs= +cloud.google.com/go/secretmanager v1.10.0 h1:pu03bha7ukxF8otyPKTFdDz+rr9sE3YauS5PliDXK60= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -github.com/0xPolygon/go-ibft v0.3.0 h1:4j8yaRgArErnZy1alQUHOSStD/ogAoEWVRn/CG0JlvI= -github.com/0xPolygon/go-ibft v0.3.0/go.mod h1:mJGwdcGvLdg9obtnzBqx1aAzuhzvGeWav5AiUWN7F3Q= -github.com/0xPolygon/go-ibft v0.4.0 h1:WwevpA/J5PI2ztQuIis/0uRlVZrJgps9NhPewoYZDus= -github.com/0xPolygon/go-ibft v0.4.0/go.mod h1:mJGwdcGvLdg9obtnzBqx1aAzuhzvGeWav5AiUWN7F3Q= +github.com/0xPolygon/go-ibft v0.4.1-0.20230612114712-fa4235351cbc h1:LSrOswaGy5kmLZTr8B1t5WnSpm8plYGAmdrUd6lGhRw= +github.com/0xPolygon/go-ibft v0.4.1-0.20230612114712-fa4235351cbc/go.mod h1:mJGwdcGvLdg9obtnzBqx1aAzuhzvGeWav5AiUWN7F3Q= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-agent/pkg/obfuscate v0.0.0-20211129110424-6491aa3bf583 h1:3nVO1nQyh64IUY6BPZUpMYMZ738Pu+LsMt3E0eqqIYw= -github.com/DataDog/datadog-agent/pkg/obfuscate v0.0.0-20211129110424-6491aa3bf583/go.mod h1:EP9f4GqaDJyP1F5jTNMtzdIpw3JpNs3rMSJOnYywCiw= +github.com/DataDog/appsec-internal-go v1.0.0 h1:2u5IkF4DBj3KVeQn5Vg2vjPUtt513zxEYglcqnd500U= +github.com/DataDog/appsec-internal-go v1.0.0/go.mod h1:+Y+4klVWKPOnZx6XESG7QHydOaUGEXyH2j/vSg9JiNM= +github.com/DataDog/datadog-agent/pkg/obfuscate v0.45.0-rc.1 h1:XyYvstMFpSyZtfJHWJm1Sf1meNyCdfhKJrjB6+rUNOk= +github.com/DataDog/datadog-agent/pkg/obfuscate v0.45.0-rc.1/go.mod h1:e933RWa4kAWuHi5jpzEuOiULlv21HcCFEVIYegmaB5c= +github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.45.0 h1:pnZo84OurElmbC/ibYrw1pZfaEFEEP2m8MgSSZK/D2U= +github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.45.0/go.mod h1:VVMDDibJxYEkwcLdZBT2g8EHKpbMT4JdOhRbQ9GdjbM= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/DataDog/datadog-go v4.8.2+incompatible h1:qbcKSx29aBLD+5QLvlQZlGmRMF/FfGqFLFev/1TDzRo= -github.com/DataDog/datadog-go v4.8.2+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/DataDog/datadog-go/v5 v5.0.2 h1:UFtEe7662/Qojxkw1d6SboAeA0CPI3naKhVASwFn+04= -github.com/DataDog/datadog-go/v5 v5.0.2/go.mod h1:ZI9JFB4ewXbw1sBnF4sxsR2k1H3xjV+PUAOUsHvKpcU= +github.com/DataDog/datadog-go/v5 v5.1.1 h1:JLZ6s2K1pG2h9GkvEvMdEGqMDyVLEAccdX5TltWcLMU= +github.com/DataDog/datadog-go/v5 v5.1.1/go.mod h1:KhiYb2Badlv9/rofz+OznKoEF5XKTonWyhx5K83AP8E= +github.com/DataDog/go-libddwaf v1.2.0 h1:fKHP5U29E597eV2hU501fcW40bL8zcQ081jEGuRw2kM= +github.com/DataDog/go-libddwaf v1.2.0/go.mod h1:DI5y8obPajk+Tvy2o+nZc2g/5Ria/Rfq5/624k7pHpE= +github.com/DataDog/go-tuf v0.3.0--fix-localmeta-fork h1:yBq5PrAtrM4yVeSzQ+bn050+Ysp++RKF1QmtkL4VqvU= +github.com/DataDog/go-tuf v0.3.0--fix-localmeta-fork/go.mod h1:yA5JwkZsHTLuqq3zaRgUQf35DfDkpOZqgtBqHKpwrBs= github.com/DataDog/gostackparse v0.5.0 h1:jb72P6GFHPHz2W0onsN51cS3FkaMDcjb0QzgxxA4gDk= github.com/DataDog/gostackparse v0.5.0/go.mod h1:lTfqcJKqS9KnXQGnyQMCugq3u1FP6UZMfWR0aitKFMM= github.com/DataDog/sketches-go v1.2.1 h1:qTBzWLnZ3kM2kw39ymh6rMcnN+5VULwFs++lEYUUsro= github.com/DataDog/sketches-go v1.2.1/go.mod h1:1xYmPLY1So10AwxV6MJV0J53XVH+WL9Ad1KetxVivVI= github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= +github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= @@ -77,15 +52,12 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aws/aws-sdk-go v1.44.61 h1:NcpLSS3Z0MiVQIYugx4I40vSIEEAXT0baO684ExNRco= github.com/aws/aws-sdk-go v1.44.61/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -120,49 +92,51 @@ github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTx github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= -github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4= github.com/coinbase/kryptology v1.8.0 h1:Aoq4gdTsJhSU3lNWsD5BWmFSz2pE0GlmrljaOxepdYY= github.com/coinbase/kryptology v1.8.0/go.mod h1:RYXOAPdzOGUe3qlSFkMGn58i3xUA8hmxYHksuq+8ciI= github.com/consensys/bavard v0.1.8-0.20210915155054-088da2f7f54a/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.5.3 h1:4xLFGZR3NWEH2zy+YzvzHicpToQR8FXFbfLNvpGB+rE= github.com/consensys/gnark-crypto v0.5.3/go.mod h1:hOdPlWQV1gDLp7faZVeg8Y0iEPFaOUnCc4XeCCk96p0= github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= -github.com/containerd/cgroups v1.0.4 h1:jN/mbWBEaz+T1pi5OFtnkQ+8qnmEbAr1Oo1FRm5B0dA= -github.com/containerd/cgroups v1.0.4/go.mod h1:nLNQtsF7Sl2HxNebu77i1R0oDlhiTG+kO4JTrUzo6IA= -github.com/containerd/continuity v0.0.0-20191214063359-1097c8bae83b h1:pik3LX++5O3UiNWv45wfP/WT81l7ukBJzd3uUiifbSU= -github.com/containerd/continuity v0.0.0-20191214063359-1097c8bae83b/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= +github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= +github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= +github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/dave/jennifer v1.6.0 h1:MQ/6emI2xM7wt0tJzJzyUik2Q3Tcn2eE0vtYgh4GPVI= -github.com/dave/jennifer v1.6.0/go.mod h1:AxTG893FiZKqxy3FP1kL80VMshSMuz2G+EgvszgGRnk= +github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/dave/jennifer v1.6.1 h1:T4T/67t6RAA5AIV6+NP8Uk/BIsXgDoqEowgycdQQLuk= +github.com/dave/jennifer v1.6.1/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= -github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= -github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI= -github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= @@ -171,9 +145,9 @@ github.com/docker/docker v20.10.18+incompatible h1:SN84VYXTBNGn92T/QwIRPlum9zfem github.com/docker/docker v20.10.18+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= @@ -184,39 +158,47 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.9.1 h1:PS7VIOgmSVhWUEeZwTe7z7zouA22Cr590PzXKbZHOVY= -github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/flynn/go-docopt v0.0.0-20140912013429-f6dd2ebbb31e/go.mod h1:HyVoz1Mz5Co8TFO8EupIdlcpwShBmY98dkT2xeHkvEI= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= -github.com/frankban/quicktest v1.13.0 h1:yNZif1OkDfNoDfb9zZa9aXIpejNR4F23Wely0c+Qdqk= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= -github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo= +github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-toolsmith/astcopy v1.0.2 h1:YnWf5Rnh1hUudj11kei53kI57quN/VH6Hp1n+erozn0= github.com/go-toolsmith/astcopy v1.0.2/go.mod h1:4TcEdbElGc9twQEYpVo/aieIXfHhiuLh4aLAck6dO7Y= @@ -225,36 +207,34 @@ github.com/go-toolsmith/astequal v1.0.3 h1:+LVdyRatFS+XO78SGV4I3TCEA0AC7fKEGma+f github.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4= github.com/go-toolsmith/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUDxe2Jb4= github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -265,19 +245,17 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -288,35 +266,29 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20230509042627-b1315fad0c5a h1:PEOGDI1kkyW37YqPWHLHc+D20D9+87Wt12TCcfTUo5Q= +github.com/google/pprof v0.0.0-20230509042627-b1315fad0c5a/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.2.0 h1:y8Yozv7SZtlU//QXbezB6QkpuE6jMD2/gfzk4AftXjs= -github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.6.0 h1:SXk3ABtQYDT/OH8jAyvEOQ58mgawq5C4o/4/89qN2ZU= -github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ= +github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI= @@ -330,23 +302,19 @@ github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v1.3.1 h1:vDwF1DFNZhntP4DAjuTpOw3uEgMUpXh1pB5fW9DqHpo= -github.com/hashicorp/go-hclog v1.3.1/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-plugin v1.4.5 h1:oTE/oQR4eghggRg8VY7PAz3dr++VwDNBGCcOfIvHpBo= -github.com/hashicorp/go-plugin v1.4.5/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= -github.com/hashicorp/go-secure-stdlib/mlock v0.1.2/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 h1:om4Al8Oy7kCm/B86rLCLah4Dt5Aa0Fr5rYBG60OzwHQ= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= @@ -357,32 +325,25 @@ github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjG github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.5.0 h1:O293SZ2Eg+AAYijkVK3jR786Am1bhDEh2GHT0tIVE5E= -github.com/hashicorp/go-version v1.5.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru/v2 v2.0.2 h1:Dwmkdr5Nc/oBiXgJS3CDHNhJtIHkuZ3DZF5twqnfBdU= +github.com/hashicorp/golang-lru/v2 v2.0.2/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/vault/api v1.8.2 h1:C7OL9YtOtwQbTKI9ogB0A1wffRbCN+rH/LLCHO3d8HM= -github.com/hashicorp/vault/api v1.8.2/go.mod h1:ML8aYzBIhY5m1MD1B2Q0JV89cC85YVH4t5kBaZiyVaE= -github.com/hashicorp/vault/sdk v0.6.0 h1:6Z+In5DXHiUfZvIZdMx7e2loL1PPyDjA4bVh9ZTIAhs= -github.com/hashicorp/vault/sdk v0.6.0/go.mod h1:+DRpzoXIdMvKc88R4qxr+edwy/RvH5QK8itmxLiDHLc= -github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= -github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/hashicorp/vault/api v1.9.2 h1:YjkZLJ7K3inKgMZ0wzCU9OHqc+UqMQyXsPXnf3Cl2as= +github.com/hashicorp/vault/api v1.9.2/go.mod h1:jo5Y/ET+hNyz+JnKDt8XLAdKs+AM0G5W0Vp1IrFI8N8= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= -github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= -github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= +github.com/huin/goupnp v1.1.0 h1:gEe0Dp/lZmPZiDFzJJaOfUpOvv2MKUkoBX8lDrn9vKU= +github.com/huin/goupnp v1.1.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= -github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/ipfs/go-cid v0.2.0 h1:01JTiihFq9en9Vz0lc0VDWvZe/uBonGpzo4THP0vcQ0= -github.com/ipfs/go-cid v0.2.0/go.mod h1:P+HXFDF4CVhaVayiEb4wkAy7zBHxBwsJyt0Y5U6MLro= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= +github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= @@ -398,50 +359,42 @@ github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABo github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.5 h1:qyCLMz2JCrKADihKOh9FxnW3houKeNsp2h5OEz0QSEA= -github.com/klauspost/compress v1.15.5/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= -github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8rF0= -github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/compress v1.16.4 h1:91KN02FnsOYhuunwU4ssRe8lc2JosWmizWa91B5v1PU= +github.com/klauspost/compress v1.16.4/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= +github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= -github.com/koron/go-ssdp v0.0.3 h1:JivLMY45N76b4p/vsWGOKewBQu6uf39y8l+AQ7sDKx8= -github.com/koron/go-ssdp v0.0.3/go.mod h1:b2MxI6yh02pKrsyNoQUsk4+YNikaGhe4894J+Q5lDvA= +github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= +github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= @@ -449,45 +402,29 @@ github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38y github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= -github.com/libp2p/go-libp2p v0.22.0 h1:2Tce0kHOp5zASFKJbNzRElvh0iZwdtG5uZheNW8chIw= -github.com/libp2p/go-libp2p v0.22.0/go.mod h1:UDolmweypBSjQb2f7xutPnwZ/fxioLbMBxSjRksxxU4= -github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw= -github.com/libp2p/go-libp2p-asn-util v0.2.0/go.mod h1:WoaWxbHKBymSN41hWSq/lGKJEca7TNm58+gGJi2WsLI= -github.com/libp2p/go-libp2p-kbucket v0.5.0 h1:g/7tVm8ACHDxH29BGrpsQlnNeu+6OF1A9bno/4/U1oA= -github.com/libp2p/go-libp2p-kbucket v0.5.0/go.mod h1:zGzGCpQd78b5BNTDGHNDLaTt9aDK/A02xeZp9QeFC4U= -github.com/libp2p/go-libp2p-pubsub v0.8.1 h1:hSw09NauFUaA0FLgQPBJp6QOy0a2n+HSkb8IeOx8OnY= -github.com/libp2p/go-libp2p-pubsub v0.8.1/go.mod h1:e4kT+DYjzPUYGZeWk4I+oxCSYTXizzXii5LDRRhjKSw= +github.com/libp2p/go-libp2p v0.27.6 h1:KmGU5kskCaaerm53heqzfGOlrW2z8icZ+fnyqgrZs38= +github.com/libp2p/go-libp2p v0.27.6/go.mod h1:oMfQGTb9CHnrOuSM6yMmyK2lXz3qIhnkn2+oK3B1Y2g= +github.com/libp2p/go-libp2p-asn-util v0.3.0 h1:gMDcMyYiZKkocGXDQ5nsUQyquC9+H+iLEQHwOCZ7s8s= +github.com/libp2p/go-libp2p-asn-util v0.3.0/go.mod h1:B1mcOrKUE35Xq/ASTmQ4tN3LNzVVaMNmq2NACuqyB9w= +github.com/libp2p/go-libp2p-kbucket v0.6.0 h1:1uyqIdE6X7ihtbNg+vRc9EQEmZPEBaehvJ2W14rUrRQ= +github.com/libp2p/go-libp2p-kbucket v0.6.0/go.mod h1:efnPrfoP+WT/ONcC5eB0iADCDIJFXauXhylgJYO+VWw= +github.com/libp2p/go-libp2p-pubsub v0.9.3 h1:ihcz9oIBMaCK9kcx+yHWm3mLAFBMAUsM4ux42aikDxo= +github.com/libp2p/go-libp2p-pubsub v0.9.3/go.mod h1:RYA7aM9jIic5VV47WXu4GkcRxRhrdElWf8xtyli+Dzc= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= -github.com/libp2p/go-msgio v0.2.0 h1:W6shmB+FeynDrUVl2dgFQvzfBZcXiyqY4VmpQLu9FqU= -github.com/libp2p/go-msgio v0.2.0/go.mod h1:dBVM1gW3Jk9XqHkU4eKdGvVHdLa51hoGfll6jMJMSlY= +github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= +github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= github.com/libp2p/go-nat v0.1.0 h1:MfVsH6DLcpa04Xr+p8hmVRG4juse0s3J8HyNWYHffXg= github.com/libp2p/go-nat v0.1.0/go.mod h1:X7teVkwRHNInVNWQiO/tAiAVRwSr5zoRz4YSTC3uRBM= github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= -github.com/libp2p/go-netroute v0.2.0 h1:0FpsbsvuSnAhXFnCY0VLFbJOzaK0VnP0r1QT/o4nWRE= -github.com/libp2p/go-netroute v0.2.0/go.mod h1:Vio7LTzZ+6hoT4CMZi5/6CpY3Snzh2vgZhWgxMNwlQI= -github.com/libp2p/go-openssl v0.1.0 h1:LBkKEcUv6vtZIQLVTegAil8jbNpJErQ9AnT+bWV+Ooo= -github.com/libp2p/go-openssl v0.1.0/go.mod h1:OiOxwPpL3n4xlenjx2h7AwSGaFSC/KZvf6gNdOBQMtc= +github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= +github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= github.com/libp2p/go-reuseport v0.2.0 h1:18PRvIMlpY6ZK85nIAicSBuXXvrYoSw3dsBAR7zc560= github.com/libp2p/go-reuseport v0.2.0/go.mod h1:bvVho6eLMm6Bz5hmU0LYN3ixd3nPPvtIlaURZZgOY4k= github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= -github.com/libp2p/go-yamux/v3 v3.1.2 h1:lNEy28MBk1HavUAlzKgShp+F6mn/ea1nDYWftZhFW9Q= -github.com/libp2p/go-yamux/v3 v3.1.2/go.mod h1:jeLEQgLXqE2YqX1ilAClIfCMDY+0uXQUKmmb/qp0gT4= -github.com/lucas-clemente/quic-go v0.28.1 h1:Uo0lvVxWg5la9gflIF9lwa39ONq85Xq2D91YNEIslzU= -github.com/lucas-clemente/quic-go v0.28.1/go.mod h1:oGz5DKK41cJt5+773+BSO9BXDsREY4HLf7+0odGAPO0= +github.com/libp2p/go-yamux/v4 v4.0.0 h1:+Y80dV2Yx/kv7Y7JKu0LECyVdMXm1VUoko+VQ9rBfZQ= +github.com/libp2p/go-yamux/v4 v4.0.0/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= -github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ= -github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= -github.com/marten-seemann/qtls-go1-17 v0.1.2 h1:JADBlm0LYiVbuSySCHeY863dNkcpMmDR7s0bLKJeYlQ= -github.com/marten-seemann/qtls-go1-17 v0.1.2/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s= -github.com/marten-seemann/qtls-go1-18 v0.1.2 h1:JH6jmzbduz0ITVQ7ShevK10Av5+jBEKAHMntXmIV7kM= -github.com/marten-seemann/qtls-go1-18 v0.1.2/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4= -github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI= -github.com/marten-seemann/qtls-go1-19 v0.1.0 h1:rLFKD/9mp/uq1SYGYuVZhm83wkmU95pK5df3GufyYYU= -github.com/marten-seemann/qtls-go1-19 v0.1.0/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -497,16 +434,15 @@ github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0= -github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= -github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw= +github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= @@ -515,107 +451,102 @@ github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdn github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= -github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= +github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= +github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= -github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= -github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= -github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI= github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/multiformats/go-base32 v0.0.4 h1:+qMh4a2f37b4xTNs6mqitDinryCI+tfO2dRVMN9mjSE= -github.com/multiformats/go-base32 v0.0.4/go.mod h1:jNLFzjPZtp3aIARHbJRZIaPuspdH0J6q39uUM5pnABM= -github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= -github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= +github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= +github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= +github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= +github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= -github.com/multiformats/go-multiaddr v0.7.0 h1:gskHcdaCyPtp9XskVwtvEeQOG465sCohbQIirSyqxrc= -github.com/multiformats/go-multiaddr v0.7.0/go.mod h1:Fs50eBDWvZu+l3/9S6xAE7ZYj6yhxlvaVZjakWN7xRs= +github.com/multiformats/go-multiaddr v0.9.0 h1:3h4V1LHIk5w4hJHekMKWALPXErDfz/sggzwC/NcqbDQ= +github.com/multiformats/go-multiaddr v0.9.0/go.mod h1:mI67Lb1EeTOYb8GQfL/7wpIZwc46ElrvzhYnoJOmTT0= github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= -github.com/multiformats/go-multibase v0.1.1 h1:3ASCDsuLX8+j4kx58qnJ4YFq/JWTJpCyDW27ztsVTOI= -github.com/multiformats/go-multibase v0.1.1/go.mod h1:ZEjHE+IsUrgp5mhlEAYjMtZwK1k4haNkcaPg9aoe1a8= -github.com/multiformats/go-multicodec v0.5.0 h1:EgU6cBe/D7WRwQb1KmnBvU7lrcFGMggZVTPtOW9dDHs= -github.com/multiformats/go-multicodec v0.5.0/go.mod h1:DiY2HFaEp5EhEXb/iYzVAunmyX/aSFMxq2KMKfWEues= +github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= +github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= +github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= +github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multihash v0.2.1 h1:aem8ZT0VA2nCHHk7bPJ1BjUbHNciqZC/d16Vve9l108= -github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc= -github.com/multiformats/go-multistream v0.3.3 h1:d5PZpjwRgVlbwfdTDjife7XszfZd8KYWfROYFlGcR8o= -github.com/multiformats/go-multistream v0.3.3/go.mod h1:ODRoqamLUsETKS9BNcII4gcRsJBU5VAwRIv7O39cEXg= +github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= +github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= +github.com/multiformats/go-multistream v0.4.1 h1:rFy0Iiyn3YT0asivDUIR05leAdwZq3de4741sbiSdfo= +github.com/multiformats/go-multistream v0.4.1/go.mod h1:Mz5eykRVAjJWckE2U78c6xqdtyNUEhKSM0Lwar2p77Q= github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= -github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= +github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= -github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= +github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= -github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c= -github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= -github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= -github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= -github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v1.1.5 h1:L44KXEpKmfWDcS02aeGm8QNTFXTo2D+8MYGDIJ/GDEs= +github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= +github.com/outcaste-io/ristretto v0.2.1 h1:KCItuNIGJZcursqHr3ghO7fc5ddZLEHspL9UR0cQM64= +github.com/outcaste-io/ristretto v0.2.1/go.mod h1:W8HywhmtlopSB1jeMg3JtdIhf+DYkLAr0VN/s4+MHac= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/philhofer/fwd v1.1.1 h1:GdGcTjf5RNAxwS4QLsiMzJYj5KEvPJD3Abr261yRQXQ= github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= -github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= -github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -626,33 +557,25 @@ github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.13.1 h1:3gMjIY2+/hzmqhtUC/aQNYldJA6DtH3CgQvwS+02K1c= -github.com/prometheus/client_golang v1.13.1/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= +github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= +github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= +github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/quasilyte/go-ruleguard v0.3.19 h1:tfMnabXle/HzOb5Xe9CUZYWXKfkS1KwRmZyPmD9nVcc= github.com/quasilyte/go-ruleguard v0.3.19/go.mod h1:lHSn69Scl48I7Gt9cX3VrbsZYvYiBYszZOZW4A+oTEw= github.com/quasilyte/go-ruleguard/dsl v0.3.22 h1:wd8zkOhSNr+I+8Qeciml08ivDt1pSXe60+5DqOpCjPE= @@ -661,9 +584,23 @@ github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOA github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= +github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= +github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= +github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U= +github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= +github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E= +github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= +github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0= +github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA= +github.com/quic-go/webtransport-go v0.5.2 h1:GA6Bl6oZY+g/flt00Pnu0XtivSD8vukOu3lYhJjnGEk= +github.com/quic-go/webtransport-go v0.5.2/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= +github.com/richardartoul/molecule v1.0.1-0.20221107223329-32cfee06a052 h1:Qp27Idfgi6ACvFQat5+VJvlYToylpM/hcyLBI3WaKPA= +github.com/richardartoul/molecule v1.0.1-0.20221107223329-32cfee06a052/go.mod h1:uvX/8buq8uVeiZiFht+0lqSLBHF+uGV8BrTv8W/SIwk= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -672,7 +609,13 @@ github.com/ryanuber/columnize v2.1.2+incompatible h1:C89EOx/XBWwIXl8wm8OPJBd7kPF github.com/ryanuber/columnize v2.1.2+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= +github.com/secure-systems-lab/go-securesystemslib v0.3.1/go.mod h1:o8hhjkbNl2gOamKUA/eNW3xUrntHT9L4W89W1nfj43U= +github.com/secure-systems-lab/go-securesystemslib v0.6.0 h1:T65atpAVCJQK14UA57LMdZGpHi4QYSH/9FZyNGqMYIA= +github.com/secure-systems-lab/go-securesystemslib v0.6.0/go.mod h1:8Mtpo9JKks/qhPG4HGZ2LGMvrPbzuxwfz/f/zLfEWkk= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08Ocec= +github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= @@ -696,23 +639,17 @@ github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go. github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= -github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= -github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= -github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -730,22 +667,31 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= -github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ= -github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= +github.com/tinylib/msgp v1.1.6 h1:i+SbKraHhnrf9M5MYmvQhFnbLhAXSDWF8WWsuyRdocw= +github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw= +github.com/trailofbits/go-fuzz-utils v0.0.0-20210901195358-9657fcfd256c h1:4WU+p200eLYtBsx3M5CKXvkjVdf5SC3W9nMg37y0TFI= +github.com/trailofbits/go-fuzz-utils v0.0.0-20210901195358-9657fcfd256c/go.mod h1:f3jBhpWvuZmue0HZK52GzRHJOYHYSILs/c8+K2S/J+o= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= -github.com/umbracle/ethgo v0.1.4-0.20230126112511-6a4d02533af6 h1:WqlyYNdrBECgDwDIEMxa4mLUSH/FfPdAuOnniUqNpJs= -github.com/umbracle/ethgo v0.1.4-0.20230126112511-6a4d02533af6/go.mod h1:8QIHEG/YfGnW4I5AND2Znl9W0LU3tXR9IGqgmSieiGo= -github.com/umbracle/fastrlp v0.0.0-20220527094140-59d5dd30e722 h1:10Nbw6cACsnQm7r34zlpJky+IzxVLRk6MKTS2d3Vp0E= -github.com/umbracle/fastrlp v0.0.0-20220527094140-59d5dd30e722/go.mod h1:c8J0h9aULj2i3umrfyestM6jCq0LK0U6ly6bWy96nd4= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/umbracle/ethgo v0.1.4-0.20230622091706-8230f57578b2 h1:yjKMn4wmRd1jFN2vgysTN+xbR673XzAIuBTncO1hWGo= +github.com/umbracle/ethgo v0.1.4-0.20230622091706-8230f57578b2/go.mod h1:J+OZNfRCtbaYW3AEc0m47GhwAzlNJjcr9vO86nzOr6E= +github.com/umbracle/fastrlp v0.1.1-0.20230504065717-58a1b8a9929d h1:HAg1Kpr9buwRxEiC2UXU9oT2AU8uCU7o3/WTH+Lt5wo= +github.com/umbracle/fastrlp v0.1.1-0.20230504065717-58a1b8a9929d/go.mod h1:5RHgqiFjd4vLJESMWagP/E7su+5Gzk0iqqmrotR8WdA= github.com/umbracle/go-eth-bn256 v0.0.0-20230125114011-47cb310d9b0b h1:5/xofhZiOG0I9DQXqDSPxqYObk6QI7mBGMJI+ngyIgc= github.com/umbracle/go-eth-bn256 v0.0.0-20230125114011-47cb310d9b0b/go.mod h1:H8SeC2PWEciymT92Mt07Qcfjr2FMEuCz/V+KPtPTy+U= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= @@ -756,38 +702,37 @@ github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLr github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= -github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee h1:lYbXeSvJi5zk5GLKVuid9TVjS9a0OmLIDKTfoZBL6Ow= -github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= -go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= +go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/dig v1.16.1 h1:+alNIBsl0qfY0j6epRubp/9obgtrObRAc5aD+6jbWY8= +go.uber.org/dig v1.16.1/go.mod h1:557JTAUZT5bUK0SvCwikmLPPtdQhfvLYtO5tJgQSbnk= +go.uber.org/fx v1.19.2 h1:SyFgYQFr1Wl0AYstE8vyYIzP4bFz2URrScjwC4cwUvY= +go.uber.org/fx v1.19.2/go.mod h1:43G1VcqSzbIv77y00p1DRAsyZS8WdzuYdhZXmEUkMyQ= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= -go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.22.0 h1:Zcye5DUgBloQ9BaT4qc9BnjOFog5TvBSAGkJ3Nf70c0= -go.uber.org/zap v1.22.0/go.mod h1:H4siCOZOrAolnUPJEkfaSjDqyP+BDS0DdDWzwcgt3+U= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= go4.org/intern v0.0.0-20211027215823-ae77deb06f29 h1:UXLjNohABv4S58tHmeuIZDO6e3mHpW2Dx33gaNt03LE= go4.org/intern v0.0.0-20211027215823-ae77deb06f29/go.mod h1:cS2ma+47FKrLPdXFpr7CuxiTW3eyJbWew4qx0qtQWDA= @@ -796,61 +741,41 @@ go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 h1:FyBZqvo go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM= -golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20221002003631-540bb7301a08 h1:VpoGhesgULkabDHoDFGayS1wnkasmT95Jq2xZDwN45Q= golang.org/x/exp/typeparams v0.0.0-20221002003631-540bb7301a08/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= +golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -863,55 +788,30 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU= +golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1 h1:3VPzK7eqH25j7GYw5w6g/GzNRc0/fYtrxz27z1gD4W0= -golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -919,13 +819,10 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -935,45 +832,25 @@ golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -983,41 +860,38 @@ golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w= -golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1025,54 +899,22 @@ golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.3.0 h1:SrNbZl6ECOS1qFzgTdQfWXZM9XBkiA6tkFrH9YSTPHM= -golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= +golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1082,32 +924,12 @@ golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNq google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.99.0 h1:tsBtOIklCE2OFxhmcYSVqGwSAN/Y897srxmcvAQnwK8= -google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= +google.golang.org/api v0.109.0 h1:sW9hgHyX497PP5//NUM7nqfV8D0iDfBApqq7sOh1XR8= +google.golang.org/api v0.109.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -1115,54 +937,20 @@ google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoA google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e h1:halCgTFuLWDRD61piiNSxPsARANGD3Xl16hPrLgLiIg= -google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= +google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2 h1:O97sLx/Xmb/KIZHB/2/BzofxBs5QmmR0LcihPtllmbc= +google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY= -google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.53.0-dev h1:Bi96+XIrXJLXPJUff19tRXb7mIijir7agn12zNMaPAg= +google.golang.org/grpc v1.53.0-dev/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1171,16 +959,14 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/DataDog/dd-trace-go.v1 v1.43.1 h1:Dez4VzRQWAI5YXJRBx58BiC0gONGuW/oY4l8fWKzOXY= -gopkg.in/DataDog/dd-trace-go.v1 v1.43.1/go.mod h1:YL9g+nlUY7ByCffD5pDytAqy99GNbytRV0EBpKuldM4= -gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/DataDog/dd-trace-go.v1 v1.51.0 h1:nFsTjolqdh8slG6F1B7AGdFHX7/kp26Jkb8UvGSIIFY= +gopkg.in/DataDog/dd-trace-go.v1 v1.51.0/go.mod h1:+m1wWLyQfqd6fX0uy6YFbP1soWgmjQ+5TveksDt/fHc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1189,12 +975,9 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= -gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= -gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1210,26 +993,23 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -inet.af/netaddr v0.0.0-20220617031823-097006376321 h1:B4dC8ySKTQXasnjDTMsoCMf1sQG4WsMej0WXaHxunmU= -inet.af/netaddr v0.0.0-20220617031823-097006376321/go.mod h1:OIezDfdzOgFhuw4HuWapWq2e9l0H9tK4F1j+ETRtF3k= -lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= -lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= -pgregory.net/rapid v0.5.5 h1:jkgx1TjbQPD/feRoK+S/mXw9e1uj6WilpHrXJowi6oA= -pgregory.net/rapid v0.5.5/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +inet.af/netaddr v0.0.0-20220811202034-502d2d690317 h1:U2fwK6P2EqmopP/hFLTOAjWTki0qgd4GMJn5X8wOleU= +inet.af/netaddr v0.0.0-20220811202034-502d2d690317/go.mod h1:OIezDfdzOgFhuw4HuWapWq2e9l0H9tK4F1j+ETRtF3k= +lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= +lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= +nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +pgregory.net/rapid v1.0.0 h1:iQaM2w5PZ6xvt6x7hbd7tiDS+nk7YPp5uCaEba+T/F4= +pgregory.net/rapid v1.0.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/helper/common/common.go b/helper/common/common.go index a758af509f..11139435d3 100644 --- a/helper/common/common.go +++ b/helper/common/common.go @@ -1,6 +1,7 @@ package common import ( + "context" "encoding/binary" "encoding/json" "errors" @@ -13,10 +14,12 @@ import ( "os/user" "path/filepath" "strconv" + "strings" "syscall" + "time" "github.com/0xPolygon/polygon-edge/helper/hex" - "github.com/0xPolygon/polygon-edge/types" + "github.com/sethvargo/go-retry" ) var ( @@ -25,8 +28,21 @@ var ( // Our staking repo is written in JS, as are many other clients // If we use higher value JS will not be able to parse it MaxSafeJSInt = uint64(math.Pow(2, 53) - 2) + + errInvalidDuration = errors.New("invalid duration") ) +// RetryForever will execute a function until it completes without error +func RetryForever(ctx context.Context, interval time.Duration, fn func(context.Context) error) { + _ = retry.Do(ctx, retry.NewConstant(interval), func(context.Context) error { + if err := fn(ctx); err != nil { + return retry.RetryableError(err) + } + + return nil + }) +} + // Min returns the strictly lower number func Min(a, b uint64) uint64 { if a < b { @@ -45,12 +61,21 @@ func Max(a, b uint64) uint64 { return b } +// BigMin returns the smallest of x or y. +func BigMin(x, y *big.Int) *big.Int { + if x.Cmp(y) > 0 { + return y + } + + return x +} + func ConvertUnmarshalledUint(x interface{}) (uint64, error) { switch tx := x.(type) { case float64: return uint64(roundFloat(tx)), nil case string: - v, err := types.ParseUint64orHex(&tx) + v, err := ParseUint64orHex(&tx) if err != nil { return 0, err } @@ -61,14 +86,26 @@ func ConvertUnmarshalledUint(x interface{}) (uint64, error) { } } -func roundFloat(num float64) int64 { - return int64(num + math.Copysign(0.5, num)) -} +// ParseUint64orHex parses the given uint64 hex string into the number. +// It can parse the string with 0x prefix as well. +func ParseUint64orHex(val *string) (uint64, error) { + if val == nil { + return 0, nil + } -func ToFixedFloat(num float64, precision int) float64 { - output := math.Pow(10, float64(precision)) + str := *val + base := 10 - return float64(roundFloat(num*output)) / output + if strings.HasPrefix(str, "0x") { + str = str[2:] + base = 16 + } + + return strconv.ParseUint(str, base, 64) +} + +func roundFloat(num float64) int64 { + return int64(num + math.Copysign(0.5, num)) } // SetupDataDir sets up the data directory and the corresponding sub-directories @@ -237,6 +274,42 @@ func (d *JSONNumber) UnmarshalJSON(data []byte) error { return nil } +// Duration is a wrapper struct for time.Duration which implements json (un)marshaling +type Duration struct { + time.Duration +} + +func (d Duration) MarshalJSON() ([]byte, error) { + return json.Marshal(d.String()) +} + +func (d *Duration) UnmarshalJSON(b []byte) error { + var ( + v interface{} + err error + ) + + if err = json.Unmarshal(b, &v); err != nil { + return err + } + + switch value := v.(type) { + case float64: + d.Duration = time.Duration(value) + + return nil + case string: + d.Duration, err = time.ParseDuration(value) + if err != nil { + return err + } + + return nil + } + + return errInvalidDuration +} + // GetTerminationSignalCh returns a channel to emit signals by ctrl + c func GetTerminationSignalCh() <-chan os.Signal { // wait for the user to quit with ctrl-c @@ -271,8 +344,6 @@ func PadLeftOrTrim(bb []byte, size int) []byte { // ExtendByteSlice extends given byte slice by needLength parameter and trims it func ExtendByteSlice(b []byte, needLength int) []byte { - b = b[:cap(b)] - if n := needLength - len(b); n > 0 { b = append(b, make([]byte, n)...) } diff --git a/helper/common/common_test.go b/helper/common/common_test.go index ff009409c5..6a7af9e4e4 100644 --- a/helper/common/common_test.go +++ b/helper/common/common_test.go @@ -1,8 +1,12 @@ package common import ( + "context" + "encoding/json" + "errors" "math/big" "testing" + "time" "github.com/stretchr/testify/require" ) @@ -60,3 +64,71 @@ func Test_BigIntDivCeil(t *testing.T) { require.Equal(t, c.result, BigIntDivCeil(big.NewInt(c.a), big.NewInt(c.b)).Int64()) } } + +func Test_Duration_Marshal_UnmarshalJSON(t *testing.T) { + t.Parallel() + + t.Run("use duration standalone", func(t *testing.T) { + t.Parallel() + + original := &Duration{Duration: 5 * time.Minute} + originalRaw, err := original.MarshalJSON() + require.NoError(t, err) + + other := &Duration{} + require.NoError(t, other.UnmarshalJSON(originalRaw)) + require.Equal(t, original, other) + }) + + t.Run("use duration in wrapper struct", func(t *testing.T) { + t.Parallel() + + type timer struct { + Elapsed Duration `json:"elapsed"` + } + + dur, err := time.ParseDuration("2h35m21s") + require.NoError(t, err) + + origTimer := &timer{Elapsed: Duration{dur}} + + timerRaw, err := json.Marshal(origTimer) + require.NoError(t, err) + + var otherTimer *timer + require.NoError(t, json.Unmarshal(timerRaw, &otherTimer)) + require.Equal(t, origTimer, otherTimer) + }) +} + +func TestRetryForever_AlwaysReturnError_ShouldNeverEnd(t *testing.T) { + interval := time.Millisecond * 10 + ended := false + + go func() { + RetryForever(context.Background(), interval, func(ctx context.Context) error { + return errors.New("") + }) + + ended = true + }() + time.Sleep(interval * 10) + require.False(t, ended) +} + +func TestRetryForever_ReturnNilAfterFirstRun_ShouldEnd(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + RetryForever(ctx, time.Millisecond*100, func(ctx context.Context) error { + select { + case <-ctx.Done(): + + return nil + default: + cancel() + + return errors.New("") + } + }) + <-ctx.Done() + require.True(t, errors.Is(ctx.Err(), context.Canceled)) +} diff --git a/helper/config/config.go b/helper/config/config.go deleted file mode 100644 index ce75a0981a..0000000000 --- a/helper/config/config.go +++ /dev/null @@ -1,25 +0,0 @@ -package config - -import ( - "github.com/0xPolygon/polygon-edge/chain" - "github.com/0xPolygon/polygon-edge/types" -) - -// GetWhitelist fetches whitelist object from the config -func GetWhitelist(config *chain.Chain) *chain.Whitelists { - return config.Params.Whitelists -} - -// GetDeploymentWhitelist fetches deployment whitelist from the genesis config -// if doesn't exist returns empty list -func GetDeploymentWhitelist(genesisConfig *chain.Chain) ([]types.Address, error) { - // Fetch whitelist config if exists, if not init - whitelistConfig := GetWhitelist(genesisConfig) - - // Extract deployment whitelist if exists, if not init - if whitelistConfig == nil { - return make([]types.Address, 0), nil - } - - return whitelistConfig.Deployment, nil -} diff --git a/helper/keccak/pool.go b/helper/keccak/pool.go index cf0bcc64be..d6934e9068 100644 --- a/helper/keccak/pool.go +++ b/helper/keccak/pool.go @@ -53,3 +53,13 @@ func Keccak256Rlp(dst []byte, src *fastrlp.Value) []byte { return dst } + +// PrefixedKeccak256Rlp hashes a fastrlp.Value using keccak-256 with the given prefix +func PrefixedKeccak256Rlp(prefix, dst []byte, src *fastrlp.Value) []byte { + h := DefaultKeccakPool.Get() + _, _ = h.Write(prefix) + dst = h.WriteRlp(dst, src) + DefaultKeccakPool.Put(h) + + return dst +} diff --git a/helper/predeployment/predeployment.go b/helper/predeployment/predeployment.go index ce6d0f4ce6..fb846829ee 100644 --- a/helper/predeployment/predeployment.go +++ b/helper/predeployment/predeployment.go @@ -153,7 +153,10 @@ func getPredeployAccount(address types.Address, input, deployedBytecode []byte) // the state needs to be walked to collect all touched all storage slots storageMap := getModifiedStorageMap(radix, address) - transition.Commit() + _, _, _, err := transition.Commit() //nolint:dogsled + if err != nil { + return nil, fmt.Errorf("failed to commit the state changes: %w", err) + } return &chain.GenesisAccount{ Balance: transition.GetBalance(address), @@ -182,24 +185,29 @@ func GenerateGenesisAccountFromFile( return nil, fmt.Errorf("unable to create contract ABI, %w", err) } - // Constructor arguments are passed in as an array of values. - // Structs are treated as sub-arrays with their corresponding values laid out - // in ABI encoding - parsedArguments, err := ParseArguments(constructorArgs) - if err != nil { - return nil, err - } + finalBytecode := artifact.Bytecode + constructorInfo := contractABI.Constructor - // Encode the constructor params - constructor, err := abi.Encode( - parsedArguments, - contractABI.Constructor.Inputs, - ) - if err != nil { - return nil, fmt.Errorf("unable to encode constructor arguments, %w", err) - } + if constructorInfo != nil { + // Constructor arguments are passed in as an array of values. + // Structs are treated as sub-arrays with their corresponding values laid out + // in ABI encoding + parsedArguments, err := ParseArguments(constructorArgs) + if err != nil { + return nil, err + } - finalBytecode := append(artifact.Bytecode, constructor...) + // Encode the constructor params + constructor, err := abi.Encode( + parsedArguments, + contractABI.Constructor.Inputs, + ) + if err != nil { + return nil, fmt.Errorf("unable to encode constructor arguments, %w", err) + } + + finalBytecode = append(artifact.Bytecode, constructor...) + } return getPredeployAccount(predeployAddress, finalBytecode, artifact.DeployedBytecode) } diff --git a/helper/tests/testing.go b/helper/tests/testing.go index 64971c065a..ce91641857 100644 --- a/helper/tests/testing.go +++ b/helper/tests/testing.go @@ -16,7 +16,6 @@ import ( "github.com/multiformats/go-multiaddr" "github.com/umbracle/ethgo" - "github.com/0xPolygon/polygon-edge/chain" "github.com/0xPolygon/polygon-edge/crypto" txpoolOp "github.com/0xPolygon/polygon-edge/txpool/proto" "github.com/0xPolygon/polygon-edge/types" @@ -237,7 +236,7 @@ type GenerateTxReqParams struct { } func generateTx(params GenerateTxReqParams) (*types.Transaction, error) { - signer := crypto.NewEIP155Signer(chain.AllForksEnabled.At(0), 100) + signer := crypto.NewEIP155Signer(100, true) signedTx, signErr := signer.SignTx(&types.Transaction{ Nonce: params.Nonce, diff --git a/jsonrpc/codec.go b/jsonrpc/codec.go index a32acd5df1..f8f5191f9a 100644 --- a/jsonrpc/codec.go +++ b/jsonrpc/codec.go @@ -15,6 +15,8 @@ type Request struct { Params json.RawMessage `json:"params,omitempty"` } +type BatchRequest []Request + // Response is a jsonrpc response interface type Response interface { GetID() interface{} @@ -93,6 +95,25 @@ func (e *ObjectError) Error() string { return string(data) } +func (e *ObjectError) MarshalJSON() ([]byte, error) { + var ds string + + data, ok := e.Data.([]byte) + if ok && len(data) > 0 { + ds = "0x" + string(data) + } + + return json.Marshal(&struct { + Code int `json:"code"` + Message string `json:"message"` + Data string `json:"data,omitempty"` + }{ + Code: e.Code, + Message: e.Message, + Data: ds, + }) +} + const ( pending = "pending" latest = "latest" @@ -190,8 +211,8 @@ func (b *BlockNumber) UnmarshalJSON(buffer []byte) error { } // NewRPCErrorResponse is used to create a custom error response -func NewRPCErrorResponse(id interface{}, errCode int, err string, jsonrpcver string) Response { - errObject := &ObjectError{errCode, err, nil} +func NewRPCErrorResponse(id interface{}, errCode int, err string, data []byte, jsonrpcver string) Response { + errObject := &ObjectError{errCode, err, data} response := &ErrorResponse{ JSONRPC: jsonrpcver, @@ -209,7 +230,7 @@ func NewRPCResponse(id interface{}, jsonrpcver string, reply []byte, err Error) case nil: response = &SuccessResponse{JSONRPC: jsonrpcver, ID: id, Result: reply} default: - response = NewRPCErrorResponse(id, err.ErrorCode(), err.Error(), jsonrpcver) + response = NewRPCErrorResponse(id, err.ErrorCode(), err.Error(), reply, jsonrpcver) } return response diff --git a/jsonrpc/debug_endpoint_test.go b/jsonrpc/debug_endpoint_test.go index cd3828a4d9..5fd5aa6441 100644 --- a/jsonrpc/debug_endpoint_test.go +++ b/jsonrpc/debug_endpoint_test.go @@ -562,35 +562,41 @@ func TestTraceCall(t *testing.T) { t.Parallel() var ( - from = types.StringToAddress("1") - to = types.StringToAddress("2") - gas = argUint64(10000) - gasPrice = argBytes(new(big.Int).SetUint64(10).Bytes()) - value = argBytes(new(big.Int).SetUint64(1000).Bytes()) - data = argBytes([]byte("data")) - input = argBytes([]byte("input")) - nonce = argUint64(1) + from = types.StringToAddress("1") + to = types.StringToAddress("2") + gas = argUint64(10000) + gasPrice = argBytes(new(big.Int).SetUint64(10).Bytes()) + gasTipCap = argBytes(new(big.Int).SetUint64(10).Bytes()) + gasFeeCap = argBytes(new(big.Int).SetUint64(10).Bytes()) + value = argBytes(new(big.Int).SetUint64(1000).Bytes()) + data = argBytes([]byte("data")) + input = argBytes([]byte("input")) + nonce = argUint64(1) blockNumber = BlockNumber(testBlock10.Number()) txArg = &txnArgs{ - From: &from, - To: &to, - Gas: &gas, - GasPrice: &gasPrice, - Value: &value, - Data: &data, - Input: &input, - Nonce: &nonce, + From: &from, + To: &to, + Gas: &gas, + GasPrice: &gasPrice, + GasTipCap: &gasTipCap, + GasFeeCap: &gasFeeCap, + Value: &value, + Data: &data, + Input: &input, + Nonce: &nonce, } decodedTx = &types.Transaction{ - Nonce: uint64(nonce), - GasPrice: new(big.Int).SetBytes([]byte(gasPrice)), - Gas: uint64(gas), - To: &to, - Value: new(big.Int).SetBytes([]byte(value)), - Input: data, - From: from, + Nonce: uint64(nonce), + GasPrice: new(big.Int).SetBytes([]byte(gasPrice)), + GasTipCap: new(big.Int).SetBytes([]byte(gasTipCap)), + GasFeeCap: new(big.Int).SetBytes([]byte(gasFeeCap)), + Gas: uint64(gas), + To: &to, + Value: new(big.Int).SetBytes([]byte(value)), + Input: data, + From: from, } ) diff --git a/jsonrpc/dispatcher.go b/jsonrpc/dispatcher.go index 77e2ba5161..0cc86aa23d 100644 --- a/jsonrpc/dispatcher.go +++ b/jsonrpc/dispatcher.go @@ -7,9 +7,12 @@ import ( "fmt" "math" "reflect" + "strconv" "strings" + "time" "unicode" + "github.com/armon/go-metrics" "github.com/hashicorp/go-hclog" ) @@ -58,6 +61,10 @@ type dispatcherParams struct { blockRangeLimit uint64 } +func (dp dispatcherParams) isExceedingBatchLengthLimit(value uint64) bool { + return dp.jsonRPCBatchLengthLimit != 0 && value > dp.jsonRPCBatchLengthLimit +} + func newDispatcher( logger hclog.Logger, store JSONRPCStore, @@ -161,22 +168,23 @@ type wsConn interface { // as per https://www.jsonrpc.org/specification, the `id` in JSON-RPC 2.0 // can only be a string or a non-decimal integer -func formatFilterResponse(id interface{}, resp string) (string, Error) { +func formatID(id interface{}) (interface{}, Error) { switch t := id.(type) { case string: - return fmt.Sprintf(`{"jsonrpc":"2.0","id":"%s","result":"%s"}`, t, resp), nil + return t, nil case float64: if t == math.Trunc(t) { - return fmt.Sprintf(`{"jsonrpc":"2.0","id":%d,"result":"%s"}`, int(t), resp), nil + return int(t), nil } else { return "", NewInvalidRequestError("Invalid json request") } case nil: - return fmt.Sprintf(`{"jsonrpc":"2.0","id":null,"result":"%s"}`, resp), nil + return nil, nil default: return "", NewInvalidRequestError("Invalid json request") } } + func (d *Dispatcher) handleSubscribe(req Request, conn wsConn) (string, Error) { var params []interface{} if err := json.Unmarshal(req.Params, ¶ms); err != nil { @@ -231,54 +239,90 @@ func (d *Dispatcher) RemoveFilterByWs(conn wsConn) { } func (d *Dispatcher) HandleWs(reqBody []byte, conn wsConn) ([]byte, error) { - var req Request - if err := json.Unmarshal(reqBody, &req); err != nil { - return NewRPCResponse(req.ID, "2.0", nil, NewInvalidRequestError("Invalid json request")).Bytes() - } + const ( + openSquareBracket byte = '[' + closeSquareBracket byte = ']' + comma byte = ',' + ) - // if the request method is eth_subscribe we need to create a - // new filter with ws connection - if req.Method == "eth_subscribe" { - filterID, err := d.handleSubscribe(req, conn) - if err != nil { - return NewRPCResponse(req.ID, "2.0", nil, err).Bytes() - } + reqBody = bytes.TrimLeft(reqBody, " \t\r\n") - resp, err := formatFilterResponse(req.ID, filterID) + // if body begins with [ consider it as a batch request + if len(reqBody) > 0 && reqBody[0] == openSquareBracket { + var batchReq BatchRequest + err := json.Unmarshal(reqBody, &batchReq) if err != nil { - return NewRPCResponse(req.ID, "2.0", nil, err).Bytes() + return NewRPCResponse(nil, "2.0", nil, + NewInvalidRequestError("Invalid json batch request")).Bytes() } - return []byte(resp), nil - } - - if req.Method == "eth_unsubscribe" { - ok, err := d.handleUnsubscribe(req) - if err != nil { - return nil, err + // if not disabled, avoid handling long batch requests + if d.params.isExceedingBatchLengthLimit(uint64(len(batchReq))) { + return NewRPCResponse( + nil, + "2.0", + nil, + NewInvalidRequestError("Batch request length too long"), + ).Bytes() } - res := "false" - if ok { - res = "true" - } + responses := make([][]byte, len(batchReq)) - resp, err := formatFilterResponse(req.ID, res) - if err != nil { - return NewRPCResponse(req.ID, "2.0", nil, err).Bytes() + for i, req := range batchReq { + responses[i], err = d.handleSingleWs(req, conn).Bytes() + if err != nil { + return nil, err + } } - return []byte(resp), nil + var buf bytes.Buffer + + // batch output should look like: + // [ { "requestId": "1", "status": 200 }, { "requestId": "2", "status": 200 } ] + buf.WriteByte(openSquareBracket) // [ + buf.Write(bytes.Join(responses, []byte{comma})) // join responses with the comma separator + buf.WriteByte(closeSquareBracket) // ] + + return buf.Bytes(), nil + } + + var req Request + if err := json.Unmarshal(reqBody, &req); err != nil { + return NewRPCResponse(req.ID, "2.0", nil, NewInvalidRequestError("Invalid json request")).Bytes() } - // its a normal query that we handle with the dispatcher - resp, err := d.handleReq(req) + return d.handleSingleWs(req, conn).Bytes() +} + +func (d *Dispatcher) handleSingleWs(req Request, conn wsConn) Response { + id, err := formatID(req.ID) if err != nil { - return nil, err + return NewRPCResponse(nil, "2.0", nil, err) + } + + var response []byte + + switch req.Method { + case "eth_subscribe": + var filterID string + + // if the request method is eth_subscribe we need to create a new filter with ws connection + if filterID, err = d.handleSubscribe(req, conn); err == nil { + response = []byte(fmt.Sprintf("\"%s\"", filterID)) + } + case "eth_unsubscribe": + var ok bool + + if ok, err = d.handleUnsubscribe(req); err == nil { + response = []byte(strconv.FormatBool(ok)) + } + default: + // its a normal query that we handle with the dispatcher + response, err = d.handleReq(req) } - return NewRPCResponse(req.ID, "2.0", resp, err).Bytes() + return NewRPCResponse(id, "2.0", response, err) } func (d *Dispatcher) Handle(reqBody []byte) ([]byte, error) { @@ -303,7 +347,7 @@ func (d *Dispatcher) Handle(reqBody []byte) ([]byte, error) { } // handle batch requests - var requests []Request + var requests BatchRequest if err := json.Unmarshal(reqBody, &requests); err != nil { return NewRPCResponse( nil, @@ -314,7 +358,7 @@ func (d *Dispatcher) Handle(reqBody []byte) ([]byte, error) { } // if not disabled, avoid handling long batch requests - if d.params.jsonRPCBatchLengthLimit != 0 && len(requests) > int(d.params.jsonRPCBatchLengthLimit) { + if d.params.isExceedingBatchLengthLimit(uint64(len(requests))) { return NewRPCResponse( nil, "2.0", @@ -328,7 +372,7 @@ func (d *Dispatcher) Handle(reqBody []byte) ([]byte, error) { for _, req := range requests { var response, err = d.handleReq(req) if err != nil { - errorResponse := NewRPCResponse(req.ID, "2.0", nil, err) + errorResponse := NewRPCResponse(req.ID, "2.0", response, err) responses = append(responses, errorResponse) continue @@ -371,18 +415,33 @@ func (d *Dispatcher) handleReq(req Request) ([]byte, Error) { } } - output := fd.fv.Call(inArgs) - if err := getError(output[1]); err != nil { - d.logInternalError(req.Method, err) - - return nil, NewInvalidRequestError(err.Error()) - } - var ( data []byte err error + ok bool ) + start := time.Now().UTC() + output := fd.fv.Call(inArgs) // call rpc endpoint function + // measure execution time of rpc endpoint function + metrics.SetGauge([]string{jsonRPCMetric, req.Method + "_time"}, float32(time.Now().UTC().Sub(start).Seconds())) + + if err := getError(output[1]); err != nil { + // measure error on the rpc endpoint function + metrics.IncrCounter([]string{jsonRPCMetric, req.Method + "_errors"}, 1) + d.logInternalError(req.Method, err) + + if res := output[0].Interface(); res != nil { + data, ok = res.([]byte) + + if !ok { + return nil, NewInternalError(err.Error()) + } + } + + return data, NewInvalidRequestError(err.Error()) + } + if res := output[0].Interface(); res != nil { data, err = json.Marshal(res) if err != nil { @@ -396,7 +455,7 @@ func (d *Dispatcher) handleReq(req Request) ([]byte, Error) { } func (d *Dispatcher) logInternalError(method string, err error) { - d.logger.Error("failed to dispatch", "method", method, "err", err) + d.logger.Warn("failed to dispatch", "method", method, "err", err) } func (d *Dispatcher) registerService(serviceName string, service interface{}) error { diff --git a/jsonrpc/dispatcher_test.go b/jsonrpc/dispatcher_test.go index 3c5ca9ad8a..171edf2ac1 100644 --- a/jsonrpc/dispatcher_test.go +++ b/jsonrpc/dispatcher_test.go @@ -2,6 +2,7 @@ package jsonrpc import ( "encoding/json" + "fmt" "math/big" "reflect" "testing" @@ -102,6 +103,8 @@ func TestDispatcher_HandleWebsocketConnection_EthSubscribe(t *testing.T) { } func TestDispatcher_WebsocketConnection_RequestFormats(t *testing.T) { + t.Parallel() + store := newMockStore() dispatcher := newTestDispatcher(t, hclog.NewNullLogger(), @@ -212,6 +215,8 @@ func (m *mockService) Filter(f LogQuery) (interface{}, error) { } func TestDispatcherFuncDecode(t *testing.T) { + t.Parallel() + srv := &mockService{msgCh: make(chan interface{}, 10)} dispatcher := newTestDispatcher(t, @@ -290,20 +295,29 @@ func TestDispatcherFuncDecode(t *testing.T) { } func TestDispatcherBatchRequest(t *testing.T) { - handle := func(dispatcher *Dispatcher, reqBody []byte) []byte { - res, _ := dispatcher.Handle(reqBody) - - return res - } + t.Parallel() - cases := []struct { + type caseData struct { name string desc string dispatcher *Dispatcher reqBody []byte err *ObjectError batchResponse []*SuccessResponse - }{ + } + + mock := &mockWsConn{ + SetFilterIDFn: func(s string) { + }, + GetFilterIDFn: func() string { + return "" + }, + WriteMessageFn: func(i int, b []byte) error { + return nil + }, + } + + cases := []caseData{ { "leading-whitespace", "test with leading whitespace (\" \\t\\n\\n\\r\\)", @@ -425,14 +439,12 @@ func TestDispatcherBatchRequest(t *testing.T) { }, } - for _, c := range cases { - res := handle(c.dispatcher, c.reqBody) - + check := func(c caseData, res []byte) { if c.err != nil { var resp ErrorResponse assert.NoError(t, expectBatchJSONResult(res, &resp)) - assert.Equal(t, resp.Error, c.err) + assert.Equal(t, c.err, resp.Error) } else { var batchResp []SuccessResponse assert.NoError(t, expectBatchJSONResult(res, &batchResp)) @@ -440,21 +452,87 @@ func TestDispatcherBatchRequest(t *testing.T) { if c.name == "leading-whitespace" { assert.Len(t, batchResp, 4) for index, resp := range batchResp { - assert.Equal(t, resp.Error, c.batchResponse[index].Error) + assert.Equal(t, c.batchResponse[index].Error, resp.Error) } } else if c.name == "valid-batch-req" { assert.Len(t, batchResp, 6) for index, resp := range batchResp { - assert.Equal(t, resp.Error, c.batchResponse[index].Error) + assert.Equal(t, c.batchResponse[index].Error, resp.Error) } } else if c.name == "no-limits" { assert.Len(t, batchResp, 12) for index, resp := range batchResp { - assert.Equal(t, resp.Error, c.batchResponse[index].Error) + assert.Equal(t, c.batchResponse[index].Error, resp.Error) } } } } + + for _, c := range cases { + c := c + + t.Run(c.name, func(t *testing.T) { + t.Parallel() + + res, _ := c.dispatcher.HandleWs(c.reqBody, mock) + + check(c, res) + + res, _ = c.dispatcher.Handle(c.reqBody) + + check(c, res) + }) + } +} + +func TestDispatcher_WebsocketConnection_Unsubscribe(t *testing.T) { + t.Parallel() + + store := newMockStore() + dispatcher := newTestDispatcher(t, + hclog.NewNullLogger(), + store, + &dispatcherParams{ + chainID: 0, + priceLimit: 0, + jsonRPCBatchLengthLimit: 20, + blockRangeLimit: 1000, + }, + ) + mockConn := &mockWsConn{ + SetFilterIDFn: func(s string) { + }, + GetFilterIDFn: func() string { + return "" + }, + WriteMessageFn: func(i int, b []byte) error { + return nil + }, + } + + resp := SuccessResponse{} + reqUnsub := func(n string) []byte { + return []byte(fmt.Sprintf(`{"method": "eth_unsubscribe", "params": [%s]}`, n)) + } + + // non existing subscription + r, err := dispatcher.HandleWs(reqUnsub("\"787832\""), mockConn) + require.NoError(t, err) + + require.NoError(t, json.Unmarshal(r, &resp)) + assert.Equal(t, "false", string(resp.Result)) + + r, err = dispatcher.HandleWs([]byte(`{"method": "eth_subscribe", "params": ["newHeads"]}`), mockConn) + require.NoError(t, err) + + require.NoError(t, json.Unmarshal(r, &resp)) + + // existing subscription + r, err = dispatcher.HandleWs(reqUnsub(string(resp.Result)), mockConn) + require.NoError(t, err) + + require.NoError(t, json.Unmarshal(r, &resp)) + assert.Equal(t, "true", string(resp.Result)) } func newTestDispatcher(t *testing.T, logger hclog.Logger, store JSONRPCStore, params *dispatcherParams) *Dispatcher { diff --git a/jsonrpc/eth_blockchain_test.go b/jsonrpc/eth_blockchain_test.go index f29b689780..d59019809d 100644 --- a/jsonrpc/eth_blockchain_test.go +++ b/jsonrpc/eth_blockchain_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/0xPolygon/polygon-edge/blockchain" + "github.com/0xPolygon/polygon-edge/helper/hex" "github.com/0xPolygon/polygon-edge/helper/progress" "github.com/0xPolygon/polygon-edge/state/runtime" "github.com/0xPolygon/polygon-edge/types" @@ -95,7 +96,7 @@ func TestEth_Block_GetBlockTransactionCountByNumber(t *testing.T) { assert.NoError(t, err) assert.NotNil(t, res, "expected to return block, but got nil") - assert.Equal(t, res, 10) + assert.Equal(t, "0xa", res) } func TestEth_GetTransactionByHash(t *testing.T) { @@ -188,30 +189,58 @@ func TestEth_GetTransactionReceipt(t *testing.T) { eth := newTestEthEndpoint(store) block := newTestBlock(1, hash4) store.add(block) - txn := newTestTransaction(uint64(0), addr0) - block.Transactions = append(block.Transactions, txn) - rec := &types.Receipt{ + txn0 := newTestTransaction(uint64(0), addr0) + txn1 := newTestTransaction(uint64(1), addr1) + block.Transactions = []*types.Transaction{txn0, txn1} + receipt1 := &types.Receipt{ Logs: []*types.Log{ { + // log 0 + Topics: []types.Hash{ + hash1, + }, + }, + { + // log 1 + Topics: []types.Hash{ + hash2, + }, + }, + { + // log 2 + Topics: []types.Hash{ + hash3, + }, + }, + }, + } + receipt1.SetStatus(types.ReceiptSuccess) + receipt2 := &types.Receipt{ + Logs: []*types.Log{ + { + // log 3 Topics: []types.Hash{ hash4, }, }, }, } - rec.SetStatus(types.ReceiptSuccess) - store.receipts[hash4] = []*types.Receipt{rec} + receipt2.SetStatus(types.ReceiptSuccess) + store.receipts[hash4] = []*types.Receipt{receipt1, receipt2} - res, err := eth.GetTransactionReceipt(txn.Hash) + res, err := eth.GetTransactionReceipt(txn1.Hash) assert.NoError(t, err) assert.NotNil(t, res) //nolint:forcetypeassert response := res.(*receipt) - assert.Equal(t, txn.Hash, response.TxHash) + assert.Equal(t, txn1.Hash, response.TxHash) assert.Equal(t, block.Hash(), response.BlockHash) assert.NotNil(t, response.Logs) + assert.Len(t, response.Logs, 1) + assert.Equal(t, uint64(3), uint64(response.Logs[0].LogIndex)) + assert.Equal(t, uint64(1), uint64(response.Logs[0].TxIndex)) }) } @@ -304,7 +333,7 @@ func TestEth_Call(t *testing.T) { Nonce: argUintPtr(0), } - res, err := eth.Call(contractCall, BlockNumberOrHash{}) + res, err := eth.Call(contractCall, BlockNumberOrHash{}, nil) assert.Error(t, err) assert.Contains(t, err.Error(), store.ethCallError.Error()) @@ -328,11 +357,38 @@ func TestEth_Call(t *testing.T) { Nonce: argUintPtr(0), } - res, err := eth.Call(contractCall, BlockNumberOrHash{}) + res, err := eth.Call(contractCall, BlockNumberOrHash{}, nil) assert.NoError(t, err) assert.NotNil(t, res) }) + + t.Run("returns error and result as data of a reverted transaction execution", func(t *testing.T) { + t.Parallel() + + returnValue := []byte("Reverted()") + + store := newMockBlockStore() + store.add(newTestBlock(100, hash1)) + store.ethCallError = runtime.ErrExecutionReverted + store.returnValue = returnValue + eth := newTestEthEndpoint(store) + contractCall := &txnArgs{ + From: &addr0, + To: &addr1, + Gas: argUintPtr(100000), + GasPrice: argBytesPtr([]byte{0x64}), + Value: argBytesPtr([]byte{0x64}), + Data: nil, + Nonce: argUintPtr(0), + } + + res, err := eth.Call(contractCall, BlockNumberOrHash{}, nil) + assert.Error(t, err) + assert.NotNil(t, res) + bres := res.([]byte) //nolint:forcetypeassert + assert.Equal(t, []byte(hex.EncodeToString(returnValue)), bres) + }) } type testStore interface { @@ -348,6 +404,7 @@ type mockBlockStore struct { isSyncing bool averageGasPrice int64 ethCallError error + returnValue []byte } func newMockBlockStore() *mockBlockStore { @@ -517,14 +574,21 @@ func (m *mockBlockStore) GetAvgGasPrice() *big.Int { return big.NewInt(m.averageGasPrice) } -func (m *mockBlockStore) ApplyTxn(header *types.Header, txn *types.Transaction) (*runtime.ExecutionResult, error) { - return &runtime.ExecutionResult{Err: m.ethCallError}, nil +func (m *mockBlockStore) ApplyTxn(header *types.Header, txn *types.Transaction, overrides types.StateOverride) (*runtime.ExecutionResult, error) { + return &runtime.ExecutionResult{ + Err: m.ethCallError, + ReturnValue: m.returnValue, + }, nil } func (m *mockBlockStore) SubscribeEvents() blockchain.Subscription { return nil } +func (m *mockBlockStore) FilterExtra(extra []byte) ([]byte, error) { + return extra, nil +} + func newTestBlock(number uint64, hash types.Hash) *types.Block { return &types.Block{ Header: &types.Header{ diff --git a/jsonrpc/eth_endpoint.go b/jsonrpc/eth_endpoint.go index ba06b25a65..cbea344587 100644 --- a/jsonrpc/eth_endpoint.go +++ b/jsonrpc/eth_endpoint.go @@ -1,14 +1,15 @@ package jsonrpc import ( + "encoding/hex" "errors" "fmt" "math/big" "github.com/hashicorp/go-hclog" - "github.com/umbracle/fastrlp" "github.com/0xPolygon/polygon-edge/chain" + "github.com/0xPolygon/polygon-edge/gasprice" "github.com/0xPolygon/polygon-edge/helper/common" "github.com/0xPolygon/polygon-edge/helper/progress" "github.com/0xPolygon/polygon-edge/state" @@ -62,17 +63,24 @@ type ethBlockchainStore interface { GetAvgGasPrice() *big.Int // ApplyTxn applies a transaction object to the blockchain - ApplyTxn(header *types.Header, txn *types.Transaction) (*runtime.ExecutionResult, error) + ApplyTxn(header *types.Header, txn *types.Transaction, override types.StateOverride) (*runtime.ExecutionResult, error) // GetSyncProgression retrieves the current sync progression, if any GetSyncProgression() *progress.Progression } +type ethFilter interface { + // FilterExtra filters extra data from header extra that is not included in block hash + FilterExtra(extra []byte) ([]byte, error) +} + // ethStore provides access to the methods needed by eth endpoint type ethStore interface { ethTxPoolStore ethStateStore ethBlockchainStore + ethFilter + gasprice.GasStore } // Eth is the eth jsonrpc endpoint @@ -122,6 +130,10 @@ func (e *Eth) GetBlockByNumber(number BlockNumber, fullTx bool) (interface{}, er return nil, nil } + if err := e.filterExtra(block); err != nil { + return nil, err + } + return toBlock(block, fullTx), nil } @@ -132,9 +144,30 @@ func (e *Eth) GetBlockByHash(hash types.Hash, fullTx bool) (interface{}, error) return nil, nil } + if err := e.filterExtra(block); err != nil { + return nil, err + } + return toBlock(block, fullTx), nil } +func (e *Eth) filterExtra(block *types.Block) error { + // we need to copy it because the store returns header from storage directly + // and not a copy, so changing it, actually changes it in storage as well + headerCopy := block.Header.Copy() + + filteredExtra, err := e.store.FilterExtra(headerCopy.ExtraData) + if err != nil { + return err + } + + headerCopy.ExtraData = filteredExtra + // no need to recompute hash (filtered out data is not in the hash in the first place) + block.Header = headerCopy + + return nil +} + func (e *Eth) GetBlockTransactionCountByNumber(number BlockNumber) (interface{}, error) { num, err := GetNumericBlockNumber(number, e.store) if err != nil { @@ -147,7 +180,7 @@ func (e *Eth) GetBlockTransactionCountByNumber(number BlockNumber) (interface{}, return nil, nil } - return len(block.Transactions), nil + return *types.EncodeUint64(uint64(len(block.Transactions))), nil } // BlockNumber returns current block number @@ -285,35 +318,40 @@ func (e *Eth) GetTransactionReceipt(hash types.Hash) (interface{}, error) { return nil, nil } // find the transaction in the body - indx := -1 + txIndex := -1 + logIndex := 0 for i, txn := range block.Transactions { if txn.Hash == hash { - indx = i + txIndex = i break } + + // accumulate receipt logs indexes from block transactions + // that are before the desired transaction + logIndex += len(receipts[i].Logs) } - if indx == -1 { + if txIndex == -1 { // txn not found return nil, nil } - txn := block.Transactions[indx] - raw := receipts[indx] + txn := block.Transactions[txIndex] + raw := receipts[txIndex] logs := make([]*Log, len(raw.Logs)) - for indx, elem := range raw.Logs { - logs[indx] = &Log{ + for i, elem := range raw.Logs { + logs[i] = &Log{ Address: elem.Address, Topics: elem.Topics, Data: argBytes(elem.Data), BlockHash: block.Hash(), BlockNumber: argUint64(block.Number()), TxHash: txn.Hash, - TxIndex: argUint64(indx), - LogIndex: argUint64(indx), + TxIndex: argUint64(txIndex), + LogIndex: argUint64(logIndex + i), Removed: false, } } @@ -324,7 +362,7 @@ func (e *Eth) GetTransactionReceipt(hash types.Hash) (interface{}, error) { LogsBloom: raw.LogsBloom, Status: argUint64(*raw.Status), TxHash: txn.Hash, - TxIndex: argUint64(indx), + TxIndex: argUint64(txIndex), BlockHash: block.Hash(), BlockNumber: argUint64(block.Number()), GasUsed: argUint64(raw.GasUsed), @@ -358,24 +396,7 @@ func (e *Eth) GetStorageAt( return nil, err } - //nolint:godox - // TODO: GetStorage should return the values already parsed (to be fixed in EVM-522) - - // Parse the RLP value - p := &fastrlp.Parser{} - - v, err := p.Parse(result) - if err != nil { - return argBytesPtr(types.ZeroHash[:]), nil - } - - data, err := v.Bytes() - if err != nil { - return argBytesPtr(types.ZeroHash[:]), nil - } - - // Pad to return 32 bytes data - return argBytesPtr(types.BytesToHash(data).Bytes()), nil + return argBytesPtr(result), nil } // GasPrice returns the average gas price based on the last x blocks @@ -388,8 +409,45 @@ func (e *Eth) GasPrice() (interface{}, error) { return argUint64(common.Max(e.priceLimit, avgGasPrice)), nil } +type overrideAccount struct { + Nonce *argUint64 `json:"nonce"` + Code *argBytes `json:"code"` + Balance *argUint64 `json:"balance"` + State *map[types.Hash]types.Hash `json:"state"` + StateDiff *map[types.Hash]types.Hash `json:"stateDiff"` +} + +func (o *overrideAccount) ToType() types.OverrideAccount { + res := types.OverrideAccount{} + + if o.Nonce != nil { + res.Nonce = (*uint64)(o.Nonce) + } + + if o.Code != nil { + res.Code = *o.Code + } + + if o.Balance != nil { + res.Balance = new(big.Int).SetUint64(*(*uint64)(o.Balance)) + } + + if o.State != nil { + res.State = *o.State + } + + if o.StateDiff != nil { + res.StateDiff = *o.StateDiff + } + + return res +} + +// StateOverride is the collection of overridden accounts. +type stateOverride map[types.Address]overrideAccount + // Call executes a smart contract call using the transaction object data -func (e *Eth) Call(arg *txnArgs, filter BlockNumberOrHash) (interface{}, error) { +func (e *Eth) Call(arg *txnArgs, filter BlockNumberOrHash, apiOverride *stateOverride) (interface{}, error) { header, err := GetHeaderFromBlockNumberOrHash(filter, e.store) if err != nil { return nil, err @@ -404,15 +462,23 @@ func (e *Eth) Call(arg *txnArgs, filter BlockNumberOrHash) (interface{}, error) transaction.Gas = header.GasLimit } + var override types.StateOverride + if apiOverride != nil { + override = types.StateOverride{} + for addr, o := range *apiOverride { + override[addr] = o.ToType() + } + } + // The return value of the execution is saved in the transition (returnValue field) - result, err := e.store.ApplyTxn(header, transaction) + result, err := e.store.ApplyTxn(header, transaction, override) if err != nil { return nil, err } // Check if an EVM revert happened if result.Reverted() { - return nil, constructErrorFromRevert(result) + return []byte(hex.EncodeToString(result.ReturnValue)), constructErrorFromRevert(result) } if result.Failed() { @@ -540,7 +606,7 @@ func (e *Eth) EstimateGas(arg *txnArgs, rawNum *BlockNumber) (interface{}, error txn := transaction.Copy() txn.Gas = gas - result, applyErr := e.store.ApplyTxn(header, txn) + result, applyErr := e.store.ApplyTxn(header, txn, nil) if applyErr != nil { // Check the application error. @@ -726,3 +792,13 @@ func (e *Eth) UninstallFilter(id string) (bool, error) { func (e *Eth) Unsubscribe(id string) (bool, error) { return e.filterManager.Uninstall(id), nil } + +// MaxPriorityFeePerGas calculates the priority fee needed for transaction to be included in a block +func (e *Eth) MaxPriorityFeePerGas() (interface{}, error) { + priorityFee, err := e.store.MaxPriorityFeePerGas() + if err != nil { + return nil, err + } + + return argBigPtr(priorityFee), nil +} diff --git a/jsonrpc/eth_endpoint_test.go b/jsonrpc/eth_endpoint_test.go index 696bed3a1d..c8309141b6 100644 --- a/jsonrpc/eth_endpoint_test.go +++ b/jsonrpc/eth_endpoint_test.go @@ -35,22 +35,26 @@ func TestEth_DecodeTxn(t *testing.T) { { name: "should be successful", arg: &txnArgs{ - From: &addr1, - To: &addr2, - Gas: toArgUint64Ptr(21000), - GasPrice: toArgBytesPtr(big.NewInt(10000).Bytes()), - Value: toArgBytesPtr(oneEther.Bytes()), - Data: nil, - Nonce: toArgUint64Ptr(0), + From: &addr1, + To: &addr2, + Gas: toArgUint64Ptr(21000), + GasPrice: toArgBytesPtr(big.NewInt(10000).Bytes()), + GasTipCap: toArgBytesPtr(big.NewInt(10000).Bytes()), + GasFeeCap: toArgBytesPtr(big.NewInt(10000).Bytes()), + Value: toArgBytesPtr(oneEther.Bytes()), + Data: nil, + Nonce: toArgUint64Ptr(0), }, res: &types.Transaction{ - From: addr1, - To: &addr2, - Gas: 21000, - GasPrice: big.NewInt(10000), - Value: oneEther, - Input: []byte{}, - Nonce: 0, + From: addr1, + To: &addr2, + Gas: 21000, + GasPrice: big.NewInt(10000), + GasTipCap: big.NewInt(10000), + GasFeeCap: big.NewInt(10000), + Value: oneEther, + Input: []byte{}, + Nonce: 0, }, err: nil, }, @@ -64,13 +68,15 @@ func TestEth_DecodeTxn(t *testing.T) { Data: nil, }, res: &types.Transaction{ - From: types.ZeroAddress, - To: &addr2, - Gas: 21000, - GasPrice: big.NewInt(10000), - Value: oneEther, - Input: []byte{}, - Nonce: 0, + From: types.ZeroAddress, + To: &addr2, + Gas: 21000, + GasPrice: big.NewInt(10000), + GasTipCap: new(big.Int), + GasFeeCap: new(big.Int), + Value: oneEther, + Input: []byte{}, + Nonce: 0, }, err: nil, }, @@ -90,13 +96,15 @@ func TestEth_DecodeTxn(t *testing.T) { Data: nil, }, res: &types.Transaction{ - From: addr1, - To: &addr2, - Gas: 21000, - GasPrice: big.NewInt(10000), - Value: oneEther, - Input: []byte{}, - Nonce: 10, + From: addr1, + To: &addr2, + Gas: 21000, + GasPrice: big.NewInt(10000), + GasTipCap: new(big.Int), + GasFeeCap: new(big.Int), + Value: oneEther, + Input: []byte{}, + Nonce: 10, }, err: nil, }, @@ -111,13 +119,15 @@ func TestEth_DecodeTxn(t *testing.T) { Nonce: toArgUint64Ptr(1), }, res: &types.Transaction{ - From: addr1, - To: &addr2, - Gas: 21000, - GasPrice: big.NewInt(10000), - Value: new(big.Int).SetBytes([]byte{}), - Input: []byte{}, - Nonce: 1, + From: addr1, + To: &addr2, + Gas: 21000, + GasPrice: big.NewInt(10000), + GasTipCap: new(big.Int), + GasFeeCap: new(big.Int), + Value: new(big.Int).SetBytes([]byte{}), + Input: []byte{}, + Nonce: 1, }, err: nil, }, @@ -131,13 +141,15 @@ func TestEth_DecodeTxn(t *testing.T) { Nonce: toArgUint64Ptr(1), }, res: &types.Transaction{ - From: addr1, - To: &addr2, - Gas: 0, - GasPrice: big.NewInt(10000), - Value: new(big.Int).SetBytes([]byte{}), - Input: []byte{}, - Nonce: 1, + From: addr1, + To: &addr2, + Gas: 0, + GasPrice: big.NewInt(10000), + GasTipCap: new(big.Int), + GasFeeCap: new(big.Int), + Value: new(big.Int).SetBytes([]byte{}), + Input: []byte{}, + Nonce: 1, }, err: nil, }, @@ -230,6 +242,59 @@ func TestEth_GetNextNonce(t *testing.T) { } } +func TestEth_TxnType(t *testing.T) { + // Set up the mock accounts + accounts := []struct { + address types.Address + account *Account + }{ + { + types.StringToAddress("123"), + &Account{ + Nonce: 5, + }, + }, + } + + // Set up the mock store + store := newMockStore() + for _, acc := range accounts { + store.SetAccount(acc.address, acc.account) + } + + // Setup Txn + args := &txnArgs{ + From: &addr1, + To: &addr2, + Gas: toArgUint64Ptr(21000), + GasPrice: toArgBytesPtr(big.NewInt(10000).Bytes()), + GasTipCap: toArgBytesPtr(big.NewInt(10000).Bytes()), + GasFeeCap: toArgBytesPtr(big.NewInt(10000).Bytes()), + Value: toArgBytesPtr(oneEther.Bytes()), + Data: nil, + Nonce: toArgUint64Ptr(0), + Type: toArgUint64Ptr(uint64(types.DynamicFeeTx)), + } + + expectedRes := &types.Transaction{ + From: addr1, + To: &addr2, + Gas: 21000, + GasPrice: big.NewInt(10000), + GasTipCap: big.NewInt(10000), + GasFeeCap: big.NewInt(10000), + Value: oneEther, + Input: []byte{}, + Nonce: 0, + Type: types.DynamicFeeTx, + } + res, err := DecodeTxn(args, store) + + expectedRes.ComputeHash() + assert.NoError(t, err) + assert.Equal(t, expectedRes, res) +} + func newTestEthEndpoint(store testStore) *Eth { return &Eth{ hclog.NewNullLogger(), store, 100, nil, 0, diff --git a/jsonrpc/eth_state_test.go b/jsonrpc/eth_state_test.go index af3ff5cbd5..79750433dc 100644 --- a/jsonrpc/eth_state_test.go +++ b/jsonrpc/eth_state_test.go @@ -11,7 +11,6 @@ import ( "github.com/0xPolygon/polygon-edge/state/runtime" "github.com/0xPolygon/polygon-edge/types" "github.com/stretchr/testify/assert" - "github.com/umbracle/fastrlp" ) var ( @@ -555,10 +554,7 @@ func TestEth_State_GetStorageAt(t *testing.T) { } account := store.account for index, data := range storage { - a := &fastrlp.Arena{} - value := a.NewBytes(data.Bytes()) - newData := value.MarshalTo(nil) - account.Storage(index, newData) + account.Storage(index, data.Bytes()) } } @@ -616,10 +612,7 @@ func getExampleStore() *mockSpecialStore { // the latest block gas limit for the upper bound, or the specified // gas limit in the transaction func TestEth_EstimateGas_GasLimit(t *testing.T) { - //nolint:godox - // TODO Make this test run in parallel when the race condition is fixed in gas estimation (to be fixed in EVM-523) - store := getExampleStore() - ethEndpoint := newTestEthEndpoint(store) + t.Parallel() testTable := []struct { name string @@ -654,7 +647,14 @@ func TestEth_EstimateGas_GasLimit(t *testing.T) { } for _, testCase := range testTable { + testCase := testCase + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + + store := getExampleStore() + ethEndpoint := newTestEthEndpoint(store) + // Set up the apply hook if errors.Is(testCase.expectedError, state.ErrNotEnoughIntrinsicGas) { // We want to trigger a situation where no value in the gas range is correct @@ -840,7 +840,7 @@ func (m *mockSpecialStore) GetForksInTime(blockNumber uint64) chain.ForksInTime return chain.ForksInTime{} } -func (m *mockSpecialStore) ApplyTxn(header *types.Header, txn *types.Transaction) (*runtime.ExecutionResult, error) { +func (m *mockSpecialStore) ApplyTxn(header *types.Header, txn *types.Transaction, overrides types.StateOverride) (*runtime.ExecutionResult, error) { if m.applyTxnHook != nil { return m.applyTxnHook(header, txn) } diff --git a/jsonrpc/filter_manager.go b/jsonrpc/filter_manager.go index 2e20dd0ad0..489e1a3eb2 100644 --- a/jsonrpc/filter_manager.go +++ b/jsonrpc/filter_manager.go @@ -375,10 +375,11 @@ func (f *FilterManager) getLogsFromBlock(query *LogQuery, block *types.Block) ([ return nil, err } + logIdx := uint64(0) logs := make([]*Log, 0) for idx, receipt := range receipts { - for logIdx, log := range receipt.Logs { + for _, log := range receipt.Logs { if query.Match(log) { logs = append(logs, &Log{ Address: log.Address, @@ -391,6 +392,8 @@ func (f *FilterManager) getLogsFromBlock(query *LogQuery, block *types.Block) ([ LogIndex: argUint64(logIdx), }) } + + logIdx++ } } diff --git a/jsonrpc/filter_manager_test.go b/jsonrpc/filter_manager_test.go index a8658f0ed7..e4aa1092a4 100644 --- a/jsonrpc/filter_manager_test.go +++ b/jsonrpc/filter_manager_test.go @@ -16,6 +16,7 @@ import ( "github.com/gorilla/websocket" "github.com/hashicorp/go-hclog" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func Test_GetLogsForQuery(t *testing.T) { @@ -154,6 +155,82 @@ func Test_GetLogsForQuery(t *testing.T) { } } +func Test_getLogsFromBlock(t *testing.T) { + t.Parallel() + + numOfLogs := 4 + + block := &types.Block{ + Header: &types.Header{Hash: types.StringToHash("someHash"), Number: 1}, + Transactions: []*types.Transaction{ + createTestTransaction(types.StringToHash("tx1")), + createTestTransaction(types.StringToHash("tx2")), + createTestTransaction(types.StringToHash("tx3")), + }, + } + + // setup test with block with 3 transactions and 4 logs + store := &mockBlockStore{receipts: map[types.Hash][]*types.Receipt{ + block.Header.Hash: { + { + // transaction 1 logs + Logs: []*types.Log{ + { + Topics: []types.Hash{ + hash1, + }, + }, + { + Topics: []types.Hash{ + hash2, + }, + }, + }, + }, + { + // transaction 2 logs + Logs: []*types.Log{ + { + Topics: []types.Hash{ + hash3, + }, + }, + }, + }, + { + // transaction 3 logs + Logs: []*types.Log{ + { + Topics: []types.Hash{ + hash4, + }, + }, + }, + }, + }, + }} + + store.appendBlocksToStore([]*types.Block{block}) + + f := NewFilterManager(hclog.NewNullLogger(), store, 1000) + + t.Cleanup(func() { + defer f.Close() + }) + + logs, err := f.getLogsFromBlock(&LogQuery{ + fromBlock: 1, + toBlock: 1, + }, block) + + require.NoError(t, err) + require.Len(t, logs, numOfLogs) + + for i := 0; i < numOfLogs; i++ { + require.Equal(t, uint64(i), uint64(logs[i].LogIndex)) + } +} + func Test_GetLogFilterFromID(t *testing.T) { t.Parallel() diff --git a/jsonrpc/helper.go b/jsonrpc/helper.go index 2bdd7be6fa..4f3fcdc820 100644 --- a/jsonrpc/helper.go +++ b/jsonrpc/helper.go @@ -189,6 +189,14 @@ func DecodeTxn(arg *txnArgs, store nonceGetter) (*types.Transaction, error) { arg.GasPrice = argBytesPtr([]byte{}) } + if arg.GasTipCap == nil { + arg.GasTipCap = argBytesPtr([]byte{}) + } + + if arg.GasFeeCap == nil { + arg.GasFeeCap = argBytesPtr([]byte{}) + } + var input []byte if arg.Data != nil { input = *arg.Data @@ -208,14 +216,23 @@ func DecodeTxn(arg *txnArgs, store nonceGetter) (*types.Transaction, error) { arg.Gas = argUintPtr(0) } + txType := types.LegacyTx + if arg.Type != nil { + txType = types.TxType(*arg.Type) + } + txn := &types.Transaction{ - From: *arg.From, - Gas: uint64(*arg.Gas), - GasPrice: new(big.Int).SetBytes(*arg.GasPrice), - Value: new(big.Int).SetBytes(*arg.Value), - Input: input, - Nonce: uint64(*arg.Nonce), + From: *arg.From, + Gas: uint64(*arg.Gas), + GasPrice: new(big.Int).SetBytes(*arg.GasPrice), + GasTipCap: new(big.Int).SetBytes(*arg.GasTipCap), + GasFeeCap: new(big.Int).SetBytes(*arg.GasFeeCap), + Value: new(big.Int).SetBytes(*arg.Value), + Input: input, + Nonce: uint64(*arg.Nonce), + Type: txType, } + if arg.To != nil { txn.To = arg.To } diff --git a/jsonrpc/helper_test.go b/jsonrpc/helper_test.go index 56b67b14c6..2e1cbf1f91 100644 --- a/jsonrpc/helper_test.go +++ b/jsonrpc/helper_test.go @@ -630,6 +630,8 @@ func TestDecodeTxn(t *testing.T) { to = types.StringToAddress("2") gas = argUint64(uint64(1)) gasPrice = argBytes(new(big.Int).SetUint64(2).Bytes()) + gasTipCap = argBytes(new(big.Int).SetUint64(2).Bytes()) + gasFeeCap = argBytes(new(big.Int).SetUint64(2).Bytes()) value = argBytes(new(big.Int).SetUint64(4).Bytes()) data = argBytes(new(big.Int).SetUint64(8).Bytes()) input = argBytes(new(big.Int).SetUint64(16).Bytes()) @@ -649,23 +651,27 @@ func TestDecodeTxn(t *testing.T) { { name: "should return mapped transaction", arg: &txnArgs{ - From: &from, - To: &to, - Gas: &gas, - GasPrice: &gasPrice, - Value: &value, - Input: &input, - Nonce: &nonce, + From: &from, + To: &to, + Gas: &gas, + GasPrice: &gasPrice, + GasTipCap: &gasTipCap, + GasFeeCap: &gasFeeCap, + Value: &value, + Input: &input, + Nonce: &nonce, }, store: &debugEndpointMockStore{}, expected: &types.Transaction{ - From: from, - To: &to, - Gas: uint64(gas), - GasPrice: new(big.Int).SetBytes([]byte(gasPrice)), - Value: new(big.Int).SetBytes([]byte(value)), - Input: input, - Nonce: uint64(nonce), + From: from, + To: &to, + Gas: uint64(gas), + GasPrice: new(big.Int).SetBytes([]byte(gasPrice)), + GasTipCap: new(big.Int).SetBytes([]byte(gasTipCap)), + GasFeeCap: new(big.Int).SetBytes([]byte(gasFeeCap)), + Value: new(big.Int).SetBytes([]byte(value)), + Input: input, + Nonce: uint64(nonce), }, err: false, }, @@ -681,13 +687,15 @@ func TestDecodeTxn(t *testing.T) { }, store: &debugEndpointMockStore{}, expected: &types.Transaction{ - From: types.ZeroAddress, - To: &to, - Gas: uint64(gas), - GasPrice: new(big.Int).SetBytes([]byte(gasPrice)), - Value: new(big.Int).SetBytes([]byte(value)), - Input: input, - Nonce: uint64(0), + From: types.ZeroAddress, + To: &to, + Gas: uint64(gas), + GasPrice: new(big.Int).SetBytes([]byte(gasPrice)), + GasTipCap: new(big.Int), + GasFeeCap: new(big.Int), + Value: new(big.Int).SetBytes([]byte(value)), + Input: input, + Nonce: uint64(0), }, err: false, }, @@ -714,13 +722,15 @@ func TestDecodeTxn(t *testing.T) { }, }, expected: &types.Transaction{ - From: from, - To: &to, - Gas: uint64(gas), - GasPrice: new(big.Int).SetBytes([]byte(gasPrice)), - Value: new(big.Int).SetBytes([]byte(value)), - Input: input, - Nonce: uint64(stateNonce), + From: from, + To: &to, + Gas: uint64(gas), + GasPrice: new(big.Int).SetBytes([]byte(gasPrice)), + GasTipCap: new(big.Int), + GasFeeCap: new(big.Int), + Value: new(big.Int).SetBytes([]byte(value)), + Input: input, + Nonce: uint64(stateNonce), }, err: false, }, @@ -738,13 +748,15 @@ func TestDecodeTxn(t *testing.T) { }, store: &debugEndpointMockStore{}, expected: &types.Transaction{ - From: from, - To: &to, - Gas: uint64(gas), - GasPrice: new(big.Int).SetBytes([]byte(gasPrice)), - Value: new(big.Int).SetBytes([]byte(value)), - Input: data, - Nonce: uint64(nonce), + From: from, + To: &to, + Gas: uint64(gas), + GasPrice: new(big.Int).SetBytes([]byte(gasPrice)), + GasTipCap: new(big.Int), + GasFeeCap: new(big.Int), + Value: new(big.Int).SetBytes([]byte(value)), + Input: data, + Nonce: uint64(nonce), }, err: false, }, @@ -757,13 +769,15 @@ func TestDecodeTxn(t *testing.T) { }, store: &debugEndpointMockStore{}, expected: &types.Transaction{ - From: from, - To: &to, - Gas: uint64(0), - GasPrice: new(big.Int), - Value: new(big.Int), - Input: []byte{}, - Nonce: uint64(nonce), + From: from, + To: &to, + Gas: uint64(0), + GasPrice: new(big.Int), + GasTipCap: new(big.Int), + GasFeeCap: new(big.Int), + Value: new(big.Int), + Input: []byte{}, + Nonce: uint64(nonce), }, err: false, }, diff --git a/jsonrpc/mocks_test.go b/jsonrpc/mocks_test.go index f1738dfc00..1078090d39 100644 --- a/jsonrpc/mocks_test.go +++ b/jsonrpc/mocks_test.go @@ -196,3 +196,7 @@ func (m *mockStore) GetStateSyncProof(stateSyncID uint64) (types.Proof, error) { return ssp, nil } + +func (m *mockStore) FilterExtra(extra []byte) ([]byte, error) { + return extra, nil +} diff --git a/jsonrpc/testsuite/block-empty.json b/jsonrpc/testsuite/block-empty.json index 3c77c97506..55408d0795 100644 --- a/jsonrpc/testsuite/block-empty.json +++ b/jsonrpc/testsuite/block-empty.json @@ -18,5 +18,6 @@ "nonce": "0x0a00000000000000", "hash": "0x0800000000000000000000000000000000000000000000000000000000000000", "transactions": null, - "uncles": null -} \ No newline at end of file + "uncles": null, + "baseFee": "0xf" +} diff --git a/jsonrpc/testsuite/block-with-no-basefee.json b/jsonrpc/testsuite/block-with-no-basefee.json new file mode 100644 index 0000000000..293c7cb582 --- /dev/null +++ b/jsonrpc/testsuite/block-with-no-basefee.json @@ -0,0 +1,22 @@ +{ + "parentHash": "0x0100000000000000000000000000000000000000000000000000000000000000", + "sha3Uncles": "0x0200000000000000000000000000000000000000000000000000000000000000", + "miner": "0x0100000000000000000000000000000000000000", + "stateRoot": "0x0400000000000000000000000000000000000000000000000000000000000000", + "transactionsRoot": "0x0500000000000000000000000000000000000000000000000000000000000000", + "receiptsRoot": "0x0600000000000000000000000000000000000000000000000000000000000000", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "difficulty": "0xa", + "totalDifficulty": "0x0", + "size": "0x0", + "number": "0xb", + "gasLimit": "0xc", + "gasUsed": "0xd", + "timestamp": "0xe", + "extraData": "0x616263646566", + "mixHash": "0x0700000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x0a00000000000000", + "hash": "0x0800000000000000000000000000000000000000000000000000000000000000", + "transactions": null, + "uncles": null +} diff --git a/jsonrpc/testsuite/block-with-txn-bodies.json b/jsonrpc/testsuite/block-with-txn-bodies.json index e6435a01af..80fdb4a40b 100644 --- a/jsonrpc/testsuite/block-with-txn-bodies.json +++ b/jsonrpc/testsuite/block-with-txn-bodies.json @@ -32,8 +32,10 @@ "from": "0x0300000000000000000000000000000000000000", "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "blockNumber": "0x1", - "transactionIndex": "0x2" + "transactionIndex": "0x2", + "type": "0x0" } ], - "uncles": null -} \ No newline at end of file + "uncles": null, + "baseFee": "0xf" +} diff --git a/jsonrpc/testsuite/block-with-txn-hashes.json b/jsonrpc/testsuite/block-with-txn-hashes.json index e3cebad1b7..5925537af4 100644 --- a/jsonrpc/testsuite/block-with-txn-hashes.json +++ b/jsonrpc/testsuite/block-with-txn-hashes.json @@ -20,5 +20,6 @@ "transactions": [ "0x0800000000000000000000000000000000000000000000000000000000000000" ], - "uncles": null -} \ No newline at end of file + "uncles": null, + "baseFee": "0xf" +} diff --git a/jsonrpc/testsuite/transaction-eip1559.json b/jsonrpc/testsuite/transaction-eip1559.json new file mode 100644 index 0000000000..33b072339c --- /dev/null +++ b/jsonrpc/testsuite/transaction-eip1559.json @@ -0,0 +1,19 @@ +{ + "nonce": "0x1", + "gasPrice": "0xa", + "gasTipCap": "0xa", + "gasFeeCap": "0xa", + "gas": "0x64", + "to": "0x0000000000000000000000000000000000000000", + "value": "0x3e8", + "input": "0x0102", + "v": "0x1", + "r": "0x2", + "s": "0x3", + "hash": "0x0200000000000000000000000000000000000000000000000000000000000000", + "from": "0x0300000000000000000000000000000000000000", + "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockNumber": "0x1", + "transactionIndex": "0x2", + "type": "0x2" +} \ No newline at end of file diff --git a/jsonrpc/testsuite/transaction-pending.json b/jsonrpc/testsuite/transaction-pending.json index ccbbe31fac..f7e0f6de3b 100644 --- a/jsonrpc/testsuite/transaction-pending.json +++ b/jsonrpc/testsuite/transaction-pending.json @@ -12,5 +12,6 @@ "from": "0x0300000000000000000000000000000000000000", "blockHash": null, "blockNumber": null, - "transactionIndex": null + "transactionIndex": null, + "type": "0x0" } \ No newline at end of file diff --git a/jsonrpc/testsuite/transaction-sealed.json b/jsonrpc/testsuite/transaction-sealed.json index 86b238547f..c54be34d8c 100644 --- a/jsonrpc/testsuite/transaction-sealed.json +++ b/jsonrpc/testsuite/transaction-sealed.json @@ -12,5 +12,6 @@ "from": "0x0300000000000000000000000000000000000000", "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "blockNumber": "0x1", - "transactionIndex": "0x2" + "transactionIndex": "0x2", + "type": "0x0" } \ No newline at end of file diff --git a/jsonrpc/txpool_endpoint.go b/jsonrpc/txpool_endpoint.go index f786df059f..0d91a06ec7 100644 --- a/jsonrpc/txpool_endpoint.go +++ b/jsonrpc/txpool_endpoint.go @@ -41,6 +41,8 @@ type StatusResponse struct { type txpoolTransaction struct { Nonce argUint64 `json:"nonce"` GasPrice argBig `json:"gasPrice"` + GasFeeCap *argBig `json:"gasFeeCap,omitempty"` + GasTipCap *argBig `json:"gasTipCap,omitempty"` Gas argUint64 `json:"gas"` To *types.Address `json:"to"` Value argBig `json:"value"` @@ -53,9 +55,23 @@ type txpoolTransaction struct { } func toTxPoolTransaction(t *types.Transaction) *txpoolTransaction { + var gasTipCap, gasFeeCap *argBig + + if t.GasTipCap != nil { + gasTipCapVal := argBig(*t.GasTipCap) + gasTipCap = &gasTipCapVal + } + + if t.GasFeeCap != nil { + gasFeeCapVal := argBig(*t.GasFeeCap) + gasFeeCap = &gasFeeCapVal + } + return &txpoolTransaction{ Nonce: argUint64(t.Nonce), GasPrice: argBig(*t.GasPrice), + GasFeeCap: gasFeeCap, + GasTipCap: gasTipCap, Gas: argUint64(t.Gas), To: t.To, Value: argBig(*t.Value), diff --git a/jsonrpc/types.go b/jsonrpc/types.go index e09bb89327..2e2a5e3f57 100644 --- a/jsonrpc/types.go +++ b/jsonrpc/types.go @@ -9,6 +9,8 @@ import ( "github.com/0xPolygon/polygon-edge/types" ) +const jsonRPCMetric = "json_rpc" + // For union type of transaction and types.Hash type transactionOrHash interface { getHash() types.Hash @@ -17,6 +19,8 @@ type transactionOrHash interface { type transaction struct { Nonce argUint64 `json:"nonce"` GasPrice argBig `json:"gasPrice"` + GasTipCap *argBig `json:"gasTipCap,omitempty"` + GasFeeCap *argBig `json:"gasFeeCap,omitempty"` Gas argUint64 `json:"gas"` To *types.Address `json:"to"` Value argBig `json:"value"` @@ -29,6 +33,7 @@ type transaction struct { BlockHash *types.Hash `json:"blockHash"` BlockNumber *argUint64 `json:"blockNumber"` TxIndex *argUint64 `json:"transactionIndex"` + Type argUint64 `json:"type"` } func (t transaction) getHash() types.Hash { return t.Hash } @@ -64,6 +69,17 @@ func toTransaction( S: argBig(*t.S), Hash: t.Hash, From: t.From, + Type: argUint64(t.Type), + } + + if t.GasTipCap != nil { + gasTipCap := argBig(*t.GasTipCap) + res.GasTipCap = &gasTipCap + } + + if t.GasFeeCap != nil { + gasFeeCap := argBig(*t.GasFeeCap) + res.GasFeeCap = &gasFeeCap } if blockNumber != nil { @@ -102,6 +118,7 @@ type block struct { Hash types.Hash `json:"hash"` Transactions []transactionOrHash `json:"transactions"` Uncles []types.Hash `json:"uncles"` + BaseFee argUint64 `json:"baseFee,omitempty"` } func (b *block) Copy() *block { @@ -140,6 +157,7 @@ func toBlock(b *types.Block, fullTx bool) *block { Hash: h.Hash, Transactions: []transactionOrHash{}, Uncles: []types.Hash{}, + BaseFee: argUint64(h.BaseFee), } for idx, txn := range b.Transactions { @@ -307,14 +325,17 @@ func encodeToHex(b []byte) []byte { // txnArgs is the transaction argument for the rpc endpoints type txnArgs struct { - From *types.Address - To *types.Address - Gas *argUint64 - GasPrice *argBytes - Value *argBytes - Data *argBytes - Input *argBytes - Nonce *argUint64 + From *types.Address + To *types.Address + Gas *argUint64 + GasPrice *argBytes + GasTipCap *argBytes + GasFeeCap *argBytes + Value *argBytes + Data *argBytes + Input *argBytes + Nonce *argUint64 + Type *argUint64 } type progression struct { diff --git a/jsonrpc/types_test.go b/jsonrpc/types_test.go index a3958c9c8e..3f2ef341ee 100644 --- a/jsonrpc/types_test.go +++ b/jsonrpc/types_test.go @@ -143,64 +143,64 @@ func TestBlock_Copy(t *testing.T) { var testsuite embed.FS func TestBlock_Encoding(t *testing.T) { - b := block{ - ParentHash: types.Hash{0x1}, - Sha3Uncles: types.Hash{0x2}, - Miner: types.Address{0x1}.Bytes(), - StateRoot: types.Hash{0x4}, - TxRoot: types.Hash{0x5}, - ReceiptsRoot: types.Hash{0x6}, - LogsBloom: types.Bloom{0x0}, - Difficulty: 10, - Number: 11, - GasLimit: 12, - GasUsed: 13, - Timestamp: 14, - ExtraData: []byte{97, 98, 99, 100, 101, 102}, - MixHash: types.Hash{0x7}, - Nonce: types.Nonce{10}, - Hash: types.Hash{0x8}, + getBlock := func() block { + return block{ + ParentHash: types.Hash{0x1}, + Sha3Uncles: types.Hash{0x2}, + Miner: types.Address{0x1}.Bytes(), + StateRoot: types.Hash{0x4}, + TxRoot: types.Hash{0x5}, + ReceiptsRoot: types.Hash{0x6}, + LogsBloom: types.Bloom{0x0}, + Difficulty: 10, + Number: 11, + GasLimit: 12, + GasUsed: 13, + Timestamp: 14, + ExtraData: []byte{97, 98, 99, 100, 101, 102}, + MixHash: types.Hash{0x7}, + Nonce: types.Nonce{10}, + Hash: types.Hash{0x8}, + BaseFee: 15, + } } - testBlock := func(name string) { + testBlock := func(name string, b block) { res, err := json.Marshal(b) require.NoError(t, err) data, err := testsuite.ReadFile(name) require.NoError(t, err) - - data = removeWhiteSpace(data) - require.Equal(t, res, data) + require.JSONEq(t, string(data), string(res)) } t.Run("empty block", func(t *testing.T) { - testBlock("testsuite/block-empty.json") + testBlock("testsuite/block-empty.json", getBlock()) + }) + + t.Run("block with no base fee", func(t *testing.T) { + b := getBlock() + b.BaseFee = 0 + testBlock("testsuite/block-with-no-basefee.json", b) }) t.Run("block with transaction hashes", func(t *testing.T) { + b := getBlock() b.Transactions = []transactionOrHash{ transactionHash{0x8}, } - testBlock("testsuite/block-with-txn-hashes.json") + testBlock("testsuite/block-with-txn-hashes.json", b) }) t.Run("block with transaction bodies", func(t *testing.T) { + b := getBlock() b.Transactions = []transactionOrHash{ mockTxn(), } - testBlock("testsuite/block-with-txn-bodies.json") + testBlock("testsuite/block-with-txn-bodies.json", b) }) } -func removeWhiteSpace(d []byte) []byte { - s := string(d) - s = strings.Replace(s, "\n", "", -1) - s = strings.Replace(s, "\t", "", -1) - s = strings.Replace(s, " ", "", -1) - - return []byte(s) -} - func mockTxn() *transaction { to := types.Address{} @@ -219,34 +219,46 @@ func mockTxn() *transaction { BlockHash: &types.ZeroHash, BlockNumber: argUintPtr(1), TxIndex: argUintPtr(2), + Type: argUint64(types.LegacyTx), } return tt } func TestTransaction_Encoding(t *testing.T) { - tt := mockTxn() - - testTransaction := func(name string) { + testTransaction := func(name string, tt *transaction) { res, err := json.Marshal(tt) require.NoError(t, err) data, err := testsuite.ReadFile(name) require.NoError(t, err) - - data = removeWhiteSpace(data) - require.Equal(t, res, data) + require.JSONEq(t, string(data), string(res)) } t.Run("sealed", func(t *testing.T) { - testTransaction("testsuite/transaction-sealed.json") + tt := mockTxn() + + testTransaction("testsuite/transaction-sealed.json", tt) }) t.Run("pending", func(t *testing.T) { + tt := mockTxn() tt.BlockHash = nil tt.BlockNumber = nil tt.TxIndex = nil - testTransaction("testsuite/transaction-pending.json") + testTransaction("testsuite/transaction-pending.json", tt) + }) + + t.Run("eip-1559", func(t *testing.T) { + gasTipCap := argBig(*big.NewInt(10)) + gasFeeCap := argBig(*big.NewInt(10)) + + tt := mockTxn() + tt.GasTipCap = &gasTipCap + tt.GasFeeCap = &gasFeeCap + tt.Type = argUint64(types.DynamicFeeTx) + + testTransaction("testsuite/transaction-eip1559.json", tt) }) } diff --git a/network/gossip.go b/network/gossip.go index b044949515..562bb46682 100644 --- a/network/gossip.go +++ b/network/gossip.go @@ -4,8 +4,10 @@ import ( "context" "errors" "reflect" + "sync" "sync/atomic" + "github.com/armon/go-metrics" "github.com/hashicorp/go-hclog" pubsub "github.com/libp2p/go-libp2p-pubsub" "github.com/libp2p/go-libp2p/core/peer" @@ -22,10 +24,11 @@ const ( type Topic struct { logger hclog.Logger - topic *pubsub.Topic - typ reflect.Type - closeCh chan struct{} - closed *uint64 + topic *pubsub.Topic + typ reflect.Type + closeCh chan struct{} + closed atomic.Bool + waitGroup sync.WaitGroup } func (t *Topic) createObj() proto.Message { @@ -38,17 +41,19 @@ func (t *Topic) createObj() proto.Message { } func (t *Topic) Close() { - if atomic.SwapUint64(t.closed, 1) > 0 { + if t.closed.Swap(true) { // Already closed. return } + close(t.closeCh) // close all subscribers + t.waitGroup.Wait() // wait for all the subscribers to finish + + // if all subscribers are finished, close the topic if t.topic != nil { t.topic.Close() t.topic = nil } - - close(t.closeCh) } func (t *Topic) Publish(obj proto.Message) error { @@ -57,6 +62,8 @@ func (t *Topic) Publish(obj proto.Message) error { return err } + metrics.SetGauge([]string{networkMetrics, "egress_bytes"}, float32(len(data))) + return t.topic.Publish(context.Background(), data) } @@ -67,7 +74,7 @@ func (t *Topic) Subscribe(handler func(obj interface{}, from peer.ID)) error { } // Mark topic active. - atomic.StoreUint64(t.closed, 0) + t.closed.Store(false) go t.readLoop(sub, handler) @@ -75,6 +82,9 @@ func (t *Topic) Subscribe(handler func(obj interface{}, from peer.ID)) error { } func (t *Topic) readLoop(sub *pubsub.Subscription, handler func(obj interface{}, from peer.ID)) { + t.waitGroup.Add(1) + defer t.waitGroup.Done() + ctx, cancelFn := context.WithCancel(context.Background()) go func() { @@ -91,6 +101,7 @@ func (t *Topic) readLoop(sub *pubsub.Subscription, handler func(obj interface{}, } t.logger.Error("failed to get topic", "err", err) + metrics.IncrCounter([]string{networkMetrics, "bad_messages"}, float32(1)) continue } @@ -99,10 +110,13 @@ func (t *Topic) readLoop(sub *pubsub.Subscription, handler func(obj interface{}, obj := t.createObj() if err := proto.Unmarshal(msg.Data, obj); err != nil { t.logger.Error("failed to unmarshal topic", "err", err) + metrics.IncrCounter([]string{networkMetrics, "bad_messages"}, float32(1)) return } + metrics.SetGauge([]string{networkMetrics, "ingress_bytes"}, float32(len(msg.Data))) + handler(obj, msg.GetFrom()) }() } @@ -119,8 +133,8 @@ func (s *Server) NewTopic(protoID string, obj proto.Message) (*Topic, error) { topic: topic, typ: reflect.TypeOf(obj).Elem(), closeCh: make(chan struct{}), - closed: new(uint64), } + tt.closed.Store(false) return tt, nil } diff --git a/network/gossip_test.go b/network/gossip_test.go index 57dd16c224..9655c7762d 100644 --- a/network/gossip_test.go +++ b/network/gossip_test.go @@ -111,7 +111,6 @@ func TestSimpleGossip(t *testing.T) { func Test_RepeatedClose(t *testing.T) { topic := &Topic{ closeCh: make(chan struct{}), - closed: new(uint64), } // Call Close() twice to ensure that underlying logic (e.g. channel close) is diff --git a/network/server.go b/network/server.go index 081bfcc061..b6be58f3a4 100644 --- a/network/server.go +++ b/network/server.go @@ -400,7 +400,7 @@ func (s *Server) runDial() { //nolint:godox // TODO: Right now the dial task are done sequentially because Connect // is a blocking request. In the future we should try to make up to - // maxDials requests concurrently (to be fixed in EVM-541) + // maxDials requests concurrently (to be fixed in EVM-543) for s.connectionCounts.HasFreeOutboundConn() { tt := s.dialQueue.PopTask() if tt == nil { @@ -473,7 +473,12 @@ func (s *Server) IsConnected(peerID peer.ID) bool { // GetProtocols fetches the list of node-supported protocols func (s *Server) GetProtocols(peerID peer.ID) ([]string, error) { - return s.host.Peerstore().GetProtocols(peerID) + protocols, err := s.host.Peerstore().GetProtocols(peerID) + if err != nil { + return nil, err + } + + return protocol.ConvertToStrings(protocols), nil } // removePeer removes a peer from the networking server's peer list, diff --git a/network/server_discovery.go b/network/server_discovery.go index 26d17f3da5..09f8c4fdee 100644 --- a/network/server_discovery.go +++ b/network/server_discovery.go @@ -206,8 +206,11 @@ func (s *Server) setupDiscovery() error { // Set the PeerAdded event handler routingTable.PeerAdded = func(p peer.ID) { - info := s.host.Peerstore().PeerInfo(p) - s.addToDialQueue(&info, common.PriorityRandomDial) + // this is called from the lock. because of that execute addToDialQueue on separated routine + go func() { + info := s.host.Peerstore().PeerInfo(p) + s.addToDialQueue(&info, common.PriorityRandomDial) + }() } // Set the PeerRemoved event handler diff --git a/network/server_identity.go b/network/server_identity.go index c1c5541ee3..27ed6bc9a7 100644 --- a/network/server_identity.go +++ b/network/server_identity.go @@ -42,8 +42,6 @@ func (s *Server) AddPeer(id peer.ID, direction network.Direction) { // Emit the event alerting listeners // WARNING: THIS CALL IS POTENTIALLY BLOCKING - // UNDER HEAVY LOAD. IT SHOULD BE SUBSTITUTED - // WITH AN EVENT SYSTEM THAT ACTUALLY WORKS s.emitEvent(id, peerEvent.PeerConnected) } diff --git a/network/server_test.go b/network/server_test.go index 62badbd85f..5d9ed1fd7e 100644 --- a/network/server_test.go +++ b/network/server_test.go @@ -608,6 +608,7 @@ func TestSelfConnection_WithBootNodes(t *testing.T) { } func TestRunDial(t *testing.T) { + t.Skip() // setupServers returns server and list of peer's server setupServers := func(t *testing.T, maxPeers []int64) []*Server { t.Helper() @@ -1025,13 +1026,7 @@ func TestPeerAdditionDeletion(t *testing.T) { } t.Run("peers are added correctly", func(t *testing.T) { - server := createServer() - - //nolint:godox - // TODO increase this number to something astronomical - // when the networking package has an event system that actually works, - // as emitEvent can completely bug out when under load inside Server.AddPeer (to be fixed in EVM-525) - generateAndAddPeers(server, 10) + generateAndAddPeers(createServer(), 2500) }) t.Run("no duplicate peers added", func(t *testing.T) { diff --git a/scripts/README.md b/scripts/README.md index bfda08cc3f..0599d0832a 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -1,10 +1,12 @@ -# Run servers form local binary +# Run servers from local binary ## Prerequisites When deploying with `polybft` consensus, there are some additional dependencies: * [npm](https://nodejs.org/en/) -* [go 1.18.x](https://go.dev/dl/) +* [go 1.20.x](https://go.dev/dl/) +* [jq](https://jqlang.github.io/jq) +* Netcat (nc) ## Local development Running `polygon-edge` from local binary can be done very easily by using provided `scripts` folder. @@ -33,4 +35,4 @@ To do that simply run `make download-submodules`. ### Production This is **NOT** a production ready deployment. It is to be used in *development* / *test* environments only. -For production usage, please check out the official [docs](https://wiki.polygon.technology/docs/edge/overview/). \ No newline at end of file +For production usage, please check out the official [docs](https://wiki.polygon.technology/docs/edge/overview/). diff --git a/scripts/cluster b/scripts/cluster index 149fdfb6ab..df005c31f9 100755 --- a/scripts/cluster +++ b/scripts/cluster @@ -1,29 +1,132 @@ #!/usr/bin/env bash +dp_error_flag=0 + +# Check if jq is installed +if [[ "$1" == "polybft" ]] && ! command -v jq >/dev/null 2>&1; then + echo "jq is not installed." + echo "Manual installation instructions: Visit https://jqlang.github.io/jq/ for more information." + dp_error_flag=1 +fi + +# Check if nc is installed +if [[ "$1" == "polybft" ]] && ! command -v nc >/dev/null 2>&1; then + echo "Netcat (nc) is not installed." + dp_error_flag=1 +fi + +# Stop script if any of the dependencies have failed +if [[ "$dp_error_flag" -eq 1]]; then + echo "Missing dependencies. Please install them and run the script again." + exit 1 +fi + function initIbftConsensus() { - echo "Running with ibft consensus" - ./polygon-edge secrets init --insecure --data-dir test-chain- --num 4 + echo "Running with ibft consensus" + ./polygon-edge secrets init --insecure --data-dir test-chain- --num 4 - node1_id=$(./polygon-edge secrets output --data-dir test-chain-1 | grep Node | head -n 1 | awk -F ' ' '{print $4}') - node2_id=$(./polygon-edge secrets output --data-dir test-chain-2 | grep Node | head -n 1 | awk -F ' ' '{print $4}') + node1_id=$(./polygon-edge secrets output --data-dir test-chain-1 | grep Node | head -n 1 | awk -F ' ' '{print $4}') + node2_id=$(./polygon-edge secrets output --data-dir test-chain-2 | grep Node | head -n 1 | awk -F ' ' '{print $4}') - genesis_params="--consensus ibft --ibft-validators-prefix-path test-chain- \ + genesis_params="--consensus ibft --ibft-validators-prefix-path test-chain- \ --bootnode /ip4/127.0.0.1/tcp/30301/p2p/$node1_id \ --bootnode /ip4/127.0.0.1/tcp/30302/p2p/$node2_id" } function initPolybftConsensus() { - echo "Running with polybft consensus" - genesis_params="--consensus polybft --validator-set-size=4 --bridge-json-rpc http://127.0.0.1:8545" - ./polygon-edge polybft-secrets --insecure --data-dir test-chain- --num 4 - ./polygon-edge manifest + echo "Running with polybft consensus" + genesis_params="--consensus polybft" + + address1=$(./polygon-edge polybft-secrets --insecure --data-dir test-chain-1 | grep Public | head -n 1 | awk -F ' ' '{print $5}') + address2=$(./polygon-edge polybft-secrets --insecure --data-dir test-chain-2 | grep Public | head -n 1 | awk -F ' ' '{print $5}') + address3=$(./polygon-edge polybft-secrets --insecure --data-dir test-chain-3 | grep Public | head -n 1 | awk -F ' ' '{print $5}') + address4=$(./polygon-edge polybft-secrets --insecure --data-dir test-chain-4 | grep Public | head -n 1 | awk -F ' ' '{print $5}') } function createGenesis() { - ./polygon-edge genesis $genesis_params \ - --block-gas-limit 10000000 \ - --premine 0x85da99c8a7c2c95964c8efd687e95e632fc533d6:1000000000000000000000 \ - --epoch-size 10 + ./polygon-edge genesis $genesis_params \ + --block-gas-limit 10000000 \ + --premine 0x85da99c8a7c2c95964c8efd687e95e632fc533d6:1000000000000000000000 \ + --premine 0x0000000000000000000000000000000000000000 \ + --epoch-size 10 \ + --reward-wallet 0xDEADBEEF:1000000 \ + --native-token-config "Polygon:MATIC:18:true:$address1" \ + --burn-contract 0:0x0000000000000000000000000000000000000000 +} + +function initRootchain() { + echo "Initializing rootchain" + + if [ "$1" == "write-logs" ]; then + echo "Writing rootchain server logs to the file..." + ./polygon-edge rootchain server 2>&1 | tee ./rootchain-server.log & + else + ./polygon-edge rootchain server >/dev/null & + fi + + set +e + t=1 + while [ $t -gt 0 ]; do + nc -z 127.0.0.1 8545 &1 | tee ./validator-4.log & - wait + wait else ./polygon-edge server --data-dir ./test-chain-1 --chain genesis.json \ --grpc-address :10000 --libp2p :30301 --jsonrpc :10002 \ @@ -55,29 +158,25 @@ function startServerFromBinary() { ./polygon-edge server --data-dir ./test-chain-4 --chain genesis.json \ --grpc-address :40000 --libp2p :30304 --jsonrpc :40002 \ --num-block-confirmations 2 --seal --log-level DEBUG & - wait + wait fi } function startServerFromDockerCompose() { - case "$1" in - "ibft") - docker-compose -f ./docker/local/docker-compose.yml up -d --build - ;; - "polybft") - cd core-contracts && npm install && npm run compile && cd - - go run ./consensus/polybft/contractsapi/artifacts-gen/main.go - EDGE_CONSENSUS=polybft docker-compose -f ./docker/local/docker-compose.yml up -d --build - ;; - esac + if [ "$1" != "polybft" ] + then + export EDGE_CONSENSUS="$1" + fi + + docker-compose -f ./docker/local/docker-compose.yml up -d --build } function destroyDockerEnvironment() { - docker-compose -f ./docker/local/docker-compose.yml down -v + docker-compose -f ./docker/local/docker-compose.yml down -v } function stopDockerEnvironment() { - docker-compose -f ./docker/local/docker-compose.yml stop + docker-compose -f ./docker/local/docker-compose.yml stop } set -e @@ -85,53 +184,53 @@ set -e # Reset test-dirs rm -rf test-chain-* rm -f genesis.json -rm -f manifest.json # Build binary go build -o polygon-edge . # If --docker flag is set run docker environment otherwise run from binary case "$2" in - "--docker") - # cluster {consensus} --docker destroy - if [ "$3" == "destroy" ]; then - destroyDockerEnvironment - echo "Docker $1 environment destroyed!" - exit 0 - # cluster {consensus} --docker stop - elif [ "$3" == "stop" ]; then - stopDockerEnvironment - echo "Docker $1 environment stoped!" - exit 0; - fi - - # cluster {consensus} --docker - echo "Running $1 docker environment..." - startServerFromDockerCompose $1 - echo "Docker $1 environment deployed." +"--docker") + # cluster {consensus} --docker destroy + if [ "$3" == "destroy" ]; then + destroyDockerEnvironment + echo "Docker $1 environment destroyed!" exit 0 - ;; - # cluster {consensus} - *) - echo "Running $1 environment from local binary..." - # Initialize ibft or polybft consensus - if [ "$1" == "ibft" ]; then - # Initialize ibft consensus - initIbftConsensus - # Create genesis file and start the server from binary - createGenesis - startServerFromBinary $2 - exit 0; - elif [ "$1" == "polybft" ]; then - # Initialize polybft consensus - initPolybftConsensus - # Create genesis file and start the server from binary - createGenesis - startServerFromBinary $2 - exit 0; - else - echo "Unsupported consensus mode. Supported modes are: ibft and polybft " - exit 1; - fi + # cluster {consensus} --docker stop + elif [ "$3" == "stop" ]; then + stopDockerEnvironment + echo "Docker $1 environment stoped!" + exit 0 + fi + + # cluster {consensus} --docker + echo "Running $1 docker environment..." + startServerFromDockerCompose $1 + echo "Docker $1 environment deployed." + exit 0 + ;; +# cluster {consensus} +*) + echo "Running $1 environment from local binary..." + # Initialize ibft or polybft consensus + if [ "$1" == "ibft" ]; then + # Initialize ibft consensus + initIbftConsensus + # Create genesis file and start the server from binary + createGenesis + startServerFromBinary $2 + exit 0 + elif [ "$1" == "polybft" ]; then + # Initialize polybft consensus + initPolybftConsensus + # Create genesis file and start the server from binary + createGenesis + initRootchain $2 + startServerFromBinary $2 + exit 0 + else + echo "Unsupported consensus mode. Supported modes are: ibft and polybft " + exit 1 + fi ;; esac diff --git a/scripts/fuzzAll b/scripts/fuzzAll new file mode 100755 index 0000000000..ece67fb600 --- /dev/null +++ b/scripts/fuzzAll @@ -0,0 +1,18 @@ +#!/bin/bash + +set -e + +fuzzTime=${1:-10} + +files=$(grep -r --include='**_test.go' --files-with-matches 'func Fuzz' .) + +for file in ${files} +do + funcs=$(grep -o 'func Fuzz\w*' $file | sed 's/func //') + for func in ${funcs} + do + echo "Fuzzing $func in $file" + parentDir=$(dirname $file) + go test $parentDir -run=$func -fuzz=$func -fuzztime=${fuzzTime}s + done +done diff --git a/secrets/awsssm/aws_ssm.go b/secrets/awsssm/aws_ssm.go index 51d444f03b..c7661e6a14 100644 --- a/secrets/awsssm/aws_ssm.go +++ b/secrets/awsssm/aws_ssm.go @@ -20,6 +20,9 @@ type AwsSsmManager struct { // The AWS region region string + // Custom AWS endpoint, e.g. localstack + endpoint string + // The AWS SSM client client *ssm.SSM @@ -44,8 +47,9 @@ func SecretsManagerFactory( // / Set up the base object awsSsmManager := &AwsSsmManager{ - logger: params.Logger.Named(string(secrets.AWSSSM)), - region: fmt.Sprintf("%v", config.Extra["region"]), + logger: params.Logger.Named(string(secrets.AWSSSM)), + region: fmt.Sprintf("%v", config.Extra["region"]), + endpoint: config.ServerURL, } // Set the base path to store the secrets in SSM @@ -61,15 +65,20 @@ func SecretsManagerFactory( // Setup sets up the AWS SSM secrets manager func (a *AwsSsmManager) Setup() error { + cfg := aws.NewConfig().WithRegion(a.region) + if a.endpoint != "" { + cfg = cfg.WithEndpoint(a.endpoint) + } + sess, err := session.NewSessionWithOptions(session.Options{ - Config: aws.Config{Region: aws.String(a.region)}, + Config: *cfg, SharedConfigState: session.SharedConfigEnable, }) if err != nil { return fmt.Errorf("unable to initialize AWS SSM client: %w", err) } - ssmsvc := ssm.New(sess, aws.NewConfig().WithRegion(a.region)) + ssmsvc := ssm.New(sess, cfg) a.client = ssmsvc return nil diff --git a/secrets/helper/helper.go b/secrets/helper/helper.go index 5d525c98f4..5217639af0 100644 --- a/secrets/helper/helper.go +++ b/secrets/helper/helper.go @@ -3,10 +3,7 @@ package helper import ( "errors" "fmt" - "math/big" - bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" - "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" "github.com/0xPolygon/polygon-edge/crypto" "github.com/0xPolygon/polygon-edge/helper/hex" "github.com/0xPolygon/polygon-edge/network" @@ -22,6 +19,8 @@ import ( "github.com/umbracle/ethgo/abi" ) +var addressTypeABI = abi.MustNewType("address") + // SetupLocalSecretsManager is a helper method for boilerplate local secrets manager setup func SetupLocalSecretsManager(dataDir string) (secrets.SecretsManager, error) { return local.SecretsManagerFactory( @@ -143,39 +142,6 @@ func InitNetworkingPrivateKey(secretsManager secrets.SecretsManager) (libp2pCryp return libp2pKey, keyErr } -func InitValidatorBLSSignature( - secretsManager secrets.SecretsManager, account *wallet.Account, chainID int64) ([]byte, error) { - if secretsManager.HasSecret(secrets.ValidatorBLSSignature) { - return nil, fmt.Errorf(`secrets "%s" has been already initialized`, secrets.ValidatorBLSSignature) - } - - // Generate the signature - s, err := MakeKOSKSignature( - account.Bls, - types.Address(account.Ecdsa.Address()), - chainID, - bls.DomainValidatorSet, - ) - if err != nil { - return nil, err - } - - sb, err := s.Marshal() - if err != nil { - return nil, err - } - - // Write the signature to the secrets manager storage - if err := secretsManager.SetSecret( - secrets.ValidatorBLSSignature, - []byte(hex.EncodeToString(sb)), - ); err != nil { - return nil, err - } - - return sb, nil -} - // LoadValidatorAddress loads ECDSA key by SecretsManager and returns validator address func LoadValidatorAddress(secretsManager secrets.SecretsManager) (types.Address, error) { if !secretsManager.HasSecret(secrets.ValidatorKey) { @@ -243,17 +209,6 @@ func LoadNodeID(secretsManager secrets.SecretsManager) (string, error) { return nodeID.String(), nil } -// LoadBLSSignature loads BLS Signature from SecretsManager and returns it -func LoadBLSSignature(secretsManager secrets.SecretsManager) (string, error) { - if !secretsManager.HasSecret(secrets.ValidatorBLSSignature) { - return "", nil - } - - s, err := secretsManager.GetSecret(secrets.ValidatorBLSSignature) - - return string(s), err -} - // InitCloudSecretsManager returns the cloud secrets manager from the provided config func InitCloudSecretsManager(secretsConfig *secrets.SecretsManagerConfig) (secrets.SecretsManager, error) { var secretsManager secrets.SecretsManager @@ -286,17 +241,3 @@ func InitCloudSecretsManager(secretsConfig *secrets.SecretsManagerConfig) (secre return secretsManager, nil } - -// MakeKOSKSignature creates KOSK signature which prevents rogue attack -func MakeKOSKSignature( - privateKey *bls.PrivateKey, address types.Address, chainID int64, domain []byte) (*bls.Signature, error) { - message, err := abi.Encode( - []interface{}{address, big.NewInt(chainID)}, - abi.MustNewType("tuple(address, uint256)")) - if err != nil { - return nil, err - } - - // abi.Encode adds 12 zero bytes before actual address bytes - return privateKey.Sign(message[12:], domain) -} diff --git a/secrets/helper/helper_test.go b/secrets/helper/helper_test.go deleted file mode 100644 index 189e082f7a..0000000000 --- a/secrets/helper/helper_test.go +++ /dev/null @@ -1,39 +0,0 @@ -package helper - -import ( - "testing" - - bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" - "github.com/0xPolygon/polygon-edge/helper/hex" - "github.com/0xPolygon/polygon-edge/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func Test_MakeKOSKSignature(t *testing.T) { - t.Parallel() - - expected := "127cfb8e2512b447056f33b91fca6cb2a7039e8b330edc4e5e5287f1c58bba5206373a97c9f09db144c8db5681c39e013ee6039ebbe36e0448e9f704f2d326c0" - bytes, _ := hex.DecodeString("3139343634393730313533353434353137333331343333303931343932303731313035313730303336303738373134363131303435323837383335373237343933383834303135343336383231") - - pk, err := bls.UnmarshalPrivateKey(bytes) - require.NoError(t, err) - - address := types.BytesToAddress((pk.PublicKey().Marshal())[:types.AddressLength]) - - signature, err := MakeKOSKSignature(pk, address, 10, bls.DomainValidatorSet) - require.NoError(t, err) - - signatureBytes, err := signature.Marshal() - require.NoError(t, err) - - assert.Equal(t, expected, hex.EncodeToString(signatureBytes)) - - signature, err = MakeKOSKSignature(pk, address, 100, bls.DomainValidatorSet) - require.NoError(t, err) - - signatureBytes, err = signature.Marshal() - require.NoError(t, err) - - assert.NotEqual(t, expected, hex.EncodeToString(signatureBytes)) -} diff --git a/secrets/local/local.go b/secrets/local/local.go index dcf44de407..2a08d1a36d 100644 --- a/secrets/local/local.go +++ b/secrets/local/local.go @@ -84,13 +84,6 @@ func (l *LocalSecretsManager) Setup() error { secrets.ValidatorBLSKeyLocal, ) - // baseDir/consensus/validator.sig - l.secretPathMap[secrets.ValidatorBLSSignature] = filepath.Join( - l.path, - secrets.ConsensusFolderLocal, - secrets.ValidatorBLSSignatureLocal, - ) - // baseDir/libp2p/libp2p.key l.secretPathMap[secrets.NetworkKey] = filepath.Join( l.path, diff --git a/secrets/secrets.go b/secrets/secrets.go index d9a9c9070b..4dcd30205e 100644 --- a/secrets/secrets.go +++ b/secrets/secrets.go @@ -31,17 +31,13 @@ const ( // NetworkKey is the libp2p private key secret used for networking NetworkKey = "network-key" - - // ValidatorBLSSignature is the BLS signature of the validator node - ValidatorBLSSignature = "validator-bls-signature" ) // Define constant file names for the local StorageManager const ( - ValidatorKeyLocal = "validator.key" - ValidatorBLSKeyLocal = "validator-bls.key" - NetworkKeyLocal = "libp2p.key" - ValidatorBLSSignatureLocal = "validator.sig" + ValidatorKeyLocal = "validator.key" + ValidatorBLSKeyLocal = "validator-bls.key" + NetworkKeyLocal = "libp2p.key" ) // Define constant folder names for the local StorageManager diff --git a/server/builtin.go b/server/builtin.go index 8aa7a49c80..f98c2a4eb4 100644 --- a/server/builtin.go +++ b/server/builtin.go @@ -19,10 +19,14 @@ type GenesisFactoryHook func(config *chain.Chain, engineName string) func(*state type ConsensusType string +type ForkManagerFactory func(forks *chain.Forks) error + +type ForkManagerInitialParamsFactory func(config *chain.Chain) (*chain.ForkParams, error) + const ( DevConsensus ConsensusType = "dev" IBFTConsensus ConsensusType = "ibft" - PolyBFTConsensus ConsensusType = "polybft" + PolyBFTConsensus ConsensusType = consensusPolyBFT.ConsensusName DummyConsensus ConsensusType = "dummy" ) @@ -46,6 +50,14 @@ var genesisCreationFactory = map[ConsensusType]GenesisFactoryHook{ PolyBFTConsensus: consensusPolyBFT.GenesisPostHookFactory, } +var forkManagerFactory = map[ConsensusType]ForkManagerFactory{ + PolyBFTConsensus: consensusPolyBFT.ForkManagerFactory, +} + +var forkManagerInitialParamsFactory = map[ConsensusType]ForkManagerInitialParamsFactory{ + PolyBFTConsensus: consensusPolyBFT.ForkManagerInitialParamsFactory, +} + func ConsensusSupported(value string) bool { _, ok := consensusBackends[ConsensusType(value)] diff --git a/server/config.go b/server/config.go index 21ecf0fe4b..f7832ebf9b 100644 --- a/server/config.go +++ b/server/config.go @@ -24,7 +24,6 @@ type Config struct { PriceLimit uint64 MaxAccountEnqueued uint64 MaxSlots uint64 - BlockTime uint64 Telemetry *Telemetry Network *network.Config diff --git a/server/proto/system.pb.go b/server/proto/system.pb.go index 91b09ea562..21e88b935d 100644 --- a/server/proto/system.pb.go +++ b/server/proto/system.pb.go @@ -22,6 +22,100 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +type GetTraceRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Number uint64 `protobuf:"varint,1,opt,name=number,proto3" json:"number,omitempty"` +} + +func (x *GetTraceRequest) Reset() { + *x = GetTraceRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_server_proto_system_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetTraceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTraceRequest) ProtoMessage() {} + +func (x *GetTraceRequest) ProtoReflect() protoreflect.Message { + mi := &file_server_proto_system_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTraceRequest.ProtoReflect.Descriptor instead. +func (*GetTraceRequest) Descriptor() ([]byte, []int) { + return file_server_proto_system_proto_rawDescGZIP(), []int{0} +} + +func (x *GetTraceRequest) GetNumber() uint64 { + if x != nil { + return x.Number + } + return 0 +} + +type GetTraceResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Trace []byte `protobuf:"bytes,1,opt,name=trace,proto3" json:"trace,omitempty"` +} + +func (x *GetTraceResponse) Reset() { + *x = GetTraceResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_server_proto_system_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetTraceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTraceResponse) ProtoMessage() {} + +func (x *GetTraceResponse) ProtoReflect() protoreflect.Message { + mi := &file_server_proto_system_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTraceResponse.ProtoReflect.Descriptor instead. +func (*GetTraceResponse) Descriptor() ([]byte, []int) { + return file_server_proto_system_proto_rawDescGZIP(), []int{1} +} + +func (x *GetTraceResponse) GetTrace() []byte { + if x != nil { + return x.Trace + } + return nil +} + type BlockchainEvent struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -34,7 +128,7 @@ type BlockchainEvent struct { func (x *BlockchainEvent) Reset() { *x = BlockchainEvent{} if protoimpl.UnsafeEnabled { - mi := &file_server_proto_system_proto_msgTypes[0] + mi := &file_server_proto_system_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -47,7 +141,7 @@ func (x *BlockchainEvent) String() string { func (*BlockchainEvent) ProtoMessage() {} func (x *BlockchainEvent) ProtoReflect() protoreflect.Message { - mi := &file_server_proto_system_proto_msgTypes[0] + mi := &file_server_proto_system_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -60,7 +154,7 @@ func (x *BlockchainEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockchainEvent.ProtoReflect.Descriptor instead. func (*BlockchainEvent) Descriptor() ([]byte, []int) { - return file_server_proto_system_proto_rawDescGZIP(), []int{0} + return file_server_proto_system_proto_rawDescGZIP(), []int{2} } func (x *BlockchainEvent) GetAdded() []*BlockchainEvent_Header { @@ -91,7 +185,7 @@ type ServerStatus struct { func (x *ServerStatus) Reset() { *x = ServerStatus{} if protoimpl.UnsafeEnabled { - mi := &file_server_proto_system_proto_msgTypes[1] + mi := &file_server_proto_system_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -104,7 +198,7 @@ func (x *ServerStatus) String() string { func (*ServerStatus) ProtoMessage() {} func (x *ServerStatus) ProtoReflect() protoreflect.Message { - mi := &file_server_proto_system_proto_msgTypes[1] + mi := &file_server_proto_system_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -117,7 +211,7 @@ func (x *ServerStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use ServerStatus.ProtoReflect.Descriptor instead. func (*ServerStatus) Descriptor() ([]byte, []int) { - return file_server_proto_system_proto_rawDescGZIP(), []int{1} + return file_server_proto_system_proto_rawDescGZIP(), []int{3} } func (x *ServerStatus) GetNetwork() int64 { @@ -161,7 +255,7 @@ type Peer struct { func (x *Peer) Reset() { *x = Peer{} if protoimpl.UnsafeEnabled { - mi := &file_server_proto_system_proto_msgTypes[2] + mi := &file_server_proto_system_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -174,7 +268,7 @@ func (x *Peer) String() string { func (*Peer) ProtoMessage() {} func (x *Peer) ProtoReflect() protoreflect.Message { - mi := &file_server_proto_system_proto_msgTypes[2] + mi := &file_server_proto_system_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -187,7 +281,7 @@ func (x *Peer) ProtoReflect() protoreflect.Message { // Deprecated: Use Peer.ProtoReflect.Descriptor instead. func (*Peer) Descriptor() ([]byte, []int) { - return file_server_proto_system_proto_rawDescGZIP(), []int{2} + return file_server_proto_system_proto_rawDescGZIP(), []int{4} } func (x *Peer) GetId() string { @@ -222,7 +316,7 @@ type PeersAddRequest struct { func (x *PeersAddRequest) Reset() { *x = PeersAddRequest{} if protoimpl.UnsafeEnabled { - mi := &file_server_proto_system_proto_msgTypes[3] + mi := &file_server_proto_system_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -235,7 +329,7 @@ func (x *PeersAddRequest) String() string { func (*PeersAddRequest) ProtoMessage() {} func (x *PeersAddRequest) ProtoReflect() protoreflect.Message { - mi := &file_server_proto_system_proto_msgTypes[3] + mi := &file_server_proto_system_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -248,7 +342,7 @@ func (x *PeersAddRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PeersAddRequest.ProtoReflect.Descriptor instead. func (*PeersAddRequest) Descriptor() ([]byte, []int) { - return file_server_proto_system_proto_rawDescGZIP(), []int{3} + return file_server_proto_system_proto_rawDescGZIP(), []int{5} } func (x *PeersAddRequest) GetId() string { @@ -269,7 +363,7 @@ type PeersAddResponse struct { func (x *PeersAddResponse) Reset() { *x = PeersAddResponse{} if protoimpl.UnsafeEnabled { - mi := &file_server_proto_system_proto_msgTypes[4] + mi := &file_server_proto_system_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -282,7 +376,7 @@ func (x *PeersAddResponse) String() string { func (*PeersAddResponse) ProtoMessage() {} func (x *PeersAddResponse) ProtoReflect() protoreflect.Message { - mi := &file_server_proto_system_proto_msgTypes[4] + mi := &file_server_proto_system_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -295,7 +389,7 @@ func (x *PeersAddResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PeersAddResponse.ProtoReflect.Descriptor instead. func (*PeersAddResponse) Descriptor() ([]byte, []int) { - return file_server_proto_system_proto_rawDescGZIP(), []int{4} + return file_server_proto_system_proto_rawDescGZIP(), []int{6} } func (x *PeersAddResponse) GetMessage() string { @@ -316,7 +410,7 @@ type PeersStatusRequest struct { func (x *PeersStatusRequest) Reset() { *x = PeersStatusRequest{} if protoimpl.UnsafeEnabled { - mi := &file_server_proto_system_proto_msgTypes[5] + mi := &file_server_proto_system_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -329,7 +423,7 @@ func (x *PeersStatusRequest) String() string { func (*PeersStatusRequest) ProtoMessage() {} func (x *PeersStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_server_proto_system_proto_msgTypes[5] + mi := &file_server_proto_system_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -342,7 +436,7 @@ func (x *PeersStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PeersStatusRequest.ProtoReflect.Descriptor instead. func (*PeersStatusRequest) Descriptor() ([]byte, []int) { - return file_server_proto_system_proto_rawDescGZIP(), []int{5} + return file_server_proto_system_proto_rawDescGZIP(), []int{7} } func (x *PeersStatusRequest) GetId() string { @@ -363,7 +457,7 @@ type PeersListResponse struct { func (x *PeersListResponse) Reset() { *x = PeersListResponse{} if protoimpl.UnsafeEnabled { - mi := &file_server_proto_system_proto_msgTypes[6] + mi := &file_server_proto_system_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -376,7 +470,7 @@ func (x *PeersListResponse) String() string { func (*PeersListResponse) ProtoMessage() {} func (x *PeersListResponse) ProtoReflect() protoreflect.Message { - mi := &file_server_proto_system_proto_msgTypes[6] + mi := &file_server_proto_system_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -389,7 +483,7 @@ func (x *PeersListResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PeersListResponse.ProtoReflect.Descriptor instead. func (*PeersListResponse) Descriptor() ([]byte, []int) { - return file_server_proto_system_proto_rawDescGZIP(), []int{6} + return file_server_proto_system_proto_rawDescGZIP(), []int{8} } func (x *PeersListResponse) GetPeers() []*Peer { @@ -410,7 +504,7 @@ type BlockByNumberRequest struct { func (x *BlockByNumberRequest) Reset() { *x = BlockByNumberRequest{} if protoimpl.UnsafeEnabled { - mi := &file_server_proto_system_proto_msgTypes[7] + mi := &file_server_proto_system_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -423,7 +517,7 @@ func (x *BlockByNumberRequest) String() string { func (*BlockByNumberRequest) ProtoMessage() {} func (x *BlockByNumberRequest) ProtoReflect() protoreflect.Message { - mi := &file_server_proto_system_proto_msgTypes[7] + mi := &file_server_proto_system_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -436,7 +530,7 @@ func (x *BlockByNumberRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockByNumberRequest.ProtoReflect.Descriptor instead. func (*BlockByNumberRequest) Descriptor() ([]byte, []int) { - return file_server_proto_system_proto_rawDescGZIP(), []int{7} + return file_server_proto_system_proto_rawDescGZIP(), []int{9} } func (x *BlockByNumberRequest) GetNumber() uint64 { @@ -457,7 +551,7 @@ type BlockResponse struct { func (x *BlockResponse) Reset() { *x = BlockResponse{} if protoimpl.UnsafeEnabled { - mi := &file_server_proto_system_proto_msgTypes[8] + mi := &file_server_proto_system_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -470,7 +564,7 @@ func (x *BlockResponse) String() string { func (*BlockResponse) ProtoMessage() {} func (x *BlockResponse) ProtoReflect() protoreflect.Message { - mi := &file_server_proto_system_proto_msgTypes[8] + mi := &file_server_proto_system_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -483,7 +577,7 @@ func (x *BlockResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockResponse.ProtoReflect.Descriptor instead. func (*BlockResponse) Descriptor() ([]byte, []int) { - return file_server_proto_system_proto_rawDescGZIP(), []int{8} + return file_server_proto_system_proto_rawDescGZIP(), []int{10} } func (x *BlockResponse) GetData() []byte { @@ -505,7 +599,7 @@ type ExportRequest struct { func (x *ExportRequest) Reset() { *x = ExportRequest{} if protoimpl.UnsafeEnabled { - mi := &file_server_proto_system_proto_msgTypes[9] + mi := &file_server_proto_system_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -518,7 +612,7 @@ func (x *ExportRequest) String() string { func (*ExportRequest) ProtoMessage() {} func (x *ExportRequest) ProtoReflect() protoreflect.Message { - mi := &file_server_proto_system_proto_msgTypes[9] + mi := &file_server_proto_system_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -531,7 +625,7 @@ func (x *ExportRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExportRequest.ProtoReflect.Descriptor instead. func (*ExportRequest) Descriptor() ([]byte, []int) { - return file_server_proto_system_proto_rawDescGZIP(), []int{9} + return file_server_proto_system_proto_rawDescGZIP(), []int{11} } func (x *ExportRequest) GetFrom() uint64 { @@ -563,7 +657,7 @@ type ExportEvent struct { func (x *ExportEvent) Reset() { *x = ExportEvent{} if protoimpl.UnsafeEnabled { - mi := &file_server_proto_system_proto_msgTypes[10] + mi := &file_server_proto_system_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -576,7 +670,7 @@ func (x *ExportEvent) String() string { func (*ExportEvent) ProtoMessage() {} func (x *ExportEvent) ProtoReflect() protoreflect.Message { - mi := &file_server_proto_system_proto_msgTypes[10] + mi := &file_server_proto_system_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -589,7 +683,7 @@ func (x *ExportEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use ExportEvent.ProtoReflect.Descriptor instead. func (*ExportEvent) Descriptor() ([]byte, []int) { - return file_server_proto_system_proto_rawDescGZIP(), []int{10} + return file_server_proto_system_proto_rawDescGZIP(), []int{12} } func (x *ExportEvent) GetFrom() uint64 { @@ -632,7 +726,7 @@ type BlockchainEvent_Header struct { func (x *BlockchainEvent_Header) Reset() { *x = BlockchainEvent_Header{} if protoimpl.UnsafeEnabled { - mi := &file_server_proto_system_proto_msgTypes[11] + mi := &file_server_proto_system_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -645,7 +739,7 @@ func (x *BlockchainEvent_Header) String() string { func (*BlockchainEvent_Header) ProtoMessage() {} func (x *BlockchainEvent_Header) ProtoReflect() protoreflect.Message { - mi := &file_server_proto_system_proto_msgTypes[11] + mi := &file_server_proto_system_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -658,7 +752,7 @@ func (x *BlockchainEvent_Header) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockchainEvent_Header.ProtoReflect.Descriptor instead. func (*BlockchainEvent_Header) Descriptor() ([]byte, []int) { - return file_server_proto_system_proto_rawDescGZIP(), []int{0, 0} + return file_server_proto_system_proto_rawDescGZIP(), []int{2, 0} } func (x *BlockchainEvent_Header) GetNumber() int64 { @@ -687,7 +781,7 @@ type ServerStatus_Block struct { func (x *ServerStatus_Block) Reset() { *x = ServerStatus_Block{} if protoimpl.UnsafeEnabled { - mi := &file_server_proto_system_proto_msgTypes[12] + mi := &file_server_proto_system_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -700,7 +794,7 @@ func (x *ServerStatus_Block) String() string { func (*ServerStatus_Block) ProtoMessage() {} func (x *ServerStatus_Block) ProtoReflect() protoreflect.Message { - mi := &file_server_proto_system_proto_msgTypes[12] + mi := &file_server_proto_system_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -713,7 +807,7 @@ func (x *ServerStatus_Block) ProtoReflect() protoreflect.Message { // Deprecated: Use ServerStatus_Block.ProtoReflect.Descriptor instead. func (*ServerStatus_Block) Descriptor() ([]byte, []int) { - return file_server_proto_system_proto_rawDescGZIP(), []int{1, 0} + return file_server_proto_system_proto_rawDescGZIP(), []int{3, 0} } func (x *ServerStatus_Block) GetNumber() int64 { @@ -738,92 +832,100 @@ var file_server_proto_system_proto_rawDesc = []byte{ 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xaf, 0x01, 0x0a, 0x0f, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x63, - 0x68, 0x61, 0x69, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x30, 0x0a, 0x05, 0x61, 0x64, 0x64, - 0x65, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x48, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x12, 0x34, 0x0a, 0x07, 0x72, - 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x76, - 0x31, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, - 0x64, 0x1a, 0x34, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x6e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6e, 0x75, 0x6d, - 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0xc3, 0x01, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x12, 0x30, 0x0a, 0x07, - 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, - 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x07, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x18, - 0x0a, 0x07, 0x70, 0x32, 0x70, 0x41, 0x64, 0x64, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x70, 0x32, 0x70, 0x41, 0x64, 0x64, 0x72, 0x1a, 0x33, 0x0a, 0x05, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, - 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0x4a, 0x0a, - 0x04, 0x50, 0x65, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, - 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, - 0x6f, 0x6c, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x05, 0x61, 0x64, 0x64, 0x72, 0x73, 0x22, 0x53, 0x0a, 0x0f, 0x50, 0x65, 0x65, - 0x72, 0x73, 0x41, 0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x02, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x30, 0xfa, 0x42, 0x2d, 0x72, 0x2b, 0x32, - 0x29, 0x5e, 0x5c, 0x2f, 0x5b, 0x41, 0x2d, 0x5a, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x2e, 0x5f, - 0x7e, 0x2d, 0x5d, 0x2b, 0x28, 0x5c, 0x2f, 0x5b, 0x41, 0x2d, 0x5a, 0x61, 0x2d, 0x7a, 0x30, 0x2d, - 0x39, 0x2e, 0x5f, 0x7e, 0x2d, 0x5d, 0x2b, 0x29, 0x2a, 0x24, 0x52, 0x02, 0x69, 0x64, 0x22, 0x2c, - 0x0a, 0x10, 0x50, 0x65, 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x3e, 0x0a, 0x12, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x29, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x63, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x22, 0x28, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x72, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x05, 0x74, 0x72, 0x61, 0x63, 0x65, 0x22, 0xaf, 0x01, 0x0a, 0x0f, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x30, + 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x76, 0x31, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, + 0x12, 0x34, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, + 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x07, 0x72, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x1a, 0x34, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0xc3, 0x01, 0x0a, + 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, + 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x65, 0x6e, 0x65, 0x73, + 0x69, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, + 0x73, 0x12, 0x30, 0x0a, 0x07, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x07, 0x63, 0x75, 0x72, 0x72, + 0x65, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x32, 0x70, 0x41, 0x64, 0x64, 0x72, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x32, 0x70, 0x41, 0x64, 0x64, 0x72, 0x1a, 0x33, 0x0a, + 0x05, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x12, + 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, + 0x73, 0x68, 0x22, 0x4a, 0x0a, 0x04, 0x50, 0x65, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x72, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x61, 0x64, 0x64, 0x72, 0x73, 0x22, 0x53, + 0x0a, 0x0f, 0x50, 0x65, 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x40, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x30, 0xfa, + 0x42, 0x2d, 0x72, 0x2b, 0x32, 0x29, 0x5e, 0x5c, 0x2f, 0x5b, 0x41, 0x2d, 0x5a, 0x61, 0x2d, 0x7a, + 0x30, 0x2d, 0x39, 0x2e, 0x5f, 0x7e, 0x2d, 0x5d, 0x2b, 0x28, 0x5c, 0x2f, 0x5b, 0x41, 0x2d, 0x5a, + 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x2e, 0x5f, 0x7e, 0x2d, 0x5d, 0x2b, 0x29, 0x2a, 0x24, 0x52, + 0x02, 0x69, 0x64, 0x22, 0x2c, 0x0a, 0x10, 0x50, 0x65, 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x22, 0x3e, 0x0a, 0x12, 0x50, 0x65, 0x65, 0x72, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x18, 0xfa, 0x42, 0x15, 0x72, 0x13, 0x32, 0x11, 0x5e, 0x5b, 0x41, 0x2d, + 0x5a, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x31, 0x2c, 0x7d, 0x24, 0x52, 0x02, 0x69, + 0x64, 0x22, 0x33, 0x0a, 0x11, 0x50, 0x65, 0x65, 0x72, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, + 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x22, 0x2e, 0x0a, 0x14, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x42, + 0x79, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, + 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, + 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x23, 0x0a, 0x0d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x33, 0x0a, 0x0d, 0x45, + 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, + 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, + 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x74, 0x6f, + 0x22, 0x5d, 0x0a, 0x0b, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, + 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x66, + 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x02, 0x74, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x64, + 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x32, + 0xc4, 0x03, 0x0a, 0x06, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x35, 0x0a, 0x09, 0x47, 0x65, + 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, + 0x10, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x35, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x63, 0x65, 0x12, 0x13, 0x2e, + 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x63, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, + 0x73, 0x41, 0x64, 0x64, 0x12, 0x13, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x41, + 0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x76, 0x31, 0x2e, 0x50, + 0x65, 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x3a, 0x0a, 0x09, 0x50, 0x65, 0x65, 0x72, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x15, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x4c, + 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x0b, 0x50, + 0x65, 0x65, 0x72, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x28, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, - 0xfa, 0x42, 0x15, 0x72, 0x13, 0x32, 0x11, 0x5e, 0x5b, 0x41, 0x2d, 0x5a, 0x61, 0x2d, 0x7a, 0x30, - 0x2d, 0x39, 0x5d, 0x7b, 0x31, 0x2c, 0x7d, 0x24, 0x52, 0x02, 0x69, 0x64, 0x22, 0x33, 0x0a, 0x11, - 0x50, 0x65, 0x65, 0x72, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x1e, 0x0a, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x05, 0x70, 0x65, 0x65, 0x72, - 0x73, 0x22, 0x2e, 0x0a, 0x14, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x79, 0x4e, 0x75, 0x6d, 0x62, - 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, - 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x22, 0x23, 0x0a, 0x0d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x33, 0x0a, 0x0d, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, - 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x74, 0x6f, 0x22, 0x5d, 0x0a, 0x0b, 0x45, - 0x78, 0x70, 0x6f, 0x72, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, - 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, - 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x16, - 0x0a, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, - 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x32, 0x8d, 0x03, 0x0a, 0x06, 0x53, - 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x35, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x10, 0x2e, 0x76, 0x31, 0x2e, - 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x35, 0x0a, 0x08, - 0x50, 0x65, 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x12, 0x13, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x65, - 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, - 0x76, 0x31, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x41, 0x64, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x09, 0x50, 0x65, 0x65, 0x72, 0x73, 0x4c, 0x69, 0x73, 0x74, - 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x15, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x65, - 0x65, 0x72, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x2f, 0x0a, 0x0b, 0x50, 0x65, 0x65, 0x72, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, - 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x65, 0x65, 0x72, - 0x12, 0x3a, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x16, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x13, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x63, 0x68, 0x61, 0x69, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, 0x3c, 0x0a, 0x0d, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x79, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x18, 0x2e, - 0x76, 0x31, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x79, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x06, 0x45, 0x78, - 0x70, 0x6f, 0x72, 0x74, 0x12, 0x11, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, - 0x6f, 0x72, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x42, 0x0f, 0x5a, 0x0d, 0x2f, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x73, 0x74, 0x1a, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x12, 0x3a, 0x0a, 0x09, + 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x1a, 0x13, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, + 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, 0x3c, 0x0a, 0x0d, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x42, 0x79, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x18, 0x2e, 0x76, 0x31, 0x2e, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x79, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x06, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, + 0x12, 0x11, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x42, 0x0f, 0x5a, 0x0d, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -838,44 +940,48 @@ func file_server_proto_system_proto_rawDescGZIP() []byte { return file_server_proto_system_proto_rawDescData } -var file_server_proto_system_proto_msgTypes = make([]protoimpl.MessageInfo, 13) +var file_server_proto_system_proto_msgTypes = make([]protoimpl.MessageInfo, 15) var file_server_proto_system_proto_goTypes = []interface{}{ - (*BlockchainEvent)(nil), // 0: v1.BlockchainEvent - (*ServerStatus)(nil), // 1: v1.ServerStatus - (*Peer)(nil), // 2: v1.Peer - (*PeersAddRequest)(nil), // 3: v1.PeersAddRequest - (*PeersAddResponse)(nil), // 4: v1.PeersAddResponse - (*PeersStatusRequest)(nil), // 5: v1.PeersStatusRequest - (*PeersListResponse)(nil), // 6: v1.PeersListResponse - (*BlockByNumberRequest)(nil), // 7: v1.BlockByNumberRequest - (*BlockResponse)(nil), // 8: v1.BlockResponse - (*ExportRequest)(nil), // 9: v1.ExportRequest - (*ExportEvent)(nil), // 10: v1.ExportEvent - (*BlockchainEvent_Header)(nil), // 11: v1.BlockchainEvent.Header - (*ServerStatus_Block)(nil), // 12: v1.ServerStatus.Block - (*emptypb.Empty)(nil), // 13: google.protobuf.Empty + (*GetTraceRequest)(nil), // 0: v1.GetTraceRequest + (*GetTraceResponse)(nil), // 1: v1.GetTraceResponse + (*BlockchainEvent)(nil), // 2: v1.BlockchainEvent + (*ServerStatus)(nil), // 3: v1.ServerStatus + (*Peer)(nil), // 4: v1.Peer + (*PeersAddRequest)(nil), // 5: v1.PeersAddRequest + (*PeersAddResponse)(nil), // 6: v1.PeersAddResponse + (*PeersStatusRequest)(nil), // 7: v1.PeersStatusRequest + (*PeersListResponse)(nil), // 8: v1.PeersListResponse + (*BlockByNumberRequest)(nil), // 9: v1.BlockByNumberRequest + (*BlockResponse)(nil), // 10: v1.BlockResponse + (*ExportRequest)(nil), // 11: v1.ExportRequest + (*ExportEvent)(nil), // 12: v1.ExportEvent + (*BlockchainEvent_Header)(nil), // 13: v1.BlockchainEvent.Header + (*ServerStatus_Block)(nil), // 14: v1.ServerStatus.Block + (*emptypb.Empty)(nil), // 15: google.protobuf.Empty } var file_server_proto_system_proto_depIdxs = []int32{ - 11, // 0: v1.BlockchainEvent.added:type_name -> v1.BlockchainEvent.Header - 11, // 1: v1.BlockchainEvent.removed:type_name -> v1.BlockchainEvent.Header - 12, // 2: v1.ServerStatus.current:type_name -> v1.ServerStatus.Block - 2, // 3: v1.PeersListResponse.peers:type_name -> v1.Peer - 13, // 4: v1.System.GetStatus:input_type -> google.protobuf.Empty - 3, // 5: v1.System.PeersAdd:input_type -> v1.PeersAddRequest - 13, // 6: v1.System.PeersList:input_type -> google.protobuf.Empty - 5, // 7: v1.System.PeersStatus:input_type -> v1.PeersStatusRequest - 13, // 8: v1.System.Subscribe:input_type -> google.protobuf.Empty - 7, // 9: v1.System.BlockByNumber:input_type -> v1.BlockByNumberRequest - 9, // 10: v1.System.Export:input_type -> v1.ExportRequest - 1, // 11: v1.System.GetStatus:output_type -> v1.ServerStatus - 4, // 12: v1.System.PeersAdd:output_type -> v1.PeersAddResponse - 6, // 13: v1.System.PeersList:output_type -> v1.PeersListResponse - 2, // 14: v1.System.PeersStatus:output_type -> v1.Peer - 0, // 15: v1.System.Subscribe:output_type -> v1.BlockchainEvent - 8, // 16: v1.System.BlockByNumber:output_type -> v1.BlockResponse - 10, // 17: v1.System.Export:output_type -> v1.ExportEvent - 11, // [11:18] is the sub-list for method output_type - 4, // [4:11] is the sub-list for method input_type + 13, // 0: v1.BlockchainEvent.added:type_name -> v1.BlockchainEvent.Header + 13, // 1: v1.BlockchainEvent.removed:type_name -> v1.BlockchainEvent.Header + 14, // 2: v1.ServerStatus.current:type_name -> v1.ServerStatus.Block + 4, // 3: v1.PeersListResponse.peers:type_name -> v1.Peer + 15, // 4: v1.System.GetStatus:input_type -> google.protobuf.Empty + 0, // 5: v1.System.GetTrace:input_type -> v1.GetTraceRequest + 5, // 6: v1.System.PeersAdd:input_type -> v1.PeersAddRequest + 15, // 7: v1.System.PeersList:input_type -> google.protobuf.Empty + 7, // 8: v1.System.PeersStatus:input_type -> v1.PeersStatusRequest + 15, // 9: v1.System.Subscribe:input_type -> google.protobuf.Empty + 9, // 10: v1.System.BlockByNumber:input_type -> v1.BlockByNumberRequest + 11, // 11: v1.System.Export:input_type -> v1.ExportRequest + 3, // 12: v1.System.GetStatus:output_type -> v1.ServerStatus + 1, // 13: v1.System.GetTrace:output_type -> v1.GetTraceResponse + 6, // 14: v1.System.PeersAdd:output_type -> v1.PeersAddResponse + 8, // 15: v1.System.PeersList:output_type -> v1.PeersListResponse + 4, // 16: v1.System.PeersStatus:output_type -> v1.Peer + 2, // 17: v1.System.Subscribe:output_type -> v1.BlockchainEvent + 10, // 18: v1.System.BlockByNumber:output_type -> v1.BlockResponse + 12, // 19: v1.System.Export:output_type -> v1.ExportEvent + 12, // [12:20] is the sub-list for method output_type + 4, // [4:12] is the sub-list for method input_type 4, // [4:4] is the sub-list for extension type_name 4, // [4:4] is the sub-list for extension extendee 0, // [0:4] is the sub-list for field type_name @@ -888,7 +994,7 @@ func file_server_proto_system_proto_init() { } if !protoimpl.UnsafeEnabled { file_server_proto_system_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockchainEvent); i { + switch v := v.(*GetTraceRequest); i { case 0: return &v.state case 1: @@ -900,7 +1006,7 @@ func file_server_proto_system_proto_init() { } } file_server_proto_system_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ServerStatus); i { + switch v := v.(*GetTraceResponse); i { case 0: return &v.state case 1: @@ -912,7 +1018,7 @@ func file_server_proto_system_proto_init() { } } file_server_proto_system_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Peer); i { + switch v := v.(*BlockchainEvent); i { case 0: return &v.state case 1: @@ -924,7 +1030,7 @@ func file_server_proto_system_proto_init() { } } file_server_proto_system_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PeersAddRequest); i { + switch v := v.(*ServerStatus); i { case 0: return &v.state case 1: @@ -936,7 +1042,7 @@ func file_server_proto_system_proto_init() { } } file_server_proto_system_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PeersAddResponse); i { + switch v := v.(*Peer); i { case 0: return &v.state case 1: @@ -948,7 +1054,7 @@ func file_server_proto_system_proto_init() { } } file_server_proto_system_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PeersStatusRequest); i { + switch v := v.(*PeersAddRequest); i { case 0: return &v.state case 1: @@ -960,7 +1066,7 @@ func file_server_proto_system_proto_init() { } } file_server_proto_system_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PeersListResponse); i { + switch v := v.(*PeersAddResponse); i { case 0: return &v.state case 1: @@ -972,7 +1078,7 @@ func file_server_proto_system_proto_init() { } } file_server_proto_system_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockByNumberRequest); i { + switch v := v.(*PeersStatusRequest); i { case 0: return &v.state case 1: @@ -984,7 +1090,7 @@ func file_server_proto_system_proto_init() { } } file_server_proto_system_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockResponse); i { + switch v := v.(*PeersListResponse); i { case 0: return &v.state case 1: @@ -996,7 +1102,7 @@ func file_server_proto_system_proto_init() { } } file_server_proto_system_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExportRequest); i { + switch v := v.(*BlockByNumberRequest); i { case 0: return &v.state case 1: @@ -1008,7 +1114,7 @@ func file_server_proto_system_proto_init() { } } file_server_proto_system_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExportEvent); i { + switch v := v.(*BlockResponse); i { case 0: return &v.state case 1: @@ -1020,7 +1126,7 @@ func file_server_proto_system_proto_init() { } } file_server_proto_system_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockchainEvent_Header); i { + switch v := v.(*ExportRequest); i { case 0: return &v.state case 1: @@ -1032,6 +1138,30 @@ func file_server_proto_system_proto_init() { } } file_server_proto_system_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ExportEvent); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_server_proto_system_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BlockchainEvent_Header); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_server_proto_system_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ServerStatus_Block); i { case 0: return &v.state @@ -1050,7 +1180,7 @@ func file_server_proto_system_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_server_proto_system_proto_rawDesc, NumEnums: 0, - NumMessages: 13, + NumMessages: 15, NumExtensions: 0, NumServices: 1, }, diff --git a/server/proto/system.pb.validate.go b/server/proto/system.pb.validate.go index 2f163f381c..71b48179b7 100644 --- a/server/proto/system.pb.validate.go +++ b/server/proto/system.pb.validate.go @@ -35,6 +35,210 @@ var ( _ = sort.Sort ) +// Validate checks the field values on GetTraceRequest with the rules defined +// in the proto definition for this message. If any rules are violated, the +// first error encountered is returned, or nil if there are no violations. +func (m *GetTraceRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on GetTraceRequest with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// GetTraceRequestMultiError, or nil if none found. +func (m *GetTraceRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *GetTraceRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Number + + if len(errors) > 0 { + return GetTraceRequestMultiError(errors) + } + + return nil +} + +// GetTraceRequestMultiError is an error wrapping multiple validation errors +// returned by GetTraceRequest.ValidateAll() if the designated constraints +// aren't met. +type GetTraceRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m GetTraceRequestMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m GetTraceRequestMultiError) AllErrors() []error { return m } + +// GetTraceRequestValidationError is the validation error returned by +// GetTraceRequest.Validate if the designated constraints aren't met. +type GetTraceRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e GetTraceRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e GetTraceRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e GetTraceRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e GetTraceRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e GetTraceRequestValidationError) ErrorName() string { return "GetTraceRequestValidationError" } + +// Error satisfies the builtin error interface +func (e GetTraceRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sGetTraceRequest.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = GetTraceRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = GetTraceRequestValidationError{} + +// Validate checks the field values on GetTraceResponse with the rules defined +// in the proto definition for this message. If any rules are violated, the +// first error encountered is returned, or nil if there are no violations. +func (m *GetTraceResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on GetTraceResponse with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// GetTraceResponseMultiError, or nil if none found. +func (m *GetTraceResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *GetTraceResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Trace + + if len(errors) > 0 { + return GetTraceResponseMultiError(errors) + } + + return nil +} + +// GetTraceResponseMultiError is an error wrapping multiple validation errors +// returned by GetTraceResponse.ValidateAll() if the designated constraints +// aren't met. +type GetTraceResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m GetTraceResponseMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m GetTraceResponseMultiError) AllErrors() []error { return m } + +// GetTraceResponseValidationError is the validation error returned by +// GetTraceResponse.Validate if the designated constraints aren't met. +type GetTraceResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e GetTraceResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e GetTraceResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e GetTraceResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e GetTraceResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e GetTraceResponseValidationError) ErrorName() string { return "GetTraceResponseValidationError" } + +// Error satisfies the builtin error interface +func (e GetTraceResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sGetTraceResponse.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = GetTraceResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = GetTraceResponseValidationError{} + // Validate checks the field values on BlockchainEvent with the rules defined // in the proto definition for this message. If any rules are violated, the // first error encountered is returned, or nil if there are no violations. diff --git a/server/proto/system.proto b/server/proto/system.proto index c49fbfbc3a..537dfb8e11 100644 --- a/server/proto/system.proto +++ b/server/proto/system.proto @@ -11,6 +11,8 @@ service System { // GetInfo returns info about the client rpc GetStatus(google.protobuf.Empty) returns (ServerStatus); + rpc GetTrace(GetTraceRequest) returns (GetTraceResponse); + // PeersAdd adds a new peer rpc PeersAdd(PeersAddRequest) returns (PeersAddResponse); @@ -30,6 +32,14 @@ service System { rpc Export(ExportRequest) returns (stream ExportEvent); } +message GetTraceRequest { + uint64 number = 1; +} + +message GetTraceResponse { + bytes trace = 1; +} + message BlockchainEvent { repeated Header added = 1; repeated Header removed = 2; diff --git a/server/proto/system_grpc.pb.go b/server/proto/system_grpc.pb.go index 674458d9d4..1a58a35c31 100644 --- a/server/proto/system_grpc.pb.go +++ b/server/proto/system_grpc.pb.go @@ -25,6 +25,7 @@ const _ = grpc.SupportPackageIsVersion7 type SystemClient interface { // GetInfo returns info about the client GetStatus(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ServerStatus, error) + GetTrace(ctx context.Context, in *GetTraceRequest, opts ...grpc.CallOption) (*GetTraceResponse, error) // PeersAdd adds a new peer PeersAdd(ctx context.Context, in *PeersAddRequest, opts ...grpc.CallOption) (*PeersAddResponse, error) // PeersList returns the list of peers @@ -56,6 +57,15 @@ func (c *systemClient) GetStatus(ctx context.Context, in *emptypb.Empty, opts .. return out, nil } +func (c *systemClient) GetTrace(ctx context.Context, in *GetTraceRequest, opts ...grpc.CallOption) (*GetTraceResponse, error) { + out := new(GetTraceResponse) + err := c.cc.Invoke(ctx, "/v1.System/GetTrace", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *systemClient) PeersAdd(ctx context.Context, in *PeersAddRequest, opts ...grpc.CallOption) (*PeersAddResponse, error) { out := new(PeersAddResponse) err := c.cc.Invoke(ctx, "/v1.System/PeersAdd", in, out, opts...) @@ -162,6 +172,7 @@ func (x *systemExportClient) Recv() (*ExportEvent, error) { type SystemServer interface { // GetInfo returns info about the client GetStatus(context.Context, *emptypb.Empty) (*ServerStatus, error) + GetTrace(context.Context, *GetTraceRequest) (*GetTraceResponse, error) // PeersAdd adds a new peer PeersAdd(context.Context, *PeersAddRequest) (*PeersAddResponse, error) // PeersList returns the list of peers @@ -184,6 +195,9 @@ type UnimplementedSystemServer struct { func (UnimplementedSystemServer) GetStatus(context.Context, *emptypb.Empty) (*ServerStatus, error) { return nil, status.Errorf(codes.Unimplemented, "method GetStatus not implemented") } +func (UnimplementedSystemServer) GetTrace(context.Context, *GetTraceRequest) (*GetTraceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetTrace not implemented") +} func (UnimplementedSystemServer) PeersAdd(context.Context, *PeersAddRequest) (*PeersAddResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method PeersAdd not implemented") } @@ -233,6 +247,24 @@ func _System_GetStatus_Handler(srv interface{}, ctx context.Context, dec func(in return interceptor(ctx, in, info, handler) } +func _System_GetTrace_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetTraceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SystemServer).GetTrace(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/v1.System/GetTrace", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SystemServer).GetTrace(ctx, req.(*GetTraceRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _System_PeersAdd_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(PeersAddRequest) if err := dec(in); err != nil { @@ -358,6 +390,10 @@ var System_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetStatus", Handler: _System_GetStatus_Handler, }, + { + MethodName: "GetTrace", + Handler: _System_GetTrace_Handler, + }, { MethodName: "PeersAdd", Handler: _System_PeersAdd_Handler, diff --git a/server/server.go b/server/server.go index 3d8338e208..e4a176217a 100644 --- a/server/server.go +++ b/server/server.go @@ -2,6 +2,7 @@ package server import ( "context" + "encoding/json" "errors" "fmt" "math/big" @@ -15,6 +16,8 @@ import ( "github.com/0xPolygon/polygon-edge/blockchain/storage/leveldb" "github.com/0xPolygon/polygon-edge/blockchain/storage/memory" consensusPolyBFT "github.com/0xPolygon/polygon-edge/consensus/polybft" + "github.com/0xPolygon/polygon-edge/forkmanager" + "github.com/0xPolygon/polygon-edge/gasprice" "github.com/0xPolygon/polygon-edge/archive" "github.com/0xPolygon/polygon-edge/blockchain" @@ -25,7 +28,6 @@ import ( "github.com/0xPolygon/polygon-edge/contracts" "github.com/0xPolygon/polygon-edge/crypto" "github.com/0xPolygon/polygon-edge/helper/common" - configHelper "github.com/0xPolygon/polygon-edge/helper/config" "github.com/0xPolygon/polygon-edge/helper/progress" "github.com/0xPolygon/polygon-edge/jsonrpc" "github.com/0xPolygon/polygon-edge/network" @@ -34,7 +36,7 @@ import ( "github.com/0xPolygon/polygon-edge/state" itrie "github.com/0xPolygon/polygon-edge/state/immutable-trie" "github.com/0xPolygon/polygon-edge/state/runtime" - "github.com/0xPolygon/polygon-edge/state/runtime/allowlist" + "github.com/0xPolygon/polygon-edge/state/runtime/addresslist" "github.com/0xPolygon/polygon-edge/state/runtime/tracer" "github.com/0xPolygon/polygon-edge/txpool" "github.com/0xPolygon/polygon-edge/types" @@ -46,6 +48,11 @@ import ( "google.golang.org/grpc" ) +var ( + errBlockTimeMissing = errors.New("block time configuration is missing") + errBlockTimeInvalid = errors.New("block time configuration is invalid") +) + // Server is the central manager of the blockchain client type Server struct { logger hclog.Logger @@ -84,6 +91,9 @@ type Server struct { // stateSyncRelayer is handling state syncs execution (Polybft exclusive) stateSyncRelayer *statesyncrelayer.StateSyncRelayer + + // gasHelper is providing functions regarding gas and fees + gasHelper *gasprice.GasHelper } // newFileLogger returns logger instance that writes all logs to a specified file. @@ -206,12 +216,42 @@ func NewServer(config *Config) (*Server, error) { m.executor.GenesisPostHook = factory(m.config.Chain, engineName) } - // apply allow list genesis data + // apply allow list contracts deployer genesis data if m.config.Chain.Params.ContractDeployerAllowList != nil { - allowlist.ApplyGenesisAllocs(m.config.Chain.Genesis, contracts.AllowListContractsAddr, + addresslist.ApplyGenesisAllocs(m.config.Chain.Genesis, contracts.AllowListContractsAddr, m.config.Chain.Params.ContractDeployerAllowList) } + // apply block list contracts deployer genesis data + if m.config.Chain.Params.ContractDeployerBlockList != nil { + addresslist.ApplyGenesisAllocs(m.config.Chain.Genesis, contracts.BlockListContractsAddr, + m.config.Chain.Params.ContractDeployerBlockList) + } + + // apply transactions execution allow list genesis data + if m.config.Chain.Params.TransactionsAllowList != nil { + addresslist.ApplyGenesisAllocs(m.config.Chain.Genesis, contracts.AllowListTransactionsAddr, + m.config.Chain.Params.TransactionsAllowList) + } + + // apply transactions execution block list genesis data + if m.config.Chain.Params.TransactionsBlockList != nil { + addresslist.ApplyGenesisAllocs(m.config.Chain.Genesis, contracts.BlockListTransactionsAddr, + m.config.Chain.Params.TransactionsBlockList) + } + + // apply bridge allow list genesis data + if m.config.Chain.Params.BridgeAllowList != nil { + addresslist.ApplyGenesisAllocs(m.config.Chain.Genesis, contracts.AllowListBridgeAddr, + m.config.Chain.Params.BridgeAllowList) + } + + // apply bridge block list genesis data + if m.config.Chain.Params.BridgeBlockList != nil { + addresslist.ApplyGenesisAllocs(m.config.Chain.Genesis, contracts.BlockListBridgeAddr, + m.config.Chain.Params.BridgeBlockList) + } + var initialStateRoot = types.ZeroHash if ConsensusType(engineName) == PolyBFTConsensus { @@ -241,11 +281,33 @@ func NewServer(config *Config) (*Server, error) { return nil, err } + var initialParams *chain.ForkParams + + if pf := forkManagerInitialParamsFactory[ConsensusType(engineName)]; pf != nil { + if initialParams, err = pf(config.Chain); err != nil { + return nil, err + } + } + + if err := forkmanager.ForkManagerInit( + initialParams, + forkManagerFactory[ConsensusType(engineName)], + config.Chain.Params.Forks); err != nil { + return nil, err + } + // compute the genesis root state config.Chain.Genesis.StateRoot = genesisRoot - // use the eip155 signer - signer := crypto.NewEIP155Signer(chain.AllForksEnabled.At(0), uint64(m.config.Chain.Params.ChainID)) + // Use the london signer with eip-155 as a fallback one + var signer crypto.TxSigner = crypto.NewLondonSigner( + uint64(m.config.Chain.Params.ChainID), + config.Chain.Params.Forks.IsActive(chain.Homestead, 0), + crypto.NewEIP155Signer( + uint64(m.config.Chain.Params.ChainID), + config.Chain.Params.Forks.IsActive(chain.Homestead, 0), + ), + ) // create storage instance for blockchain var db storage.Storage @@ -267,11 +329,23 @@ func NewServer(config *Config) (*Server, error) { } // blockchain object - m.blockchain, err = blockchain.NewBlockchain(logger, db, config.Chain, nil, m.executor, signer) + blockchainConfig := &blockchain.Config{Chain: config.Chain, DataDir: config.DataDir} + m.blockchain, err = blockchain.NewBlockchain( + logger, + db, + blockchainConfig, + nil, + m.executor, + signer, + ) + if err != nil { return nil, err } + // here we can provide some other configuration + m.gasHelper = gasprice.NewGasHelper(gasprice.DefaultGasHelperConfig, m.blockchain) + m.executor.GetHash = m.blockchain.GetHashHelper { @@ -280,11 +354,6 @@ func NewServer(config *Config) (*Server, error) { Blockchain: m.blockchain, } - deploymentWhitelist, err := configHelper.GetDeploymentWhitelist(config.Chain) - if err != nil { - return nil, err - } - // start transaction pool m.txpool, err = txpool.NewTxPool( logger, @@ -293,10 +362,9 @@ func NewServer(config *Config) (*Server, error) { m.grpcServer, m.network, &txpool.Config{ - MaxSlots: m.config.MaxSlots, - PriceLimit: m.config.PriceLimit, - MaxAccountEnqueued: m.config.MaxAccountEnqueued, - DeploymentWhitelist: deploymentWhitelist, + MaxSlots: m.config.MaxSlots, + PriceLimit: m.config.PriceLimit, + MaxAccountEnqueued: m.config.MaxAccountEnqueued, }, ) if err != nil { @@ -494,6 +562,18 @@ func (s *Server) setupConsensus() error { engineConfig = map[string]interface{}{} } + var ( + blockTime = common.Duration{Duration: 0} + err error + ) + + if engineName != string(DummyConsensus) && engineName != string(DevConsensus) { + blockTime, err = extractBlockTime(engineConfig) + if err != nil { + return err + } + } + config := &consensus.Config{ Params: s.config.Chain.Params, Config: engineConfig, @@ -511,7 +591,7 @@ func (s *Server) setupConsensus() error { Grpc: s.grpcServer, Logger: s.logger, SecretsManager: s.secretsManager, - BlockTime: s.config.BlockTime, + BlockTime: uint64(blockTime.Seconds()), NumBlockConfirmations: s.config.NumBlockConfirmations, }, ) @@ -525,6 +605,32 @@ func (s *Server) setupConsensus() error { return nil } +// extractBlockTime extracts blockTime parameter from consensus engine configuration. +// If it is missing or invalid, an appropriate error is returned. +func extractBlockTime(engineConfig map[string]interface{}) (common.Duration, error) { + blockTimeGeneric, ok := engineConfig["blockTime"] + if !ok { + return common.Duration{}, errBlockTimeMissing + } + + blockTimeRaw, err := json.Marshal(blockTimeGeneric) + if err != nil { + return common.Duration{}, errBlockTimeInvalid + } + + var blockTime common.Duration + + if err := json.Unmarshal(blockTimeRaw, &blockTime); err != nil { + return common.Duration{}, errBlockTimeInvalid + } + + if blockTime.Seconds() < 1 { + return common.Duration{}, errBlockTimeInvalid + } + + return blockTime, nil +} + // setupRelayer sets up the relayer func (s *Server) setupRelayer() error { account, err := wallet.NewAccountFromSecret(s.secretsManager) @@ -569,6 +675,7 @@ type jsonRPCHub struct { *network.Server consensus.Consensus consensus.BridgeDataProvider + gasprice.GasStore } func (j *jsonRPCHub) GetPeers() int { @@ -627,6 +734,7 @@ func (j *jsonRPCHub) GetCode(root types.Hash, addr types.Address) ([]byte, error func (j *jsonRPCHub) ApplyTxn( header *types.Header, txn *types.Transaction, + override types.StateOverride, ) (result *runtime.ExecutionResult, err error) { blockCreator, err := j.GetConsensus().GetBlockCreator(header) if err != nil { @@ -638,6 +746,12 @@ func (j *jsonRPCHub) ApplyTxn( return } + if override != nil { + if err = transition.WithStateOverride(override); err != nil { + return + } + } + result, err = transition.Apply(txn) return @@ -790,6 +904,7 @@ func (s *Server) setupJSONRPC() error { Consensus: s.consensus, Server: s.network, BridgeDataProvider: s.consensus.GetBridgeProvider(), + GasStore: s.gasHelper, } conf := &jsonrpc.Config{ @@ -822,6 +937,7 @@ func (s *Server) setupGRPC() error { return err } + // Start server with infinite retries go func() { if err := s.grpcServer.Serve(lis); err != nil { s.logger.Error(err.Error()) @@ -901,11 +1017,13 @@ func (s *Server) startPrometheusServer(listenAddr *net.TCPAddr) *http.Server { ReadHeaderTimeout: 60 * time.Second, } - go func() { - s.logger.Info("Prometheus server started", "addr=", listenAddr.String()) + s.logger.Info("Prometheus server started", "addr=", listenAddr.String()) - if err := srv.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) { - s.logger.Error("Prometheus HTTP server ListenAndServe", "err", err) + go func() { + if err := srv.ListenAndServe(); err != nil { + if !errors.Is(err, http.ErrServerClosed) { + s.logger.Error("Prometheus HTTP server ListenAndServe", "err", err) + } } }() diff --git a/server/server_metrics.go b/server/server_metrics.go index d7737ab180..ffcb0a1f6e 100644 --- a/server/server_metrics.go +++ b/server/server_metrics.go @@ -15,7 +15,10 @@ func (s *Server) setupTelemetry() error { inm := metrics.NewInmemSink(10*time.Second, time.Minute) metrics.DefaultInmemSignal(inm) - promSink, err := prometheus.NewPrometheusSink() + promSink, err := prometheus.NewPrometheusSinkFrom(prometheus.PrometheusOpts{ + Name: "edge_prometheus_sink", + Expiration: 0, + }) if err != nil { return err } diff --git a/server/system_service.go b/server/system_service.go index 7bb27ab827..0661ee30e6 100644 --- a/server/system_service.go +++ b/server/system_service.go @@ -5,6 +5,8 @@ import ( "context" "errors" "fmt" + "io/ioutil" + "path/filepath" "github.com/0xPolygon/polygon-edge/blockchain" "github.com/0xPolygon/polygon-edge/network/common" @@ -20,6 +22,21 @@ type systemService struct { server *Server } +func (s *systemService) GetTrace(ctx context.Context, req *proto.GetTraceRequest) (*proto.GetTraceResponse, error) { + path := filepath.Join(s.server.config.DataDir, "consensus") + + data, err := ioutil.ReadFile(filepath.Join(path, fmt.Sprintf("trace_%d", req.Number)) + ".json") + if err != nil { + return nil, err + } + + resp := &proto.GetTraceResponse{ + Trace: data, + } + + return resp, nil +} + // GetStatus returns the current system status, in the form of: // // Network: diff --git a/sonar-project.properties b/sonar-project.properties index d79c46c4d5..5565a9e4d4 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,13 +1,13 @@ sonar.projectKey=polygon-edge sonar.sources=. -sonar.exclusions=**/*_test.go,**/vendor/**,**/*.py,**/core-contracts/** +sonar.exclusions=**/*_test.go,**/vendor/**,**/*.py,**/core-contracts/**,**/tests/** sonar.tests=. sonar.test.inclusions=**/*_test.go sonar.test.exclusions=**/vendor/** -sonar.coverage.exclusions=**/vendor/**,**/*.py +sonar.coverage.exclusions=**/vendor/**,**/*.py,**/tests/** # ===================================================== # Properties specific to Go diff --git a/state/executor.go b/state/executor.go index a4f8d932e0..3a0e1ebf9c 100644 --- a/state/executor.go +++ b/state/executor.go @@ -6,16 +6,18 @@ import ( "math" "math/big" + "github.com/hashicorp/go-hclog" + "github.com/0xPolygon/polygon-edge/chain" "github.com/0xPolygon/polygon-edge/contracts" "github.com/0xPolygon/polygon-edge/crypto" + "github.com/0xPolygon/polygon-edge/helper/common" "github.com/0xPolygon/polygon-edge/state/runtime" - "github.com/0xPolygon/polygon-edge/state/runtime/allowlist" + "github.com/0xPolygon/polygon-edge/state/runtime/addresslist" "github.com/0xPolygon/polygon-edge/state/runtime/evm" "github.com/0xPolygon/polygon-edge/state/runtime/precompiled" "github.com/0xPolygon/polygon-edge/state/runtime/tracer" "github.com/0xPolygon/polygon-edge/types" - "github.com/hashicorp/go-hclog" ) const ( @@ -26,8 +28,6 @@ const ( TxGasContractCreation uint64 = 53000 // Per transaction that creates a contract ) -var emptyCodeHashTwo = types.BytesToHash(crypto.Keccak256(nil)) - // GetHashByNumber returns the hash function of a block number type GetHashByNumber = func(i uint64) types.Hash @@ -112,8 +112,12 @@ func (e *Executor) WriteGenesis( } } - objs := txn.Commit(false) - _, root := snap.Commit(objs) + objs, err := txn.Commit(false) + if err != nil { + return types.Hash{}, err + } + + _, _, root := snap.Commit(objs) return types.BytesToHash(root), nil } @@ -136,15 +140,11 @@ func (e *Executor) ProcessBlock( } for _, t := range block.Transactions { - if t.ExceedsBlockGasLimit(block.Header.GasLimit) { - if err := txn.WriteFailedReceipt(t); err != nil { - return nil, err - } - + if t.Gas > block.Header.GasLimit { continue } - if err := txn.Write(t); err != nil { + if err = txn.Write(t); err != nil { return nil, err } } @@ -179,15 +179,25 @@ func (e *Executor) BeginTxn( return nil, err } + burnContract := types.ZeroAddress + if forkConfig.London { + burnContract, err = e.config.CalculateBurnContract(header.Number) + if err != nil { + return nil, err + } + } + newTxn := NewTxn(auxSnap2) txCtx := runtime.TxContext{ - Coinbase: coinbaseReceiver, - Timestamp: int64(header.Timestamp), - Number: int64(header.Number), - Difficulty: types.BytesToHash(new(big.Int).SetUint64(header.Difficulty).Bytes()), - GasLimit: int64(header.GasLimit), - ChainID: e.config.ChainID, + Coinbase: coinbaseReceiver, + Timestamp: int64(header.Timestamp), + Number: int64(header.Number), + Difficulty: types.BytesToHash(new(big.Int).SetUint64(header.Difficulty).Bytes()), + BaseFee: new(big.Int).SetUint64(header.BaseFee), + GasLimit: int64(header.GasLimit), + ChainID: e.config.ChainID, + BurnContract: burnContract, } txn := &Transition{ @@ -206,11 +216,36 @@ func (e *Executor) BeginTxn( evm: evm.NewEVM(), precompiles: precompiled.NewPrecompiled(), PostHook: e.PostHook, + trace: &types.Trace{ + TxnTraces: []*types.TxnTrace{}, + }, } // enable contract deployment allow list (if any) if e.config.ContractDeployerAllowList != nil { - txn.deploymentAllowlist = allowlist.NewAllowList(txn, contracts.AllowListContractsAddr) + txn.deploymentAllowList = addresslist.NewAddressList(txn, contracts.AllowListContractsAddr) + } + + if e.config.ContractDeployerBlockList != nil { + txn.deploymentBlockList = addresslist.NewAddressList(txn, contracts.BlockListContractsAddr) + } + + // enable transactions allow list (if any) + if e.config.TransactionsAllowList != nil { + txn.txnAllowList = addresslist.NewAddressList(txn, contracts.AllowListTransactionsAddr) + } + + if e.config.TransactionsBlockList != nil { + txn.txnBlockList = addresslist.NewAddressList(txn, contracts.BlockListTransactionsAddr) + } + + // enable transactions allow list (if any) + if e.config.BridgeAllowList != nil { + txn.bridgeAllowList = addresslist.NewAddressList(txn, contracts.AllowListBridgeAddr) + } + + if e.config.BridgeBlockList != nil { + txn.bridgeBlockList = addresslist.NewAddressList(txn, contracts.BlockListBridgeAddr) } return txn, nil @@ -235,13 +270,19 @@ type Transition struct { PostHook func(t *Transition) + trace *types.Trace + // runtimes evm *evm.EVM precompiles *precompiled.Precompiled // allow list runtimes - deploymentAllowlist *allowlist.AllowList - txnAllowList *allowlist.AllowList + deploymentAllowList *addresslist.AddressList + deploymentBlockList *addresslist.AddressList + txnAllowList *addresslist.AddressList + txnBlockList *addresslist.AddressList + bridgeAllowList *addresslist.AddressList + bridgeBlockList *addresslist.AddressList } func NewTransition(config chain.ForksInTime, snap Snapshot, radix *Txn) *Transition { @@ -251,55 +292,58 @@ func NewTransition(config chain.ForksInTime, snap Snapshot, radix *Txn) *Transit snap: snap, evm: evm.NewEVM(), precompiles: precompiled.NewPrecompiled(), + trace: &types.Trace{ + TxnTraces: []*types.TxnTrace{}, + }, } } -func (t *Transition) TotalGas() uint64 { - return t.totalGas -} - -func (t *Transition) Receipts() []*types.Receipt { - return t.receipts -} +func (t *Transition) WithStateOverride(override types.StateOverride) error { + for addr, o := range override { + if o.State != nil && o.StateDiff != nil { + return fmt.Errorf("cannot override both state and state diff") + } -var emptyFrom = types.Address{} + if o.Nonce != nil { + t.state.SetNonce(addr, *o.Nonce) + } -func (t *Transition) WriteFailedReceipt(txn *types.Transaction) error { - signer := crypto.NewSigner(t.config, uint64(t.ctx.ChainID)) + if o.Balance != nil { + t.state.SetBalance(addr, o.Balance) + } - if txn.From == emptyFrom && txn.Type == types.LegacyTx { - // Decrypt the from address - from, err := signer.Sender(txn) - if err != nil { - return NewTransitionApplicationError(err, false) + if o.Code != nil { + t.state.SetCode(addr, o.Code) } - txn.From = from - } + if o.State != nil { + t.state.SetFullStorage(addr, o.State) + } - receipt := &types.Receipt{ - CumulativeGasUsed: t.totalGas, - TransactionType: txn.Type, - TxHash: txn.Hash, - Logs: t.state.Logs(), + for k, v := range o.StateDiff { + t.state.SetState(addr, k, v) + } } - receipt.LogsBloom = types.CreateBloom([]*types.Receipt{receipt}) - receipt.SetStatus(types.ReceiptFailed) - t.receipts = append(t.receipts, receipt) + return nil +} - if txn.To == nil { - receipt.ContractAddress = crypto.CreateAddress(txn.From, txn.Nonce).Ptr() - } +func (t *Transition) TotalGas() uint64 { + return t.totalGas +} - return nil +func (t *Transition) Receipts() []*types.Receipt { + return t.receipts } +var emptyFrom = types.Address{} + // Write writes another transaction to the executor func (t *Transition) Write(txn *types.Transaction) error { var err error - if txn.From == emptyFrom && txn.Type == types.LegacyTx { + if txn.From == emptyFrom && + (txn.Type == types.LegacyTx || txn.Type == types.DynamicFeeTx) { // Decrypt the from address signer := crypto.NewSigner(t.config, uint64(t.ctx.ChainID)) @@ -331,7 +375,9 @@ func (t *Transition) Write(txn *types.Transaction) error { } // The suicided accounts are set as deleted for the next iteration - t.state.CleanDeleteObjects(true) + if err := t.state.CleanDeleteObjects(true); err != nil { + return fmt.Errorf("failed to clean deleted objects: %w", err) + } if result.Failed() { receipt.SetStatus(types.ReceiptFailed) @@ -349,15 +395,27 @@ func (t *Transition) Write(txn *types.Transaction) error { receipt.LogsBloom = types.CreateBloom([]*types.Receipt{receipt}) t.receipts = append(t.receipts, receipt) + t.trace.TxnTraces = append(t.trace.TxnTraces, &types.TxnTrace{ + Transaction: txn.MarshalRLP(), + Delta: t.Txn().getCompactJournal(), + }) + return nil } // Commit commits the final result -func (t *Transition) Commit() (Snapshot, types.Hash) { - objs := t.state.Commit(t.config.EIP155) - s2, root := t.snap.Commit(objs) +func (t *Transition) Commit() (Snapshot, *types.Trace, types.Hash, error) { + objs, err := t.state.Commit(t.config.EIP155) + if err != nil { + return nil, nil, types.ZeroHash, err + } - return s2, types.BytesToHash(root) + s2, snapTrace, root := t.snap.Commit(objs) + + t.trace.AccountTrie = snapTrace.AccountTrie + t.trace.StorageTrie = snapTrace.StorageTrie + + return s2, t.trace, types.BytesToHash(root), nil } func (t *Transition) subGasPool(amount uint64) error { @@ -384,7 +442,9 @@ func (t *Transition) Apply(msg *types.Transaction) (*runtime.ExecutionResult, er result, err := t.apply(msg) if err != nil { - t.state.RevertToSnapshot(s) + if revertErr := t.state.RevertToSnapshot(s); revertErr != nil { + return nil, revertErr + } } if t.PostHook != nil { @@ -401,9 +461,18 @@ func (t *Transition) ContextPtr() *runtime.TxContext { } func (t *Transition) subGasLimitPrice(msg *types.Transaction) error { - // deduct the upfront max gas cost - upfrontGasCost := new(big.Int).Set(msg.GasPrice) - upfrontGasCost.Mul(upfrontGasCost, new(big.Int).SetUint64(msg.Gas)) + upfrontGasCost := new(big.Int).SetUint64(msg.Gas) + + factor := new(big.Int) + if msg.GasFeeCap != nil && msg.GasFeeCap.BitLen() > 0 { + // Apply EIP-1559 tx cost calculation factor + factor = factor.Set(msg.GasFeeCap) + } else { + // Apply legacy tx cost calculation factor + factor = factor.Set(msg.GasPrice) + } + + upfrontGasCost = upfrontGasCost.Mul(upfrontGasCost, factor) if err := t.state.SubBalance(msg.From, upfrontGasCost); err != nil { if errors.Is(err, runtime.ErrNotEnoughFunds) { @@ -426,6 +495,42 @@ func (t *Transition) nonceCheck(msg *types.Transaction) error { return nil } +// checkDynamicFees checks correctness of the EIP-1559 feature-related fields. +// Basically, makes sure gas tip cap and gas fee cap are good. +func (t *Transition) checkDynamicFees(msg *types.Transaction) error { + if msg.Type != types.DynamicFeeTx { + return nil + } + + if msg.GasFeeCap.BitLen() == 0 && msg.GasTipCap.BitLen() == 0 { + return nil + } + + if l := msg.GasFeeCap.BitLen(); l > 256 { + return fmt.Errorf("%w: address %v, GasFeeCap bit length: %d", ErrFeeCapVeryHigh, + msg.From.String(), l) + } + + if l := msg.GasTipCap.BitLen(); l > 256 { + return fmt.Errorf("%w: address %v, GasTipCap bit length: %d", ErrTipVeryHigh, + msg.From.String(), l) + } + + if msg.GasFeeCap.Cmp(msg.GasTipCap) < 0 { + return fmt.Errorf("%w: address %v, GasTipCap: %s, GasFeeCap: %s", ErrTipAboveFeeCap, + msg.From.String(), msg.GasTipCap, msg.GasFeeCap) + } + + // This will panic if baseFee is nil, but basefee presence is verified + // as part of header validation. + if msg.GasFeeCap.Cmp(t.ctx.BaseFee) < 0 { + return fmt.Errorf("%w: address %v, GasFeeCap: %s, BaseFee: %s", ErrFeeCapTooLow, + msg.From.String(), msg.GasFeeCap, t.ctx.BaseFee) + } + + return nil +} + // errors that can originate in the consensus rules checks of the apply method below // surfacing of these errors reject the transaction thus not including it in the block @@ -435,7 +540,22 @@ var ( ErrBlockLimitReached = fmt.Errorf("gas limit reached in the pool") ErrIntrinsicGasOverflow = fmt.Errorf("overflow in intrinsic gas calculation") ErrNotEnoughIntrinsicGas = fmt.Errorf("not enough gas supplied for intrinsic gas costs") - ErrNotEnoughFunds = fmt.Errorf("not enough funds for transfer with given value") + + // ErrTipAboveFeeCap is a sanity error to ensure no one is able to specify a + // transaction with a tip higher than the total fee cap. + ErrTipAboveFeeCap = errors.New("max priority fee per gas higher than max fee per gas") + + // ErrTipVeryHigh is a sanity error to avoid extremely big numbers specified + // in the tip field. + ErrTipVeryHigh = errors.New("max priority fee per gas higher than 2^256-1") + + // ErrFeeCapVeryHigh is a sanity error to avoid extremely big numbers specified + // in the fee cap field. + ErrFeeCapVeryHigh = errors.New("max fee per gas higher than 2^256-1") + + // ErrFeeCapTooLow is returned if the transaction fee cap is less than the + // the base fee of the block. + ErrFeeCapTooLow = errors.New("max fee per gas less than block base fee") ) type TransitionApplicationError struct { @@ -465,18 +585,20 @@ func NewGasLimitReachedTransitionApplicationError(err error) *GasLimitReachedTra } func (t *Transition) apply(msg *types.Transaction) (*runtime.ExecutionResult, error) { + var err error + if msg.Type == types.StateTx { - if err := checkAndProcessStateTx(msg, t); err != nil { - return nil, err - } + err = checkAndProcessStateTx(msg) } else { - if err := checkAndProcessLegacyTx(msg, t); err != nil { - return nil, err - } + err = checkAndProcessTx(msg, t) + } + + if err != nil { + return nil, err } // the amount of gas required is available in the block - if err := t.subGasPool(msg.Gas); err != nil { + if err = t.subGasPool(msg.Gas); err != nil { return nil, NewGasLimitReachedTransitionApplicationError(err) } @@ -497,7 +619,7 @@ func (t *Transition) apply(msg *types.Transaction) (*runtime.ExecutionResult, er return nil, NewTransitionApplicationError(ErrNotEnoughIntrinsicGas, false) } - gasPrice := new(big.Int).Set(msg.GasPrice) + gasPrice := msg.GetGasPrice(t.ctx.BaseFee.Uint64()) value := new(big.Int).Set(msg.Value) // set the specific transaction fields in the context @@ -519,14 +641,33 @@ func (t *Transition) apply(msg *types.Transaction) (*runtime.ExecutionResult, er t.ctx.Tracer.TxEnd(result.GasLeft) } - // refund the sender - remaining := new(big.Int).Mul(new(big.Int).SetUint64(result.GasLeft), msg.GasPrice) + // Refund the sender + remaining := new(big.Int).Mul(new(big.Int).SetUint64(result.GasLeft), gasPrice) t.state.AddBalance(msg.From, remaining) - // pay the coinbase - coinbaseFee := new(big.Int).Mul(new(big.Int).SetUint64(result.GasUsed), msg.GasPrice) + // Spec: https://eips.ethereum.org/EIPS/eip-1559#specification + // Define effective tip based on tx type. + // We use EIP-1559 fields of the tx if the london hardfork is enabled. + // Effective tip became to be either gas tip cap or (gas fee cap - current base fee) + effectiveTip := new(big.Int).Set(gasPrice) + if t.config.London && msg.Type == types.DynamicFeeTx { + effectiveTip = common.BigMin( + new(big.Int).Sub(msg.GasFeeCap, t.ctx.BaseFee), + new(big.Int).Set(msg.GasTipCap), + ) + } + + // Pay the coinbase fee as a miner reward using the calculated effective tip. + coinbaseFee := new(big.Int).Mul(new(big.Int).SetUint64(result.GasUsed), effectiveTip) t.state.AddBalance(t.ctx.Coinbase, coinbaseFee) + // Burn some amount if the london hardfork is applied. + // Basically, burn amount is just transferred to the current burn contract. + if t.config.London && msg.Type != types.StateTx { + burnAmount := new(big.Int).Mul(new(big.Int).SetUint64(result.GasUsed), t.ctx.BaseFee) + t.state.AddBalance(t.ctx.BurnContract, burnAmount) + } + // return gas to the pool t.addGasPool(result.GasLeft) @@ -558,9 +699,43 @@ func (t *Transition) Call2( } func (t *Transition) run(contract *runtime.Contract, host runtime.Host) *runtime.ExecutionResult { - // check allow list (if any) - if t.deploymentAllowlist != nil && t.deploymentAllowlist.Addr() == contract.CodeAddress { - return t.deploymentAllowlist.Run(contract, host, &t.config) + if result := t.handleAllowBlockListsUpdate(contract, host); result != nil { + return result + } + + // check txns access lists, allow list takes precedence over block list + if t.txnAllowList != nil { + if contract.Caller != contracts.SystemCaller { + role := t.txnAllowList.GetRole(contract.Caller) + if !role.Enabled() { + t.logger.Debug( + "Failing transaction. Caller is not in the transaction allowlist", + "contract.Caller", contract.Caller, + "contract.Address", contract.Address, + ) + + return &runtime.ExecutionResult{ + GasLeft: 0, + Err: runtime.ErrNotAuth, + } + } + } + } else if t.txnBlockList != nil { + if contract.Caller != contracts.SystemCaller { + role := t.txnBlockList.GetRole(contract.Caller) + if role == addresslist.EnabledRole { + t.logger.Debug( + "Failing transaction. Caller is in the transaction blocklist", + "contract.Caller", contract.Caller, + "contract.Address", contract.Address, + ) + + return &runtime.ExecutionResult{ + GasLeft: 0, + Err: runtime.ErrNotAuth, + } + } + } } // check the precompiles @@ -626,7 +801,12 @@ func (t *Transition) applyCall( result = t.run(c, host) if result.Failed() { - t.state.RevertToSnapshot(snapshot) + if err := t.state.RevertToSnapshot(snapshot); err != nil { + return &runtime.ExecutionResult{ + GasLeft: c.Gas, + Err: err, + } + } } t.captureCallEnd(c, result) @@ -634,21 +814,14 @@ func (t *Transition) applyCall( return result } -var emptyHash types.Hash - func (t *Transition) hasCodeOrNonce(addr types.Address) bool { - nonce := t.state.GetNonce(addr) - if nonce != 0 { + if t.state.GetNonce(addr) != 0 { return true } codeHash := t.state.GetCodeHash(addr) - if codeHash != emptyCodeHashTwo && codeHash != emptyHash { - return true - } - - return false + return codeHash != types.EmptyCodeHash && codeHash != types.ZeroHash } func (t *Transition) applyCreate(c *runtime.Contract, host runtime.Host) *runtime.ExecutionResult { @@ -664,7 +837,7 @@ func (t *Transition) applyCreate(c *runtime.Contract, host runtime.Host) *runtim // Increment the nonce of the caller t.state.IncrNonce(c.Caller) - // Check if there if there is a collision and the address already exists + // Check if there is a collision and the address already exists if t.hasCodeOrNonce(c.Address) { return &runtime.ExecutionResult{ GasLeft: 0, @@ -699,10 +872,31 @@ func (t *Transition) applyCreate(c *runtime.Contract, host runtime.Host) *runtim }() // check if contract creation allow list is enabled - if t.deploymentAllowlist != nil { - role := t.deploymentAllowlist.GetRole(c.Caller) + if t.deploymentAllowList != nil { + role := t.deploymentAllowList.GetRole(c.Caller) if !role.Enabled() { + t.logger.Debug( + "Failing contract deployment. Caller is not in the deployment allowlist", + "contract.Caller", c.Caller, + "contract.Address", c.Address, + ) + + return &runtime.ExecutionResult{ + GasLeft: 0, + Err: runtime.ErrNotAuth, + } + } + } else if t.deploymentBlockList != nil { + role := t.deploymentBlockList.GetRole(c.Caller) + + if role == addresslist.EnabledRole { + t.logger.Debug( + "Failing contract deployment. Caller is in the deployment blocklist", + "contract.Caller", c.Caller, + "contract.Address", c.Address, + ) + return &runtime.ExecutionResult{ GasLeft: 0, Err: runtime.ErrNotAuth, @@ -712,14 +906,22 @@ func (t *Transition) applyCreate(c *runtime.Contract, host runtime.Host) *runtim result = t.run(c, host) if result.Failed() { - t.state.RevertToSnapshot(snapshot) + if err := t.state.RevertToSnapshot(snapshot); err != nil { + return &runtime.ExecutionResult{ + Err: err, + } + } return result } if t.config.EIP158 && len(result.ReturnValue) > SpuriousDragonMaxCodeSize { // Contract size exceeds 'SpuriousDragon' size limit - t.state.RevertToSnapshot(snapshot) + if err := t.state.RevertToSnapshot(snapshot); err != nil { + return &runtime.ExecutionResult{ + Err: err, + } + } return &runtime.ExecutionResult{ GasLeft: 0, @@ -735,7 +937,11 @@ func (t *Transition) applyCreate(c *runtime.Contract, host runtime.Host) *runtim // Out of gas creating the contract if t.config.Homestead { - t.state.RevertToSnapshot(snapshot) + if err := t.state.RevertToSnapshot(snapshot); err != nil { + return &runtime.ExecutionResult{ + Err: err, + } + } result.GasLeft = 0 } @@ -750,6 +956,41 @@ func (t *Transition) applyCreate(c *runtime.Contract, host runtime.Host) *runtim return result } +func (t *Transition) handleAllowBlockListsUpdate(contract *runtime.Contract, + host runtime.Host) *runtime.ExecutionResult { + // check contract deployment allow list (if any) + if t.deploymentAllowList != nil && t.deploymentAllowList.Addr() == contract.CodeAddress { + return t.deploymentAllowList.Run(contract, host, &t.config) + } + + // check contract deployment block list (if any) + if t.deploymentBlockList != nil && t.deploymentBlockList.Addr() == contract.CodeAddress { + return t.deploymentBlockList.Run(contract, host, &t.config) + } + + // check bridge allow list (if any) + if t.bridgeAllowList != nil && t.bridgeAllowList.Addr() == contract.CodeAddress { + return t.bridgeAllowList.Run(contract, host, &t.config) + } + + // check bridge block list (if any) + if t.bridgeBlockList != nil && t.bridgeBlockList.Addr() == contract.CodeAddress { + return t.bridgeBlockList.Run(contract, host, &t.config) + } + + // check transaction allow list (if any) + if t.txnAllowList != nil && t.txnAllowList.Addr() == contract.CodeAddress { + return t.txnAllowList.Run(contract, host, &t.config) + } + + // check transaction block list (if any) + if t.txnBlockList != nil && t.txnBlockList.Addr() == contract.CodeAddress { + return t.txnBlockList.Run(contract, host, &t.config) + } + + return nil +} + func (t *Transition) SetState(addr types.Address, key types.Hash, value types.Hash) { t.state.SetState(addr, key, value) } @@ -912,17 +1153,22 @@ func TransactionGasCost(msg *types.Transaction, isHomestead, isIstanbul bool) (u return cost, nil } -// checkAndProcessLegacyTx - first check if this message satisfies all consensus rules before +// checkAndProcessTx - first check if this message satisfies all consensus rules before // applying the message. The rules include these clauses: // 1. the nonce of the message caller is correct -// 2. caller has enough balance to cover transaction fee(gaslimit * gasprice) -func checkAndProcessLegacyTx(msg *types.Transaction, t *Transition) error { +// 2. caller has enough balance to cover transaction fee(gaslimit * gasprice * val) or fee(gasfeecap * gasprice * val) +func checkAndProcessTx(msg *types.Transaction, t *Transition) error { // 1. the nonce of the message caller is correct if err := t.nonceCheck(msg); err != nil { return NewTransitionApplicationError(err, true) } - // 2. caller has enough balance to cover transaction fee(gaslimit * gasprice) + // 2. check dynamic fees of the transaction + if err := t.checkDynamicFees(msg); err != nil { + return NewTransitionApplicationError(err, true) + } + + // 3. caller has enough balance to cover transaction if err := t.subGasLimitPrice(msg); err != nil { return NewTransitionApplicationError(err, true) } @@ -930,7 +1176,7 @@ func checkAndProcessLegacyTx(msg *types.Transaction, t *Transition) error { return nil } -func checkAndProcessStateTx(msg *types.Transaction, t *Transition) error { +func checkAndProcessStateTx(msg *types.Transaction) error { if msg.GasPrice.Cmp(big.NewInt(0)) != 0 { return NewTransitionApplicationError( errors.New("gasPrice of state transaction must be zero"), diff --git a/state/executor_test.go b/state/executor_test.go new file mode 100644 index 0000000000..79ae3c96e3 --- /dev/null +++ b/state/executor_test.go @@ -0,0 +1,156 @@ +package state + +import ( + "fmt" + "math/big" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/0xPolygon/polygon-edge/chain" + "github.com/0xPolygon/polygon-edge/state/runtime" + "github.com/0xPolygon/polygon-edge/types" +) + +func TestOverride(t *testing.T) { + t.Parallel() + + state := newStateWithPreState(map[types.Address]*PreState{ + {0x0}: { + Nonce: 1, + Balance: 1, + State: map[types.Hash]types.Hash{ + types.ZeroHash: {0x1}, + }, + }, + {0x1}: { + State: map[types.Hash]types.Hash{ + types.ZeroHash: {0x1}, + }, + }, + }) + + nonce := uint64(2) + balance := big.NewInt(2) + code := []byte{0x1} + + tt := NewTransition(chain.ForksInTime{}, state, newTxn(state)) + + require.Empty(t, tt.state.GetCode(types.ZeroAddress)) + + err := tt.WithStateOverride(types.StateOverride{ + {0x0}: types.OverrideAccount{ + Nonce: &nonce, + Balance: balance, + Code: code, + StateDiff: map[types.Hash]types.Hash{ + types.ZeroHash: {0x2}, + }, + }, + {0x1}: types.OverrideAccount{ + State: map[types.Hash]types.Hash{ + {0x1}: {0x1}, + }, + }, + }) + require.NoError(t, err) + + require.Equal(t, nonce, tt.state.GetNonce(types.ZeroAddress)) + require.Equal(t, balance, tt.state.GetBalance(types.ZeroAddress)) + require.Equal(t, code, tt.state.GetCode(types.ZeroAddress)) + require.Equal(t, types.Hash{0x2}, tt.state.GetState(types.ZeroAddress, types.ZeroHash)) + + // state is fully replaced + require.Equal(t, types.Hash{0x0}, tt.state.GetState(types.Address{0x1}, types.ZeroHash)) + require.Equal(t, types.Hash{0x1}, tt.state.GetState(types.Address{0x1}, types.Hash{0x1})) +} + +func Test_Transition_checkDynamicFees(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + baseFee *big.Int + tx *types.Transaction + wantErr assert.ErrorAssertionFunc + }{ + { + name: "happy path", + baseFee: big.NewInt(100), + tx: &types.Transaction{ + Type: types.DynamicFeeTx, + GasFeeCap: big.NewInt(100), + GasTipCap: big.NewInt(100), + }, + wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { + assert.NoError(t, err, i) + + return false + }, + }, + { + name: "happy path with empty values", + baseFee: big.NewInt(0), + tx: &types.Transaction{ + Type: types.DynamicFeeTx, + GasFeeCap: big.NewInt(0), + GasTipCap: big.NewInt(0), + }, + wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { + assert.NoError(t, err, i) + + return false + }, + }, + { + name: "gas fee cap less than base fee", + baseFee: big.NewInt(20), + tx: &types.Transaction{ + Type: types.DynamicFeeTx, + GasFeeCap: big.NewInt(10), + GasTipCap: big.NewInt(0), + }, + wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { + expectedError := fmt.Sprintf("max fee per gas less than block base fee: "+ + "address %s, GasFeeCap: 10, BaseFee: 20", types.ZeroAddress) + assert.EqualError(t, err, expectedError, i) + + return true + }, + }, + { + name: "gas fee cap less than tip cap", + baseFee: big.NewInt(5), + tx: &types.Transaction{ + Type: types.DynamicFeeTx, + GasFeeCap: big.NewInt(10), + GasTipCap: big.NewInt(15), + }, + wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { + expectedError := fmt.Sprintf("max priority fee per gas higher than max fee per gas: "+ + "address %s, GasTipCap: 15, GasFeeCap: 10", types.ZeroAddress) + assert.EqualError(t, err, expectedError, i) + + return true + }, + }, + } + + for _, tt := range tests { + tt := tt + + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + tr := &Transition{ + ctx: runtime.TxContext{ + BaseFee: tt.baseFee, + }, + } + + err := tr.checkDynamicFees(tt.tx) + tt.wantErr(t, err, fmt.Sprintf("checkDynamicFees(%v)", tt.tx)) + }) + } +} diff --git a/state/immutable-trie/7410_readable.json b/state/immutable-trie/7410_readable.json new file mode 100644 index 0000000000..7e582d47ff --- /dev/null +++ b/state/immutable-trie/7410_readable.json @@ -0,0 +1,656 @@ +{ + "accountTrie": { + "079a8ca10bd34244e1c9c92980526f090ec6b6cac52992a6a2d4c8f78f35180f": "f851808080a01a43c8e838c70073f22eb72cef68940e72a4b6a8711a73fc40c4803a47c4787f80a0aa0501033b4cb2732f45ac6ec31a3f58bd21b4a8d675dd4e9d143a3ebef9f5508080808080808080808080", + "1a43c8e838c70073f22eb72cef68940e72a4b6a8711a73fc40c4803a47c4787f": "f873a02080c7b7ae81a58eb98d9c78de4a1fd7fd9535fc953ed2be602daaa41767312ab850f84e808ad3c21bcecd03172430aba056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "1cbf50250961fcceddf28e78b51758a27697625fb4f41547380286d38690efcf": "f85180a031d1eb10fdf37ef90417d463e9e3d1dad5bab6a3e8b38ccc4eaa744250317457808080a0e98d73f14c784cb1a2782058fabda51afdb2e6f19347bfa00299c0fd960275438080808080808080808080", + "7af909cad6f85f8cde7145f8ce00e6291269d63bb3145b9c6b0ba7d1bfdb3fe3": "f873a020d511612a04be33a906f4a2f355cad1fe0ff4e5259b845677431e9de1a89524b850f84e808ad3c21bcecceda1000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "b57c2d7989e9b67f8e019850d3d8a8290e971398b028e458728351578dea7b4d": "f8769f3eec2b84f0ba344fd4b4d2f022469febe7a772c4789acfc119eb558ab1da3db854f8528248d08c033b2e3c9fd0803ce8000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "cbccf9f17eecc98379ccf4a140a026a8c2585ca3b0901563e4f9a9f1b15907c7": "f901d1a03f84f317ceea01d67e9da286f143aea01d93cc275c3d9fad2722ce1aeb8a39bf80a0a65cefec668d4a8caa4614f5bd8c22cb6a89387efd124add03c6a29f7ca5c4f7a0ec7a9e4d6b11b2e73c2950ef2c2eb3109007070aa184d928abb3593332366f52a00a5426c2c1c724762a0a59e81f6d3386d66d7fd5b0f2e8909eaafd4d590355f2a0079a8ca10bd34244e1c9c92980526f090ec6b6cac52992a6a2d4c8f78f35180fa048431a96134f4c7b241dd5c282c352e9ed6e8c0a0cc0663b6dc435514d29d829a0e31ed7224b4a1d1fb39677e4a2e7404b8dccd70bfa62725fb24377c71cab65a9a0364969fa64ed1edef177b8a87bbe20e26615582bf935df361abf64c0b7e2b589a0a20860bef0bc90a25310ca9dfde953060116407763f668bd32cba72582909d1ca01cbf50250961fcceddf28e78b51758a27697625fb4f41547380286d38690efcfa07f20ac3a7307ee8054cfb13327949b7cb3c4ba129bb2c9efc225a1cbba70e12aa0e0a430b6cc0eb1c8f2160c8f114e5f53df7da2adb83ad4cc4df66fed88cf80c980a00627f2d180ee2cb033d4dcd5572903723c4fad4f6fb41ebd7b7f58cd0c347145a00f31a4067b26d457ae8724a2d8d41d63bc9f4ec34c008c959b5528d040f6bb0880", + "e0a430b6cc0eb1c8f2160c8f114e5f53df7da2adb83ad4cc4df66fed88cf80c9": "f8518080808080a0f4bfbde517227e1dc06a4f7dad964f892016b10b8f7e34a6b785df99b778e3048080a02b552522c790b0433d466408318c5c61bfa7e2dbb9c2e13bfec3d1d51290addd8080808080808080", + "e31ed7224b4a1d1fb39677e4a2e7404b8dccd70bfa62725fb24377c71cab65a9": "f8918080808080808080a00ba7e530fe4d735de2592c5638b234c135d2f70c088da1e20605596e33332ebca07af909cad6f85f8cde7145f8ce00e6291269d63bb3145b9c6b0ba7d1bfdb3fe3808080a08a0977db0c40a342485134dc58b8ec9ca0c4d0b37ec2659d0d7333265623b7f580a0e2e4bceb82b6f7009ba7fc3c188cae32138588d9d6c69b97933388e7e02ac69980", + "e98d73f14c784cb1a2782058fabda51afdb2e6f19347bfa00299c0fd96027543": "f85180a0b57c2d7989e9b67f8e019850d3d8a8290e971398b028e458728351578dea7b4d80808080808080808080a0b352e4c72d853473be5eac69cf10adfdc61a3747ec26a4b424f0a29292fc1d3780808080", + "f4bfbde517227e1dc06a4f7dad964f892016b10b8f7e34a6b785df99b778e304": "f869a02058c2c1ac06ad29eab5b631a2a76f7997030f5468deb7f384eb6e276208d046b846f8440180a0135f236339b97faa1a721e7235b386ca95080dfba8b57f0cbb2dd58959819bf7a0e86cf7cc93bf311f1751ca156a07c54a62d0769f9a09b61afd05b037a4713e1b" + }, + "storageTrie": { + "00567c7cdd86650bec3c336cc930aa05ac2b63e92fa726b295bff1978dc6ab9e": "f90211a0471068f6b9e2fd5175d0dffd385eefdd104b4dc9f5800842cf3ec8d4bbe6bebfa0a9dcf1378700d82c908f416919d9bacd50484ffaff9d6ad59c334ce7f4501466a0bcfac5f6db5e6818f4224f192b1f3a0486397d8828bb24067c1433476bd29b3ca04ed4f6c0ca3c5a4ce495b86dd1cf9cfa8240c2e335c3a8a551756ed0d3570f7aa0187a59c4a4995516cc2bc5cda57dbd92c3bbe4ab9609b9cf20ca2fb1a53a2da7a0e4ac1f6f1954c232b2e52095e2da95e6faa424c3ac50b093929ab46bae55b8d0a0aa3440ac48aab334411813b2c19565d9d203b8d2290d10d857c1a0a21300216fa087b63dcd8946445efd03560e7e9da922168ec931203738dacbfc15d6aad1125ca056bde8be391a620b0403918362c2d23efab0611b7a71fc82fb070d127bec045da072d7c05b767b37ce2df41e072e926c8fa9b81ea1782b74b6e3ce48c233e41e9aa02b57918ad63adfbc7568eb010a3a913dcd05c4c062aee46bcd833b27476a612fa0f68386f34ac8642aed0dfd1ef529744d637d5aa4e176b899156aa8847114fd63a0c46f88be29860c109dbd7aee11778ea53e58323086ad7ba9a1bed3baf737eed6a0a367e4d9a3be5c6062d88e2139348149fb76b2e80e91457f5dfee989f3c0c017a01fa007ed8b910d71ebeb5c50615c0241e48ed5d4553e08b43bb6cdccebf485f8a0760214f1ea0c2a4b06303ff42deef40df228e03ef56526b3d846cf7a0cce0f5380", + "00a7df79be1db7e933de735cae2a7f090c2a7a9aa53d0f5f644bd09a07d13134": "f8419e33037749bf5af8ba3f2c748cfebcf81578c7c063fbeede49b5661b6a1b22a1a0defec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0de", + "00f493022e2595e2ae4e7f3200f3227c21890da2f6b41d4a7ae3711d33728e38": "f90211a0bfe397072abb61b53b346d53ddbef46adaf6ec501d43c3d396f97739b4b80520a0f92ae4b2d9ef7de568091b7e2e132ec7a062f8ca28cb242d7e55cfcc30f58d36a051dadc1aa4646d72ec841f2c4023909d8e14707ebb7152fa17fd6e2e297107bca0b5a62a82b7639bfcc169b8f9877776edb5424c9ccf99290f1ea7a4daaf27c554a0cebc3fad56671c5769e75c9ddfe1a2b5704b2e90ca22b9b99ae637820a5ebb64a02e219edc68e9b851c1e25837004ba7d0bb626c0070dfd5a36da149d97de5625ba028acbe1752d045030eed44d425ba79c1af43ef8d0476f6d68376981e5e88acfba001b5416200b4750bec0d2bb6b699fe5d2844187a39a7f9609d4f8e0acda82fe3a001a50169f40ff2c5591c1016934015a78bb65b409005caf8194a102940ec16f0a0c0ba342529964c458d74e308a4c5d3b820d9fe070977a0b6e522fc6fe9f62202a06165f5b68d169b0e0735d19bca33c657410a16aa1659a177868094ebcc097a87a078ce528bcb17b0b62486027de39829ed320651c9c039a15b4d19f015c3cea6bfa08fbbb331f552a4947045918b81db1602022564eb1bdfd142f584f42a69d4f36fa02951268a9660414df24770534c3684e7a30aeafd3ce267d112859abc25e5a20ba026bb1e4c5601ac6aa3215f6c2b4380048f9cc86e134f755006490d7e726db2c0a0b061012d20af5d234bd35f2fc151d1d317bd16de22285f86e62f111e0b8a688380", + "015d270f3764bf8ae4eee0a546ac8ffd49b0c9ee885245df980a0c4e182563aa": "f90211a0e141fcb98f85e87bb8b8ce35c883974acdbefc3873d44576bdc99d580e76ec92a077ee2dc4146a32b01e8460db3274e890ff27ff6718bee07c2e81f5ab56064f1aa0c69723b8eee941c18761a9b0c92e3909b57af75d9e70263a8f9a411f39528502a048ca89beb7163525e531cf8acb18cef55918a08c5f8e13edc845f19daf9891c4a08583c4c6edb284e6af62277e6b891664999951135074e0a5981c9ddd5155b9e7a0f4dc42e7ded8ede43acd6e6be2bc324619b9cf93fc4432607ac2bd1855e70e75a079ac01e942f819ab0106fa9bb0486362da2f7581a15fa36961310b8b2afb517ba09bf65427d3a6ec93b8ddb161404fa06cebd03fa51d737b424c24d76d49157ccfa00779dda32eaa328229b98306a77ec4a298f1c5d47c20fcfffff947441ace05b4a065ff0b248aade96072df8d754591771ea679a585d7445c0a75d9d2221c0c6c6ba0791febdcee78f9a456b93d6837a3af10b52e2df5eab377b3ef9a4420c46028d6a0aad09f05adbd6b308b30ec2c69ec9c88b41832ef9ddf187c18047b4efc742d7ba001e6ea3a8b0f065897e39f412c0ea373e09b3ad6ff5c45c48abee880930f8773a06b513933b6e3a5974c1af516bad9feab7ff8a10c47dc957e15fd04cc650d96d6a0289169dd3d8ad996e9d9351df718f7c56cd8a510b0765df5ba763a78fdf4c7c3a0fa34e726a851f88ebf246cc2c108e0fcf7a02f53b80aff0ec56fce187fdcb46480", + "023e05f135e193efdddbaee178977c260cefcfce0a49f16d669e09841e6abcaf": "f90111a07458bb22b218094949c3434a71467499ad4738a5b5dec09108807c0bd7a5efb8a053430e03d5bddfa87d798fd75ad0d150f88250c21788a9b5685a74f7bbe525e58080a049607ff8e8a4c2cfdceb12e03f0b13166ae9d6ad163f2f6873c2760a48543baaa0390ca4accb091aead43fb495f8a0dafcda165c4ca908b86e60750920ea9a8d6f80808080a00f2e9306cb003bf4f5e06e1715074bc6cf57984ef0ad4336f05457b63f5980a880a0267f17046e467e9f11a6fcd873f68de23edbd1b98e3cde996c8650e0a54faddaa0fb8c0ecbbb25d738bd8fbdd89e5f6c9ddecdb6c8fc72ba6a4bbd9feb3b6f6deda098860b5844e3a8e8c13d05275b4a0bf7be7e4d5b47e14ec7975886318d1923a88080", + "02788dddd0412b9776b73bb77e9ee771f7458bd7499b4b1f0af897f885c7c6a3": "f8d18080a0e943b01b078864d06f02501832b0707d072728d512b1b30291b7c782ac52a3a2a0011593f4317372286957e8f9b47a6f38468660fee1297eba774658deaeae118fa0f0b6554e3c7aa535de48890ed6626ba9dd75b7ed46c636c347df49d2880ef62580808080a0a3004dbd486c091bf1a04e09c3e0a628f904093122682406523eb69f630956b38080a03fbe3364c2a2450528278f488da3918dbd14839a0a43514d60bd665fbc1f8bea8080a0dbcc017e0b20bd7c82c3eb9d6396dfa68a2e0d67051fa3322b4e372ec3ed47ba80", + "029992bf1bd117630e2a7b067d841f7262c1cdc59102cd729e8645a6eb4181b6": "f90211a04e2584c890a0dab0f2e393e7c3a9be3fd36dd384335b7ed0acacece3be514ef5a048a7e29cf8dd0f6850ce297e689416f324acf518726998606464895039a5cf00a0b9774feda0b704119a51a7dc221a1fe8939ad401a0e513f98850e5f6d9f41a5aa0e4cfe49f69c4f5c088890253050d14907990acaf2d6496d32f7c9cbc6dc77dc7a06dff2dfad15ccca45c84bee9baf648879d79af19346b8bf37dfcaf4df54816a2a05b396e0598d4a5161e346ea0aa2fa0f50e2cb2e605282b00cbb921412a7a1a8fa07dda3f130810c3683e87d943cd258bb78e16dddd772f24ff4eea9258421a70f7a0da68687a9b35ed6f2a70b85ad12b3a045deab691b94abcd4da36555f39cb5d44a0beb8a6db01c3937079eda2cf512963ef8b155653133ed848b191f8765b1cf468a06a78de0605c5d4b535fa67d6fd11c26839791169685e97a6d2f84439903fe389a0afae15ed4d407a28eb2c6f28dcc8f849e29510efc2039448762366033bb4e3dca0eef79425f276ff1f89096d34a74891f9b831a3b77b88b89b97c65665a79d6b16a0b31b004ae4c8d3765bd8d2e09a7c83a4f43962b6d8471f00810da2a39960339ca0993701ced777f3d1699ef5268be0a3c9cf1e978ed1676ab4db44145ee14f84eea0fb00cc3fc1c54270f597f182ab1f00eadf0b5291c13ee8fbe51fc05eb3a07371a03bf3c302f951e9a100533d177aa32bd7dc07a5fc372f89f6784ee905930a9c9a80", + "02d9c976fbd2de150dd04f9f3be6968267ed8624e184a019fd61933489ae78ad": "f8419e31a80794a2e8646cf28280f9ba1296b884b97617a98db6a1a513f5fae630a1a00b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabe", + "056d8c961e5ee897ce79ed1585ebb1281c28b85f7f3b8a1bbcefa809789975a1": "f8f1808080a0a25a438b53db419b06ba86680101db133d5aa4be62a90a886c82f2ea8b8d92e6a08430b2a01eb4d75888a1e13e44c0617aea812ccced5a56ef629be8cf043b55a78080a045e7a1be1d3e871c0d76a1d15a9e1788a1e4c1d3343db8be009d032572e045cfa0a5514fce0b516ebe2169e0086954de106ae4d5e507d97ed0a89fbdca931b39b0a07bd9854e1bda3e9c6fa9ba1a4696757374e91da688250451f0b56b0fde68d038a0fcef8054763af3dff0c963f8df3d06bdfe5730257341121ee24dbfe7b3f966b28080a0a6d1b83ae92d9dc3fd1e89f255384124caea4f6ac89b55f175d35233a8ecf877808080", + "06148280c6df9f5d39b7e6c687b4fae70fbe889b8c3069e3dd79b7a2b94ff3db": "f9015180a0008dcbd554834b26d0c99a930382939fbcd288e17039539922c4898a47b97067a02bdc3168e57b967072a0020f24a4c3d60f232e04e62dfd0030618513e041cb6fa0dd0f8c2e7b991d3962bc25fb2823dced92927443b6d7121cd71083681ba9da978080a05379a17158cdf7def23141da688b505ac9078aab428ff6730d55d42b6f146a3d8080a0e953e4415ac1cd258910d8c197020418e790eed7f549ef363fefff45430ba60ba092a3db6240d350dfd3fd265ebee2e0adb1e11b29d2df757f66ff6e1312668824a0d93c4df928e125e4b02982f30a41737d8db103edc0ad7640c72f68fd51be4ab1a0cd0a2392eb551ccf3f5e00a885e3e3e9d15d3f33d485eff45f8934c24b4015b480a07bddc10bef475cb67a3d70874d5a8a855093331565b3a694e019a69e2114bf9ba0ad42351d76c77a9b6ded63e2d58d4954bab9200eb9efff12f16ff2196e89638780", + "06338a8b9ea91eddb38de1faa04e4784653e71678da5f9af483dbd1e295f623c": "f90211a070637c256d39d05beae2f655371717e0795a9f93429820dfcae562a12da5c509a0223e9a0fef9833721eab0e6bd167985074d2e3256f5a925bae949650093387ffa0e70ca022df7793435bf43c3f3b669ebe9974f74199793b417e824c025579916aa05a8eae7185727f0e3e0e55a6d1c92a02be474bf7cc0a21afc0de93f2fc548f49a059ede7c3b818979fd7bc2a01e8881cb7fd41011b1599ad3ce65248856394be6da0fd68a08f603dbd3aa5729997e4e10a83fe7e1cc3a8217c38d5a76e4e48bcce19a0365d5ba3beeaee81adc3ad3c79b18eadc5b838effbff2c9247451de2cee26b8ca05b8026fb6d9565b902fb36cc76a2e42520af3cd4647823dd43b821648adfe5c2a0d5359725bd4e840d95812a7348f72cc2b72d5848d162d3cb6ee27213af750a10a02f56b284637146d58282c18df381c05a24f063bcec312cfd8bb468f88d9df45ea08def8f5618c8805eade0f660715ab3f6cdc13f1574469ca8042b07e85dd9a1f3a01aa20da3b6e470319962a87991e8c619019af40a1980d716da7c46a11db5143fa0735970a3569f64c29296a5dfc914f5dcdaee47e7fdd52808a1b1581a2217ec48a007d77df92225fc0ec04d3b288f99d2cd45e8f32ed9cc1ac0b4f0c846b6774e28a04562853e1af3c22ebf2d2cf4b28fcc89456da9eaf2255c94d935a67257e0eb54a0c299743f285087429f19a60a2e4d07216f5fa065a3b4e2a9700e9960870b928680", + "068fdab22ea07c60658ba3d8cde35435b9eea250409af363915ba94bd41f23e4": "f90211a0b14a26936987ffb2309b25cdfd00215abe31b0a58795d3f1ea8c966ce1bd8ac3a02dae6a2796b027f9bc3237c98143d607f0f50f4e444e5599950e0958c9caeed8a07ab98847a17f5f8eae2cdd55edb0cf6ff2d4f0e6d16a3ce87f122fc85f5ca368a0233ba0c981ad18f49a6393a59ea62586780f042649ffdf038435cbaba5eacbcaa0ebfe68a5adba39698f9ff4f9797c409b44a66c36353b0a2a45197620e162fb34a0a02ef35388c0095ae15b8a1bed633f3bf03153ac99bd232e7d6254f41eaad5e5a0e1df5d8c0b6c6e069fbbb35f7fafa2c13f1423dd53b45da478a535189ac6ea34a04ca5dc5cb48efd291ba7dd10e0887fb2e2a6c76f5ac8e5b97a50c5d8583cf91aa07e6ffbad32c7e2bcabc84674ffb9eb06aa8852ade69502340f4b03b5f25ec261a03399fb6f73fc5e0be348ef5984869c69490244898506134fef35b66919f03d6aa04835ddb3e9a9e91216b09b9a9203618eb42ed80c54d5055af5ea3c8fa0f36e53a07c82972aded74f8cc215244d97e28307f73790488b7a21b5242d54bf1f40b4c8a018fc2e2330a4d429e92bdc45106fd1c82e8df26a270dba2b4449dbe0fc6052bea02c6219de2d21721a69a4e1f7e72442a2071668aa6a99c9c66ac6e8ca2ec34b8ea036374ecb0fc371680877e401f141258372589bb3af2740b6355593fc0d0bb463a0ae2cf9d86e4a3d5e79a765e518c8c3f6cf7f7b2a85dfe62ea6aaf4c4c7a69c3c80", + "0819a182c07122df1df57599dc3d6227a01a2a55e6311575b0081a8f6f14c936": "f90211a0384207a78392e2dff3dd54aba8e09417f36b656e1fc6cff26d38d371a470788ea0c61a5eafc125d17705154a826f8a0290d22bb499292e19a95c1bf6bd501d935ca0f735c55ce00c83a0273434f40fad42a3615ab48ad3f61eb3a2da59f09bc56fc1a0da47a0e34b8dc2cb429f8357f129ef6a26b6056aa51fb106363835e3aa8cb06ba04a477e1d39b740d6fb6c7c034d2f1211cceda0f46fdcd5ff09e00d66165ffb9da0cc77371dc61b9c612891413fd1d1734cf93950a472a02b10e47ed3f7e878bfbaa0fb9711856b7bf8ca08fd24700f9a9072415f85893125aaae813bcba74bddc192a02228b1ef1c31f8fa8e4e292ab9132901ddbdb6c08430e86a760894620106f419a04964e8cba605f670e80854640f6e0ba0ba69e3178721d08ecc5a47f859111878a05bbdbe0e8e741b9fbb74d182591230e0728f34bb9bb580e6aadf3fa30d48c9e9a0c93480bd8a38949cbf42c01ae88522785a105cf92d1d274a597a9a6a034861e8a05a8af56e51d32c19e910022052868ee372d4b8043886bb3e420e93824ea6b2c7a0cdcbfd97a525db5deacf713a74e2443c5ff9c540e38f070c5fa00dcffd7ee320a09583880efbffc3466a9829c43c69699ba813ccc050a0e0192ff0882f81653ac6a06fe2fcf9aed2caac885eeb8e7e407a4270f8fb30347cb01a8766f2610a6478c4a04b6c1e65a46c587ee0e548f01d907796b5fe8c7dbf6c11d0b04e92d3ba5b8c2580", + "084d01bbc325816f824a6a5cbe87962f9192be41c55a294ab54e5d2829428301": "f90211a0aa898ef3a5f2f4e44f7ea16a62bbabdc8195cd5f1d2327885b112512ca98ddefa025570eb1b43f299f201eff21394b7626ba372f518303a913d397bf0513dff07fa04ca67589dc10f9b89212ed6572af5433d9c3d82b7b652db1a808a14ae3c1fa67a04f7d4dcd20c533f5561b7274a6038360b6ffd518672f2b27ffa6e9454db1f78ca0e5cdac661e8411ef431da9abf0ecbe19fef7b490fd3f3adcc846e40fa9aba5e6a0db23e72670fb5c345e9015442e94c4668b68fd778e842598028fe0c7bf583793a067b50107a3022a9185a2b5998634c836e3161529c2c9c3631a9447e15b99b1d3a098ed64d8a838ed4b0a897a27c6ca6b8f8baf5aa3bfb5003b86072f65e85ef071a090f3b9f81e179e099b9154b6dae425d3f18352af55786e767a6cfa946d90c13ea0b79df6744f053966539abe638025db0b9456054e475acc1e28e4748a4fd6a314a01c2f1abab13692188969fe6525194d5326e0d4485bab5cc3b39a6e3f07990baaa09cbedcc8e17f42094ec6a38800cad84cc34062e64ceacb1a04ec5e3d676aa65ea0efd17f1a0824e68c8bbc8b5fb4aeab4f3ccecafdfbe98248c239ad5b19382823a099ffb746b6f7bff6e98c7bc1d1f01d5632cfd5eb2105befdddfab3be09c7a138a0801c5a05dc8488c2f83189d04aa46c58f196abfdc585b6a792ea630177fe4b97a01b36b41cf2a72f734888a55bf4346a3fa0c55ed381297ae18e74c7faddf5919780", + "088c8cf58072d3f3ccecfb162df0845a14e89281d386fb05b68d09bdd0bf7ef4": "f90211a07711a775af98e88a5f09f7e86195157fb58b7e289ca5716ccef68665d3cd79e1a0c4cec992bc6f3405d6e443264bdbcf904074e9d797bb523c69c1eae5d957aeeda0f45ba1a79edc239f7a3e2e9e14b33c699f8b2248e52a21f4ac51fc453dcf5482a0700ef44699e5759d1b4985fc5896ee96fd4ac03f76aab2f9541d0de2c5f21474a0691bb54352af6056f9593f6d906d04fbf5bd9dd52f1c2090713808b3e73ff30ba098cb8d8c9204ecf78dc89a6b9c6a617751b23a85a9ecd6f14f8fc9b996997b8ca046bd7514d99fa7db4524da6c9c0af989d2e884ad21d4699340baa991a4c7be1aa0b0bda08d6d4f44891e7faf42a539a393ef61d8c4cd42fa34c94a42d8fe2a823ea0b5d189a8b3f1a848bc326e16ea29e352847a9b2b9b2ccb053252ed555aaa0275a0da2d58f4b9eb7a2555c49d3829ef09e7089a13286faa94d42c241107ed198600a032bdf996b9f6546eaabb7949dc8900f361964625c36d9a4bdd3799d7661ab270a07c6a8ea7be2ab328b6a327153060430bd07644c5bf0ce72ee9fab2d9538cc7e2a09f8d4e079a518fca1f39788ae37f0be45918500e88e6449225f4d6f1bac70179a00983df6b8a08fa2becf5f6ec6891acb733f3b7367ac2ce33bf3e2c947fa6af4ea0ff2d76b2042a583e16cd976593ffddd8a6324037fe78dac6c896b9c1b6613750a031b879f1e9c21fff189095094a4373782a489deb28a75e426b63fd3b95c4ade180", + "0976838ecb5884eee898f1449ef015447145455023b7ea37d8813f97e9f70147": "f851808080a0f982cf0b997675729bb85639b6e152dd536d41b598620f6a786a810407283bef808080a0b70b4f6ff909f6d27f1e2321774f3a4cdc5996fc7d8c05da9cd898907b922a6d808080808080808080", + "0a0e0e4961268408114c1df2764e4a6b8ad84ac1e1a3afb87f1cb3e722080285": "f90211a072173a92bec14944f6bf87b65385f4d6d1af9345633207d8507fd51e8bfef81aa05b0a6b46eb3716ea6f4674a329ccf39673331aeb7cfe49cd2bb97d29e9b3ded0a04d2ff52efbdca6b59d9655ba87113a93f5cbdb57c3d33beb89dd5e984f756dc6a04e8982f41620a9b02889f7f0c396f4815feb4253a0fbbcdce8d36f0d6d7c2930a0bc54f4d7d6a46b9731a9ca3b2572b516b2cd373cc473b8a38cd836de02eddc68a0379136db1a846416894a8f87d3c1c8b20232bc7ce1ed120c3792275a0bfba31aa0efc9763cdeda240e018b17c8607563515bf273335854a4f6c19092d6c49bfdf3a0aa47e12e9b140c237524fba6cabeecfa1bb65783f611b2cc62a237b1d005c47ea0999473b628994ba7ed98b3ec000745f58eb838ea011f81c4fa62ee29f4a1f677a0bc6365d37e64eb1b4ef7df8a48949047a83fc4d6ede331d9a977b9c445039cd8a09e645f08f542dbc07ef46745d1d35c88f9d12327eb66b3457c5228e67ed9dc20a0285227bb890674880f49e5a288bfdbc7b6dd868d73f1d21dfafcee1119ac9064a05311b8f01659626cf832f995300b736c1bfc24a43c72d2922daa0fda935e48bea0e7ff567033c7679c4fb055641bb42ff39aafd2e9bef81dcf20d32a2808718060a08b0e0db1f0817781baeabffaaf46d3def228d6231c7af536f59e3eefa3e5c42ba086d2e287c53212ce83a062b5cc64174f1ded6d5bb721d80e12eda7c0f7387a9380", + "0b280dbc3c33d7b51f70240ab01371ca210ace47ea77009c1b484f50402826be": "f90211a06662e3cc8a6169d6fb3bfc0f649960ab09305e01f9b53594e095af282aa82370a00c9f7298d426c03bff50c90479d5595bafa45766c365d3f06406138293ddf091a07d152b2a669383b29ad72d143f7d43deee5ec1182dcd012e17cccde89e887cb7a0264eecc9c66651bbe5841d6eb38c8b8613beff5c09bca79153dafda26f4ac214a0c80274665a42e8ce5b6437d13c1a165361f417dca820990560843218d56487eba0de5a408032511bce0a62b9c21e3a9af5fa91716d3a698e91d640a656bd634a55a0688152bedf35d0b3fd49114e4ecc67e3db1bfbca3b7d6b446e78baa60f45ddc5a05d3f3e3a8298b4b82551b763751e60bd03d836d7b48f3314905f4abf4a7b7a08a0e4262ff9f84ebd6f4ebb136fe4bc50f9bfb88bf13321cef717fad3094c04e149a0df81b5b0e37d60598f2f6ec2e388e2744c3018c76c95a372d605d6bcd97a9b78a0f33b3762daedcbcd555b777e429077ffb39ded1905a8efb60322e5586d0c4116a0a4059b7e6b2b8e0364fa30cda7630c0845c7bc051a98d0de02a1774f96b328a1a039404f5b95869f245c32a47a131d9e68aff085f5e53e331b39c1f947f31257f6a0b9fbd2612880d62ed54062709c0bdc9d62e62a1922418ff48d9c9d3626255c7ba01574d33cfdfa7a09d5c8bfbad9fe8bbc9cf38caeabfbbf9820ea6c61cf10264da06bf27e421f815ff81a737dd7241377660bc80b37e9beb2d9f7b91cc1102be5cf80", + "0d3b2b3a3e48bc00281b776d0793faca63d878e86822eda6c6373e782574ca13": "f90211a0f7150eda9f75be8b10400df4341342d0a964a03f74ba2c385329732382ef036ca0e4fdee61c805172c10838be0d7170c3a6c84022b879e04bcadf7180c0150876fa04912ccda03dee09891c6b41c336aa352500763319963d6f4c4cb07980a009663a0d7c756b8747fd79d367e54e1b700b9db891a88a3c4bbdb870cc3c3ab620cc0aca0bf8acb84e3c23b9b8d68310c066eba50c1b4029113d6d9e26bd6a2d575335f3ca08011240b594b7189076cc49b81b890984679301b65e9db25c56ba3605cafc1eba01d7d56c6e1f34dfca0615c5551589bd17afbf472b5e1112fab98ba709fb7eec9a053907a38af836114fdbaf7ab535117e1789288a466456f7b75cb5e785518f554a003acfb8f28db4dcc0317d3f32f8bf5262181a05185a39893d3f3368d6c284f0ba05c4d9f86239411ebc1b662c958d4156162497b583041af5953139a2e4b8ea7f9a0bfcd7e1866e469e1802898c9c8db3a092125636819a9717dedaf7996262ad4a6a063eb99b8270f5a9e892b163a87b297b404b49aa44d8759395679c704b2795432a06fda998c25adfec2e28ed071dab107954ca73b7dd5d9e451161114b5858ed835a07edc6ffc3f76f9f3d8f854beeb93061be76cb3bc49ac6490b5ba8beb51068258a035bea319bb49911060233e908d29dbb16fd1ec11a50d016dae875b2a1958d61ca06db1f40b7faabb4608b7cd522cb4805102d275379f2f56e8b7fd1903130ee8bb80", + "0df072c2899efc8de1ed0d84eb8c75bde585e97bfd12b0a18f0a69e9cc8de387": "f90211a04af102b2fa3689d0481dacb746423b534615291bff4e45497a2ab27244566a7aa0179d5ce46387a0e88f9147c1140169e06ac8185d205b192a132472823ed565a3a0a63b19dffe7e8f2c82633a2c641754364412b99dab77f5ccfd5183a96fcc222ba0304e5ee52cbe7681a3db9ad72576b34d87dd799a56afe503fb757e02c4ff88e8a045c07ee4403109146f7cfe165959fd999ffa8a101e1026ee21f322ed45e25a08a004f9bff28367eddecf2f62f38d967d769b96f2bcd0c2ef82efb068f4e6419716a03420efedcaf086169764c3c68f9bdb25730890a6989fd0e4e7fdfe844acd2b11a0e938a958ed19321ab83ea051a872ef66ba4c981905235d623070d6b9ab56f7f6a0070f1bc7620d27f392c8a0ed5d2500a8219cb69a600ddbc974d95f15f3087de3a02640a2eaf6148db42325eeaee01c55fef997f87226aa2aad3757b8b436f9ea2da076cae627572e7cf419d0d5ae9fd1584e9b5e13bfd4789e150cb24a85bd0b206fa0d7233f721ea2bcbe0639e17350230f5d4f31966422c6a7fe570738d6a757cfd0a0394420a28f0416b1548ceb6ea758c4b7ab8416d90c1169a9416f188cefc7961ca0cdeb4734a4bbc5eaabcd9129b2ad3a90b9f94c130ba9872fe32e5553114a80b7a09cf7b5dc0055ca3d8409355c5af35c56e586607ad7c347710a05b455eef57269a0f655327263ba6c584bd18f4505e1839ded7c2ef3b83f5e3cc80baf8426875e8f80", + "0eaa4ab5738a4277f8eb227fa2c8af8aa97d633645c4bc261a3f71a52c2d720e": "f90211a06c6e183bdc04a389cd39b60ac631fc937aa4b6e83419c44171368b34e2c7caa7a0fd1f40b6c63a059ab8d9701cb79ad91e0f77126c63658fc0b03544dde711782da0c19d91c2a81180de78273b7461427b337647ff9b42e79a388433396f4fa150e1a09f03fee8a9bb2365586c3e6eaf96d5d800f7b5a02e965baa970abddf42ae6ef3a02a9042151594738cf4b61bbfe309a4d0a5913f3044d72daa8eee2085999d69aca039555373cf2b0bd698d1d92744487f415931d5f10152a8649abf764c4535b7c1a00a59d20ceb39b6ae74f17f21928147213c2295ec7bbabc895367e44271dfeea9a07cb32370e8810296471daf1d5a7e303bf47edb7cd5b9cfbf7664fc44e0a789fda05c5da18ca949a0ea72f80d3d1cd1648454d562c0a1058dd1b00a069dff79b255a0aff4b18b5843067936a27e1d93224e806f6c216ad4e72a8522c057d52c95773da05cf9daeeb01e6fcbe397dc63463707e1f7d5c68179d4e18889100e4cc0a4e6a5a0dd0cd2fc41294efeea51516f42a480395564eb6c7eac5b54037652085c6c5462a0986aa8213d7ca238843d2adce2b9a2e797a6bdf6d6c3d7ff427d1093f112caf6a0076bce7476116a47edffac116e2592d7669e5ca460891be8da01cb7e0962294ea0af7bf7deca73677bcd3c202b2b13da521a929ec4f2e635a9e6965fdf31623305a094e44dcd0e8c80687a0b4c015abcb16f09794ae623a859ae788603f51577d1d880", + "0f16d99b8149cdd636b00e3e5623f709399982841ab9210acbdddb06e1ac2524": "f90211a02a2885b1a72d4baa691fc8c883ab69fa74cddae6ebd2028b402cd8705fb2c2c0a014691f2f532d4f5e15ab96cceebd5e90420d80f1a16d46b32844887164ea2717a0eefe719ed10ef1b61cf38448ce1a42628bccb724a58d6e5f9867ddfcbc27b8f8a0f25cdef62a036ed6107b5b46bfa0a68d6d50287fb12d7a0ea3f8d4ef3d4452aca0f44c6be4e507a65023ff8ee38d86304290da4f0c823a1cc4f3f640777f27ed4fa0dc06bd5baacab1a97e964027b0cf1af2b5526dc75a6f285b0c24153df8852c10a03b7c87218cb4c3737638de3cabb9d995b14d99d5bbefd3d6ab41a6a638dac4bda08181fc1809c24f212472328c67043e9c2bc884baa4f1f417b37bf500fff41381a04df1e36111a6971c215da9a2ec47f6fdd971f1dac9103f7f357e84c3fcf9cb1da0b3d7dd85e82a49ff2d157e9b7c8d6b8d4f17b4720b69ec21abde970f4580f634a074385f59e3422260dbe06cca4d91cf979c5197876fae0afada27ef91af49b3d1a07d2a9191c1e94dbe8c26d55852405cefae7e1ad2fa64c79dd5106d507a56c315a0ed9b9980d4440a3f2def6b7628678ee2c10284ec2e771a6e01fdac893cb36108a0c89e8a859b2ff542dda37467103651268be0bc72415d5b861fb8abdebb750bdfa02d8ccb9cd2d05b6084ba4f1a88cc47d63d9d9fc0c3b0d9a80eb3a256523d1317a0733f4b94743dd80ed3a301c11d30928d8306a3960c86d7398ae3a09bfe7ea04c80", + "123b1a213154d80867e4c50eeb7898c0850b0722d487533744ab207df1336518": "f90211a04b6d7083f5a8a64360b197e7364516b37f2b4f6278f235143b961268d1372e6ca0d543807955cd07da46f740c561e8d128731deb1185f68c6739d6e5c3287b70c1a08db75e0e5ef9ea575fc8933b20e9ffbbb28f0e4d88c9f21a797a6ff3fa6820f5a0ebd5332ca24e5ca847eb2cd1cc0d661668632aa02bf11fc096b1debe0c727236a09c385129b140428377cc02d4334d52eab433141470888ac66883e44bd64c946ba0fde1e4ac21d7528f90aabebe45fc13bb7b2c0a17e492e8b734f971b02b814916a05ba067587b1f1c9ecff934dace76646ba8ebfcd0daa29faced0cb95279da10c9a0c085b4153a361d74b35b23116ad768ecf2bc9d4ae18bca680d6b9a72597e7983a035c92460e5ace6fd55a3c71aea5f7ad1770f30eaed01be6917d09213180e16d1a04b8f98f7d3608d29e7bad83389b1ded13df8e0cd496ab2afaec15a51b810d68ba01e7c6aff251a0bb09f278b73e6945e58fd0b3691a2d87233bf388b121451c5f4a0f424524e15bf7904d5b0ab04ece08073bbebb2fed66b58d6003d69b688ea9057a0b66d081c3006b961228ea1bd73f38c82d2b5467f8790ec1da1a2d2533fb58b9da06a9c283d04396af907812ffa7d28b4f06e332a2d23b4fb766c7b78669e0f1bb9a0ec8972f15beec00c03f1a83ba36f03c33e6b8952aaff8a81cbd08112c5f5ab92a0fb617882d02c69c87240a7bfc0b9edef6947702e866391241c057acc846ddf2180", + "135f236339b97faa1a721e7235b386ca95080dfba8b57f0cbb2dd58959819bf7": "f90211a0c9ef4bef7715b41226d59feb20be7b511c33dc60a9ff64ffdf93f0858edddfb1a0156fb97551b1cab868e730b9cc4f4a063e7f95869ac00eef789965a2c7a57e3aa074b7181a85d773c8f24663cda8388ac6df8f5f56cf9229dc97f7920ca39fbc18a0ac87e70fc7ef7fe6389288cebc1e790e25491bfea114e9db2312ee688debcca3a09bebc1d8760826b3bdeaf111cae1f5d3793bee1aea2b837b6433feb872f79d59a0764ce32d1a586bf7505d0815efaa9dc8b56b084e9c4499e3c5ce98a4081c4608a03979b14ae2085de9cbd50f62f4dee7e90a84eec8100fb7d47ce108cd82791451a0c0906a846ae684eec3864a80092f59acaf47e9e080d0fa37b2b0600422a51bd4a0123b1a213154d80867e4c50eeb7898c0850b0722d487533744ab207df1336518a09f0f9fd3c8d6caacaadc2c0947dae4f1f76f905da468265057b8a3dcd5d72918a09a03b15cfd03fd8eba10b1263bcd49e3320b40dc802163f22f26e535af275a83a04b35e582f15c2bd913cf035aac7d15090035b0482c8f251a9356f34ab1c9dccea08dd682f2190a96ad9e62c4459a96e275077a365300e8a94de3a1b9aa7fc1ab1ca09fbf100487cc3810607a8765e733294545ec457d91f203a7cdc2d2b4670abd1fa048376b10e7dd81d7e813cb6f4a8d36978eb47e7353a6f6197b9b7b4de6a0588da03e10b1fdafeb71e1dd31f7d8cab206066d4c40c44bd91f3fe76e2059bba1cfc880", + "146059d13f34ad5457f9b100536215da8245ba48d27b3fe4d0ec566fdae0a847": "f8f1a05b3d2f49cbb9d1c5912b4427fe5c9093494b1f51742491c68908435be7f64a7da019c39c7ba8cfef51fb505785f6e92a24eef7be18c2e46d37c8fde62008b65bdaa08f75e476a1a5b0249b049837ab5b8ed96c3bf290bac67761415e468be3e4f9be808080a09e9fac210b1ca4d0aa4f645ede53a4165d7498bfb82cfc45db6c1d8337b12ddea0a4014d67eec9f6b06b129b3fc9906f28f35e0b02acf26ae2f7213139382b7eb380a063163c92fc9dc42be61b7049a1fe49083a565d40015ea2f02986d9a0f2534c588080a01d6b660e07df224a887b604300a8274261d7a3417bf59221b774641ec0f4ac9280808080", + "147312cacdf36308c90d8b59776a3f1cf059cde76b85cf99382a0d14aa8f7683": "f90211a0154acb03abad55fb49b8af8080d8b7056675d2fa54abdd3c09d4361026c42f57a0395cfabfbbc40d80f5d48031792739cff4500fd7546e19edd62d67ff0febe9e3a0147340e5db1587ef993dff118de976ff2b9cadce9ef735e695b6a8ba9486d808a0e83c0b7171b4c0afe10305eacb581a7a1ef05968350e80ab2262d66eb68696e7a0c3db196c82de790c4b8918365b074c3b15eadad43c074a24de7ebe0c6042407ba0db2c6dadb93f8378b6cf684b2a642f3fe5b92e09194ff44b83efba07c9dde79ca0123e31ffde5f7f7f1968d8c7e405a415944ef3776046391c15f1e62cfbb71c07a0d5626cb68f579840457a7bc4607260af2798fe34a02f1b80871b7e240eb3eea7a06c3d79ba9c7e2d70de5b00a1b7711bb9980c5617e7714bf851402c6eb62ac91aa02b3bf1a5ba307a7fb6444a27f39affab16c5c5dc51a59a9fb18c4ec93bb51f36a001be0b16f74a0a35c2c9f1292ac63a0d5a86e505d4c7effb1f1f5012990bf9eea0fb58299ceeaec8beb5b56dc1f73dcda0f55108d4ef622e61bb451fc4d63c491fa0c73b0b1fb145a03ef39d59410880867f9136e7c539eadb36cfcbdfb03c5ec015a0b6e8f08aa9c831884af5e3076f7a5a782b601bab3f31227c4df83ae56cecd833a09e483c1e0f3f8794322189bec2cfb16a2f2183e11d7ab23177ea964918cfbb0ba0106dc313f14e4e9580162d9aac66ad9389a902a6f782efff0ddbc2fe0e51a93180", + "156fb97551b1cab868e730b9cc4f4a063e7f95869ac00eef789965a2c7a57e3a": "f90211a06078179307f48162e042e41a29e87df84e0be78971d2144755132a7ae182a726a0398d70e2a99fc8116154189b4b3e363b7c1ab89e82ac870f4ef18625a79fbb11a0a5b9ad3b312ff578213c07cf92825266e9ced5adb18671ace9fc2af4bada0efda01f6da886499b7bd2559bfb8051496b63a99338bccf99f071d4ab182785937f59a0654e618c69cadb39bbe41ef8e635dfb196fe8adc24cf7fbbad9629f7e71e4e3da0a49d6870b2be04193b49cbe9c16b7e897e18ba3e19b477932de8fde578c1fb6ba0ffe2f055cb3d69b3f6e91b5021c4d6156f618096258db4ec130fddffa90f3ee6a06e7be549158c8620ddd60ca2d888434a1cf0d295f87e261f5d5457b394c8873fa090adf05c69d9d161148daf8cc7cfba322e6d6b722f9003ac950efed0edcbd3e4a08afc93ffbe19bc48001013377c3f32d00cc6c25238f0c044474e294569d2412da0518876e0f325280ec3ba986c3c7880b115a9c207373a627320f39490c22ae7e7a035de7be5749ad715ce0b80379fcb18b79e77f2e180bb03d788dc5b4625974171a048b75528a6934e1b85bd9a59d61ffbafa2154ffc822fc2570be2bcc490bb762ca00333d99c64200facd1ee29a6a1b33ecc45d9d8677e31a97011b846ece8ee9fc6a018a19d48b26e8ff937563c7c14489058332983283395b9770d4ccc7213ccf3b9a0d05b2c08981f3e32224210a1be3a3de94f82e3018e108c3cd7bf667681555bff80", + "16542f514f2786aadf924c99e251da98e1195b6122774562a273318518a1ae1e": "f90211a01aec9b1bd1c98fe37c2ff03be7b21d70dcc31f3fd824ef4ef6aaba262a652eeca0ce8e246e7279f57beda7545bb3fe71372ea432afd2b33d0beb8268e74d611dffa0cef1d01a9be2c600c5bd236be48d39278d330e6ebcf47c98bc470c3968e63f4ca09599fdc64fdb1aa8dea4adc401341ca88aca2ac00e403f8e44cb911e9b5cca4da05496ddb6be25748be8dd8177fc99708f09e4a651a8a10286c9fc9208a0a5f090a04e472c98af20f0c220cd7bc96686a7bfa0a0ae0bab9e69ac09894901696471e3a0a15a461d184d3f48a58bcbb3172587ae8b6ed30e99bf5da0148ff8f460aa914aa0907cead42b202b1d6df89ce58354888822fb52cdfbc9802d42e81c576bece1fca041d8a628024ce92afc6aa36467ba7430dbb32093d119be810bfcc45839a09733a080e8c5102f36fd74098da575ef09ea6567462bfa4b1514eae892b54994ec5a92a0efd6326a3edb23474e81c2d10d1d03d56aa3a1155557549ff369e3f88a29c39ca0d54fb658fbf854b8f7b0c123950e540d6803711360cfb010568ec7cb43c3d89aa06a7fdf3279d1c8d6b53918be8464f4e193dd0919645b3a422f40b19403ed6aaba0de3dff98369f0c2c0a542863e33529548ff126c83017ca0bee197255257d18b7a0d7f3e60960e5f1fc37bdca70d8e3b929286c244a04de124a2c710bb5b2cda2bfa09f41de32fbd02415d60e4e1c2bcc8524ec3a89e26649007d5815409a1c33d29e80", + "187e9557c004906a7c06b0602ae8340d3ad98047e9a7c975d3bc84e420de9772": "f9013180a0378411201fd63f6180636ea48a2a45173fc2627fd052c6f765e09f70bd1a1bb280a0e661bae10ccbb4948baa1d304bd6bcd230fb0222cbfde542f85889c92cac7e7ca072cfd91698c5e95a281b8eb08801611a11519101f634fb4d61b9e3ae9137495a8080808080a01a04270e9ee2e77708ddc4e6e6c4b281f5110362137701e3546304486fa1a245a0178277ce5fabef84b9ee5b881010f6c57ca00a18a5fb762799c84063f9004a62a0274c7bf43bd5eca6e5a0dc6594c9fe5066fed8acd0ab0e3618ad55666944ab69a07ce1e92056d889762146126ef502e927e78de1c3ccf6343476ac668684688116a06c338317abde7c64583f16052264c9b4984c41ecea19714de2bb31a5772474c1a0a58261faf56f88850161307b7a4ccb756484ba1397f44869afdacddbbeb066d480", + "18a19d48b26e8ff937563c7c14489058332983283395b9770d4ccc7213ccf3b9": "f90211a06971528aa8ee3f884dd1ee574e8345901a6633cfa4054815079995c7f50b32c6a01e40f5bbec62062dbedbaeba874255636c646f687980a2bc9d08fa9ee96a3ea2a0c9304867f75ecd03ab15b818844e3285fc0a1362bc9fcb4e594a82cc3c4fb9b1a09272ee48bbf1a9f2873300fd63df59767e10c7eb3a293b3bda742b0feda40ab5a09ca3957587b2696f37c40c038cd29ed3b0b94614f0aff3305737339a1449360fa046d56fcdd2f0e778cb4c52e526fd0ce9d5fd65392346075e190ac62e637454c6a073e61baa8c9cfcff1187d8e8a41259449572d13f912df61f1dc2e690f68ec2a3a07f870fd46ae70f8fca136068a10eaa74ff756d067acbeb9c5174bf31804d5595a05482434eb96a04163bab2de812fa78935de3a67af29ffcf99dca3f05fcfb8058a0f47a1b510cd5312854913e742e8a01748561145bd4789e43ab2cbccb08edcaf1a074d00b1b9280dbc094e43082412cc3b3416fd2c3aa4954b0f5a23a9163930b0ba04052dd9100525820575fb7451b4b60d4fea985710e41c2b10b24c872fe8fb0c4a045db18d7acc6ff1148f5756732b10c2c8103fd57ea1f4ba3409eba113dfcf8b0a040deaef35bf7c019c611e4597b0fc737fb1b3d42594dff401556c8da4d14eff5a06377090dfd8841506b41218b867f548bfc4433c7b89f469562cbb5bfd487ab2fa0b33cb2f59382372a377710410a85c9da40bacd8d81afbb61dc1dbbc36c08fb5980", + "18fc2e2330a4d429e92bdc45106fd1c82e8df26a270dba2b4449dbe0fc6052be": "f90211a064a1d0c9c1327bb003c85459f4e6023335e44f3aa0501c817e71e6d7e7834c86a054cb9ae21ce893141807b1be540f9095590cb98572bceee4c8ec538bed21408ca04b7adcc792ee953c8acb92ea330fceb56d76d4448d0eae231416643a469144b3a0d9591543a76e60fb5afed0ef96b9f56063369471da62884494f6a47a88bf21caa07cec599952f12641e7537e2e25c874393701b133d7980be66f4da253705d2770a024e26ffb49a0c92a267bcebc29f341ac44fa1bc6601c062e70676427eb29a92da09b4cf04c357ebb339d241bee505c3b9130a6bd712a4b12aecd793fc94b4aabbca01dce8921c11032f283aea9990eb3e8ccc300c7f9a46b2a5c1ed0646ed548676ea03c72bde16c213546b1e222a538ffd17699ee2a327c2f7d02a5f6d1706a30e5c6a04cc070435a45691160eefc396802c040c8fccb0a39bae2a5a52c2e810bcb5c2ea069bab46548c16440ac803f5970e7f370f67eeceac5eb8d2f91f6c5272a0956d4a0895731b50872138f274c4ebdb38751ba0dc336e5b70a91724ce5f1ee39cae87ba06c529fcd302f358c4c72efabcf13ab6d6ab83f32f255882ce0e0953730cd7ebfa0705e6d2d9bec284c214c6349f4446b97a218347952c874d936fd9ca93df61137a09e193fadfe6a1cd22b27733098d7ad42507c1ddc6d7d59f41cb396edf4a084eaa0ac49865d5e9a871e6f8c4c3cf2636a1acb607f6c90fb7475ac4a9f2327f267bf80", + "1c9a9f46c4d688a8e102e19b57cd78910cd6fcbe7a7e9e5d310abe9bc3a7ffd2": "f90151a00711c908a764787083f5198dfff6c4a27d42307284e9f5c2964959a941878e5b8080a01ba0202579bf5f455fab03ee56aa132f7f1c758936325655f9ed70355fb9432aa0c6bff9d47c07bc008d9d8490a60a243945f0c4e38b1e5addcab9a0c511cd4dd2a0045fc6732666a230fdbe028df8d9b116e7c075e1e8c0e6d0bad47ac04e450cfda03a6d5369879a24b2c33f5aec9a66a578ac6c5b1cb0e3aef0c5a5d40eb010cb2d8080a0c46978c3b59f391fce8242d175ffffc0d8aaa2e414248804e613145302b2046c80a02d9595c3f2a61212b66f606c797f74dd6456503acb13fb4e683a79ab455841f0a001bf09c045435b3f633fd70797f05b4915165cd45b3399398e0e36dc21e3b189a0a0a47224a98b75e280781ae2edf12872149982c1ffdbcd4c0c0ec3d2a403db87a0aa52eb79be291249a909398223c2c7b1f2e88a4b7d86749a3489bd5ffaa30bfb8080", + "1d0396e06998d362ea361523d6926d0c5b1aa893b414a84d8ea6720152c1dc52": "f90171a038a4cbd66fa514f5746e368ab70c7842e56f10f5532909680c7e8442698dde6a80a07e69ab8a81f999a1aa4bd3a6d8cf2659476a25b3800eafc76b8e3ba61cd0adbfa0a980635d4e18318cfebefa5984c2718561c08ceca747d270731943b4e285666f80a0939653ad22cfa2baa9eb55e72f806868641da8d4cb3305533034a2476618bcd080a0ad53b0ff8311926d27e360fd5d75a5c641c9b7a99edadf1d7cd28a4fcf18a7f680a0bb3c5fb0646efbe389a2b8bbac6b96250819527082148c07b78e79bb7d1da32680a0fd0e970e9474c2cf723100bbb69b74ab707e3d8980c252ffb4ebce983f9b8374a0641bdb70db6c642abcecaec579c280e85cda5d6387f8bb12323545f6a3176a95a00ce141d08ccedca5e63dc9e1fb1ffdca2999923b599df4cf3c29dd8d6affbfaea05757f8e8ba0b783dfafffc5fcb593bac65c190b4a4ae47c68cfca36e45360e66a01e2c6562d7b1d8a43017de7052546975b9e993553e786e127140a25a6acbd54b80", + "1d6ae070e7ff94fd948b839a3fd67da45f162cb8208828a5d2310cf3f422175e": "f90151a075566dc17908443f88337ab8f327c95d210dd4c20b81a13c6e7564d802dedcfd8080a0850e5abfa00ed652aee2b3fe809652b05581fffd2220712de0e0d39e4e26cf92a07484581cb032520d60d612b5b42e2a1d54b53939a659aeec72e1501230a2106180a0859e866fb2db068df76d18c230645b895fc99ed8e6f0758479a45ee6a833eaa2a0e4cb8e13158f76ab97292976542df7cf15cf1535f8b3b9f2b6873c033b386c17a04fc5e76e1b6752d9d94c3a4925c4551ca64eec046da006180fcd027fbff19f6ba04cfad536a133c6f8024bb417ed92e19026b29243edf19cd6fbcf9d3afe58829da0aaf9780bdc0734fb8c578b8c3de4387590271fa903aa4b8deb5c87eaa2f1e491808080a0e026f27e9587168867962d743789bddce72efbb0ca4526ebff4125a5bab546d8a0e9ea7213d92f621c7e02c129676b9b3c4919ac21d8d96eac09b78f5246f4964e80", + "1da84049aa01531cb34e6752ea2793ac51824aec9831b0005a7f3f84796ba06f": "f90211a090c9ea7c47e710e6d10e2d344ddec799dc72f449325923d622fe48f49a623f11a0d5ed5b662b3c4ae850fdeac45d5cdd0e0a5c9aa2d225371330af034905c5ba01a060f4de379a6e43f9b56b42548d4898157d930d0ff7628e9cd205eed65553a232a088c4d863a6e64413090490b1eeda9afeb928e0e648e3f04298bfa08d740802b1a0e35e7c0d9fcfc30399e408713324b54b7a69bee0c7a239cfb74cb619d45a5bf3a0c0e22243a4c2dba3c3684f2815496ba18d2da39fe90d20197d29a0af7499e2eda00a3b34fde61bedb39ffbef25b63698bfed6f51b7530fa0f73dfacd22681baf67a0088c8cf58072d3f3ccecfb162df0845a14e89281d386fb05b68d09bdd0bf7ef4a0cc448077aeef7a6dccb244b1ea2f45bbcad8d9ce53dc60578325305198bb0f2da07f9cfa185f20a43dc98fd84ba389e73f6dfbb7093a0158b2564543d58d83266ba08d51d1a345c99e4aaa8d856ea802c6396b2527f42a2d75beab066e94b4ed5bc8a04179995564df67ae66a439f3c3162786d392897f945d92ac568a1284622e40d6a0cf8b5c2ddca4970914e91453811c679830cd5aa871d722c74ee285a84d9faab2a07af05217a1fa7357914cee12ef125fe72f92e2b061a1311c2c6c047f1b0cb7e3a0f0d410a57cc9181cc033ba8b01f54922d002a2cf19ac78b8afd9439f432f935fa0b1f98846d6f1835fb5e4907da07cb1052217bcee6c03096fee542caeb7cd3db080", + "1dc5adb8c3afd19c5c0491b441f538739af9e9a0bdf1c050109de3cfc70353f1": "f90211a08857c12eb96d832b92f51d7cf41cece5873e4c10b17af9f4fea0118ceaca8503a0801be3c048912cb78c9f1b8709c7a2a3116c4f6c61d318e2cb4aa8616498e77fa068bf93018254edaf5b86f0bed0ec1673282b5a8c89bf39ea4cbbf43ea636cd73a065ea0251360a0c9382c94b6b461dea9e6d34e2aada721d37f98c5f7246a6a9f7a0ee9824dc08adb4e34aa3f575c1fac8fbba3daa7d2740a8f5e9b50727815f5593a0588ea2e8ffda17c1e0d18d80a5db366c43a52f89341ba1fbbe20fd5b5010788ea01fe78101f834f80ee71a4e0481b677ace69a66bf383e0f34992416293ffafbb6a02466a0498b29820f32776b0fc297047c0a64ff0fdf6961f3037836889df4dc96a0c44854e615d6174e7e5197e04d26033d4e433173524df999935318fbe7102f64a0c2fbc05301f576de6f362ff4cbbbf21fa0176e009a2093a3601c32ae53525f33a0113dd52f072f8dff00960ec26bcca7146a4588e396d3cf15b079c947ebddaed6a03ebce803130ac496dccec9b324f74c9942c394ded403dc12befbf920da3d343ba0dbb82c705bd7293ffbb22269238b50029fbde4c38de44a75af7fe57cabdbcf3fa05995f00d61c70cd83f5f4d389272d8c0288feaff9506f28475a5632d5a03b7c5a0543c5adc6cb70f17cad1d4683bee1799714e67ccf8b534d44f5f1347ad2f3601a06e7fd310f5d11ff727acf4c27f69f995cb5ea66fdf8364df4ee4d45af3bd2b9480", + "1ea1be3a80091c7126e1913feec45ae1d13e01826d0bf9a6629851caa6783675": "f90211a08183567c6a0372d7938dc2510cb18dc4bfc57d66a1b6e64e3d59cd28c02e27c6a091c56e137f92b3e1cf99644cc03261c785c74990e1508557db5c98b7f499c70ba0c7fb6211990633f9e814208ddc7db15be38cffb9faa6ab10d45b3a40bacb35d0a03028002d4d56b538ffc748f1c2f15ce509974e8c0d1a54c94e88984b7d915f84a0cff963d252b49c7d72dcccbe7661bb15cd411b913f2ac47414c2bde6f0e2246ca00c8536eb53c7a987505f80b42f52252816e3f0864163d850e1097899ace97e0ca0f2c6eb28933174a95ba2f599409a24c6c2c27bd2fc00c4b57fae0aa7c2fcac4ba001fa86b27b61a80912331babc69f005428331e01d4678cee5337251c5c87d6b5a0da263dc977ae8a598ac4ebf1dcebce846333ced620d8964c35c7da306a74992da0cdc75fa9865fc40ebc29e2fe74c83f117b82b0d101934766dc142f17bbc6eb04a036e4b7caee623af058c7e528edf5c0119d436276ae3b4726084612bfcf17b442a0138914a786c7701e7683025092e559ed175769ceaf7d4e1a083efcc28602ee45a0f48dda2860ff2431edd1c839da7194caad08494e9c06fa1a1c80e7f633a3bb8ca01f6e2954bce48d59cc2849a3de63f9f2171aa94440d37a739804f66cf3484a3fa0b9770a6c407e470b1e6543f94410d649c8628aa3954350a8929fd57b76de4841a076403550fca7257f89007b4c22744d6b75e303ffe191696ef891d03510358f0980", + "1f20b9f30078dd0ac3c67b8269a6870a8db581d361125d86e3799ea7324dbac8": "f90211a098c50eaca21d6a8d3e923580bcb037c11e6c2b04bd5b83f37e4acc79b4e6af41a0229db3e7d78f404dea7e85c0a0937fd3ba876c8f3e13391725f6956ddd2de284a015285ff4679e4b5f42b01fdf4c2c0a7674674a4c97ee1783d4a54693fd9d31baa06c65b9df26d32f6fe5d883dc4788865554f6d7d84c33083186c25132ef0b83a3a04ad4b3b8efe21ae8258d839cbda1bd1e7250ca993fc2d49d271c2c8b4b7244cda0501f0cfab59d47f3c5b47b9e974db6bab22d96486f5df98873d54c60e93cd174a03e745a25b1f92ce88897f399eaf7ad3205b9460fcf0f9f9423bbeef20bb61d43a0ed458c90f00d63a294d9e3b445de61d9bd030241e5614a8a0b649330fa16d542a0d620ee98d1d3c370024a3660bb4a4f8d39ea98924ee0b0b4df1b076ed4f2ec80a0cd45e89ed1fbe13685cc55ef908ef787baf7b801b5634c42034e831457b8ea4da04d0a9043bca5a93cfd73ada3874e33fd821da3f1be052ec0a3e72f67db3edda5a072ff327f63741b881ff872de02d20ae4379efeff97d855a3a07e0fc822eb13eca07a1a2f5e230836402d99a484f708354ccd186e4e4b875ea36f2370cc556d40a9a043db4b1c4c5cbc015ca23cd50e0e1e9007d2a0a6d258fb6f6cdeec62a70b7cc5a0f30747068dd251739f20acf607419b843e5814608211e314c8c4d7bd13beebb5a0c60ba4673caa7b3017828364decb09e94fa533caa1989d0737dca3f980fbead880", + "1fa007ed8b910d71ebeb5c50615c0241e48ed5d4553e08b43bb6cdccebf485f8": "f8918080808080a0fd0c4c6c40e8ff7309433986aac58cdf2e0f68549e51fa966bb177b1b7203b3880a0653473b7bfba908adade3297d600310287f8d69e708af2d2267fa4e568d884e1808080a0a10f3738b44e01b21c8ca23c8420607060f2ad025ddeb7d38a6d95b61d99e956a059cd29e1439e6a15cb55ac34b423aed9ffe13c4a1d88303331650845742ce9ae80808080", + "213cda86f44dfdc6e0fcc7d1c587b740cca5ebe7f0fa1525f27b94a84418e27c": "f90211a0cc995795a246e706f1f256b174337c4ba11df6d475be2e1712f7dc659b079915a01801d58ce26d479332882f6e3d54a779046c61fa05af5702a88fba4cbe82e49da06baa9a28079f464342c536e25531833119033621137f18dba7cb07575c386bfea01a9f1527bf6da849ddfe27759f51629a4de94c575ef3a5edf3f1a221ad76a320a0cf1ab848ddd3061d418b76f9f5022b162f6874d220c88fe294bb692cb886a7bba0d528911adcdffa713b2a259abe017ada11e7786ecd75dd73154f2dbc9aeaeb26a09f653f43a8eb2db0236706898545a7f9ed4ab26fb32748d1ad433a4b637dd5a9a073bf2855aa97b0ad491a87ded8296ad48c7c34c60c385671a357e799ff3b99d9a0b37c0400876a655da2847964176785a48b03153e153bb79b757065c04aafe314a054c9f09eeadde8e65d336f1370126bd8bb0a649a12f87d369a38508beae43433a03d7f472b72c3a8e24650c22a86c28c10eaff37fd5ea5564f758000f681f77a20a059d47af9c489bb7e4e66e703986f385ffaf8d4a49b5ed81562d84bbfff7e88f2a04198ab2624286c72a822ff78a89f94d99e2e2f15c807b4e0c223204b16f38b78a0732f466af8d8ecb06c4ff9f2cc18d421067077875075b24b9d1bc72410cf8a51a00039c46201b305f181038a94d9deef6748c7eda16feb7fee6f2c51b5359d6ab8a07a70f4f5dbb9dec15e21977a86f50f483caf55bd378bce54e1df81a4e7c5ccc080", + "217ea47fd3f307ffb3a071bb720fe6aeca55c2ccae75876c165febc1a607f2ea": "f90211a0cb6dc37855fe135d9e2f706bf10d5db729e6b4338ec369a421f56db61275a3a7a0c33f20dbd4b806fb6f90d7b2f5de1ac637e36a2c7a7eff7cdfb210659bbe5656a0029992bf1bd117630e2a7b067d841f7262c1cdc59102cd729e8645a6eb4181b6a0d0c8622325af4ba3ccc5feacd32713069dd75142bf19323b9c9ee420ac42b03ca06b5e56d2bd98a82cbb98674007d87ebca5483985b28a36cc815ce343e1b7f56ca0d0137ec4864686c84854f685ea25b46606ebc4803a1a654291434b0e8a896142a037def1ba13a45b61fbdbc65be1914dd7d09ee5ec632857e98793cf68e4c556c3a0ab42b8a0a4ab70cd5edbf515b6f75b1558378e49bcb847de06edf9bf2d675722a0094d1001b16ae609a61889ab3a8f480a32ef52792a1005ceaaf9d52a6daa3496a0fba3f6d01efdfb81785c3afb8d3671ed8a2136e2a3f11678b481dc3dd280315ea07f5ebcecbac751b51d6f159a5594407e8b6132efb629f1b57c2cba239767d876a069d03a7ece4217e3cf1d65c6f7e311a613b4ba5acbf838656626e3b281ce639ea03f863826a20454aa5251c77c8c19803169ffc7ecf3631633ea365ee7ba94affba0b09b1fd44124730bdfa561ea1e593e141080ae8e05c30f44e3702936695322bda03f91e9200c55c06e68eb32e49cdb42813d58de886677a047ada39eb0c587796fa0de41b847101abd13384b2e0919950de153d6a94e28595b7e9f204a5014ed337080", + "21b94d6071040b17e281fd3063a7bdd1d96a213e0c61730d95ff55a7e05e8c58": "f90211a0e93f8e6220faa30e5579c6df966acbd4725fbed33bda95261a1d51c19882931ca06fef50b47968be99e2fb705290b0a5345eb006eddf37ba480106982dd96eb194a056321ff8c992990f363a2016e952e6a8b6206a4db8926dd0990e8175194093b5a0a122434bd144fe018e5eb00368ed86bafcd75408592961aaded2ccb80f3bea33a04fd7388c05c5049d41a010b8b193a991799777939526cf3a746c9f8b6e5ab1a2a009dd8fbf10ed2d9af2b75ffa816896a2d14ee90b622d54cf3598696314932c37a05fd77b0d01c57ea42ae7e7da29bf1a72fd0f396342f35f408f8b5db15ac28d98a0c07b640f45202ab33e0d2add56c1e05b708475acf75cef1ee3a3d5a545ddff16a0b4d114a968ac45ddd1ec3711ef18a4c6df039f2eda281265dadb2b504c0d98fda09057972fc016d291329ef38d0c5a1ee549c500a57c38f48dc52030b6fbfb2669a0ff89cd8e1c0f040fad5c0fa7bca821642c100c0fd0fa33f3462b6d7d329b0d24a08f49c749f6588a2a57f527d27d5eb6c0719276d2f857339d2f59d730bddd5bf8a0c0e0ea4b4924e8c21d6e5c0b2bb87225cf96fe8f8fe7d52bc2053993ce6d9297a0fdcaf033d7cac8b1f20b110816d6019b539dc83c0b3ccbff412c4a3476e1157aa0872c0395b96cda5cea44005467ff2e43a6fb00b67c3f4cc392ebef6c3b561133a0ef02e5d7fe1ddeca5038256d8d7dc3b2fd7855d2034d488abf0a6a2050882e6580", + "2228b1ef1c31f8fa8e4e292ab9132901ddbdb6c08430e86a760894620106f419": "f90211a0fb3482ac9338bf268bfbbbf8479cc55032f4d13b88ed8c48d1638f64af6f4d7ba044c863267b84399765b6615792a1f164d762f86d5cebce4ec8432ea660fc3c64a03fc007c4b6e035741ef32029ee2125e1ff5e5831e11d3779341292703478c9a3a0c879b27280ca0e72223a2a629693466fdd34b1006b96422d7908593c140f0da7a0bb175ed3e16847464092f1c8429a4fdcabb350e325de0db476d0b3db846c1e77a08a6c3007a3c638b56c8b6c06c26090e493da5001b145c94dded42268ec31f61ca0782c8dc7dec84878133498e7701a2363b86db9283b9a485a63812b815b8e83b7a0745f719a86874330d43f0c4857b58ea3c5121006ff4b2799555079d87fc672aaa0e7d1395aeb8e549381f46e12e4c8ec5538228e93d36641416fcbe0942bd98d60a0de82e9fcd39aa3110a25aed2ebd502d7057380019ea0ae15c050a12a961b5c09a0daacee95953c74bc1b73f08117287826c2b97041e680168cdaad18b21a903713a086b5f2d38fabacbb12e1da44d6600d96ff949095ad6ea742cdf8b5674a5eff53a028e5b4ce42b0c9d1126087742d6e1fa33b17efcbd2752c8dc8b2b78d45d0709aa0f9ed284e2a6922941ce77c4124b7b523ffaaa3c22647fc2b55d423870f527918a058c80eed9c5c134f6570ec4f5d96b452d1f84ab8c0566603030a5590d2faada9a0907d0344ed23d7c7c406820615cf6020b0c3b2e9ecc3836c2c8c8f31fac0900180", + "233299e13d87f02f2909deba397de4f97527c217d526d15e5ba17f3eb6781d4b": "f90211a08053853646153738bb495570227a839c769bd43e870f46880102d408e7d1886aa0883bbf53c0babc220e58fc9862c4bd7ebe436475f2a6cc56bcfbd5f722a855d2a0146059d13f34ad5457f9b100536215da8245ba48d27b3fe4d0ec566fdae0a847a039b90bf1fe55c3b3b1705d2cd2a18894288e07e883dabce1248cf4cf6fd68eb8a02e6a1bd7003d4dfccb53497cc8032498ea0a67d796f1b417c2a9acbdac8099afa063ee4d35efd018c9ca4b54b7b6b12fc57a757fa75b642efa66a3f7892faad0cba07c904a2d9e7b3ed0aefc0c4eddf2dd9d6b6e72541e9ecef702764ace265b9692a0ea47c0f1bbd50259cbf9ba41ce582b12ab6e54ca8a930d5499bb7269a6c59763a00f7ca9deb3b5f427e279980920a4743e40162a62442678309064eb7cab63ec6ca09d3b3f92c09578c30a5c0927e901497715a8172d38734c40150b4a2fffb61433a03c5203a6827d0b94cb1ba6141879c6f08d5acbaa65c7258ed26208af73e09606a0e30680f9158751a33f0fba1f6da47626587b94c83d9be3366b0706616004a8dca0babe072b70b7492ef5274a114b4291f5ebfabbb387306f525668d2a0408d725aa0135f8f113bf7615d234aa365e1a4e4bef71894037969b28bd43c12a18a27c686a01522f37072e9350294a756f6b4f7689dc5afe20fe019582923635edf3c285340a032bf9db1400a84f0d6b4a7392fff4daf4054fde1411e7a63b7275e8e719926db80", + "234b49e2fd87964dc7849cd79c50af5d0778db0b4349ec54f97f4ca60956cdcf": "f8518080808080a0cb6e86aafc535d7324bb97080f7b61bfe83f17cfdfad0fae3489b80282df0ba9a065cb648e191f0d2659faa082f80b6a284853a1ddd60914b975149021cbfed60980808080808080808080", + "261105c27f7b982277b88ab1b1ceae7136782ae16c16fb005d833cae16031327": "f90211a05c47a3ee1b80b54280278921d3781a18e1d03a0303e62d41eabbb233f50ac992a0397b3ae09e7b5eff7312040fd75e2970be26b0b9efb676d6f2dd5057e2b8548ea0b2d9c6566cb35f54d81464f1be04e36d3fb00bb2bcf75b880fff26a196e8dce4a086835fee3825ec6d92fe7bed98fee500826eca6462a90d2135dbc0f259a1fe6fa0912588951bb7994002dc8bde834276eb726fc7d9c39e272413849186c19ca2bba0c0b7e78a4de56ccecdda99eb8a5ddb8c9d4fd5921bf6ba06aef279525d8d8ca2a019b064b0f6eca33614512cd8ef583df7f4a910221442092de058f9d97196d36fa08629634fcbcbbbb449f016cbe8bae26bdee9375e1f11780a7392b34ff9f73ec5a091c35a362311f09ec305def4ed64bbf9bc658f35c74bca10e548f0b336964084a0dca26f9e4f55d2c39b6c1c8b7b4d7b25668d3a176b77f350c9edec74e66d41bda0d706322a3d0cc1d9ed30c519aca353ee54e97744c2d8b19df188cc9efd89efa0a0358a63589a07ab1958aaef5b9520b4ae2dbcf649b1a7aa3c4990f8413ecb4d97a05f23c86ed17e642dbfe39ab7828d5d1a8fdc7b077d31cbd8669ae8f07bf6fc8da08b07b85be8db7d5c69195ca2f65e6ffb9a203dac4e864e98e53cdd2d2690aeb0a0a69b13b4100461a1d5edf8c571f18b4c734a0fca87ff69dd74e43fbcc2f52c05a07d259aaddb74f1775c278b2a7c032bf3d5de6773293ae6680ad8da16c906d7ee80", + "27d01748601b67f84204741ab93ff1927c513f58bff22bc4e1e1d22700bce5ab": "f90211a02fe02828db6e648173e317d1ace39deadd38eac809498621acd64492405eee02a0773a0218701040a5612c297b8b86163d50c76d5aee1b31e924192cf236459b79a0d11cb2a28b5aa32ef5ac34b890f9007e38f9225bf138fb34c543435929270995a09073372e7902de47b6ebd2a292e8d9953c8f0819c2aebd5010d32d2fd337441ca00e91639b7c89021258eae08b2725674e68d2d365fd950770aff94c3d5c393a0aa0138e0b71b7442f23de2f92f2ebdcb67a837b3bc2789a2f0f0f5b7761342f46dfa088da855d798f614e1baeda090ec2037c2be5b5a5c1d8207c6ea6bebc3d4c69c7a0f78d739e65674ddbb52b181e4fc62dd9f1adc3bea3938db501589b3982ccf6f1a0697b45a5bd90e88d261738d596f6356129d8cc2a67244e360b25f55b7caa9a8da087aee177ce76f33974d5028589ec418f628287b45b8747a0dbf0552fd72bea57a0b3668f78fcf3c1630ef6f2d1629e794deb00c60c7c8352273c18e74cae268c7aa06f7b7c4e2e98fc2ea4a500c9bfd4b07e82cac262568162c007c18e3efffc6cf6a0125627d02c395759fb0b36ff8af1cbf78ff4034466a15c699b39df9ed271cef1a0703f48055c07bc02e5b8c45ff90f592e8192e766909eb3538acb1c22655e2b4ca07cf3ebb76221d4d96a08bc63b0cb2bbdae4b455c7ab18d7ebd3ddd9988259baca027eefac794971eed60ccfc2ab083ea5ecc976159992dcb7f41e34eca00642fcc80", + "2951268a9660414df24770534c3684e7a30aeafd3ce267d112859abc25e5a20b": "f90211a0ba32d656c4618673b416a6f3cbe398bad96c0d77a76b7a78a10566de2f641f10a05ce57288cc0cc9a492cb3b6d63c52e63b8218eebc401c8b45115e59a37ef4c54a000caf97a1be60651bd062f769a3bc8557af3b2fac6dbf266df1129cdea806970a036f35d605dcda682737dac011f7780f5ef39e1a1a8dda974ba5dcd02a97b72f8a0250cb77cf77af5e0f362315e5941dc3fa297f2668b7a81bbe5a9d58ca82a75c1a031044f56e6ce77effb1990472bda709e50f1bc75e3dfb58474e891209498d7f0a097ee492d79fe162c6a21e23d61042e38989363f993cecb5704546a0710544a5ca0a8c13ff6ac16db5d06e9f4b2d660f58352de92fc2eb2af81bec36e1b259a865da04f4aaf593d2f20a795b91ed3f2ce4ebf66959b1837cbce7eba6d7c2fcda2e080a06ad2643781882649e073347c18f740bee90a1eee33255d40360a1107acbbf386a02512dc913fffbbfc88e003e91d3bc22bc0f12de5173ef003675e4aa1166d90e1a081977396ffa2c485325608396b999c28059a6cb6597f04d6ebbe183683d1b705a035ecf21922d6d764f509dfc64e23d96d3051ff3ebbfbb4cee23b21725757476ca0b9b40d4e9a66c638baaa738faab4fdaa648111b02e336bb4201c5a3e2f8b4004a055da0cce604f960385aecb50ee7dcb8a379a1c8f0b8afdf507188e91523fe94aa01b4f47cc6078373dca5cf27992c32ad0107dac718dc125b7398a7f32f903256f80", + "2a62f90dbc8a93a11d923328df94528856ee8546cc3da3e1b9ac004cd92c2e4a": "f9019180a0d2612ac9819702ce18497c2962ed0593920fc1a273518e6631d2372d6d3860a2a04f549a013e44e1dc74e5adf74edea023750c0a3fd986b0d3ca9bf7090856c4efa0543d176dd3a6270f0cf55b58e5a286085b678a1e1dec441e31f00fee7142139fa08c9cd1cae3a5d6ff5dd1e09c81038aa3a9094977ebff39dcf1ea21e53c607720a0a1562bbcdebe339f609d2d80741b04701b0750d37ad4927526146c6caef985e3a06aa269f1cd128d1b626589e57cabdf97b961aac2aa245e914ea937fa571d024a8080a0d6e376cf453942691a4fb1fdd8c2fd3da1c350ad96c6a50588bb941cb278487ea0ea2e3258ef3435ea0834fcfdca5b64806b062643d36ce6721d17256cb7aa7b9ca075fd9726e59b59c7216ace5f3a95dc767590851a7384721a1df8d679683eedcba01b1607eeacc9e9e2cf0edb9d965833d6ba10261f86ef11d195d64fe0b4f76e10a0dcb0fa0c04287c30b6ae3a64d6bfc1caaffd2b251a219ef07a56eaf885e13eeca0b3132c700606e301d2c8f11cd7d0297eed438b86bbffc07e620d2e73922317648080", + "2bdc3168e57b967072a0020f24a4c3d60f232e04e62dfd0030618513e041cb6f": "f89180a088bf07ebd4298108d401f77a8b8cf15fed9cfbfcbb128eb908d7316d11fdac1180a0190834d0a48f98666fb282bcebcc5ccf4f9ebed6ecba787a807b7bb5293876f98080808080808080a07325fca424ad02cb239fdef999b4c7e7038ea5120ca2651b70513b48e97d9dba8080a0935097dc1f0c5338f335eaa356755bbbe2147be65fe94276fcecf027b94209f880", + "2c6219de2d21721a69a4e1f7e72442a2071668aa6a99c9c66ac6e8ca2ec34b8e": "f90211a0503f739339eb75cc38754d328c6058d4c07defd7be292c2d8a6e74efca3af29da0c14eacfe8952d2c1a31e8210c8089b61c2b9a6905cb1726801782824278e39c1a0971b5a62eaad43e77bca02ea9b1f30de3b5bbedff418cc0c1e15438c7265829ba0b13cdb9c08e7097e11eed7b782d544767b29ea55873ec57a4c6f78814bbddc1ba0d3c91231cc26d0777387793ffbe3b8e0f051aa37c3589fa230ca37a8ffb8a52aa03e065d058e6c7385ce0a585c4ffb1eda68b75a8b11f67613f6edb5b8b94d56e6a0d078592c2bd02256538818527f9c9e5abe68b29c4b90ef42f173dffaa6052048a0081be2cde020b254b98c7c426e24134f35beed839179a2311ee8cdfceab701b0a081c9617d676d614a989b3ba6ce7e12ca5a4e41e9ffec9e9e8cb0bdbca7519e13a00c7e3897e12a0a0b3d5c171a9e563fcdda9976a6053b0b57ae60ad862a8f6509a0cc8c6110ff1b98620f58bab267c3c5b4db7fbb208f867c215646292cd046d8cda0838943e8a90b3ea1c64fffc0e3561d16c5915ed0c9d17a1808ea2a2d292a3b38a0a1627ea13127b4baeb6754c4b42db2b5c86a76ca1442416ef33de9621b16b0bfa0e9df89274442b4ae66662c9f0566ed0076d1ba38bfd36b96a96f54f03f39a20ca007dc025978cb7886e3d071b463184b57fc30568c24f8d4ebd1fd5f9c788293faa0bb698990e9203eaaa73b384d816489e25dc5a4af045eeb2fe6a11fff3741525b80", + "2d512c7518b2a42e45c998930db9e4ca1ad1ff4d054a056653caec7f589bec6e": "f8f1808080808080a0213b2351ec61b79833f4f284257d4f771da6d057cf4a867129624740a71042d8a0847537a8616a61a259719941ed4ee55bed5ee8a7314e39232f2e2c49c33a5c97a00ca08d2a13504d7dd33bd0aad2ea3baddd2820b5ab584055a237bb0cb1c42c9da08c2c3d1ddf21dbb361b40ad3d5f70b8ad1cb7539af77848aec76caa0c6b937dd80a0a76fe52be499ec406691fe60812412eb39ec23a2dd524dc66a48370b1978f550a03a62e4a95293c0b31b49b9005d4c480e8ba467ad5591c0e27af4c980e1daed5a8080a0a036c67874f5ed4be294a3fa0291a2f78357c915147b9ebf2101428a1ae951fd80", + "2ddf54bc06f3e1618b6961043571ca20879253eab6889c1c76885138ee34b458": "f90211a0300a0d8bcf45aa9e7633b1c946d91108b1e552b2d8f45eb5e7816947e0bb9216a0b453d72598f344cf288be6ab46a5ae169dc9da055ebfc5c03346f92ac067c6b4a061690c6da747e945b247ece6698cb0cac5ee00a525b78c0238b13a27841b4181a040382f49dae46d55db3998c554ea514aaf253e94f09136d492c95484be353d06a0aeeedcfe013b07050f791017808a7f02082a40c0c37501fc369500284cc0778ca02c1b60e904a7dbaff71821bcdba0ad2cdf3d17c910d8c547033fb624c2078edea0a02a040514fe7c97112bad6205cdb617c9fd5580edf08dfa09aef46393c31eeda0ff58a543a459d90a73c6153c1536eb0b880d239f8e2ff4a49a375a8ab3cda4a9a03ead5eee639887bf174268a4706d881d574768c4cae621a14599844180d91a43a00e134d184fe742d19762f263c846d4df40725f8ab04b3595f0433e3507501b3ba08e8e895a397cb8a24f91b1a02a7a10973ff703087e0d5884eda645db5d5d2874a0c24cbe4dd005673f9e5dd6823782294d91d4d568f93eb83670cc086cf552fcb5a024116e5048f7cd7016a762da832a1efc842c7a25c2c912b4a892ebb13f5a5b13a0261105c27f7b982277b88ab1b1ceae7136782ae16c16fb005d833cae16031327a01b11a7ab7b4a638910cdb700776f900324dda6210678dac5440b12d7d9545dada0e539432fd78a7164c7de1d2426f8113e2a3ca2b59925db026ca2a5e2d14a348580", + "2e73916747bd1ea38d34d5e4a7533c5aeb1c0f80b2e070baf23d9ca9996dfb17": "f90211a0f739d159073e2e35eba3db0c5ccfd367b545a8d9de89745a4f341c655041dae6a06407d2c3850b3de7fb5e594facfaef37d554bbfc61d2e0f1cc95d4e74f8afba1a0b868f2cab98504def0e3754ae4cdb39871e63c7f487a4112e75580bcb3a1a978a0e14d8bb5b51656a11d9b10a253494c36e4150873f4a244b85d5dbd8bce06d16fa0acd4dd99d96729011fecbd6161851ae15b8e2ff619449ceb7ccac82bb6fbd0a2a02b3b33c740e177bd9a34d32ab652230d41589bfe62d621a76fa1926747506d42a0ccdc99b093b13044563fdbac2ac048a5f5a614e58a37a243845a22d80006ef86a0d51298b81d60c0b73858e760474c17aec296f549b123975fcbb1278914ac8ee0a0d69ef37cac2623b69f72dc9d8582c2a6c8e511e6691f125d0aa3687146308d8ba0bbc21923a14bd7efb5ec41719dd9abe37339ebe7a0732bce58251b2f777910a5a00eb725b9f6866b8a1a940bdaf733a01e2b5b883bd662e4fa512f86e6e63d61aca04f98d9d7a83447140408d5371e82cb47fca3fb62bd648a85ee018c18a94209efa065c57ee5e64bc6f5e62d5d7d112ad94aaace59ff178b8f57597ce24fddc92724a051758e48291337c415ff7d0e983dcc4fc0ad049a427637282ff90e7eadc0772ea0bf429b0e14584939e8b6c40b3bb0967b899e5435d5bc3239eebf889a92644d95a0215d78df150a0dfffd95469da19e7420a3db0ec1148df73d29547f49acc05b8980", + "2ea8f2898220d76cc68b3378120c7bd1a8081fe6dcc4258a63c2fcc053814539": "f8f1a0ab3001b16f035e257446b2a6c5911ff9edfeae3c54e8e604d0066cb4de86336e80a0f7a2c2c0c5103d01962d4cd00648908d1052f943252db512b6870deb9502bd1da0e901bae6a956117f97b5d4da6e1146a40b1502488bc67f8e4397155ee6c43dff8080808080a004b9c6ef89abf6ec52d93417458ff6f1a99c129022c5df159326804366d8da4c8080a0ecaad37fe1476a617644caea9c6cb59226c7c4b860f5a7a212be99c1f82c3271a0b7b1e932a472a251d118f0e60ac1ab39b32d17cb5d9174b404cdcae96ebee97580a0ba455d68425ec8c34b96bc2267142424da9b2d184e150c117c871b381468d26a80", + "2f076749258f1190b54bdbf383d447c0161c1f5c859d10973e204fdf7827fd48": "f8419e37c02a42821e711d8b306dc8828b969dca8c2110eb133a7a9e2daef2be27a1a0f00dbabe000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b5", + "2f5321575aeeb91f8da931b9b252ae053fc510fb0e18a28292d0c8562cad64ac": "f8d1a0df0ea67c100337d4f6bbbd5d66b834572cd306112ba367a202de85ee79f184f6a05429a0e3dae5c4b60d00f7b4f387a501a55e9d2aecc29a0febb92795a5795da1808080a02bc8ecf21b3d69ed1f980a52029077edcf69ead2f5939930f10baee99575a9328080a06a9714986e00640158a455c0d49305d24575160e1da41a9410feeb6b8fae19ae8080a02e9af3bc2a598a02ab1de318254f6edd72f7a1ee1809bf5cfe23f60b56ed91d280a0609e67089d5ae50069fd15f7fdf11b4fc1b5e9dd6d3068f1dd85e3ff0c8ccc93808080", + "3047f6408e5055f987993312a846bbd736edb6df01e841a8779977e29aa6eb5e": "f8b1a04c7446da0c1786c9731019144cc027b7ca01abe57df2573f8d6637ef853e999d808080a0728f1e5bbb8da379fa17e1827fa6d442d26a68836b003fd367a7a87ebb7b7f41a05f9039fa6cd9fb5dcb5a8b04e865f05f073cac3a7a266c9de0a0b4cd4e80f8668080a0ad6bd5842bbab9ebd916b6cf0c41ac648658622185495a4630020230437c7e678080a03517b6a725051c4db0d4fc84b7134c11e79861c79a0ec2191d09d63a32ee0f078080808080", + "30918625375c49f396b96291f10f4c29b285e2923cfcc6ff963ecb85a7757857": "f90211a0f596d6ecb39f5d5184bfd628fe957b4aa9e8c43b26740c26ac2afe7ec82cb42aa02c91aaa98821541eaba63ab99e169009113b1330689d5abb642abe88bb4cf378a018e24b9f9fb6a925cd6b4ec457d2ec350e66341187e038af63af5ffd8f96d05da02c7076e5b20388ded2be36b4aa64ddff31aa51175ccced011af6ef66eeacd694a0df69994d6479c94f6550520e19c36c5661e64ebbda9d2ca3bd13398800608f29a008b3a3a6b31a6fa98c1e2241bf6d8e53accaceec2958d793d94ff54b0e053486a021b94d6071040b17e281fd3063a7bdd1d96a213e0c61730d95ff55a7e05e8c58a0246c1c22b4fdb4417a3be2193ac13a8b1885567b500508f07c72d3e1b4385f2aa0cea46ffb2ffe24e25b6436074dacaf352f8c9bd5565b70f30ed4809fdd2c61caa08f6a06f7f5ddd58c9cd975451fa026150572a39bee56be03351fe40e45ee834fa080b9da78110c619f4809ec492a50f6e03e8c13d4f3e423f619defc30ccfabc78a0f1538ce31593c83ebbb2a6dfd899b3967a70106dde58ff5633e20f19d21b412aa009470284bfdb3d153bc8e034c7b65ff59e290ab66b063dc043baacc47b3cec85a0c7c2000e2a6aa6343174bbae74555c317c21699cf7f5909903daa1d34b679fb5a0c891f491974096e1a3ce570c97bbe0d5892051c7260c391290c7503b34ed6152a04c1cf77bad3601215f5f743a6c591c893d7ee024a24d8af374628f77c7c6214f80", + "30cba20b2fa16674b4063e9958a82ab444f4f1b342df1b0aad139916a7224959": "f90211a0fb9e088f053945585bbce5fbe3371c8f7b11a3856602529b48c23eefbc42fbffa0c4029accd8f241e82085a959855e1496b2f2a271de6d90717e3449384c0adddda001db903ddfa39ef9ad09a4444370456749b5de95a1eb95cd713e95d192b14d90a0f897acb77d09199525df3c290953070abd2ae2fb009d64b1cfd60470b5943dbba04053440df42f6cce334c0abc6ab849bf419166d70d691ad2384f5b90ed1afba2a0921219934ce54b3d31d7e4a680a4f62205a92813829d522334d6036e1272de6aa0584f9bea748cdab124667621a63ab8275492fc572b5b35e1568e4b8410a3d474a0f68239c46315b5a2d49632d5deffb70f3aa5eda8d183a379a48d8866e52fa07ba003897ca3745f8e211b533d635bc00efa7524926dc97d1b50e5b19ddd128d77a2a05b5ada8f0cf2732d469afaa16acdd43eebf40ce98cceb344dddea1a96d80e8a3a07f94c3c987bdd6f0b04cb667aa51260ce305c094122a89201206c267aded198ba0b8d9a1e83f92f710416b357e1b062593ea1eaf3333dd5be6daecfee7db4ce2ffa0ab6e64d12ac795dbba1ad190463fe3281ebcc4fd80bb9c4b68ba7e560b7cbf19a04cf09ff8214307c576d4ab9e7adaa3e40553b5e992046783d628641c161fbae4a08de762be3d5f028416286413a8455a9bc597d5f0bc67b991376e78ff055dfa7ea0b7e16dffe60d55c19fa2920f0c3e6b256e1e45c0583fefe444e9aa04708ad2ee80", + "319a9dcc15e8a4e0a2a166c2a81f37693b6dade76926211e2c3f96967ac44a52": "f8b1a0555fab40f4f59fd03776c57d5e1989ec3ac38414bbe613157cf85cc8a64e8f1e8080a0b784786f056513f59bb0cde10fe5cf9ea6c167c39b52f84f0dfdf6588a62643480808080a0e9109cc1ba1b7a274f88b8852ea137d3b2370b8f34b9e42e47b8dfdbd3fdb36980a08638aab8b707c00eae5cd8dff350db1ba28ab5c1bfa30a350acd796115f1cd38a00ed45ae7bea7efb495a5c065beee107c3d8799fe65113af4c3621259eebf2bcd8080808080", + "32a8aa4eae262d2b552cadc763c68c8428ccdfcd23faa756b9818678c1bb7d56": "f90211a0f71305d6c27f3126aa03aed08cf4ad76173cd9339945642682df5944686b3f55a075723aa1022feae053164eff03de339c85ef12779f6f88a413a8f7fae72d7692a034bd945ce4c7f55cb71521f0c36c9d6ce38caf4cd9885de75a01021ac953c59da06721087cc363b10611cf6f8c64975bec1115bde643953bcf75b7e0d958ddf58aa0f2dfcf7c3672e8d1622f4ef514e6a6636f5267eb752c002a8ea57adc3ba541b6a0f7b103c5911e937e8cac881a33a093fb3b928ca24b7fcac34d5fc5cb188ad44ea01628f2693f8bd385d2e7f882bb9c437e92b6e987cb4fbf874ba3ceeb88c476d7a0dff35da212733cbed590a3e3bb8eaa45ace4448d6dc426da882cb3b058bcd639a07b8e94917e90e53e6ccb0fd78931e333133e0d32e66426c0c00845420e6f2cc9a085fafd665b06ceebcdb92583510b1b1e39df6154e9049c651c06224ff1442ea9a09e2a49a6cbf5a55954431571075f4e8f083e8f486336aea8dcc083d1b5ee312ca046887c532b3ac41b943e8b801f30daedb483a60cb5e082b7c44080e52face440a0ea60c0a9cf4ec07c61b4ad4534afed1fba9dabc00fed6ab98054135690f6d1c2a0352e3443b7356cb7ee2a498d5346d82c8fd99ba377e9655550564e7938c6504ca06dd2b64671177a602f3cbef7918b6b886fe011a5572a76cb66884eb2d3d433f2a0a439c67a3142a0724297b80a32c7ef07652c241573f15bdc9538211b7b17a91980", + "33386b2b812bd72a1580bfbad0f8ea0bdac53f36bf3b8905765056b8bb314120": "f90211a07d90b7438b96d0c7ee74a598b3cbe8c1f8e3f85dd3f05f18a8429a47c42d4cfca04c9552016acb3f4581fe8dbbc41ed1e2db68199796ee9e9b535e10f040bd12cba05646494d189e356fe5a4d23ae78e6c609315a5ee61f3df14aeab483ee025d919a07b81c1b66a1bc640fbf1f996e3073fbd69429f763ed694d8eb27139a4792c0c5a0439da4eae561f7b1385e48a57a34e6f3e746cbfb7407935317b1397162332bd4a0954b71eae9a9e74570d6db015261970c2f4f23b42f42189b0c307f042f754181a0e35c99751d1018b57bfba6f984c9aa4601f2ec3d6f5aeace09a6e8cf99c09867a0e1ee6a2975ff27a743859b08860d78cfc3650511c2f7e4b5e12599d44d3e02f0a0d25b79681b6b992c086b20fb9d7762971ded3faabcf3a9d2f4f0bd067e4a8894a062a1ced4e940393055e511afafa67368f9157166f1c319d26ca13f8c5a4052f2a0ad1dee3f2979282ee02f570220033e79596bce509b1ce2dd1ed8e743204a62f2a0dabfb2b30a2d0ff115da803d93252db2170e07b02b71c0cf1d8bf3769d7d9080a00bc00a244051b82b67db48604477a94cadcec72a00b639531f7fbc37fd0fb61aa0c49508ad9ca4ff6fd223123ed4e3d6cfe7df4cabdcda9dab38e022547a959cf2a0340188cb3dcb9161c58d538b58eb999dc408c52d1e2130c3ad885cb8e3bb6539a0551039bcbc3bda42a2eeabad1241ab44c37ace63681150d15402bb66864fea5380", + "33df31e890c7f10da97a88b2bc5a56292e0ea8def1f7ac1383842b1a0132bd95": "f90211a0b687d008aa94aad56bddb8133d19a3d96fa7faf729f4b25549fea246cb645298a05c2d7e41422560c2bb79efe524d847d5117f6b4e70ee950df9ae23818c0fd2aaa09d70cc0994f77094e2658c03605f24633a7e5e6f0dbd8a51b95a61a4ddd80320a050f05b7eb7d85dd555f7c051ea679ceddd061ca826bcdc11000ea77b6bfd9076a083873a46a133163525fa752cb8069f1663c27ee96015345acaebb6cc51e8909fa0193397466d079761d45bf2e15198bbba32e1839333ed17d91e29853711fd2a5aa091dca3fcf9236d4efb0122f68af15ba2805c5dc59c4575a64a85024b03178a92a0f33530d450f5de1250ee98690733c01f23c79d693aa38cea35804252d754fe20a0e0c0ac0df12e4d23287571a283dc6b66330eab82e82eba53075c3f822cdc2171a07719ada8b27bbd07c1ad9d582db0dbe9a01efe35e61ff0da4bb0b70cd230f869a02e136bd74d45e2df3f708791ae11e36cb3e015b0795ca41cf7098588a9cb907da019ad0ca1178d7eed371d4861d0c7421fc26fe7a4793f0911a433c3976ce545b3a0ec6633b74b67cc70282bec89727f7f249bcf44822e97cb4737310cf33b49d53ba040687f5d005dbdaeb328d8962131dda7c4711d8b830f2cc3ccab325a2b3d4d5fa0674bfa651b1b6df5b6a6c6c011204c1fa16d412500280bb2bd037287113bb80ca0341968235ae4038e959adc9f6eaf55cd676be8653394d89f16e0678be7546d3680", + "340188cb3dcb9161c58d538b58eb999dc408c52d1e2130c3ad885cb8e3bb6539": "f8d18080a0dc330ffb9c65e8cb532f6b0e777464d3210524e23abf5c586558ef78ad0079c08080a0782e0c173fa8923c0e86018d8e6b040b09d6df4eb69ee56e6a831b4dc3b12a7c8080a05c5180e84990050428fc2be9afd2f9d466a8136818d94592b78a79e5cc9e1926a08a40a0100fc07099604a67598e7a41f57f929ac30687d755bdf60e5e84d73be680808080a010d2621d98e0212b5a8db447815fe1dffaf2db02a4714a93e7301b9448a43b65a011c2907f40e830d84bbb7bf2ba92e009f0f1e4da1ffa600bc579521b1f4d2dde80", + "34fb87e29438a1fffa11b93547e8d04758bf5efb223a2018f23d7e82f89f2a40": "f8419e32280ee3ab6e374a0164cebe54d393bdbd757c3ffce8cdd83d083463db63a1a0defec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0de", + "351f49b334aca2a1a88f1774e8f5f3d4d5aef063b3ec1d8f77e26fffe13884d7": "f90211a0a93e46eaff96478be1366fcec8654ed6881b371c4d6106f6a1790f0289277883a0d28c18e13afe286fe2b20c319c6baeffff9d6c267f19a3a654ba82313ee368c3a0603fe0e9f289621544fd55399f428213d07b8cbc4191a4951f16491552f21016a08be30478f9e59fcffa9c334ee93a9852db5eff2128d5bfffaf64e42e12d17897a0bbfeb2e5d36fb0d2d331978a9ffb35dd920fc619b8b1b1dacef60ce79740d66ea041323e470a55090faba3a8761ee4675c269ac679c3c71cf6c25b02a03a364ce0a0af1d465d8955018ca31782855c712b104b98ffe8d26a47ab287124640d779ab8a03e8f56df3ce63d28b93322f5f2c7f6b603af354cb0ecca36e4c0b8fb944f84b3a0f636ebe99fe3b858dfc727f4be9ad6f600fda1eacf911deac7c50c977b1391bba070396790765fa3c15e2f15083b650afab483714a76180b5d5d0898e1c7f1b5aaa0022d25eae28ccdc302279c5efe7e55340b2acf2a181051b9b0917cdf16cff2aca0dbc030165c1e3d612019ac3f7d0d8e03eae4abb1661ebee9da445b7543520110a02ffc080051abdecedb340150b070f29dbb4125b4947332e4d60a368ff10f02b4a0e5d6cb2cb0ae24044c3be4d196dede5d781cc11041785416ecfcfb7d553410d2a09e1980f0286ac18b84916646deef179ad586b638de15eb084f3fc8a6a7818054a0fd04f892e94866f46bc67717b51e39069d815433ae81d22ba57fee38197d3eb480", + "352f091cf3b2040a345f06c96e7951e62ff6080f90fe9dc01082c892e492c191": "f90211a0f97bdfd4502103bb567df29ee0694a12b5fbaa8d18f6ee71e7761f1ecdad1d90a0caa482827e86d181120c76dc3a387ed2ef4a060512ef069761e46dd0ae36f247a014ddf44fa412008d1474dc05213d071811fc028823d2813d9977a49cd1acde61a0bdd0c560b880c38a7d46bee3a43ae970418b3df807cc51d061b1d267ddbd71a1a02a22ed740df193d59c2243b1cece7c80fe72db9ca1757d66e7caf3fc08b6c7c2a02bcfce0095d842ee2ad23d02e1949a26d7d9626d9cf22f9e900f5324772f0e3da0f4a0e3cd5d97e73506413017784dd6f1e33f061a354397e0b1a56e58fa9b806ca0dcc9dbf005fcea417fa7beddea8da72767d82c9be70a4fe25baeafe1a158fc1ea0d3250b7d995446f64647907f0d772923b83515ca18299158063b1062a6e0401aa0e464dd36ba4e3ee346304f92a8fedaa9730b7fd77836f8803cd6ed0db00ec9a7a0a3601e249fdc62cbcd1579e152a19b9203449b102a2c87078949e553bd51659da0aa6c480cf9ede965816682cdb99e7f3c5a62baae176b72dbac0e27997c1348f3a03b3318df3cb0c81229deaf3ab72806e0ea417a8b2ecc52e1eaae041b6f476f78a04db38a94f545e3cca425528efbcc2f85ddbb1d460a975e66d98e285e1c0a71e1a09d5ea6a9670bf19041f977baf110967e1bb3c04166b619d4370461c1782f1fc3a0502f8d31f0e3419ae95d6b0c1f914a5cbb223996fdaaa76c160939ddbe588fbe80", + "35c92460e5ace6fd55a3c71aea5f7ad1770f30eaed01be6917d09213180e16d1": "f90211a01ba3b7ebc7083b3971ed261547a2f5f1a9f8c46f5b218fae72be57ef5f23b9b5a0fc6ac87d10550c904ab264584511899a12edd23e6801f80ff68b5ecd7f774de1a0e2db3fcfdd13306b3d052656466e2e9706d3619f9dc753a6827d04f4a9ac1c0ea01d6a1c24c64bbc9cd18fdcd46c80fea8d488ed75887fa31c05ce6564e7292dc4a0f1383be4d7fb5342d50b0ea180427f325d4449c875cd2751f95d8c84c280b2a3a01d7cfeb1bc2dac55061059dd4879a84a1938e55fc91519c91d12b10aab86349ea0dc8181e6dcdb6789e29ad5088bc979e3684556984cde5bfd733941656e52a9cfa09779e74af651bebc8064fa4dcedf0ea1d1887aeac1da02a18c939112cfb3f73aa02b1b6130687f690a6ecb5b5cf278e184972d8a2b7b80a16b400db20d5cef97fba0f86132b520369be5b22be0cf8f11d59dde496ffd06d39f3f4382cf1750867238a0c163bb1d08ce5f47ad12dd20e813524e9ab1e7df8cd40cb11dcfa1123cc2b464a00440390a059d2cd8d4fcfdd14a30e5a1f468bba28481b365b8a8492ea4c64de5a036f5a1053bcddcf7800d764cf6b65781a9289dea6bca1da6cdc9c86bf6a9c5e9a0b54c1ffc2900df0749148f1686c327c73171a4ab8e1decc30a6039356d8f2183a095231e944eb277a289826b94ad1998a247a83c318ae8823a257fdcd0e0d40180a0e3d7020041eff5135f1c20c3e7ef7dae9f4458d4cb23dd74a7b27af3f135f0cb80", + "35de7be5749ad715ce0b80379fcb18b79e77f2e180bb03d788dc5b4625974171": "f90211a07dd334682ad04340534dac571420563e12dec07e7bf428077a14dbcee4e61883a02c362b58777d008fe70c1d29431af65c67e423ccf5dddf89d225d4b18a8910e8a0b1817f7f16a7b5d7f2683a749588746e02039e91b9f3f6ab6c1f7d94dc264274a02696cd27ea9033e6f469ff0498353cfec363ec3ca3b2125a3c76d1460ab4fbefa0d59a430939cd95ccae40d799b395f29fc0fab8030aa32e267dece6fa719bec70a068155b38777ab0a56c106b8d342e56cc515da6a3bac1fe3ce202430d605063aca093eb22fce415ad57f73c106d5532f46b48575004db20cb27f606f86affa9820ca0ced74d4dd711926312796cb73e891d42d5f04583bbb9f65c14e2fbf1f098bb74a0dad5074f837ec2c20a2e176ea2aa47e5a6486ce1e83e11358dc37d7b53f36c23a06c9761a32021da74497b22902bcdff0e1e08d63f5bbb2c6c231bcd97b5dbd3eea0bd8a42a728f2df1a4952fb0ba6184fdef06e905921651baa957319260c20b13da035061c0d4e91bff9030cdfd45d293cdc1c01bbd128db8b631554946e3e6b4135a0bdb692059679e655db8c058884c95c08dd32988e555acb442a0b1f2060deecc6a0d965851d41e33ff2069828ad97e4ef175a9fcef2de2f0e1d5510a23e1efae0e9a0eb3d868e6cfb5ec2dcb64353858136fad82fd968e1f4ff7595f252c41361e472a0a51ddeef009ad15e4158ed8206d43c00e4fab767e3a364183fc42b6bf2915b2f80", + "35e2aa19a97f67ab742e104e1d8eaacbe1d584a6d645b2611eb587d5a31920dc": "f90211a081592bf1e8e07ff838859bbdb4e2848efa64c26f4de05f177bb2db0e1841d60ca08e269e250d0e979e9b5ea21b3bb4e13489f6ae121d039e6bdf0ea1c18e79dbcaa0406978fc2475be66e65bb0bec1150283f09953754c3fb08e78d5b6008d01a4aca0a9a6657db7b1ffc9b7c5181e0b876f5d660440fd5a0970e4027b4afbd9ca4684a09e29eca281c928d303c9daaaadab8b0d49dfbe7c3348247a315ba63fdbb59aada034c03f086e96386e68103cb51019ed8bd52a0724bc97ccb506a77e2f377509c6a076bb06bd39d957dcacd6d7ee9c4c760b43efc57ae96f1183c7d3d1303682d69da07527dbcb4f2cd5bbea0c8aadc2d7f9c62a47743d5cbaa8ddc7e6fafa2cdc747ca08537137f19303515afa1ead5f04ea7d537a51e3b27913539cc461552a1af346fa0eafa7fe4b63d2ef5695d8796e03750edf0f901fe8e650af42ebfa8bad1fa1653a0a08c63b09aa02e40f3282f9633eb0a719ee888c9495e9c0b13b1ca20af5b0cb8a08f07b99b208e9dce86c97b9efa0ca9c581d8ec3d0c587bece3d3c29f1dcba359a0409ee2204104f89364d8ff702eab8fb8f3f3605cde756c6b5dbe31b6e3c426a6a0f58dde8702ff92a6b5b794e7b21a801ccde3c6340ab800af6e649a989e1d8836a0a4d9ad6afaf5a1ef480077fbd324becd03e5d64e8ed0919acbbecfb2994f2384a03f16a7d45beb6634247b3b4c13d20095ac65e19f11f5ef73c9839741a7c0cdc880", + "364d76b7e3b2592165f3f230f886386a3109deea68cb89f02aa0889b35631081": "f90211a07a9cb3a03da54602db9ff52e32a1d66d907be4ca835ddcf6096ba58ef9d5ab00a084a9ede2e3c7a9520b093922af992c21bd2e4439584e3e4ca164c5b237d72ab6a075935b87cb5c86539232da70a34219ea7dee9369501015f78623650413605a11a049942eabf678b897f018a6e069034cd01cd4733ad99a7328cac51548d995f6d4a086e13736582a41648e65c6b25296a7c8bfb0790c1b60b0c9933e47693a1f21cba0840f2b5551e154a7cbce3245ffebdf778c06f8249f0fc8677de63ab26a9987aea0d8cfb2bc08221d145770ee03362b310c6ca2eaf91082a10d4e6398fc42f59491a0f87116007c5bd281ef623749e2cb5b70a58780339f559bd0e474282a58c289a4a012c631552e81b5010a823b8cec3da02ac1392b805501b74c8e5a47624161a2b4a05896d899ad0b84f26f14b5ab176a91feb722f5fe9227bb84d920e08255d59de1a0233e1f65fd7ad4277095db17b2c2340c9ee9b8f26724182a71ee369ace04caa5a066397da5d271e64818798e2f37d991783d2ec7be870f2ade33354af437b40907a0f07f078cc52f6cad9a7bd99cc65b53999b2d08915f1fdf0a4c27366ee344dc45a06eea92e4d6b00ed36c967305f5244ad9f070af12c972145547eaf34ee88955c4a0fe763937a1ef7f025d78822923f9bfebf1bec60ad6f42852460fff0d1389c24ca09765a7cde4dd9af9a32c9ae542fdb13196066f06669ff9b061ed44d278cc052780", + "38c407ee099396fea70641e034a9adb064feb55ee847cbdd16efb3088ad0bfde": "f90131a0eaa0c4cb777640ca66e3ccc8a96add286e331d9c97de5dfe74914955d4330ec1a0e829163300261b3d87d0c7d6d471e5a56b574c002228488b10e1a3780f412f2080a06930937c080b0cf158c7471321e9a6101a692de1406aef07256c6f909784a8afa099642b3f00590eb1853d37be12322afbe89bc3479eafcc241657058c43f3bb0780808080a0f0570d0215c72c80f88b99fbf3066173f08d70b1a38710d2c8f7da1b338c63afa0f12f3f649bb77b95f95af0da0b7fb3551c80cff7cc3fcc1aa73d1296118ec8faa0d9dcf09b4e25e287e4683e76261acdaefab82b871ab09d5dd65da5065b83cb5580a028dd75094542ec3120346a146e07c65d6e16ef4442ce9e86fbdbc9192aa3f64380a0cef96630ad5be040e91bb32b5a753e09c3bed4ff07c31708a4bb1a2fda76be2180", + "3979b14ae2085de9cbd50f62f4dee7e90a84eec8100fb7d47ce108cd82791451": "f90211a07b44c72886f3d3e96f257d1265972ba9616177b5055ee45835ffdc0e627d4ebda093138eef616cff0b1eb5303b0a19c81968a61d98d67b6d6e9687abb8fbc24539a0b552306ee77d1d42500088da9bd8043abb00f22b0de77a95c34fa882765cc98ea03363c174813627645b9b5d678af35f5cd41b066d7d0aca6c56f98567299c1469a05e90023969e99dadae2cc3744af16a5dd3fc38e66db777d380ab9dbdcd752331a0d2acdf341efd5546d58ab22f801a9e83906de77871398be1c09ee5543ee21687a096f0366d2c3fe2e119a28366e85c96741d4d8e0b93759ca05f9ea8c0a5fbc64fa02110202beb9f5d1291ba7d837e06b6cd25098033d55712d3636984a4355eb6fca08c4d037248f1e876b855c0af4998d265dca626bb3ba7ff58262373343d0fc09ca0b00002f24b378c8f3f5eedf4ac6d134798a4413d34d16ffffd97ac81c3d11a87a00dd0c7c97df01cf94b3378a5630d60815d41f16f399f0a0f15532dd4a9a9d98ca0f28a6fdc2ee2915b35ca6ddaba9195a836e2378250c73e5546866cc74af20565a0a26ebcff23ddee6272de9c6d19bd955af8bc050da35198ce8e472c36796d86c1a0ea20d5a286aaa075afe2aaac98f53de26fa250a220d0f36ab4bafcca40628e74a0e4e7cd62435218a66d71cb8d59124df4379b20192aff3504628fbc9e23141414a0ac3fa07afad499090ee0504149efd5ffbb692227f13ce4e711c25afbc42e680880", + "3b4f0fb6fdaf2960de68ac16e541328b49d12a2401305c36dc8474966b3db08f": "f8419e3b08f6bdd1b62e712ef7d2d838e79e828bcdaf725e4ea914ed0f1f0e2394a1a0deadfeeddecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1dead", + "3b9f979bce0c4e71b0ada08233305fb42b28cc6ea5b118a71dee59b7f4a41386": "f9011180a041aa3667291d1a1aede4a0d106750f51d5e415504262411b2f34ca35637dfbdfa065ed69960271db1bf64e6520c909354773c6bf8a47b6c60f04ece48bed55dd7b808080a06dec15d6550be8f9003f9b8c92225492fa68a82e1d973ab52e85780dfd85c54b80a0497a280cfd9e04c9644e0537bd3a0e9ec49dbbc98c6976f7829649b044439e4da03260eaaaae93ad207f3e53af71044c55d0ddf40cb64c73318e1aa1d4957469808080a03e8363d02a7abdc271feaa79078b06807194f35b3450422a6ad8125338fb44d6a0266c4e4d19b7ec0339cd2795c63dbd018f81e479715cb03a28f9ef74339938e6a020af231645431a55df0d73c5460e4283ddbe4fa856b726578de41dcfe156f7808080", + "3bbf6c6535a3025f1241b51863b866240ed9931e748f1151290b4d6a653668bb": "f90111a09d7fe2349228a26b04c1f29fce533fe4719c8b173e81a538e54bf2b9d8ececdda0efe4122fe7c8cdb70e3901de720b2a568da7137a77907b6426e266252714f5dd8080a071229f863681b7dcb6fa1b011a3ecb551db477782a2da44380d05d66e3cb2b0f80a018c38b5d40f3478fc935a61b1a04b1e5428543028be6885e918bdab29eb33fe0a03d09e76a097d20b3d81b4b77dcacf35f42b4b8670448dca0cd04c991755d41df808080a0de4df359335ee25ecc15beab8805a17b2870990f4c5f440f9a13964e66ec5dd38080a090f5024d3ea68b0552f989adfaf032d8e476d10859a0eac0b9bd427eaa39f50fa0383112f1cb7cf0ea8ac4d4292b03f85451e49f24100dabf6978eef9a75c743a280", + "3ce9848a03f46346998366b6463b6a8b7292a11d9ca88e7b09180414d3dc862a": "f90211a0bdc7055bc036c070ac439d707d1036d7ef09fc8c11598e91366f155b7dd98208a00a3a474a2cabc0608cf43321b2a501cab74bbe7ef4360287ef26d0daa6e1d617a0a1c5a1f274a57ec5d9266ff6e4adfcb36a1a481702788b26b3e1a09062616be7a024c4e6a218c94631c8b592ccf5d79556968e90540d4f2eb4cbc696a4496f6378a04a196a217d4779421d6f16f3c5e4c71774297581edac672565249030b8025763a0f6f2adf9d99c40adfaaa8af04d8ee567ac24bc5fef5a366ebee82d84d4a3dab2a029ccb2bef54d42becd507ba6a1c2697ee3db7c3234df9e12470c369b91f3c86ea09bf1f58f54133a91fddb5de5dd17b2eb206e4d442063634957114c5f42475653a089789256c17ae705e6843d5377e49afc2e38fc67b2318bac1df7adcfdd9332b0a09e188b8ef859f18bc5fd78fb850d6c7b616cf4af74ae09c192a55ff12fb38deaa0e4fcacb1b84386560467ede11a97a3c8633b0280bd630d6fb6dc4dbf34b855a9a00795ba7b29db84bd95b6f7cdd593a55a7b6f3631e904f91b33b57ffeabe9498ca0feb263c1068bcf20da3f2d4d869c6a77932d2cc11c1a41250fffcec286b74dada05e26a870655f93d2c01dd44f36db8c6335b8a28e3bf18cc35ece2dd5f2250241a0ace05f43632b41dad7e1dffe274088fd9f245b1bd4964ccb1773e7f5c601aa2ca0560e599211465c8be0ea593c4aae9661d5738b8556e3bd2175410df85439093280", + "3d69b5c506034c07d79a910dff5574d882ec9f5fce414521f4f0fe0d2b9fd6cf": "f90211a035252ad0c1b042216e446064fe62fe34fd70070b8777cf16aa5d5ad4169b6bb7a0f7261242aa5d2015de9272a781712f2ae68f64468e0226557fef6747eba17260a0a3a61a074cda9666fc259193fef8e93c0bb5ff30ec7dc809ef7b029e3723012ea05c139098057d1b2a2f7a5d8fea6c6707df1706c1416cef9dbd317c84296c987ca0f591a21eb6ec9a43ee6dae1f3ce1aa2f325e5ba5094d7a56edbb94d7f3abe8f1a03984f269fbc7749b9fc5a0ad851affc5678b0e69a1988a915c18e50d86a4ae6ba0accb7aa10bf06a11781d12757829736dd24a29ef152ed3dfda429a7911e6543ea00b4f2d2c3e1fed8f9cee9f6e1dc89a18e7eb2c920c39a19b8b73be57fd84fc49a0c78383a4daa4571ce7f9dbb12613ebaa319e4bf5cec634a8878481ab50afda2aa0ad3e3ea14534d872123a12790b31463925dc4f6b67890cf4ce9c732300dffe2ea07038cade5bf3f1c0cc390ca269355428b0acc08f16e971127ad838db11df6a58a0470df882ad012efdfcc4f76614a56bd2f5e0685c82cc8215738c54cc1c4ad353a0c627bed6886ed02399a189f56888b942d77bf6cc59300686b5ed77cc4153f2b0a0b2da5feb95604d3ea1a9721d0022d604ac74b2444d2a525f271c5e44fa8739cfa0544344f1d3beed0e94f8aa4ae42dc5b33f95e36e6597277e97859ac62e220783a02a8b3e808b6fd58d530ae68709b0accf86a031e04ecd11556eb241834c6460ed80", + "3db13a12eb71d23b238d7c68c6daaff0fa9d996232af6bba35a404cd24e4e7e5": "f90111a07096f2a2e23b843798fa206ebeda3570c9950944463874618d513f52625142d4a09d91272a9919a923f1908c2ff02dcdcb4ed112c7c93851708c78aed6022f55a080a002d9c976fbd2de150dd04f9f3be6968267ed8624e184a019fd61933489ae78ad8080808080a038cdbd05061085c9a4d1791f0af283219d8f7cc32d41c0d370db17d02d198fd78080a04e7b46d258a705ffbb5ef02e9102bc92f359583afd539250bf75aaceaaf0e17aa06fdddb0a08b0707aa7add6bde7db8f681873a50e5c9a1935dcc21b272836c578a0fe9d760f2888c47d73394f9b732b363df59995b0f18e894ec9fe1959c0a647bea0b2cd109125a195335df79abd32fcefa9f568904647c96838cf22e84d780c063180", + "3e065d058e6c7385ce0a585c4ffb1eda68b75a8b11f67613f6edb5b8b94d56e6": "f8d18080808080a05085a3448cf7a9a038a091c82da9390e2ba3eeb50235ef4039b0238db6ed3d40a0bd2a4909af6dcf9371d32f5fc561ac72a4b467ea343d67eb607c525ae1d1d99580a03364f8c9b491a56633ab538180dfe33f0857ea12404ad5ad5241420c2b6ca4bb80a08b12cad89d808ba0a0881f0ceafffdbbaadbf1e3f477221d6f608e2c789b6069a0074fd7d0a32890ecef3a0dc7f7058d8840041837c2e53c15e3c1d0c7a34a24f2808080a0800a2a5b06e8ae6c0c7e2ebf9adea7dcafa343c4671d7c0a26c32e230092595180", + "3e10b1fdafeb71e1dd31f7d8cab206066d4c40c44bd91f3fe76e2059bba1cfc8": "f90211a0f048fb947cfbb117dd191e2b76ee648df0dea92ad3a3ee0e1b06aaf246290f61a0f87cf1de42ce407325b3f0cf4673c7c795ab329b49a3af9f8f4d85e640cf839ea04e4133588db316f671ca012f6730d2b6cfa2885fbf44d10ceb52ebb8534d6440a0fbab0a519c7d0fa113b70ff40a755fc01f71ce7cdc1a9bf9b0ed9d9dbf682d31a0a8816150ab2b71213ca709ec93bccac2329ef3a6b8ed4166a3b8d6733e43800ba06a7cf49cb514cae10bdc567541ee924b54a7cfc7596f22fd07f9973c54ed0f27a05494d18a48ebb156216acf5b113eeb52dd3f91e61ee626e1e415c4992cb072d0a0518675ad01e281673d4ea985d13b40f1e76841f19b9d72accfcfbeff758457bca0068fdab22ea07c60658ba3d8cde35435b9eea250409af363915ba94bd41f23e4a05a28436d62c77d9db05211ba59c3ce91ffac1fc711a5f0908a8250e48c3606e0a0e0ea26a5a67eec2338093a9559e6605e65b539e895f26e41f0f3cb56163d4b15a0824d5b736916472ffe5938dd302942fc92e6190a2fc6a14ca00d99867f140726a025ac3db51866700b784c8c00e8d9781180b766917eb9dba8fa0941171f09c774a0dd169ff5471f3dfdf894322342261793bb1a17329dae12fcb6bb27c223069e6aa0f9a9a358ff9b051bb648b66c985a3ab37d9e2a5c2f5dc142e8f949eee508317ea0a6ceb67791b38f55ccc0d46918f7c4b8bfc82185e4826ec6b8b6c2c341a523dd80", + "3e745a25b1f92ce88897f399eaf7ad3205b9460fcf0f9f9423bbeef20bb61d43": "f90211a00a38c42ee24a80dae2a47e2006797c7ea80db11ec92d12b9f640973b4fcf3e86a079fe33b824fcef9b333902ec60a1ee21e3f6d4f9fcfa81e305bc3a28da66bba5a08135afcad98a21e4986ed6843266f03bfa263db55b65dea84ac36b494c8e3798a056c37703afeffbe15e1b94a69d83a50e160d32586a8b78fc2d4eaf7701599859a069068bf9f2d68540885b6b9614a469e244438f07bcb42a5bd30f33fd6bff0edea07fb042b5f04abd9e7d20eb43a93ee5e4f6cf53eb9895d7d2a197858882b25c83a0c10175f876c3df6331e035428fbad9acd97b603f958782c6626e0aae4652072aa05754082b25891642379e93babd281c9f20765100aaacdf83a828a70bbe4b7c66a0eb083806a9d5abb6004efe7bc020de17abd5ad4ed6e7d482955b6d3e35c68693a0a2f32bf692b7d688475cdacc21fd7dc39e602c8c2ac022d0370444c269d4982ca09eb65b83436f844d348d3124e9b2c3ef44159c4947dfc8347f8837558925558fa07709c3c2a61387711e36ff2ec462395e283acc52c80b30e2d9a3a0290e6198a3a042d3d2f7e27ca7dc97509ea5a5345a36096d1dc66756ddca22fb3551c00eac7ca0f238c24879af1f3f20b5634d94497cd204298e5f1f6f1288fa48bb2d61380924a0a507663a262c9d9a272df2f325c25f1b7607c4e7bafbe4b400e87253eb36708ea05ad6c0f8bd7c85c4b8a40d46854836840ff43e46225c1e687dfafb2937090e7780", + "3ebce803130ac496dccec9b324f74c9942c394ded403dc12befbf920da3d343b": "f90211a07dc2c04993e97df22ab8a5680d4682003ccb194a9b2eaf620076c7059fcaff0fa0f492f19dca58365288f03232028f85337cfe7e3d13dddf5bc0b882d359f2a0b5a0db5246c7fb85d20fdd7697ef5b74a19f3b28f60e25ec87048d70535116f601dda05322f325eeaf839ef98e4c720ec8ded29bfa2f33e5757dac9842fb005c51ff19a0dd10e5269d9173c18a0d6fc2fdda32a944673191cf7148ba16013bbde7f3bf7ea0ce78b0a1136d498b97567ceb95ac1dbe896e4769e124c2587a930a4bb86fb099a03c8ce7981c254245bc9c0488b864fd55a47543fa81c339b5e5d899ecc41be11ba0eb892ebdd2792bf116ce97e64426f984bcfcc1ae87dde1a92129808f1f52effea0cfbc10471a3550c42237d64f7973ee5e03cfcfb17a0c3b04646869ad429ca228a00c69513d2b4cf4b62fc12bbf9d84ddce64dce165853c07b721db5295e8ed71a6a0d8333e00f44690a52dd806f27e3e7775fde6f72ef05e4b7ab6f2022590e82b66a0daaab278e57affc32e722a7987def9c9e8bbca4fa253ad06179e8f27795708e3a0167eb31d4ba684e22f8a14d039afb387da5ed64d1eace5b684d64703d511727ba0842436f4aa415683981a1841d9c339439b26e45e35d82449eb7b4985f15fe9d5a09d501b30850079e6a45444f3b7c292a2fe42a41f8ed546335f61df4cb4b86b81a0e904e8981e2f78221111e7907f72c7377bbaa0b594c06494f5a272f5ab6d44df80", + "40acae8ac67b44fb79a17c6dbaf0ccec294d1b11994f5feded8472c8935d2950": "f90211a08a81b14a2dfc4d1d1016522f5c2f9cee67a48bd4b5063dfb387d68c050cec044a07b6308c26ee534b711149b73f70a8c17f3d59347f7917cdb0d48b60f0aac8241a0cf2e13be7626659cd54237c1b756e762ead0c9feb45035f080185f3fdf502d32a065b8151dccb9ea646f665acbf7347134317ed3a2f50d9b7dc1c0cfd1f4797f7ca06e1418f5c9956919e489591e0ac656ba3b6d9cac188492b3fe5c18dac382dbfda0bb4e5ce2d9c4c53b71b19fc7b3f13255c06eebab89ecba1e552e8971c9b94458a0ee89aa263ff21ba93813b629226d8500bc60077b284b7b5bf0ed47eb7a813385a02115fc180bdeb0514f62cf7733c57ce3ae932329b2655b0723ad19617f548dafa0953ca1be32f71d97bf55b70e764b81919d514f846bbdbbc9253c75a4e25a9a23a05b4ef9bce666f89a3222bc218b67b404ac50751a4cd2225411aab215248b8a1ca033da2aad4b89bf5bedefdef836366c3931b19d3e3f17f9a5fd254929adcfa0aea03d9dae4f09762661c2f624cbf0c70d15fb90fff143f44bcff1aabd7f42297d0ca027a47e0914848264f477acea2be466df2965020576c16227d56fd4e150dbdf38a051b4f8ecf17f995336b11d8d2257c6b64b522f2c256e1eaa088194875f02840ca02e029fb42fcb83a29a7e19eb368bcba3b4de6f011b3be614e0bd352a82e41d21a0f130bdec7e26b0d15a52a72d20042001d1af2ae0abfea018bc5c6e27d44e7f4980", + "40ae4d08698d20dd478b7a5313f033a5a9976fdda23a6b106ccc6c941caff1a1": "f90211a009aa224e7988e9f954ed55a0d0e24ec650ad0b88f1ed3b03e48b7e54e8a0a6ada08a4e985018aaaafa79bce08e6d3e3bfac2d563387584f18e04ced05ca3bab265a0e9784edaf4b46f553743853f41e36e9ee342e185b20fc723b5f14abde8763b7fa0e089a1ff25de664744ecb1e30e977d9bf3fe2d6e85fe4b5380ece22388da8432a03ce9848a03f46346998366b6463b6a8b7292a11d9ca88e7b09180414d3dc862aa050f0fdee12b49df08fa013c5ef2f7bdf1505cf61b6db540c7954b8a72de8e0b6a0b34b9ed39713c1f3ff56b2083cc7a5214933aad83a6378514f1233f3f951370ba0081f45d3825d168a6479b5f3bdb6d06d694cedd0196137e5eed6f902af71d135a0a9e3be7a0da9853e589613fb805ef5f0b3c94f9718cdf036fb45d56b2148a8f3a03377af2b05083b18b0d4db4fbd1426b3e1f93ab7776ac474495b2386b6faa11ca04aa82c3fd48ebff32e68afcd305bc5d2b0ba023921a386a6e5f6aa0c5bc264c9a0b399e1f0bc99cfa0949a7620265b0db30e18b674c9b293e4977e79139b91d6dba00932cf3ea5e36f7fc65757bb400898d033e3fc86080dfaa592aae8d892eb2475a0b3e185d9ae735e522d1086c0359c1fcafeb9afde22d06d993cb47733d32b7111a05cc719f556d7654181ad34d7e79c7ca5c45b2992cc68bc5490682665f1f0f55ca0151bd74954cc44054c432698e77cfaf449ecd1d456cf93e353e4b9fa89933ec480", + "40e6efd8aa0bc63817019e3353df6a5cb09e4b814570d10603f594eab130125e": "f851a0f0b5ed88d92aa883a14245fa7da521d044c68c7636aa2de95f5c678049f511078080808080a0ad167ca515e3462c878c5f881151193d47da4ace9e5152754e7fb6f436d124ca80808080808080808080", + "41aa3667291d1a1aede4a0d106750f51d5e415504262411b2f34ca35637dfbdf": "e39e3e06f1f07c45b9a6b2d87091fd8b6829f3b0077495b8c6c6fb5143da4bf483820801", + "4244dd9f96367c3df36102cadce07bf565fa939742928d8549ae16433551272e": "f8419e376498190028c9aebc48eaad5d35db68a0ce586dc0698bcbaf462198121fa1a0cafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabe", + "43133fa8e729d429cc930c42f073ad308b68fd9feb1621954115fa8b7543959f": "f8b1a07f74333fb5c158dd04c8e308f282b1d0be051bd81974741c5d031ce91d945ae6a0218a91450a5d9b0eb4e95ab04c38fd641e565878b74026ec4f5a28a96a896375a0e437793e7316298827a8219a3b3d9bfdbd5268f0953ea6d4cebab3b93af02bad80808080808080a02cc1f9f3767c07965012ebaed1d4602a1b3a4b1ca0e6ca3a76a79aac1a12cc7580a0e35df76cf5b89dae998bb45c85a88aca6f9ebf599a96f7c4777c113bf0c10fd980808080", + "43e7c78ba174dd20a60619da5e1d34625ec653c153c339fda9fbed93e1c9dd1a": "f90211a0997605a9fd17c84a0fb7f7d7f82bcb0e110b1ee2caeb346c7faaf6eb6747f976a0dc2ac72d34d1f148f07eaa350a1c09f15efc0054b4b0d5f4a29202f0753e68eaa0526a7f1698dad58bb8424c15451eb19ad7b0f1ba8bb52d85dc4db75e4c3eb68ca08a5d4301a6def4a6960b518f022a2417977e66516875cbb12b5e2e1713059878a0141534b037e1b6f78e38ca397005946cf8ddf047ecccdb4065c35fbcbe5a58dfa059086c218a2cffbc29ecf3b698bc651dd766d010dbe0b1774b264ca1de603fa1a04f6c99d8febfb5c58b8031b99b65e0be0e35ac0fae8d3114e4c75ca84e1030e7a0260a6b78103fdac4264414378078434c38be5751bcc429a81e98c16393803c13a018c880d68799a9f167e759997692cd6aa973540877bf22adf656feb2bb6fe7dfa00c452857f16ee17b86532965a3e569ddf5cf0b82f10eeadb47f3dafcb445670fa04a70fa2c68bfe5f3ad8ab343ea70ba87b7df4372dba140a596508444efb4c778a06d364072533d279aaf35e0ca06ffd6cae66a9f975750b5962471c52f76004391a0a30c7aed3f564b2e7cc4331fe1e7b57503ab71d52648587cb4d06fc7e1478bfea0e72ffa8bc8e24c2e4ce45156f9a61d4871896c1886722ea41a9f57b7d1eb1cf0a0be3a797d2026d43356623e86f0c8ccf5955ad90bda021571fa06667775e29ba5a0c2ebee2e9ef4b2f76d2ac7aa6a3c0a449b93cb3b75d2b53e333d5dc279eeac5a80", + "453cca3ec06cde57ab5af155f45886f1c9b61fabbc16ef7b668420a2c154d39f": "f8d180a0997e07ff40800c3c246df3b2227bce4247844bfc7d00de38df3b0f205944a831a0cc1e44f7a040b07e8756d3b3571e3eb4b909498967ee55712942b40a48dffb96a0bf7664bc8053d85aef4d20421bddeb6d390788bd42808ba88382486a9c9534c9a0aea20816cfe01ebb8dbc1c8fe9fed466ee664ee935129f596276ef98fd7b7fc0a0750ec2ccf819d3a775773782c0990f067db0d99f5fbe48b53b063221a4a99655808080808080a0b5723f571b144658462e2a6ddfb204732c55b704d0730f0b11872f54fccaa0ca80808080", + "46c2d54a8d8a3da2146056b7d34ea3faa0e411d09ee4b3b78dbf6d8a23dc50a6": "f90211a0a30c806532766775d7a1498ab662af9850c53595d444e492a540ec7bb6ff2a3fa01304e42d011fa6195d6308b3f58482178899b7420d31dc19d2a132fc344f4c2fa0682742fc3b4dd9162f00050d45dc5aca39f6863340b3de371dd7ca0ad288d019a06c7a20e5c580cf3c0ad8df02ddaeecb303acd6a46d29d0b440cce22f1fc3e996a0a66677d461bbf6adb253753e53e38cf6317f3c7334e5a63a14f708fb532600dea0cdf6ac23206da1eb5390299e7d4a496513d40a21dfc32fb69e17fd75b835a36ba0c4304540c7f0e4d166eab23c30a49812bc89f94914b8dedd0c531ac3f6f3f60da05ca34b98fffdec21cf5e17fab7472fd990dd7a21f47b7e2b1477db7c6cd1677ca07c7ebd793ef47c1d39de0762cd8d0f6125536d965a25efda82c1f07adbd4f25ca031dad6f1a75d67696381ec2dd7277992ace7b3ab6d6625e6f7d398a975a82cd0a07ca86631ce759719917275ad805c64783450a3995a0fc2fd002eacea845a040da02909509f448b0f9f9de6d93214fed95bf098b41183ffd0587ee3fd884851eefea0362e79225582d5020a686b4da876772569a0737eed44e3a916bae16d9a161056a0911f4dc5f31b69f295dbb6227399da6a4209ca5a5ad9cd72ea8cd61e97e70a74a077d50d6f9f595a0db56ec8d6d4dfa9c857319dec7974f890c882397916485567a0c8f090014c762386e01800687edaa33a80ab40e7c2f3dd48def4003d8bbe39b780", + "48376b10e7dd81d7e813cb6f4a8d36978eb47e7353a6f6197b9b7b4de6a0588d": "f90211a02e73916747bd1ea38d34d5e4a7533c5aeb1c0f80b2e070baf23d9ca9996dfb17a09fb6786e08ba3b04cf821dcf0693c788ff4b55d36941ed8bf3a443e5ea3cb242a04f6a9436cfd85d3a9c168ce655fd3dff04dbf62cec998ecb55292564db496823a0090b07c0a0244a382ef466fd141d726aa3c80aabb82664c6d263c74d9c1f6eb2a08250f4f9aa977ae32ef0f3ebff2ef9b913f7cd6647619dd7c03bba56f5c4e178a0ba0efc02e6097c1e099074bd4dc4e8306c2f51a9bd8111138a171589a70e1977a0bb26f3635184edcabdd44fd72442ec6e617cfed8144f11a3c756031c7068d649a0ce3c68c7a3da8c478431036ee8ec8460a663dca7b30a0f2943eab4fca2c45033a0d12e171a753dc1dd8ee041dbff0b3a0cda71eb648d87b465ec1a47265b57f94ca030918625375c49f396b96291f10f4c29b285e2923cfcc6ff963ecb85a7757857a0147312cacdf36308c90d8b59776a3f1cf059cde76b85cf99382a0d14aa8f7683a000f493022e2595e2ae4e7f3200f3227c21890da2f6b41d4a7ae3711d33728e38a0bc8552350a2538390333646fa9ff91890c5c3812c45109a9d38175a2a3870079a05da0b9540887740f719b5918f7f0789ce703dede81fa04f4327333075f13a6bba0fec2b272ccc01f11d1e7721dbc228b66a96983c3cbb3324383e5e09269caada2a0d69f695517b8359b40cdb5a9ec85843478f2d256f7a588ef7643e15d8ed0cca280", + "48c8682b93c11babf440c77f107e1cbdd2f0771980ad3417ec12a9a58a5e12c8": "f9013180a09afda2a0e77480a06e11d09e9c342bf240450d9e221a8799e233819a4f4547e7a0bb28b10c873a8be717d4142d7b96dbfcc1ef7c8d6f10c438f30c416a96b298e3a02fdabaab4e280990e13425f924e004e01fdd62893fe066f1a710f6d325c37a8ca0a4432466ff4a30172ecf841857e07f8a4579ee34ea2accbbde104c381692cd7da064227f467b812f1aa41f28e98ad8ee0dc8cfeb8fc0e088a688ebaba4fc36d0b480a00cad063cc7bb2e7240a5167365d3b6f618f268cb31cba27ae8d5a2374c9519f68080a097da69b641640af0717fdb0b3b55ac7e93b5917904e9cdd201ca4310d74a6304a05b2e29e5e3f1256fc1626d6cef947c681c2ba97ea5f4f722626c74a9d4c9e3298080a09381caf8faf51929b05e29d333397fe3622f77cc1831ed1258a1c13103e5a42c8080", + "4912ccda03dee09891c6b41c336aa352500763319963d6f4c4cb07980a009663": "f8d1808080a082c5dfe325222827a12ebbdadbee2dfeedf96d9ce46d24f015622f3589808d6080a07d94b1b8c6bfc8bea71aafc1723865e0e8eaccd1b0803215676c0e1eb78b9c2780a0a92dfe16ef6bb0f0c76657e05fe15182ce0336f8b40879548b69b1acd1f4eb908080a09c3730c278b5dc52038397a36e56314e7acf4f8f73b4125a42ce685a756e60fa80a02d41f50687bf6af4015c34a4e0d7ffd4947f5bcb2f942e3f9618c1670de3e7d580a0c9307ea5592cb8364f1a63dc3d6738d1d8ba570f7111868755255eb906edd2098080", + "4a80bf00747a6d7552ca2301977516b493acc9742fe0deb2263864ce18be979e": "f90211a0b22625fe14ab8ad808c0626410a32a68bc96471d3117247fbf06408747d4060fa0c21806ae7d1baf6aebf9250db5f950f91f635e0f51cf0b22c1d2905caaed9ca2a09deb67240c6104a9a9624598e2a7e55e59b229c8ef9a0cf056bb732a97844a9aa055b1b3554e08f3981eebd786913e85c9f9b903ea2318c625ad125dfb4c3f4b55a0aebcc8e4eadc88923ca4d53aa778e062504260ed5bfd16058eff660c0f1f702da0671c057afeb749b90766fafbe83daa8b0a97849ccafb36af3882598c2318fba9a0ed68b82ddfe139752d7e4cb427e48a340dc9625a6ec8c525801c8b6d93238c92a05fa1ca26438e04946f09b559b2bc2befb175a941c88aa1b97692457360d022a0a05573893366387572db13bf9cc77f1f1ad89640d557723ee809a22a1fab0b3556a0a8a35f8bad4594aa3ac1128f02cba7de80486c451a559a15113f3c990cd98355a0c2dcae4fb914d0a909ead4e63b9068e996e8cb321bf123712b02ddf8853c197ea0d990f3dbe1dc84d16f17bf8f856542642a91e5b345a6aad3d7ede8c3dea578bca0a40ec6b1c85fbdb13f25e039c270bc87154e277ae2b4d4965ecc1cc25e4827aaa07a730290e40a6f113eaae9549ddc4ed398208c2d980549584267832920d18196a024b6c9618f4dfd8a74eadc7bc7b0d4749eb3ad761cdc8d22c2f959e3f1874845a0577f1f6787c833d16b037eab7205aa6714f4072b55c94d0f76bb996732b9ca1780", + "4af102b2fa3689d0481dacb746423b534615291bff4e45497a2ab27244566a7a": "f8b180a069f573908e8fc5e27de3bd5a7fbd61c1b7cd494ca0ba4ae86721811492bcfa4880808080a07297c2f4086417ce48454b6ebf8798ec1e1451f5cf9526a4e30f35607fb7754ea0ea72222d7173a1fa190d8d2549691ee1f27c9ec950b8568f73eabb4d4800826e80a0c36642f9f506b63a0a9e89cb55e9c804599241eb429c8e4227fb503b60ad96ef80808080a0eadc924c27252102387ff446a4b4502e375438ae22b14be8c7f86006d958ddf58080", + "4b35e582f15c2bd913cf035aac7d15090035b0482c8f251a9356f34ab1c9dcce": "f90211a00e4db1035b04655db35f57b853cd6fb8b9511aebd1d72dc339034bbe2175a120a09530637001e8fe5bce4eacd2fb59f0f7321456d808284db0ae0b47efbcfa0fbba07b3b8f154a855b7c00ebd0a6d39be77b79d23eb330f5f174db38aa9dcba71965a0ba1a317160d6511f7c7c07a43a8c835e075b0f5f49f3fab4244977a1530e6b3ea0a0d32f84b5f7f3260bda8cef349e39e79cbccb0fb6ae64df72f1a987ebde8bdaa05d442ffd8becc204cf4231cc115c4519e5eb7e9804ce314996ddad62efca5e03a0af7a421a3f3f128d09d801350510cfcdd9d576c2018e6b8843bb113fd8743d8da04a18ebd6975e30e6e3ecc90c882e8461807bed5b244a1d106bbc1b6082af52bba05f79f37df995cd796c2c97ed9420e68bc83bcee92d36bcf79177733982697b75a09e7e35310f859d75bbeadc72d51134c1cc6a8cc539034a789c7fda75ee268d4aa023269df298fdad07cb9cd26e1cee1439717f5144ae7dc3ed5814b885a3ffeda9a080eeeefa37d114ed34c4910c52163e137f2adc21c000d49b74aba447bea38f15a09a6b157b3bf95c77ff027160d3f589c1f49f05589d4a4d7aab106b2232d2b46ea0b0846221076674fcddb287f65c4a85a2638f1b1537d58360daee74785b76b096a056b7991d25fe5a6adbb15ee7b48bfe7ce7a2de83692b3eb86c67ba3872393f34a07a61af2c13e4cdc8d4cdada1d964fba750aa04cb1fc265d346c45f453f89d67880", + "4b8f98f7d3608d29e7bad83389b1ded13df8e0cd496ab2afaec15a51b810d68b": "f90211a08fbdc5771cf39d4c604412f1a80304dcbbfdd287f4c28e4d876dee21035df36aa00a85a25c74abe9f8ff3825b5b85906e5a2fd714b00e788fe0e953b109ae5a837a01e83793d940285498087857e7c4feeb3e086ea6c33fadf543919da6564fe1c3ba0061f926f1a9ed0cadba5b067d85547eb145adb2fa07596ae3cfac20d43497543a0efffe8ada26b778d15b0f2c5a66aba4da47d48cbfef497e1d0b2735f2db2484ca0b96946d1298b0e049fdf340edf7dbe4a7748c76b5b186f84ae3c207f4d0a4a8ba0b2414512e643998b67b4c35f0b829c682c48bafee1904a25377796a81c0fbe77a0833b339730a8a85537ca4921a55e32bccdbfa07b959d0280f0ad35bda468ae15a0064aa80f7649cc440f180fdab2530d1bae5d058acc80ce7d8490d0084efd318ba0675ef9c80c03ebaa4fdc25cda815a72d800f73406ffd3158dc0ef6d061d8c2a6a02420f75153dcda0d2e86104761323df65cecb61e5e45790adde728ebb091e5c0a017a7b079cae6693f2b4c95d5d336cd590d9cd91ab54bb1a583e0f6dc6911b26ba0dd2121ee467cda4b7aeda33b9b38287995371cd9cb803b92efb6ff8415fd1cdfa0d12dd9d51cb18cbd21c0c00816e4c7889ea54bafe9d08b3b6e6ccf28d767ee25a0bbd507a5cef34e74acde372b1338d17cf13e1997a830fcc85139da2fea030ce4a00c390b9f877d78205b725b580212b8551fe0d5c28fb9dbc4de1f500ea53e150980", + "4cbc377795a99dedc57288023f3ce5e6cef68b26a77987cb561bba4d5d829995": "f901118080a0074b7957d0955f1f9f5aee367a90b5e04aeaebdb9922b92d06c195104ccb5ac780a0525bb08fa7a6eaee3e63fd7026e76d5b0b2ee7efd1ca0bc4db6b2f129f21ad6480a020d29324c13264396666ab3fbadf56ee67b9a201a2a3454e43ee9bb2bfbee356a04ad7a50b4ba56a4099dc38f27e416ca4c58e17c688f851e590351db71adf4255a0e4273bc56ac68bc6772925c5ce68b518fa92887da4b8035f9c79702d8dcc251780a00102bcd8f7875741135ab0e9bb19a7ceb17f4802a174d16bac82175d85ee725fa0baeab809d8e04b47ed90154a804d478952febd456c30a6c44307460f3ce7d694a03819ad799ee26c82755eb9a1b67d357134a4a893d024440f7dae334caeddd41180808080", + "518876e0f325280ec3ba986c3c7880b115a9c207373a627320f39490c22ae7e7": "f90211a045dd82509b15cc00a737e00f8bb3cd55de77d7e5f5b707a6cb7a65e40aa773b9a080084a2f69c215f1a7b49a4f13ae100e5ee059f7b3fe92615c787de6f588d067a06c1b42eb345210e1da445d7659b6aa60a17a0f7f04194e88be8b35e752908c9da071e319101f8b979cbe3c2ce0dfb6211df342288993dcb2f5ab148605e441cde4a0332be9a0d2b6e34d855e227bd47e2a3be4785617ab1571ed6b23906528b03d9ea0e84481c24cd5b58b3251009d714726852a4c0800637f09cdd7a8c62988cae67ea0dc0942124b9d4e3d5ef0209c7c62d48040875901cc4bee988380b51ebffb015ca0a88c1c5458008ddc71395603bb3a871ab4454cf251603e8ea5a15e2bbcca7641a078b169dff2f1236f5da7dcac619b5a99e4b7cbc10c8b83c20d39f4ec89c509bca0b4b4f09c9cb49d3c2a93c8f8ac9f0e440c8a230f2c3cbaa29a75bb9aa0d5e1bea04e3adf0f409c74da026d9b0bb5654f78dbe3156360aa93bdce2f640c6730930fa023e42cd5c5c408ebef83e47341512ca3ade30b6d1d345fc20951a263a907f826a07c6cf01e9e8529745db59ce6135f5a442b63af0b96ef2041e0857fad60d0dd7ba077e6ea63e6350bf5f925b8ec592b34038f19aa9e7434a491f0c80d9a7e420cc7a03931d22df3f4743cdc9190debbe32510264acc26d68f1e04f3f3421e2503c759a03f0c8132f093ec2a413b32b653cbfe46bb25e376193c5eb8ad28f0f0a5c8a76080", + "526a7f1698dad58bb8424c15451eb19ad7b0f1ba8bb52d85dc4db75e4c3eb68c": "f90211a00cc293a15cb63a3dac4f0555aeb40d10745fedc7ac9862b308ad044081de0916a0d0dfafd2b3f4860df4d325129fbfe8e80a5cc016246263633ebc3e3b47fd4945a0d70d61e3e6e536bc555d97f32fb7413144f4d3c5c5c9e1182d93526d19714725a0f473d925f476e47f956655c8b2a3b34e225543d18eb073b4b6d995b7340b2114a0f5dc519a97102405d4125eb8b450978419869169872985df9124ee582533095da0ea689e0bf5392d27cb657c6717040265b9758fc80c76089f4e7d45bbccd3ea38a0ccf19419a0b4fdc371ab67fa4d61ad0a65d1a9ed59df2f0937aa0428ce3aa580a0206787b88e74eabb6174d3720a5c3e8bff7175f074b8799386bf604b33ec4a9fa05a1e6746cfb6b2abc45ea7fef1a323821bd13677353b11ba1d33151ca4c9bde9a0a28021206766ccf6c362a479d78062c6f7e08e87072387ccd3f511f79ee52080a08c30e5239807f0b5981e6d2fc67e399964d48dd61c8624223fb5d30681967e1aa08d0f19316106e736367545c22c092e975fda455f823b9c31452244849106732ba0b3c1912d57f95fb60ee7190553df044515b9b4a515a27963f9d255727c45139ea05995ea374f77c082f8a1a11e172d689579a24f0b30b09b9afdcadb288ccd4bfaa043133fa8e729d429cc930c42f073ad308b68fd9feb1621954115fa8b7543959fa07a166b74bcb18be0380ba88fc09b516815e8cbc1b7a2f8b506870c71542aa92480", + "52abfaae552517380d3072cd87ae415f45305f4d42f8a4918aa91b76a496aca4": "f901118080a08d26a5e8227c9e2ce48abc151012518cda9ba6b875e3a49b66c48235058c4921a0c9928efbc5442307c3b51d5d1c20a78e8d543a6362b7142c266dd7aa46db917ea0e8fa101db8a9311808076e0405644852e7a45707ac57d79212ad7a385496761c80a0ec7101039c64a4cc3fb093df41d6effc8ce9e91b3ae14b53043d91aaad5c42e7a0b7623015aeffb524ededf45dc702ecb5e61e4aeec17dba39e5e8938834cfaa0a8080a090f0d3e9518598dd6be5b14154b228a886ccd347b85c6608819ffc9caa481b0080a0e7df9e922b8f5feca72dab09bb086d9a3cabf0cf03e4f95f9c7b9c57066c66b48080a05d997e56d4be69a4f4db0906e03aaf04db963faca8b32bd1717e119cafd6910280", + "5311b8f01659626cf832f995300b736c1bfc24a43c72d2922daa0fda935e48be": "f90211a0c5c139fe2c800f05b95ed312443537c69dcb246098a9f16186211c84c365fc1aa030512ec0b6732cf6613547257201a09f917ccdb14402def14a5c32f3172f85dda0263cd07ff7dd1cc508db2539cf3293f9a2d01682800edebdd9e839c9d091f25ba08db307c8372137ac750c62d3bb1e34451f71974f88bb34cdd4c13b5fb78d2ef7a0eca20a151ada80499afde8ae740dccb0aca77ff53c3c1f6fd5b767779c11dd19a0dd7644614cae4a6a8ec8fab813ffde552ea3f67d37fa39f1511c0ded6be299bba066217a22a3556e32c90887c25445c2668413aa9307b8544e17707f868c3056cda048c8682b93c11babf440c77f107e1cbdd2f0771980ad3417ec12a9a58a5e12c8a0064f7027b911b948fd2c75da2e863ea0eb725b582bb457b17c239e4b3c966007a0e9d982e035d7dfe79f2725ea924ec35b8cc5fa32f21e72554ad4e597829d649aa0e1081ea707a660ea5d33210344f099e8643835d1d5ad69c708696b2f56cc1069a0a8bc8092a8bf6f29779e58169ef45de42537adb401821685aa884b47dd51df83a0e9fd09771895386ba628f7c3145fee467f890b5ac4d6518b9c0182e6a91bb6e0a0812d44f57ba1e61273564c4b0545402a3767fe782000494419b2030779b30042a0018e7df5d6e71e975433a45ee39a40099048f924a69a364bffbe29d05fd4c46ca03492077ed2d7456600fa1dedf4cea038b38cb4b12fc0e8d7fc71377b40df717180", + "5386c6fbf5d564afb63b718caa68eb7265a74d6652dc7bf7aa33fad554407457": "f90211a0d1044c5c73457b4ca87ded35848516d95f8e1c3bb6afff915b2c2a03606c27bea0be61a3cae35934dc9b3dd7f92b15a2ec50a58d9054a0b4d8ec40c5f0182ad7f4a0ed34872238341ed7972779c78db277f3360126021919a1c9a5fb0184cd6473c4a0a5e7f6d696b0e680979d1db5d6cac842abdc860250167a14de6116c11f223272a022390e4a7df22622887ea7abf2a7bb069704f740d8da84f033d75298a1f15af0a0f062c3411c41a41ca06a0dd2b5aae5fe7b8dd70d8f4fc8c7d80e039887f54b70a0521ecfa38da1ba4caa12b09836b3222987ab962a324654fbdbe3ad87eb998fb4a02603f2dfd2b20d5e793d612a264ec42c6b710c4b8f0b6b345e965a3b6a2974d4a085a48db8eb906dacf6c799a2ecff6cb150424448446d62f21c50145da78edda2a0e6ee1dad9b150ffb92036ca07454c4fe9660929cddc386918ad5ceb68f67f1d2a0e819034f8b6c3b1511d60fea5335e8a1c8130d639258ac8e41d8ff583a46bfe2a020530e188d089a82319e4f58a49a945f7482a7baeb37acd19586da0698caec7ca08a4334b25721cae1f3a70dd94bcbb9058b6089d5e0e358c0da30467499139c9ba0e8bce9226ef9a6728fc172145131313760b3ecc8a736e741c1cb8c2c250228c1a048122994102d40472e7d4808ed477d376c4993ca4de034de9cf56a969b779018a08b14ab82a4267fe7875b5dc5ec90e82da9970d4cc030f4a95396c632339599d180", + "539bb6abe86c897995685b00b9499580a23ae7733456a9320092df93f20154c3": "f8518080808080808080a0beea111a520072d3d236e49da3637088a4dcd4c5c36c5348c55f9b4516aafc86808080808080a0622becce00e4bd7e6ac45477725b9af58da4996f36d60ff591962f487beb712f80", + "5494d18a48ebb156216acf5b113eeb52dd3f91e61ee626e1e415c4992cb072d0": "f90211a0e25c2b7149a40f39072edfd4138aa49cff6e1afb73ff63d620205e9dd9780e2ba093f3be049bf3b4284e29d4c9267db5645a48c08837955f37a90d9a250cde9c0fa01f87c09a84e529c99fbe03e65879e892862acfc8a645f21ef754b9ccf354263ca01ca5361dfb1707639a2bab72bf04acd64af0910a25e807a99607fdd70daaad73a06fe3883447164aeeafdd1cf3d5db510487a7f34e875e30ad94bc5291acdf40d7a0da90fa36b0960537b63d219ad17a84c813ad55b7a7dc56c579a684dcb30745e9a00c8ce2adb22de0f795ebbb7c1777fa22bafe853acbf0f8289e0a100f61e29fdaa049ce358613feb163cf981acd5b03f88bcf5960f2d67d42c22829a8991f87bd20a092fbefd5c29c5a48ba8f1cd54d61c7950856c1ca65c1a24ef290729aa5ba5f97a04ea31bb6b8b6bee89d2223fe917d5b296e3c730caa3c07542094bbe26a0e9fcea0145820cc59301cde4af3f3326b663258b26305fc8e76313ef096fc07c3d0433ba07dedc5ddc6c8713d9d45e35981ae25c45006357e89d6cc7fd4395e94b6ebd627a0c98f7908307a282142397708fac6b55ff00a57fa889e3cca03eeb5ceeefd05bfa0bf6fb4259da9400376a4b223a86d24aa714abcbe76f20408fb8dc95030ec07c5a0d3dc523d6bb01eb2747a17841e44b49d721caeeadb8d152b25bb2d85c0628527a0f61ebc0192a353029eb25f03fef179041e081ee3c958d285208734a9d0913ea880", + "54b5b7a05f312eb11239ca33d57d07a7a8c02a090298187795104b4fc3577da5": "f90211a03fce32647fdb83f957b74f1363b6f4349edf5f96f435daeb6637f7140c85706ea05784f4524b0e6fd843a7692c9435579dc0db63dd6dc80bcd34475539156b098fa0093d1ef313df98db53af4dcbe9dd4280858628602b19164c106a146fb5a19b58a04b22526e2f06f4873eff75124b6b29db64513d9054ec7bedf1c88fa665bd6f2ba0e6517b1c04ff2f297604b90dcdf2d26eefb5b6c183e23e47a0bd1a98f15bd462a087f54a1a156eea72f3dcbe7f54a4f3de634c9e84f521fec520026167ce42252ca002ca2e85b40bf909f92f85fae2d468ac18e9131c3b610773a731dc12b8271d07a050a01e95e440f59a4f30ce13ff7b61a0b8e4579d56764b545180ae4d81ff5bf0a0cc90cf094d5ae1122de60afe18049d16b310c979a8170a07498d3cf5e19a044ba060c56f26ac1db7a4c15ca253506ce21c8d6af1273fef8f5d15669902cae031a1a09dc9e6d32abbeb4425089405ccf5b0793da68618106eb5d8b114b09ba70c0f97a088f363f76e2e0a423fec25a5e7f0f72ab234776d39f56edfae7711fa7abdb968a074bfbac46bcf6c9bb6aafe10080c70327bc61ddbb82c39982e0b2e0f12b04fcca07cf7826507b6e95659296cec1ceae75db3ceee278a7aa0c0936b83bf989675cda0028bee3ad0dae64208da16495a5798421175da79db81f1523e134655e6ee7c11a06c624a61e7df14cb75a09a4a7bc4ac87ee4bf0a8e5a72323bad4f0690185d36880", + "559b18f4b2bc206ab507131fc345b00ce8e02b659d1ae94d6235e2df71b03ef8": "f8419e32800a1213e304232efb47c8e7d833b6fc73c770da17ee5dc21f52e1c33ba1a0cafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeaf", + "589b2230042938899c9cfdd0e63d41f8623b07e195033477f127e1ef38efc4de": "f891a0439d20d949a0673a672050afa2f2d162ea871d7fed46b7866d4e889a6f4d21dfa09bc7d67116e54b7680af768ab4911d6d6de7902022362bb2143db522a4c61fc680808080a09a201772b848a2731ed6c7ec0901c2cb3607a9bf67dc92ae651e0418fc81d8f2808080808080a066e6e9071c5f5a89d8b19c971bb89333e64747d2bd34c72d0514be3b76999007808080", + "58c7147ba81e83310642bf04961c3c86d78d8083b0b61b0de364ff7806bdbfe0": "f90151a0491bd4684c746d5c0c55b4c2f765dcfe7068dd484824df57679324f15ca1962580a0ba207f6c4a2b8aeee05c1f07db1090a24a8400b12a1e4abafbc7e8627fd3a08e8080a092bc5e067d52a5d08143fd5d61d007221a3a438174c0f80638b417fb082a64cc8080a068a58599246028ea3b7bc22cc257a92a4c9d93a7b4300a4f9d50f7996fba68eea08c3b7c185ce814cbc05b41720b9838f3dbdd5ecb475b4bc09af96c3453a03dcfa0c3a8f345dda4482ff164f60c90de6986a2c109e333a4c88dba3c3a5affdf4899a0855acb118e7759585a74f3be53785867a1ab3b80f7b2a0f2f1060d09f4762f6aa03b1823567c9d2bbfa40d868b1fbc6cc50aaa5f68b5c1a9bb18b99a3e9c8601b980a056c63d8ea16d0ba4ff3203b2231736716d18136df900245ad194ab2f4cb50c35a050b96b28421a43b9581f62e44ebcbbb8a0d600e0de0b278944ab34f08b684c3e80", + "58e24a13e84452e9787f65cd823850a33ce73355794e9b166c4d2fd4a1375344": "f90211a0eb5519d63a3c198af4978ef69319fe72e73c747d74dbdf1e4210070e5cbf300da06f2f5afa81f9ee9f8a6173c729597b9b2bcd7de9d9c3a6953e74e69bd0600227a09338b3f075f76948e5c950ee173a66497d6d78cd5b62f665e103aee9c6f9f041a0daf85ac10460b918c58401187ac8abdacf2c48f928e32717b0ebd8ed18f9518fa029dad142a0454b0f7547f17eb674a47a413352831c1c03b4c0494ff060021380a0611f3aa464a7b897e5358366cb7b72b6c0d3bbbdd2e82bf31ea08c802867d92fa068da8bac885860d34b07e3873291f94827b6936913c13d001b713359b86eacd7a068b6e4f27d774e94a3fa0b459b40f871a37c04861c86193bc73b526d5a52ac85a0fc020c83d11c3d97cba4a9c3bc5b25c5e8b2f23b8f81844568f640e6127d8ed5a09cb38377affedaa847f00cb59fdd07e8a643f0beaa8320b9f0f4662afe91c9aaa0872d835f976505a1b621f207dc3c7bfcb93c59d001a62d4b5c40b2138f4dc361a094caf3b5d84a74040ecba1fcb27ffa101a25954384f51e6b6c9425668e2668c4a0662757e4c03dc5c51f08cebfd6689491066c8ab88d8b5fe7541510cc8bf8d9d8a084c3dc717fa59d329f55d5396593f4394590f7fa91ea71a52f787822174eac5fa0a25d976773353f17ffbe2698b79621602af32d546276962b4162145951b70b2da0c1489d10a0c6aeb862e253c543a336e0c8023defe300c927e801b44491e084e780", + "59d47af9c489bb7e4e66e703986f385ffaf8d4a49b5ed81562d84bbfff7e88f2": "f90211a06587e0ce70c271162507560f3fe8357dcd9abfb922970ea0112773b3ab181ae4a087aae9a9a4190a9df5992b87af64a5fb689ce7241250a7ab13c0ba9fefd0d008a049cd353b63ba8c2de15bf0c6a698a30d62184cc9035c9d321af1533284cb857ea04c685b56e82c47ac7eac221a0aa7f471a00eb13bd534e243e3d361c6e636050da021f919bc5dbcabfade5deabb5aabfa25016b01714207c3dab7aa5d313a1d8228a0a2be317a29a338e58f63e18be36197742b1eb56d5786527a588b25553f8ab429a04539385b52397edda383f91cc5853ae137ed91919a6c6dd1d1842a690ea45065a0e2132382e995c7150086a0148b106ca87c28aa544181274758d1fcce0d65c06ba02d3c6623d5429802bdb571a7c57f42c9a31f6e94cba541c906503c997c505b83a0977c9ffe44413eb6e390cbe0d7de17be6bb726177e64b3a0aff0e60eef3ac8c0a055ec2b071d2df26782d0ac326cfed5a2594afc9182e77c8808c1cf27632cfc74a0b89321d9ec2ba39e9167137be346dbe9132f8d3cc5a025bc48943b11e9040679a0f9731da5be992bdce76170350f290d9d754195f3926fe8b4b65d2f9c051e9a1ba04fb7e26a66fa75da7b26e158a7c003231cace142c8fe68917924dae2380fd1f6a00c77001d6d1985ae2510982321997556e53e955e662c3ec60cab494de0edd6a1a0eb11aceaef2407aba6f846702f2795ad7e9182e1fec9344943ec4f4a2f89985680", + "5a4100b75834827fc8a55e32abb5fd6f5aedf74d5b1055c12743700fc7a18206": "f90211a0d3bbe3376b92b6322993da253aa69e39d9f5344732b705422dfea87fac649f10a0a29b4ae49fbe59924168914fbd82a6c61f6fb574aa43d2afb6f8159e111bf5c8a01cf524682b827b31fb2321c70a969366763ddd8112753cf0193a69c3d600462ea03c2c6b6895188b04b1601c6c70ae0ddb9f2e1c1e1579628e16855fb95c6e56f2a044925a8294aea7a4e269d3ae853be02d947504b8389f611a24fb6cb7c7a11dd7a017ada36fb657646e324fd8a3eea0d387e780c704a7f305107c4bee533423450ca0b47716d1d566bb445b41cf129322cefbde28de6a7d98101c83cf481e868c28f2a0f04c1b30b08d02fbf08cc17156f930ccb09938832607b112ba09c1cb64cffe12a0c05abe971fb1959f86d3d8b47ab6c9ccee955a19c0ad0316c2c1b403f9851530a0dc5aebcd769c01a865da8e5eb48aef9c02be17d9267c207bd1a105d6fe3a3706a09fb728eda131abdc60edf9c9cf4a00bf535bb3c913217c2b43bef5731a2fba52a0689fee743e2e01a9a81714d3524c0aa170a4163241b9c0061fbdf66aa13ebf1aa0548f261effa03ac90b56b7e970d3e3c9dad33cd9d72faea04b284a0f6bdfd866a01c9948d151b07a91d407ea823084052c3f4f78c564b6b3bb38ca75ba007db55da040f59a3dce51501a8b5afd7e222e4b1b3bdd9429cf3403e5e791043d8c7b532aa005a38abb278959fea63fd4452b436c83e402063bc493c12e6fe56fc0730993bf80", + "5a917fb3dbd9dd806934b82b250f1cea646f4d4ec022381c97e0a506b4c73b1e": "f90211a0706add3c5d7bd3dd79a7e4ab0b5203f0c32c52181d8f5fdf7fea4daab87c6b6ba01c70928f08cb19eedb842436d0013a7b8b013002c9994602834bca6a7f581f62a0231c0b517e77d1c5e743e8f6a81ce899a6728cdc4b187bdfb2d6bc005b547c11a02a00caca7e5ce0d6eb5059d6f592cedc5703e2d6a5d99ac078b9006d3e5cd24fa0aa16b58aa281969af6e13987ea62cb2df75d5b2eeb06ecabb681ba555bcd5d9ba06ffbe55bb2478df414a9eb34102e28e931a52b168f06cf56b961112c0265ba80a0f48532548c579ebef79f3ef571d6e03af5946fd51b2b9e1217b73caff101ef68a03b9fdd211b405516a2d58d5b9fa30161a318808b79f4cac8783f1a80e7669fdfa0feaf7db50a77624ea0fa9a52bed67af1e624c342a4e1ba6e67de936f7dc17cf6a0f347ed5e8da4b5a0be39dab68e6ac20c742dc73a5c82b7eaa2f7ff61646aae4aa0e7c7c6621e55803152021a4147dc4a1928fa9effb5abd23d3baf1c9bf0cb0ec9a06e9035aba6e69156dd5276b9b6f7017d872047a3ba65e2afa397020eb25e6ce6a05cc5d050b03eca4d5c17f120be6cd1dfdd60008e5e6dfb620b58a31e496f7070a00c3b255634d85335fed60e7746eb2d425610107489150291e70e8627f5106e84a05c78250455faa148c2cb9d97a3c929cafa3e7c0816b32270a6535e41bd26018ba0e9dd79c8801ff3374c753d9f652459fff720af298a8b7914623265fec3ab994480", + "5b3d2f49cbb9d1c5912b4427fe5c9093494b1f51742491c68908435be7f64a7d": "f8409e3507912a1fc64b16e527119c3941d64e6c1a0190e0b9b5bcc3679de1e5c0a09f0ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135", + "5b8026fb6d9565b902fb36cc76a2e42520af3cd4647823dd43b821648adfe5c2": "f90211a023895ecff945cf18c67ee281fe470ce88724393f30ba3f2bd8d525f21f735b95a012300ca909454407a97d6d0ead7ec82789cfe61e59495d9d0c547de291fd9ec5a009b90b18ef6c3ba0d056d6f4686e55dd5a023f211f4918027425258902b1deeaa096387968192aeb51b9191930d662ffa30cb09265ba770e67762869d934d94505a0a5a23e921964fcd395f822cd13602463114cc8ecb3687d554b9a26639918c193a0cdda3b2eb952a9ab62bfd102377d10acaa9a3bbe5fa840e250e064f1e16be525a01f22c169b9f4d827c0d5e6c63cd9b1af2d1eba6e7a5320688c7f7c1c17a33811a01fbcc29eec852e0a5f45aad7a2bc7423626c40f130669a8724dcdc30c82a7dc5a0e6e23187ea2558fa4176653eeb457afd7786ca98a415b9a04872f15f7f48466ca0917aa551f69402acec8ca30fff4700b423eea909a5123f105f169c424154a6fba0d7353ee8bc94bc999e2a11e432bcf8a4d9a1e068f5e4d57c29e88306e460936ea0b79811242d6b5b05530f5ab13df4ba3288c729127a334da034bd9f8e21b7f4f3a0c7295f55f80b2bbd067b646fc228af7f24e2c3a13c24278e3b235bc7db4cf2ada04ad57bf11f356611e732b326b870cc58d5a9f83eb6689f3fdcd61ac21b3ac53da0a26117c6de217cce807c516ae7dc07438e7dc00035a900f1269f169c57e46bc3a093edb0e17d36cb5ed7c303efa6437a6e7762b5a8e748dd4aa25d6aa84a89c61680", + "5ca34b98fffdec21cf5e17fab7472fd990dd7a21f47b7e2b1477db7c6cd1677c": "f8718080a0077e9d8b31d0cca8f6c1173321c3f7f544a948ecc722a7d9347facf76d0c5f89808080a03c65e781ed7063e63eae50321fb0b3a97542ae989a6503a0f6ad61e0afe0b714808080a031f8c65cc2123e5094b65902a4592ad4fc981bccebb06e1f3b5679d380f6f3b8808080808080", + "5d28fdfdcf1f717f9306d8b47c1f1783fb1145865430f1c81c9564886ea09f62": "f8d1a04ef8478a52dc8bf1a586feb63979e45b030cbc9f032bf6dad837571ac825f462a0465595e21639901aec01b531e32ba4242c654c9b98247b19501f2226cedd90d4808080808080a00061d728d5c92a4c9900923f5dc512bf5a6e826b0b39691cf7116c57807601498080a0aef8eb2aedea9399a5dfc37e8a8af79229f3698a6fbf852e422802611464813180a0b7301a5693321394c88e56fc8f05f471e0b4529d5947b6afb9d2208f53fcbb0080a0aa16118293f352200f19021d58f11537434b443112579e6ad36ce374fa40848480", + "5f70bf279f3576da619dc1809a9c2e5e114e96bc774109bab9973557c138315a": "f8409e3cbc140ffa848297c614161e8c79ffecd6f41f11a82a0e9e62a249865113a09fbab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaad", + "5f79f37df995cd796c2c97ed9420e68bc83bcee92d36bcf79177733982697b75": "f90211a01453893def0532a0bc5efbd0c6022910eb7f755c0a7017dbebbcb8c611d0ed5ca04e4490c5eb12a9f9d167a2d6a2e62660c542053a2a966ce80d38375da1b6050ca01d71652f8a93211117cf33ae30dcc579ab1a7d654000b10070d224c58524a78ea042d9c4df3a6f6a87853bab7c3602c2345092a081eb3aacab7057491c475a3b95a08ba642a3e29ef5903bec1ab6bbb98f408a6b2c9c86d0bb0a5d750b8b4cbb3287a0209a6c5f554f4da4479aa1bbcc364c32f4456f5ac5d7503a8f67962717cd8425a0e455c9e9c13f83104d5b848239206ea5cacb2cfd5e04cdb6eec0d869c36fe076a04676c068b78e3c1fcb50caac9dd0076a7b401d4d01c9503de8664a29bc22da24a01b7a118f30121123bd4a7b3d1342ed48108420e8b8dbee33608f970fe4f84869a0407826ea8b225304103f31999bd42b1baaf317a32ec763b3136055a6e83dd52fa055116cb6c19957b47aa2526250ae02b21b979ba8fc7d394807a2af9cad87fe1ea04d588cdd79e60140281aad9a52272aa7ebf8af282290b23ae22c39c9a20aad12a0ad3237ad2f7a197dc36506da26f684c85d3a7a745dd7d64d067557ec5f47cb7ea0fccac1597dbb9c323776eef714bdc7e013d0abe2d23de672ee20f1eda5846efba0f91354ab58a5db0df65bd0ba6fa05163bff0902bf84a493bd449e9c6f88d33d3a08643aeca1de63acd548c24d64c37ce0933e6fc73e4c48e35eb6edf3a9f0c03f880", + "6054510ea248ca03e66a9c30451faed45c5d72fd8af1eebd88ce6572da505ab0": "f90211a00ac4a7c23587a9d868336e2d81f876bb02da0a00c0cc8a18c798e0228d271127a021abcff76a755696a8c4540529459db6e843dd95fe69a96a02c2f168e1c5a30ba043047d0185bffd48f3d0f12cb108fbf3a37cc680733431fd020d80acc86c0941a081c1b66fb93ed3bdf7383080f30d1e46216238ec4e393a36ef1fd5437e2c4ea1a0237d2c203ff8a97e419f8ae28707cc9e790ea4f6ec9d2af6695003ea9bf662b1a0ffdee49c5a0109eff7c53ce7c254ace02363105b9a17baaca3db3f8b0949f1e6a0f118c6405ee680ac2c222ff2368b66c87460ddcc033897df266f95cad77b7997a023ecfb1745dab64561aa6b7d1578d55f1de5deb9e1030baf4247a51f728bc7dda0056bb7f5b1bf88613fbf745bef880e6c9d1479206714198220b0d376519f7802a0214f83acf9e1544e645f554b4de7ad61cf4463e1d404a8278b1f493924a3d9dba0fe02cc23f4fca279a0f0a849be03e8c9ba6514e7e5d76a7fe80f8a900222df30a0bee118d1db9208378150b3de47a6ab000acd40f5b55d26b82e6a4108320b7a4ea00429cd167a4badd884e89568dbf0c0d32983a0b006d89b3b571ee7ac7eb00da7a0585e15ae02b89629267ab0ff0f7de957b948c68f40ed85f4bb84baed15515f95a0c86a0140e4a86164578e4e16cd06efd0e8837190b7bd16cd6072bad07c399f66a01501ab200855812c702dadb10e90c934c9d02d7869a4adf69f7541362f9d87b480", + "60a9dfb7064ea5340ed5cc15b3e3f40a900c8353a49a2b6fd16e437d05e273e8": "f8d18080a0236a53ac6f12ef443b721d7589736175cc26564bf183635e4d2cbc89cce7ea218080a0f0189b215ca523d2f5594a18e5621863d7d8390ed611a8d68978e64e32a6335f808080a0f3a50aca49ff65b7e4cd6950ecdd24be4b5c2967005c7db9e931b97d2fa7edf8a052c7704cf1087763aca4a6a61d1d2b782b883ee4d914150a886cf8ded4de5059a0c25fe80a868dd8a8305f376ff7e9148640364081caa676849e01f0b7851a4320a0312931ed99bd6fa9a8c59aace89e16af131fc8174648171af9fdf752b35f688a80808080", + "62577f3664a5b2a2157a2bee039da7cba8ec8fe53c74e295c7be5e5a5d87432a": "f8b18080a02624a8325bf9a75a0918e486bf9b2acf8c86fdababae4fc6864b23815917b7e980808080a03cc7ab48175454c18cad5337245d7851a1f26b7e38146a18336d604569791062808080a0234edf61e26809525dd4e9dfe7e9f51f06c7c7796d00f714ba819436d30c2e9c8080a0b1f1d01488e5a7b27f449dfaa25b1d068b2fee46573690edf6826214bf89dab4a0a281c879a3e839025195c8412ba538372eb31752a332b3128a45e492bf45069b80", + "63f85c72bebf49533806c997afac15e419e28275a0e6120cf41d46ba54e1d287": "f8b1a0cc04fd687aa8b045ed3f19cca9570d2156d1a0086fa93757bf288f44738d57dd80808080a0ddac20693a5bd90b652e8d297f43ca7cae39991d7616fd324caf513050d75baf80a0aee440b996fd1dcd3c5f1e0ac8fd6de9e2dfd72ba481b8498b2c1606307268d7808080a06ac202a99af6d72d39e0cceddebe0fb7fe247fcc380dd3dac0e6a58f6db67c6da08a9c1ec1c1d40e30fb0a7f7f043be480842aba2c910e515700dd28ce98a96bd780808080", + "6662e3cc8a6169d6fb3bfc0f649960ab09305e01f9b53594e095af282aa82370": "f90131a0f87f6592db5c93caa57967e06fe9803e7adf2e9e78c5761bafaec0bc32cb9c13a07939779dddaa24b3502751e031877cd885900f1d73c2846c9b48d85e91b18527a04affd7899591ab68d58ae8288641ce4d5135568d2d1d7ad1f058c9a45e647b54a0478c946cf37879a2ac6a26cdc77387050830b9723c4583986e6aa535cc22796d80a0f8952b96a671c10c374759fc85af1adcd8d93ee3c9fa5f7958513447cfc2a88b80a0c01c724de9f3184f28c38e6bdd66ce7582aa110aa452c85921dd3ad376e3f31580a01a419a5ea698f832224c8a64df8f7d632b6b0f6691a20803ceb604b337fb8aed80a0780e7c9ed97b5280b829080a0a7bdd33ed9022d4f7baa693c3e7c1486419af9380a0608dc83fc8375921c398ed4489f1cafe45afb806cb80d64925da6a8338337f04808080", + "67759dabaf844e3b0df1d3d6bf5b938b975881f74035551b4f7c0c1112024dca": "f90211a06c56a3c53cfc3c2d37a3938b789e2810885b82d054b171e7e6ce2f5a47fda600a07effa21f4b435d9fb68013d80d53d2dc58cdfd88b3b25532efb0425f4e8bc34da091d05bd82009f99569ce5caa068a10beaf90e4a749b9772d69ca63f84bc9e6fba089afd1b9457008290ccf0888f42b039c6fdbb2f47df1b323c231e321415df659a0f8e2547cd12a2a7e1829cc60245c5db493740d1e0723202a103cf723af9443b2a076969b0736b6b474a0d2f495d5499f6ecb5bda8678b3abe3900c05340cf93856a0fd0ab259aa106eec091fedcb0d6cd920d6f263fec05d21c225b8a4a840ec6f45a042dc57ed247a5960b118e25263ef52901d0d395f09304d63a0ead917e0aa20b4a08c4ab351daa371f04926abb76d8617ff1ae13adecd7d9154405c30b4acb70af4a0d1bdecf9f51ad6e11360a457c25fe0c05d4bae175ef1e189f5664e0580a42740a04878f25a3b582d86695557c0ef9c93e48957be17c202a26ad1bce0e72c9d1c30a079e89416d2e4a9800624290f6148b0104ec923e66ccca16347b51fc5f5718e7ea0a111b357d8d1a6003e96c6019dde23dc73eedf13d1482935b5628757bc12be37a0ab1801fff9c660a96bb53a4d488ffc8587d3cdd1977257b723d3ff229c3e61faa0082b9fa31a7a5b5f90c153378dedb9e84f66d0e00444b2227184761e2a0ed1cda0b9b52c2b23480fd435b810ec53e780b07f89e1cb228d849c30c6aad542e725da80", + "679881e250d50de7896e20719f546c1cff5d86e1abfc4cfe79283f7364ee43a5": "f8f1808080a0f7d023f162b4864b06ef11e3b9432beb1fa5777bf3639e9d9f7c11d1cfe1f3e98080a0db3a76fe49b6563bb26101bd52e046b417ccdfd2f25de3dcc63f435dd206942480a02ecc984217c0f0cce06f4ce9c70046ed025486d69f9c4d0cc6d43d7b6c141e7a80a00f812463e43922a0e07222fd8ea3a0408e55c7a5d4f888999d7b25228505cc1580a0a73d6b7351f50a8562418933b00d2fc4ad609ab55dbd4e69715d5858fea2118ba00fd60a306fff11586eede21771c7667c48392746d9133b8b12e28b00f8b12584a0bf1e3e52731ad105acd7e687dc4960e657d31b3238a56520558101fb3eb172fb8080", + "68155b38777ab0a56c106b8d342e56cc515da6a3bac1fe3ce202430d605063ac": "f90211a0b2d9099274ed8d90a4aa7f34c8d4bd979c5ee280471d4d163e0ea23550119f84a043f96465d05ed324f23ae33210362af4600f0d0e2ff4a4374b0f42a8b96d37dfa0e724ff4de1b3a05b2746df02918b4d180651a36e6d55a9f3b3b977bbcd4f3c18a0a6951f9c97133b338a0c06b89a304b5d2677f41ca830ff4d6a386f9299e21854a0ac5ec0ecef921f06363a72e5b89e609ddeb83f8ea5aff9a77cad0be567c9717ba0f9fd8484d1e7296dbb97eab2e41cb0c13c8632e2ad93042d2b30de90f360a37ca00bb3cd4edc9f905f387e3e5492793eae344594864117481c4867c57490084093a0f58cc91afc0ec243df93ea02d30106e8305d44259502296b3825e863736c6f32a0d3c44a703aab27a6bd4b7face4b7c9a4ac0ee3442cacb4de9f115c56206f3148a0f4084a083de7f6428b9d75d184178f52fe5343ab62d05854f4a77c8146891eb9a0261448377b90b66debbdfd5738e5aa8f1b4068abf933c22907483684e00d61c9a0eb8d36b40e4a7d73a976ad73f621464649c9b92318faa888929dbdd3c1ba3919a0901cc26815774c334fc1e75ebc15f39ccb1c61e7beb2f61dd2f7581df27ba437a05c862778ae63c399ab0e48696c1b688784a5769df23481351dc18091e41d0601a025ab85e795788ad54af4d292f25cfafeec8b6647cf159625adead509028ed51ca0afb26de13662effbe2f8dd309a5580206bfffa3b79654a3926552ea88053836480", + "6a7cf49cb514cae10bdc567541ee924b54a7cfc7596f22fd07f9973c54ed0f27": "f90211a03a5b71c5f4fbcc2635a9219144675f20ee72226b0d33f4e928a733c46479d846a0570cc553a8b1ddd4e04555eac7d15eb7d7fa611783922ae140b51894723f7f73a075e5928bc5dbc5fb661b4b23055add26b907a86d3ac47ab2139723bbd0131955a08d25f3acae606452ecee2294429b57dd54d3897a01fa3c19d536d079c881084aa00ea7186183c1e1bbd52f8081e54c196f8eed8e4fd6e34e704e33a12afe8e17eda00c74075e3235166755b8c72970c98a072eb74f6759470ca1e0ab6cba8355ad30a0146ed512f6d9a718863942e69a3d9eb76b994ecf19d8d4acda5db08d44a5e4c0a009755c7798c429bc45871e24a525aaa62d9649fed091d557c2252244495007fea0225f34b5727b15c6dcc648ab65259f7ba2c2a8dabedcf04538d187ba986b0214a0edb0fc804fd72117aee1d83a4c48a762d2aa78f380cbf3ee4ea8988750311e67a003c1841e894b2a28e87fd0b8e85f55d6bfe44d7ca98af7cdd07b286c57994776a0a2efdb820295ebfd180faa85c2b45ad9fcf1e10a31880ebc9cc3395defe23770a0d569da6cc43c96b00e79a01edb794ceb882a5460f0e4d7b5b0287dcc1d7e0ed7a0a3523d112e6d4f0b0399548dec5fe9dfda3541d92c5886391c6d11306e6ba662a0786896ae90751425d9872b3b824ea1a24ec84243261b13decfd2e5458b10f740a0f9bd43040c4762eec1816bf24bfb6a11fbc3cc1fbbddb7634580639c09893ae280", + "6a9714986e00640158a455c0d49305d24575160e1da41a9410feeb6b8fae19ae": "e39e37fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace838248cf", + "6a9c283d04396af907812ffa7d28b4f06e332a2d23b4fb766c7b78669e0f1bb9": "f90211a0c46ba0d152f58f060f5979ec848e23a5cb7a3a2b50072bc304e35073d80e22d4a04dce61b452744bf5fcdc491bdee1d98c02cf7fc462505f04c5d79bdedc68dfb5a0bd6546e2d17c8c6ac310b26f6408b8f64e7abf9a0fa2dc3781abf78f6cb24247a04b53ef8c6d1219defbc70d0e02187753fb9d1ba27266e60d7a2a297c4963e4ada0e1dee92014db8abdc10208518d2c0da5ef2dd3166d2dbc599d16795de85b3445a0d6fd685310b5b9474459b59c39ba22df8ac0d80cbc05a81d569333d7c0eb9fc4a07f2cee6d1d7cc4f0dd6b4d1a276ca3d41fa08e6813e61618ad35c968c08bd7c6a0d0195dd5d53e37b510c8c0ddbf4855b56503718e3c6b047a761b8a34567c95d8a07b871e348dbaa1a282c71790778cbd16322a21cee52e3c5ac3a75b3b6f790f26a025092010bd9a6dbc54ea577fb29e77ee502e61383e7f621162ea407a3d1dd32ba0b1ad3b8b183dbc21e4fb4c924e56918a7e55d4bbbc4f738aaa031d46e4cc4c60a0f1940301d48d682c95709a15b38d5a1b1ff9deb46c1b32d1d5e1b5dab725bdc1a08c96459ecbef21ce485c8ac96225e1f8991addc388887f08e449a10b6ff8eebba0452acc1076c8a2b90d21c99d77de577ec00632bc968e2e787a9f316ad2303cdda06702471596edf1060297c5463bcead1ecd28c8ce231f94f83d3821459a2e0402a06f9ed4c01c36e7d7760c984f7c9dd810c95b0dd3ee002b5c1a64796150d8fde780", + "6c1b92c85bce5b7393737f0348e12b829f234ea0746c421e3a48974e4f2a32e6": "f8d1808080a0e41f6dcff340ebcd225054225efcd47dd18f89f40284b5c832c880ad9f22815ba0b18398fc7cf3dc531c3731dbce1333d531424eb82a50127b41cb8b319e716e98808080a0aacc0706c288329ef421934f3a2a0bda0d110bbe551e16914c19065ab41b718680a0e02f618bd92c39eae7b2ed2d4d830de5ac73fd6e690332bf85129fbefc175535a0559b18f4b2bc206ab507131fc345b00ce8e02b659d1ae94d6235e2df71b03ef880a05461ab23ba1709f929b3bce72fbc4322b94afe8ccf55e5ae03d606e5f1e86259808080", + "6c2408f18e7d22a962804d27dc31b2f66ae084c67d724589d69d3d3f70b2871b": "f90211a0e4fe8f1a84f1915dc8af3b800de132031ce7b25318626652194a13a98df6723da03e30c33835d8df0bffba182325d9de1c97cf4d62ce0ce922c636235b7528b9a5a06f1b0f3ccf191ac996f295936455b555647959b3d8fc53b303adb9af884a0700a081ce8f68da8deb1df56f994ae1c027c50366081da770f6e4adf44251e655507ca0ca85a6defa44c0bc164d8a92530c3810e97e6b17883d8fea2db29c5541587c7ca0cc471eade157103c4a1693a6fa2a5b0ad2f143e3d438104064b841fbe84e3351a03692b0218d13481b658be2fbb0ff37ce01e009bdef1e012634a3b5601bb74e2ba05d3ab0ce212f1f0a83536b648bf178523b7fa11df3c40c8df6444c01566e326ea0bff655145d28ee93ed7f08e7625f40d004cce0a51901d615be1e27f2181585d6a0a669addef22ac7767e40d6999b0c358fdf6cd8ba46cd1f59aab787040f8fbcd2a01c556f0ef040bd2cfe5b01113b711720386dce1e1b21aea51e3f5ecd85e4f1dba0c5e4787dac75a57162652d49a6c423a2041c3c1df508570071bc5e7bbe5c15fba0dd8e912bd9dd03b37858cd0a7f76d0817a3ec510180bb99a9d4529e10470d87ea0294330fd8893d75fe006a781f86a99fc94b2429434ebccdf813d43639fc0fcc0a0845a83472c2e6e1a5270d88fdab952090e0bebdcdf593e1a5a6e33d483b09c6ba0146a0b037d811e2a66dcc61ef1d552fceeb7b086d607884b293015c6a0852bd680", + "6fe3883447164aeeafdd1cf3d5db510487a7f34e875e30ad94bc5291acdf40d7": "f90211a012fe117f885ba44a47ead5b2598c1a58355d0afc5e74a26f29702774d1af6610a0f3b1230c6b239ae5fedfbf2e5cf3308ca97a9e7c59a952e091622f4c9f5ae62ba0ff73b73d39984b4482ed458dba0dc2d7f582a51d50bf8afa171e18b42d5ec3d8a07a82bad662fd8481a055cd1f6fbfd0b81a5c5b12c01d73994c9143289e0d909ea0617730a5ecf60470dcd4138e4e7634042e49737326c96bf8255598a0bc364702a0ce40bb6d2876169d2920dcb793dd74de492b1f2d02f83afe8eb699ce0b338dafa00ee4ae9e8b55659a0648549c9b035f18c7d4435fda20f4a513e4304e8ded003aa0cf46466ed63d8cdee49753c6e51555468bbbb538b3aae10da9d7638b745c10e1a0ff9e51218e356dd242d747c8b7613f7f48f37a52fed96ab815a558afc4edc991a00fc708d3e801941d2f5a369019f4e8126d6e16f19880a467e37cef4815af0e18a054cc666991ae1c525ef21f07065005b3c91f2bf8534af2f2f8bbd0ac4afb8fcba0428b081a94417ebaeba962a0b896802eef99e7689365d974cc997afb7d202dc0a031282adde5307e899b3b21d93a54994fcdce8c3a8320cc8fd55b14d270ba95bea0949d42353700f91eac2e12999d67e49d1d07c7aea0fffad02be1afe33dfa317aa0ac2a657ba9337ee60c6bf83775e3778166d0fc6f5db557ba1067dcb0d06885d6a0b01c9af44fc9d2d372cc996c7be08814021f37d090c2cfb446b3dea84d9a8a8780", + "6ffbe55bb2478df414a9eb34102e28e931a52b168f06cf56b961112c0265ba80": "f90211a0baf2b28a6a27cad6abb4bed6e5de7230c71de4ec14af6f53c62d0d9d0e596853a0396cbadd566a7188a2f3da36ca7b18265ab2454113ca0e339ac02bab1cf6c7d8a0cc84727abcea7bf8e56435d797657cdf143e9ed8278e38aa19aeeefd8b65f49ca05c39d961998763557e7f6f2ee04b941bc3416c19f224922398b7ba0a18661bfca0b09acf227040d30daac7b9d258edfd3dba8d98ff71f0f64b928c2c5e3da26b7ba0bdc92e374d2f792469673a0011e76b51a2a39ea9654a78fc0a3cc1b957e92a37a073ed66654e7c4c186d83c326cbd050c441f1282efdc56d9115d97c18d5569ba0a0186f17dfe735180b96c09a84a38098951d5c4ff8d8aa8a7380f7a72577a108caa05d0b02dec2f5e051b314f90ede5dd42052532f3808d024935bf189af11e99a42a028bf83ae22a5f3a1072a4cddb0f14c1837d341f10d1c7fbbab20d1f01cbbd035a0cc5dc99deacf55ac3d75a56942c61df8fab14a7d58ac5ed051c0b180edbaf1c2a05a5158a3b25cdfdaae8f315133337163ea1a0f91dcaade5f38df01a4a4e01104a049e3adcb4c1ef3cf130ac2dde1baf9ec7a0123717a29d1ab08ad1c6eecf7b2fba0fd00f73dfda52da297067f8f8821d95f3d777a2ba14f262ff9348a5733ff7258a0752e7eac9c60a9cd58c59e75e913317c36cea80cadc124419fb4b7e1909525e5a0502be84f79218b7dde943b7c3fa264dd632fdb0baaa67a4093f0670e31e982eb80", + "71229f863681b7dcb6fa1b011a3ecb551db477782a2da44380d05d66e3cb2b0f": "f8419e3cc36ee8235bcb4bd76383bc714e7b0cd4e6e439855daaadac13e0d7c2bba1a00b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabe", + "7345922d5b77934f54986728a7d9f45a8eaa08ac4a8d3748e4ef036cd5d29ad2": "f8419e3e8dc505c565004ff0c79417ccbe0ccb936617507d43642c5da141d0c1bea1a0facefeedfbadbeeffee1deadfeedbabefeedc0deffbadd11f00dbabe000ff1ce", + "73688f1853da9869f39e9ac69079ae097aed51539b44c9698f2e79fd9c9092af": "f85180808080a012b39091db6c15920e4fa4d011b49ccd95583a07d40475b446f97bbf22015a4580808080a0649a9dcf72af375c8a8cef1d3dd946a59cd674ba3dca52ef6c049fab9e12176780808080808080", + "736890168847fc28b2bb10bac44eb5010a7a2d51da18f0aa2db63fab2e5ae5ef": "f8d1a0af0d17837e8e349faac4edbf0025cf2cbc3309eabd3e121e240ecf9155c26cbaa034fb87e29438a1fffa11b93547e8d04758bf5efb223a2018f23d7e82f89f2a4080a03c576bf8cf3354c18daf2a8a0c2ea1e06ee36bb991c18e478115e2fea70f5785a0fbb671d7812bb1e5b321f925cf5c0feb9f07e6e9c51b74b701dffdafb41b0359808080808080a03b75383d80cc8337be3eb2ef685f24e2270102f9a5cead245a7c68a391f6c6a080a0a00fbe746954dda652f57e0697e781cd7fc9f7ca842c21d57df3f48063e744d7808080", + "736cca1ee36169cead591cfb85bf3193cf3eaf0618a8e2fcf0a30bec5eed727e": "f8918080808080808080a0008c842f7d9bdb97ef01a4ed5a7240f1cb289b17fcf7226cbe90a876ff0331d9a0a975975a2647a60e9a4699dda7a3245d595e7dfd03e39492a03d9d989d0b87bb80a0de5c9be9e7106d79e67cc080b0e769d3b1649501dbf6aed00e26964b867ed90680a03a1cae0f0f4dd1c6ec3cb204c506ce8683d20aac191ac1de5b7e225dbe541249808080", + "74b7181a85d773c8f24663cda8388ac6df8f5f56cf9229dc97f7920ca39fbc18": "f90211a0b5becb50edbd55ed62f7b8440a4a590fb3954f73a76c4991f7622e0e412fa236a0df64e4b9404e985cc0af4cd6503e29aea305e504b59eeefe52703a6e71afe421a0c04700525cd0a1d86454ed97c41757b61dabdd9e2638600a256304164928ce05a081c04829c1a1be727e31a218277cc6f4fa81194ac187bdce597be58c4c95cfb3a0330d05bd50bd3b37e309ad9b2dd9a1f5464b13760bc03a5a6343dc7fccf72eb5a0f4ec1e678469e4424d59a5acd602d45f638d52aaffd744f011000105d4ac8762a0eadfb0149a5d30729dbd0d70ff94bfe45cd757bcb122356ece8aa151eb1e1a76a087aaaeea20c93567ee07ec8360304fcbca0f4880ab6f84852c1659eb6dfe5024a083f81ae990e593ab5c396cd54d79f13658f9e93627b063c96339ed0bda558ccaa09b0329c81f07d2f8bdacb6ca51683767e974f26c94467274181a5fda52e9f873a09e340c711c5e5ac2d33c797c3a0090c6706313e1af8ec16fbe4e5a8aa8894eaba074c3845aa04fd27788bb27836bf4b138b2acba8e83b2238555f11c0e7c668fa9a05a917fb3dbd9dd806934b82b250f1cea646f4d4ec022381c97e0a506b4c73b1ea0cb3dc35fd95666fb836fd4f275fe2f8e0de6b0f4cfe5cd2140ffa7105ed1071ca0a996f0c0f7a430014ab94072688eb7c1d3d6150b55519d71e6d633aea01cb26ba0e6da914f0eb30efab6765c983d587081bdbe7ec95e9633afe1862df21c853d1480", + "74c1aefb3b0dc4105cbc831b2380889af471739d63190e9f5d0303f87fe12e4f": "f90131a076a1cfb5dcd3a2b8b184f28506951ee16435f2a78ae3e58738be444b33d701f4a0ad3aca1c5880013fffdcd73357113ad0baf5f0bcfe82f0f96c1e3b416ddb045ca03543b0ac4269ca559a8b8bec2e2d468188fc05ab29d31f48f73fe7dbab9c5f03a07de60303c5c86b10e445fdb0a96c53add6485de77cd3e5f65eecf08f55a3314a80a09a2d5e2ccefe7e5e487b1a56cfd784d03f4a74ec0cb6970a5c4cfa8f523e79a7a009935b3988afd1ea1babf786e785a8606e210f9b148e8e73b4c7d295dc920dc080a0765736b731e4da2e99bf0055bcd28745f7fd48793ceb69e3b7cf93c0a0046a658080a08547453c9ce3c9407da13d79821fc88c5fe60460c10a8a76acbc3eaf2e72cd92a0644aaeefd86245507c1e26bc80dbbd9b25e7ebc6282a5164a6872d0e290238cc80808080", + "7557c94d2d3164e3e9ff6dbcf53392292a8ad291737332cfcfbfd9732375b7f5": "f901118080a04cd66d1c5d124150b115bbbff434a07ec6cefd54f5e7d8a764007f67c20be04a80808080a0f18d5aa1e12515dbda7d0e82a36c4268ece16436967482f952b8dd673d44b808a045478b827a770a1b4b76d4fcd876daab328be435501c2c21612d3898b1090165a0d1c0414c52ae15a2a4f170318a617e0039155adf696bf6ed5f434988b42910cda0f14b3e405427c60a91dd06294e81549c23960eb99354e79cc050edf05ef4b7b3a0f4882736bb1b9b8df6eb40f5c955e45aff89dec5a74161ba284b1d9102c41beda022a437d8b2571cf4c3d2b2bd42b4d896610cae228573689f17a7cdc26f54f49980a04b2a7aae369a6b3022afd09b441c9156f81526274accb30b7db7bf799c3d71078080", + "755c433a56f18522cd8f0a0310bdb1c4c8251481f9c54fbfd95c94b8de5d6b57": "f90211a056e59523531d067eb78e624e5726c1b6f5fd358da182d9d158e2171973c94dc9a01c228408d5096b0d7981112cb19d091075afae2455c9efe4184c0ce920cba88da0c4940bcad4d98c735a243864a3205f3a376d8fcd680810c2f0db4dbc348cb117a055acb82ee48cec1ccd8d34cae4bbe23215042caf63899eee3124044c3a1f0300a0564b7ebbf7ad387632c995837a6db290e8f8b8efd24eea8b251105b50a62e4b9a0a0ceb26f746c255af4ece54c60886148fbe4028544da65fa85551dae38a88e4aa0d9a4f4fab214a55e00f0023f130749dfc7ca0ea13b490d7cedc4c486ef9e4413a08f7fc94c386df03ddf511d5c895e4fa3907b924b6754c7f271ad09bdb5e89448a081f8a92f1954d137e2ea3a262b951f1b0444253946b140dd3596ed01ba97572ea0423e085028db8ac11f1ea2d782df30bfbba4645d75ed5028ec4142e525c7eff0a05a3d7b5af4e347bd3418b14a75f0ea36f1d3d57c25671353a205288d4b923b2aa0be454dd57476c823ad12466d95b99e10a2839e25200a0ac0ba12a968d9eb253ca0b48c00a0928e1249f862c2f29eb998471f685a5b3cae4e4aec8e3bca13a097bea0d54a8d15ddd0aa4aa4099b33385641530f64b5a61e419c23d628ee0966b1875ba0b339eb823f8bfc8ab8f198d4ed19d4ddb5ce3b41b0c9c0178b399aac76715954a0fd2e8eba75b0c3d5193c7476eb6dd1b3bbe4d30783c6445ccb5e6dd1c5a2845380", + "764ce32d1a586bf7505d0815efaa9dc8b56b084e9c4499e3c5ce98a4081c4608": "f90211a023d1d53cb8ca4cf556363d4e7ba23a359feef8d4ca26478a3eba7614dad2dc54a01ce1dfb27f0e7e91829d6546cb94cedc2cc9a251d0745b132bee44fe1023a884a0dc2262ac0cafe5ca810451e64ce444e7b387358bb84a8b077d504ca4a3ba4f63a09835402d3489035116f956e324335bffd241a5f82b91eef98b6af7ece497db70a04114768837b66885e30402ce3e11e74f8fa8a836538db2f8d8fe5c30dd443e0ba0f294569b57edd4aa3d83bcc69bdd79db5706b11aebcfbeafb1e3df66bf46dcf4a0ac465f2063b68d167cba3e4ee5c9bf7989675f46db8103a38e4e5157fd3bc21da05441a2c290c22aa815ac8967d5441a0d9026d6dd9d0c56dcc8b5bdfb557545c5a02a572fe4e0fe565a49901c166d61f65d5d23852cafdb4b396288d40f0190b54aa0fb79ddbf41bfced108b8090924fb4f5894b94bc579b72187285659eb3275ee95a052786d16e5414adda2b603890d2b94dda36142d19d02c6b114f57f1a39aef5cca0755c433a56f18522cd8f0a0310bdb1c4c8251481f9c54fbfd95c94b8de5d6b57a0aca141351b47c5530f7b23d4bad49389139de7392478a9cb2d4c6f031059cb64a07ff8aaade805a20624e5ed35cd0989171c3ad04f9178cf730c2d288e0507787da0abd9d3ec44bc5d2068826517627794d98005456ad6c30e22eb9550c6e1a2ddcba0ea0b5fe9a84ac21f1e5eee73679f9d641768a22cfa95424b5c43cbf098d19dd280", + "784141a1f17e9dfa79ab10c48df5d167645dfddb05daba0785f001e58284d2f6": "f90211a0a2b233eb5d444e7b2141b1f335683e2ed100f32f9b43787b5ab6b79366e5bd83a031f0be93927dc594c89d24086484474b4fe8a67ffa3d5a9e7a51c01d7891d9e9a0d8d738e127563eb592bcc2e492981e2a54b1fc2a2eb8eb1fa83158609828067da03e0f8af9e9c7bf8d1a4eed4ea541ed39e3350087a366ada761e32f15c838b066a0204df356bc5041369aac0c46932c406c1cf0e2f8da6f279ecccf0f8fbdb33c13a0d0a43bbb5eca93be28654e3169694b1a4b3ca98da06639f91b6644123613c58aa019815d0e795674d61df9193e4a1f87d6b91a564d57525c02e0cacf2a7c71ab63a02d6d8e4a0ccf938d5747bda9f93f901ebfdbf2b69744f50db346de84375f1bd7a01b48fd9aef0e568a338d2b1ff4d78706abe67ea2971972554926715924849aafa06f974400990a402e1fbdc6273901bec7a7a0815bf2207fba70a784d30f781a70a0af280be0be5b6bb8c3272a3acddcdbdd75e4615c2c3f5c7b2ac4854a1fa3d0a0a0d1c498d35bfafdfc1b86bfc79afaed0bdd875383cb5b105cda9155dd1d81a408a03595c32bb80a00b9517b4481091141355ae77e8a81811ed751db9be5f699db3ba0fcce16a42ae730e0660e22bfbf4501dfaeb0c40f28e0ab6c278e1adab478e170a0b082a4b3dbbd0c45a33c0af47dce3c3b7f2640c27f1f73d5fcab88dd3b066171a089a7f1ae49abc818fd35783e1f11841204a1eef679ab0b1e23887157aa795b7d80", + "7878f4859c33a0ef095673ef7b6a818d7d523cfd55a051fecbb4f6aae77e42a8": "f90211a055c7267549b6e3171726d8b1363c9a8fa153a8b575a84841bded1dbb0710b3faa0bcf934f350e0309dd0188a7077a40cb42afbf169c186231e88114a03d7c13181a0342a51013ed54e26f78f278a438a9814b054d0273306bdadd46783be10c6d783a0964bb24d9794848c141b15ee8f05c217896a9c8c443160e7855b3d4a96f50792a02897010cc08a86c7e5c7f73773412002c57379c020501109651f35be8d46c6c5a0027152b5b413260ad3aacac46b0b9f0ead1c8a7e51ad040fafb61e97407ec45da0f256e8bd06d5083788121d2115e6ae4ae4cf969e5b67e0e23e181271997b63fda0e0760601147c295da27cd8936fc25bbdf4a288855b35e2fbdfc528587fa4e6a6a0eb05ac041df17cee28a856dbeefd9e220db430eee470ed015119def96b2bc80aa09586c7a2665a3b38c3ad63e1fdb0f48e7144ced71e8ead6e1f25a2471de2ec19a03626920647169f7ad3b7134095c839841ac8d812369b4bfe5f65f40600e720a8a0fb49cc6e4a739bdf6cf1f2d159485577383fc7289a29dc064985af915dd207d1a004ff10360efbd23ba2c1d0a25dab9f8ff7f88a6aa545e294eddbb3a3a8879b91a06a552338153b1e69b26046d44c2dac9d6dd310a3f8d211d41fb186b2711f29faa0989acc32d5a80a6135b90f65561cea67082aa560c69d5b609e27fc02d0180c89a006148280c6df9f5d39b7e6c687b4fae70fbe889b8c3069e3dd79b7a2b94ff3db80", + "788431d02e7da5d3471a412a4772a44e561e2ed990510d9a021ad715978245ee": "f90211a096370a289146721a3eaa479da457333f9064b77df0f9fea7a74794f128888f98a0976cf3a85a039ae53fdbe2026f90aa5a4faabf723623553b587cabe880f59c45a0d2ed7b116efc5ad7d400fa446ff001294dd9af31e8ed3a0000ef4eb59bd3c506a0015d270f3764bf8ae4eee0a546ac8ffd49b0c9ee885245df980a0c4e182563aaa0064ea4a6dc422bae4cc451cba5206e1899e3ebc4db4c837ee964c3c9d4f083eca0bd5f777c97d4551288facc0981621537b48117007664335d380576c77323e177a0046979e27086accba57edbc41fde47f6b531a8f5f1f8b8c01ec2ba1c7ca15638a0e17427f1c4d2e656090a325a3cc1b3202b630b9be971ea1650bfedc60a4dc0e2a0514893b7f39591ed78724944a477d3156d7987ca38a4cd5603089c4c432be4ffa054d5a95591c88b693c68b066ee9bceced8eee12f74a384ee539108f23027ebc0a0afa2abc2141448a5b4b14e98d1909328965249a400d7b26b9965c5c4d375fd9aa09145968967b9837513ec76610f58e9a2820965e49ab639974d32a9f8033e1949a0ab497fa5f0e759cd565fdde5cd5e2110ca598b8da2a411e9fdffd3383ef608ffa0554a1a759b5d925d17d46008936dcd0e6f0af04289d221ca63f7875b1ab7ca34a011dbf4aee265f1cc415dd77e94584d08cd9fcca80c6d776db6f8311adc281904a0a042b895ee1c8f0cedb1a3254aa29e7414aebf82b74256ca8e5d247b3cb3228580", + "7ad75d94848616268aa277bad1582dac2f26f94d028321e58f532dc66369f602": "f901318080a017a75f7eb25e4e4195a57a01ae89d4d0772056f381f50e3072612929ca659f0aa0bd89c4c660ae2e5e8bef949ac76130268ffdf1ea660d74c142ad82d4538fd9fc80a0b5f08995ba21a777f717394991cc29e0a67b093c56e784054f27374ab4f7c689a0c273b8d88f71529384131445e3c5600114d6eea9c34229f0a5dcaca3f0e42ed9a0929a9ae10229a1a16bde3c9b9d67152f081870419d8bb675bc89d525a1085252a073f72600f8263ed5ee503f36b588fe35b53afd44490a74977ac477ea3c3b384a80a0a6704c6275e7c435e6eff666508e5e15eaec072dce82b9df229e950c8d757d2280a00c434fdf46d9fbebb3ca3aebff154dcb112cabd9303e4e09fd1488f6bf07bd2e80a03414f256221a45959f9fad9c8278a732f7da0415b785fec3eb94da733ddf7c048080", + "7b44c72886f3d3e96f257d1265972ba9616177b5055ee45835ffdc0e627d4ebd": "f90211a07acc1b5e0f1b6dc1e1894b60bb6cf50621054545d8c1054d23fac917b335100da07878f4859c33a0ef095673ef7b6a818d7d523cfd55a051fecbb4f6aae77e42a8a02e176bd85ddd115919c1a12de12d9a38f1c1adc3ecc27349f10761dbcf4a47eca089a00e4bbd52e2476308c9e2840f60fdb3ec22b67377bc29a99547ee8def5806a01ac47cec70bc9207cf87911d420238cfe9a5411a4aa8edf3e87553c97260f33ea0111f842c3a5577cee4d5c1e0955c79ec083ff5f54cfec4c6a5b8f1090afc354aa066300055b6e104999853c24523cf18cca94bf832943a4c0250b7b758e7121502a00d041f59f32422f13840abc96cd49ca3be8cd0eb60a761448effb5a9646fcb79a07a18521ea6fd9a932341c9c474c068bc22c21cdbf17650f851e0982263319e5aa0c47a42fc07fc9e984ab0ee07b7d6ad984b4365b78fd90f17ecb32030c88c70c6a04a50fcd6d85d0cd18f1d9d4ab83c6a3e4070579b50793a96059aa2610bc97675a017d901df3ff12b3fc837d57af2c34751a974d52001512fff66a9fbd51fa6af46a06ad50d405c81b9cf58b427ba3699fa3d6f8f7013a866ff2280cdcc76c8cc2ab4a027f5f46aefad128ca2a1d0d3e6ccc1c9aa28da7a3f64231d276554eeda5b4c20a0e33c449672eee5fcc36b061665f100b55ca6a77cdf5c75a36e65bb7519ff0c01a069025195a19b2726d66b77268618fa69f75d14faa4eb8d23ce77e010053366e480", + "7b9864f4d865fad4c3c4e247fb0b8d8abb6164c25d12d7e64ce47f6cb5c0127f": "f90211a0f94111f1d84fef29de3558c85ded6e0c16ebd3f04a09115198b1e0db52c5024aa0065a6f0536087a23fb15a438f4ec64e8b9d9bc605b257be527533636a8d9aed3a00f483a6d0f9ccf7acadd99078376a7d65b7f67698bd0b3f6f573cbf06d291ffda00a073c71d1e1fb6846198ec5d93aa007018cbab03253fc9535da55183e1b593ca04d54be375ad19482a470e53530789671f174c77fc3f23ff11ebd24ca80e77ac1a0a463feebfeb38eecbdcf3eb2201348ad1e06d6eac0d1521434f580fb3bec757ba05b6b362a57f801afde9006fae514c9f6334caaf2e52fd7cc2d8bcf2d243e9b63a0ea09d0da17792075d7b128a40ecc0e1c76be7f544a17033b19329568eceb91f0a02b67b0f29076310fdf4427222b304420e63b4ef49bfb764585a7a72a6c734582a06d86236473e8839f3ab311ebf07241ce0b33418f57eac70a37a87400fd3ccf00a07ac9ebf3fe5290c272f7635d094efa03dd90e52d083e693dc7f12103595f5fe3a0317b5edfc605e415412f22360ae801df9b034d784668b1ee8852bc9f54988098a0266d8cf6014aa76f86e2fad4f6eabf7a02555dc00a0410d663db3f67d6adca9fa03399e0a85edbd48a6b8fed99985e9acbbb3390d0eb21cf646a1b98cd9d4bc228a0b6b809a7bda41fbe525c9f19a6184e565a7e7bff7520f4f8ded00cdea697f833a07931ab684cc3568e97dd9cd4eecd410a08e1205ac4c0c58399692ef7e0ef7f9680", + "7cb69b6a8383d8995ec6980b2bc70d81c3df0392a01cbff4d63734ecad5535e5": "f90211a034ecad3eaca98a098d0b2ff9c52f4f334450cf9681782559a3c2e3b161a45944a04bdf6a36a0b9beface46ed82298b9750c2650591754b7bfe804c5e3edf93ab67a0b39d0047584843b8e3c00dfbe2e192bf7b66970decefc373e121408dcbdbaa54a06a0548cb0a033398e76ff9310c75139b5d197ab59e6bb876c35f4a9718b9f5cca02076452b2a56867e5b1e8c9a9fc3a75fdad6dc6d6672fd91e2e6f557ccd46608a0838fe35780ef5e57a47c1239fb522ed42500c70f485341d10b86099ef978f256a0358f9742e7e5a0f46fd6c1053fe485fcc47fda33a8bd2ffbf837d724addc389aa09a2d2a2721ffc7179eb6177e35083b989787c5a360aa25c857aefe34f44485c5a0160423311ccb21ead7476e44fb2dc89680b4c8b5d48cd7ec60e44e12fbb2387ba04faf6086df14e26f9c40dfc949abe017364b3b1a643a6b6ba9bc64d37d6f7ef0a06caa044cfb11133a54e31f65ef7e87e3736bb1dacb94e4a4bada3cbd04405301a06a7f5f8bf6fdd722c2181613b96ca286456f1a7f27025b4d81a3b0be0f7821e4a0c84068772913a8ee284e9872b0e1a8f27740d7fd1fbdbb396f5c8955daa40872a08ba08d3d391c051c93be77599ddc7115c093bb2f76c37e72acd60a2be63aca4ea051eee52e4e8c2f17f1f5caf1fe6c3a11b1da1f1e76f957a3ccae3dc82b215087a01a502db3b3427662cbfafb9d3e38927cf67c5080b17babc7b42c0b72ca5f14e780", + "7cec599952f12641e7537e2e25c874393701b133d7980be66f4da253705d2770": "f90111a03e45fdd08931efff294efe4a778f9db1ce4b6db8391925e0d58bba08188917b380a0414b84cb26d8bac9ec92eb7b520aa021e67dfd16fec2d5ae1b0c7a4edee81a4d80a0b05b9b0832cc7fb5a790075484af256fdd54cb44c0433e7a5d6511f402231a7f80a0d54c0750a92301c779f5f33736204b35a6827eec183a852ba586ac34f632d47ea073fbd2e7b046f897c03f768acd887f7e97d06fa7aacd3462b93d94b23a3f98f9a0a35ebaf1e6cda39232e51763d48b9417e3983f021a07cdb59c5a7cd759486d3980a07fcd40d85e4a258797ea716265a6a2c8131f219eae409314cbee8a4bdca5742d8080a07f7aff7fefc4b0a67fc7a1e5ae4afb3473dc09e11ab6b4da1e602afccaecc8ca808080", + "7f2cee6d1d7cc4f0dd6b4d1a276ca3d41fa08e6813e61618ad35c968c08bd7c6": "f90211a01dc351f4234dbd9d1ce3d693b97c66587b96f586b457da3ee3ba4f869c47a416a0755b12207e8014906b99ac7f28f052c1ed89f3c05954124eed36a8b65b52e526a0392df5aa7824a9e316d54289469654644794a4613f5a811435d558ad03599a30a03b01f891feb09e964b45d6716d66e05271775710c5a19228c99bb4186627a0baa047b7a7a08e00662a54b7f800e19874a143e0e201d46839ccd6c1e60b79646fe2a0225fd60a6e72111b2cbeb00b0207a4dcead31f2deb4f5df6031eb6e5ffc19597a062c438cc1d026ee4ddf51bbc913f571e4d1a75c6eb787a1ae811595c679863c2a0dcd48e6564ce3f3e50d4b94ec9aa600bc523b864e60e12773ba3af8247fed0f7a0564609ee6908502a8be7d70f86b35f0cdc26804c088260806a9238ff71fad3a6a038c407ee099396fea70641e034a9adb064feb55ee847cbdd16efb3088ad0bfdea0122e6c155ca17a5112bc43b32c0ca0e0176ea7ce6c6feb23a843ab496a28957ca045ac40d09d7dcd2ca9bcc74bb9e51655578b4394cfa5689e06829b79c7dde34fa0ab653347b84f9f801b848cb435e3d4424abd56273998151d8bc6839a9adc4264a0a12e9ada6b074bdc0aba70269f96b0150ee70da4b69b0e0869f2738e7c0c51eea0649529ef72e5b2ec0cb5c0a92e08333f6b49f43d70b32e58ac085ba552c2f1a2a0034e6a255bc75d3cdfb7fa7442f9c273fb4caf3eedd01283bd5247d616a981a380", + "7f5ebcecbac751b51d6f159a5594407e8b6132efb629f1b57c2cba239767d876": "f90211a0b287237f150c5e3c9842cc9507c140f5a00041f91c35c5ad391a656a52609d00a06288d5452f8163c682cdb1cea1bffe67ae9d01a8e44539262d0241d3011cddd4a00e2fd6d9c79ec084b41823bd8b5c53ac995c2f49ed57e4b39ceccfc9977ccc2aa0eabdc12d588977612b934c2acc600a0f2a3de7203c9c6d8b8999bd861867600da054d6b21c6375aa16580a33744e56929b13b123505e36fce62b58504bf672bfc0a0e1a68619fcbbf15de03d03cfc922ea9f48e8eced39ac60071fc64cdbb8bd8c66a08e22c309926e1cf7ac54c56bc72de258f1dbd0ab2f3a56e3d7377d957f0ab26ea050c705d2490718814000dab00d3d6d345523ab068608b862abdb93bc7227bc19a0041d4818e2fd9891b356a1ef8384e600fd983fde10fc399b51c9786b70024bdca0243cdf58e5b0b258ae41ee15500bb4f6478f93f56f7f4c6e960a5786f7100b79a0736890168847fc28b2bb10bac44eb5010a7a2d51da18f0aa2db63fab2e5ae5efa0559a7172603b7557d096b37eed94be13653f19a701648e69681177395a2f113ea0eec66af29849a60fca456413822efaa878297ba1fa7cfc61e2070ff3a86f0f8ea01b246b85f01db291b7a9709e7880a364ebb5adaa726f94ac65ffb9bbf468e06ba061543ee2c16368246413f4fa4762303e3ded754cdc29e5686b0532d6da54e25fa0a5df9772ba13fb96dd6f128959f98b1d28d7c1db9236a12637db91207711d29280", + "7f7aff7fefc4b0a67fc7a1e5ae4afb3473dc09e11ab6b4da1e602afccaecc8ca": "f8419e32beba7beacb218156e8dae090c68a2df1991741e3d730c8ada8a0cf2876a1a0abadbabeb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafe", + "7f870fd46ae70f8fca136068a10eaa74ff756d067acbeb9c5174bf31804d5595": "f90211a0af4ab1216ffa07e5920171e914dea4cc6ee9057b10ccbe9ebbc522bded083572a071405b161909b12d9d929827f46cce512c7f2d399c905a393f158fa4632da365a0300e323ec41b6bb5892ed5a4ceb4fbd3acc623ad814319708354334b8ed78a54a0ef5a162b77400a3a2513a451dd761ab2ba5c94ac8286248db5855c2e2fa788c0a0918644935a06f5393f6e581fe5c8c04bcb74f9bcb02ad9a900eb60e1176bdf18a0e0ef4d63e8146dbb7efe00d3eb0bc652a2e25e44297cc7e1d9d6cf229975738ea06d9ab805ba7a9267d02d74160e144523c0657f36511656cd4eebe27a9df7c86ba05cea72786fa51ce63b7051093155b41026370451518b20d02aee4b5bd2c94e3fa0d7c05c4f6967c867a66eb10380b3990fbd0455d512be308ed375ba1cfb6570e8a02599c9d2b361f92baf62556e565a1c107563bf69b1d8129a28f230be6a25529ba0b79c6cada83ec120f23e4475ee6d876c4c109df748bd23216dd94ca20e58d217a0b43159e292a79427249edf04eeda6fbb5c45523acfd309659222872a0d28ee32a094d8f012749bd6888bd490086a172ce1a42785f8f00cb2bc3ab468be591be8dca06cc3da8ad4901b7df96d9d8fda21f14719cdc3c09504054e14e11fa68f84c778a0cc11af0f9118146a2a79da861d02353e3543a9736e58401363d7fc0079ff5c01a0a0f40d6b464cbca560013bb4fcc9b1d7c8a74e2b1a4e0a29e74cee3e4f10464b80", + "7ff8aaade805a20624e5ed35cd0989171c3ad04f9178cf730c2d288e0507787d": "f90211a000567c7cdd86650bec3c336cc930aa05ac2b63e92fa726b295bff1978dc6ab9ea09efb481badba4a830f2b99ff41b4123330cee175530e7b039fd0605415a79d16a0c853594ab9eac1ead253644192396929ebebde637676e5a1e9a12026d20cf0daa0351f49b334aca2a1a88f1774e8f5f3d4d5aef063b3ec1d8f77e26fffe13884d7a0dec3133da333080d08039aed7048c4a4e85a1a008d8b353e287f5fac14c2539ca06e06b6ce1b9ebec4004c1f29079a510c9202f784ec457e5fee503724fc0b4203a0ca74a882564b008ab4eea3c7e0e4963c66d17a14e7acd7c6e05136312295d3eaa03f1117e6b45eae49fe9affed93cc525f976fab88d7f50b414ed077ea02b96597a0a1056d1e5ea1332c57f1c5819ea68e0b59161cd7f28d877cc3aa9662239b3382a0e14638a9bc594915518631faf7fc22f7eec60655c22d473a52f1f0e9d5e2b913a09847efcdc3662dffbc18c90f9526aeb6fdae49ab7c708560fc20f5bccb02acfda09e07c455c3c896fb4d6f4b8254a537cdc463525b2af08a5a34f3f874c3ea4457a0fd37cb0d4cf8abbb41923af02f4c929bb0a8a7b0971823639dde10f18a7fe9f8a0b646e6ca09dddf4701fa175a9518f55aaecb55820ae2e4661f0d7654b1995672a0301475735d079356875c7e1251c640bd00054748261082d8525130bc665a16aaa00ea4c48eeddb9a2cccfa27a76680309ee89dd1a69588861403c565a41d785ac780", + "800a2a5b06e8ae6c0c7e2ebf9adea7dcafa343c4671d7c0a26c32e2300925951": "f8409e3836b6940b9bac1d844615d99c1df521836d72784ca339ccfd7a4fab5a1ba09fbab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaad", + "80477121625573a0171f2daa2f688e06446e142fafc61f03ae66fb38c533498d": "f8429f2012cf6cb19f2ea37c60be63f5dcbf7ecd86bde7947c5f3507d22578234796a1a0d0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0deffbadd11", + "80926ba0200605c6e1cb0bb853611924719373e99c042eb8c9f50edbe5424210": "f90211a0a529fc6a22fa3e716483283bbc1ce6d2afe62025483a667e183440895a073f53a0e3f965d6e476976ae186a0622b7cad7c91ddd3495f51127d6cb8205d7b540a1ca0d1cd727ba27d0d1560347abb129c8103578ece7124dafb685b2b79353a9fae29a045de8cf1515b62f9624f9fcbe2fe364482d7180bac7c551b028f09fcf3a31744a03aaf6b815b0d9c0980494cf3a78fb95f2a62d669c501870edbc4b5489938b391a09baf901189fa058449b7c8e47bd36877a6f08a578dd4c0e5e8ff1d3681037676a021eefb9110fcc210e09b5e66f24797730e51aefd5c8a5d4830fed2404981746ea0e4834526dfcdf201276c9aa87df65db72a50b17f9f83bbef2635c023834428c9a0d9b1808f9ffd34eb7006fb7f5a4229ea5687298e4414b9c4b886f7db84d49f8ca090dc17d5ed39fa1a073c3d57aae32eeb284ec6e3d1693e3b787b1d923f2245f7a017164a8c66aa73efd887b514dd98614198eeb016d88ee6408cf1c6902139b612a01e2eb42105a26d5a56321a53ee8e0f722b934a909207f0ffed815430cac051f9a0312280af6a249b287b833c26839ab32ff925405a569e07ca2bc1167b67630cd8a03842fa8951652c9a103c2e9bd56ca8ce3ebc6b74c1fd4c5aa9fad04c066123f9a047e370e89fc5a391d92c75f8d1eca96f0c5435172f207f1a62771d16bcc5525fa0ae639913eb7ea5beae9b57e8cbd619fe46ca0f863cd0ea87f177d1e63e062bcb80", + "818b80ef1b6284136a81181b9d19fe1cd8080758a8514c4ee11d5b1d4e7e1ecd": "f90211a0244ef721d4eef8bc47d420296bda40aecfd0368d5ba90123b017f45d5262b479a0a75bc7720177c52f6b0909629cd155014ab8f43e576f16282ca6f90055844948a0dbd48f9832391df49596ec1220ae9f68e4ec1691748583bb9225cc29e3271d55a0c7b0df678c466229e7508861e97c11cb0a805bfd6b95b7b162bf9f41f56c8e9da0b259984e7e7a337ce590fa1da63e771026237a8b36ba245506b4942475cf3395a015f26ab0aa7e5c9ef92f5f9f2cdbd6b237c13d9e79b277780390860b83bf41c4a01d0396e06998d362ea361523d6926d0c5b1aa893b414a84d8ea6720152c1dc52a00f30363087ee4d86bccfc1617235d97d4fef9e424873674f04cd8a7544c32767a040671e20c81ab75f989e9b36610c5f16c5d9d62fa8ebc25f831bfee8c1e6b1b8a02867abbad3ee3f49be2d6008cf7f7e5e9994922b5556e5ace7d9e2536882ae7fa093805f0c83197b20464b314bb781911199b53f0de1d013551497343811c34890a04342c8d86be29cda6b29a2b7a9428aaee851e4290a92aba257fe24e87e81c824a0600d563b53b2c1a35b3f607c4e456254b8e70f5b52b15d356fecdc12f74a51b5a047dec039d260f09e20097f4754feb63b5eb3c5d5435fd4a19d8891bf0aa1670ba02d877ac02ddbae46712a26395934c8f012d796f0e29dbe6ee071572397f1d5d4a07435656496e4246100a99ff837b5ce05df01efd1685256da651b3da28295cb3180", + "81c04829c1a1be727e31a218277cc6f4fa81194ac187bdce597be58c4c95cfb3": "f90211a07806f428cf0f984d74495625fd2eaf9c7ff4adc588853a14eedb3a6bcfe37bd9a02a1cda3a8ecc27bdd5dc446f65ab25ad943c60ca9a29f1c4d33be60c571df278a005373d9bcabe6efaa085239039f022073d0aab5a2bb42a53d32d0f81dc525c84a041e883129a5b288b18044385885713c514af8edf7c372531cbed5ec05738d988a020b700cc5a23e6b3d8cecd767f2ab7055a6a1bd54377e83c8f11ecdda1555514a0decf9a8359242cf76929f9936f16c4fb295ebf58cad9f46fc73a130a197c7d7ca0088a8253f663929de7910fce3d124d5e6eb981a4999e68c143c44f858e53aafea097c6efea1738d6466ed56120865e88cbf46ba69ff3562d5caa4648539e659a14a03ca764223cbfd74efbc6cc0d377a8ec2b44d480163aaf91926ba5b9b638901c4a01430dd0efcd252aab8dd5541b422d926567754532d7dd9539184873f0134ce09a04a80bf00747a6d7552ca2301977516b493acc9742fe0deb2263864ce18be979ea0fb87593a6f84e4f92a7ca66fadd88420347cc6bcd03a87e7f59c94d55deeb1e8a03dc85afe3ffe5be018778ef1632df1e2c9aff48a1cb0f294880a84c7d34c26f5a08d4d254738befb9ccd61007a012ba3a95a64fafd75d646d76fe88484ec76e181a0560955d06eca635eae0d0db13ec1b5a9392a8b1caadbf430ba9cb2532dc9ebd2a0a9778cf179786c0860e20ce352063b6625dbe73e86b23f0c419e2f052bfb237a80", + "8250f4f9aa977ae32ef0f3ebff2ef9b913f7cd6647619dd7c03bba56f5c4e178": "f90211a05fe2dd0119e46b98e63dcd03a75c02c56993c94c5e9e8df3d700561d8e40617ca0a90cfa8a7764b75cfecacbfb58546c950d734e53ee7a491f85caefb971686607a00f2e11b6e65ef0ad5eb5d91f42514c94e5809f5886d61154ccbce5ddc0ec9e56a00d3b2b3a3e48bc00281b776d0793faca63d878e86822eda6c6373e782574ca13a0885c3196c5ee3a9784228ded1f05ce0477d4dd3d24cf823e5e77355301e80262a035d37574f3fa9dd98c9ca077a043ed67e982d315707956f2642b639039d1bfa6a0209ab8ab27e648ca128a82bc4cd9ace947e2798e7ee0d2d35d3f2f538680ab57a005123a49bb32432b6c90b68feb617409bff3a438af54effed9c9cc192e32b756a011d8c37c3d6830a33a101a649bc28fc2fa45808a55d83ac7d077cc25ee227d46a0e6956db12014e97cbd305770512f5bf4cd903867eda68437af45fea244864469a05b79f26be29b9cf4d422eef737aaf0cb5fac47741da937a6d2116aa0fc0be2dda0eb82588f24f0900c61cef7fceb48d65c0d98ba65b5ec56a3c4de26086349429fa092c5976f345988ad06ebef47d64d763e2cc92b2569a791f7b1678a2c66468fa0a084a6ff615642b4f0381c1d1c21781e25d8fa558e990e09e984fdd095128d17d9a0ae4ed5b1ac8ba52df06975fcb95c83244b46c38ffe0feb71dd49e41e251e4519a07d45d6777e702e020dbfc992fd3559f20340a6a5f7017f3d944c2a9439fb8eb880", + "825c1fd6628db8572adac976d5a460a42fa3d07cdfd2814e7a1ee1a99eb7aeaa": "f8b180a055e22d74116d3eeabc319d5c627c8a8378c7883edab3810a6207a4ebafe1cc21a01a259923ae527e266473882ded96de0e2ee893e2b402639361102bfb48c845e8808080a05a1039dadf538f3a3ed3114d41b59d85512df6c2accb2a3cc62f9c3f13cd04bda0e4190438c89bb34ce09021d82a9265f3dcdeb29fc655a67b2070fa102f9d237780a0d1e200db0abeb4c881bb58709f2eb5397582b6a9f2a9f090673b6a1bc6704a0380808080808080", + "82d9f35f03a655d92759de441ac6dc6b8a939589cc53c8555a562ea59f4b0b6d": "f8f1a0a86e3a450ae186f46384cf031ec446874153457f0b555fe8fc8fae9a0bd8c3fda0403598cc4c26e89f73429609de527dea1e1508ed04df9407e884fd77e6ec3aea8080a0ac1c4cc9085c6c54164fe64ce93e8674a0078168bf0735327f0ef62b3bb89c93a0d2b031135e6f2ab2c0e69e100d72c4f10a9032a537ad33ceaa4e65ea637204fe808080a01ab0dd993c713053c36c46a8c8205dcbd56c75ca8af05e234ac2b10dc04ea901a0e07de1cc829fb173a63f887e0e22566d77c71f293c321ab39765e33f7f7b601b808080a0c9d7e8685df26d2e8beded49094f3a0c8535622d27a279bd84d1f540b7ddceec8080", + "845a83472c2e6e1a5270d88fdab952090e0bebdcdf593e1a5a6e33d483b09c6b": "f90211a0a3bbf5b3d7200cb0f990ad966bde240ae61015b761ee8dce64cfccbf0018173ea059e473b157a738aa49ade075d75e678bdb0691b0a8f1bd1bf1c4be5e921e2433a027d3363c778e7a3dad5182efc9de710d56414441d38dcba35e08e1b6bf6fb6caa0feab0453c302be628b362b6479fc10814f7bd497c8a612968d9ca555dfb0092da0950c6ef67980843f6e7ad09bd673598335bda07999376b1a1f4b863e1d1f81fca01ddc4abdf6ec1d65ef79805bdad42b4b8f636e9891b3e91a13772eb54234790fa099020d49a1177fbaddf71edc16e921aeff53e90ce95f46875a55388b7bfea428a0018f9928a491da94b1a45a649d76cc1f712e2c1a507d17860b709e30bb8c0501a09f52e585f3706e360973ee279ecc0c0d70d611cf745f31eecf845fb2df14018ca01981b718aa912e488f6ce1512e53f52c3b0fda5e83d239088633cd354235c5f7a02b386e1d0ac6a85060561a2c72d57de296c1cdc2aff2e767235d2531bcfee7efa05146e4869598ccd093fb00d9ef067e393f5bf687f4ad42488d5613ce1c151691a03ed47fcb9bc6dafe82a55ccc9c553a9c16040e5d86f5cf45e84b7646a3101d29a071b68ae03f96bc0be43d0250e855bcf6f553a035052714a3d5941e9472cfedc7a063f85c72bebf49533806c997afac15e419e28275a0e6120cf41d46ba54e1d287a00dc300a23fc00931d881b34f91f83571205b6981f29b386505795080a3db624880", + "86d6e35bd591d67b348101bc3b87d40f8f81c78c60bfedc53e87b7ba4c1c432f": "f90211a0eafabce3b257c3957f2f65dff3b414f25156c65becd85a969129ff7c268680baa070b8bb355e6bc7824e2aaf2502c388abb6382ae46fdd6ca617f61b7c546a2d49a044170b0b2f904b74ad679cfb53c5ee45c7b4c3c5099c595d66dd4164942c612aa086e98a7aa4831f6a9c305bfcedabd55b39ed5a4dd143fa0797100724d876fc0ba0a9889b77088ee3d979b817989cc34c2eaae58319612502c2b91d86167d46310ba031e91c73568fb2f157cc9924a1dd361bcffffb6c0ccbdc1d95b4c8f0d7517a73a013aad5c238c7caa6ef26c914ea5f60dc4aee82022b21072e9250028701c7aff3a0b5333424ff8f3d9b2d1790e829d27fb07c43e0a7410b647f71c7680123c71eb1a0b4c8fa352b648d5bbe28baac1122e5a913bc7dc9951c93e48fc10bd172163ec9a0a161e0193e1b229db9b2bb586810426794eba3b4fcef324508cad6a29760b526a02a62f90dbc8a93a11d923328df94528856ee8546cc3da3e1b9ac004cd92c2e4aa08dbdf0209fff987a6e7e9cf577a2fe8732f92704a5ab01455375663019d98eaea003a4a7aef7178fd76060a5928b21fc6957f84fe78b331e32a063227231d28911a029ca6c14c96f0b14c187c8414b515907c5176018fdb406decdd011eb5afa1cf2a098b746d6b68934da09e8e96868dd768b1e93947f0940d1560e018be6420d1e81a06096ec0d05663f76780fea2ba1192030b6d3ae0fa33f0fbbd28106b28d877e0080", + "86e13736582a41648e65c6b25296a7c8bfb0790c1b60b0c9933e47693a1f21cb": "f90211a00feaf17708ef6805766ad6ee353d960da748b079d79e655c3aef70f403f24e7ca07aee31aa053d15089e630260e777c1f06d21118de759ac7154b67e346fa85746a0aa27556cc94e8ed338010370548631321b72808d786a43293daae2b8f06bda1ea092cb0750798b6142ad968d811bb6c4f38f06f6b85efeb20d626c65c33d09e53ea00578b8afd40b8d1c8ad4ef60ce03c778c357cb63287eea584e03c153eda1fb9fa0e6864b9874664405d167ef15c4a0d3ca2214446ce2e51ec7d3fc07ee4f7d3be0a051ac8cb9f8b39839ceab32a0b9500e97bc64ec3740918c1adc57f898ebb13ae2a0fe68a78ac2105620b432c6ace732a3ca8c61cb094188dcdf5b5161dac65d962fa0358eb0c86620d5e0a7a3ead0a4e8961d55f5fc207f8a55d60c33b7f00d7fe740a02a6a203cc53d15264bf4fa33b1091b5c54a0f8621260129199a6999e3c551e38a0915f4c5b4c2567406d58be20d75eb55b25ffcef1ccdef48d357f683f47c2ea0fa0ddbfa59992e79e3abd2ea49a86c2498641a020eb360b1b5d0411375f35ef4419a0253f8c2568b195cdce99a70e3e87aae59dfe7389af80a835db1e82bb148476e6a015b3ce458d9148e5839e276d0f10d9060a561512b3c0f651d46b73a3a49906b0a01cc6562f9d6ac28ab42374daae4a12fc86b8488be924b4f5e6f3447bec450d0fa0ce88a26244dab0b8ee3d5bf6544913fac5fd71cd476d42b71dc0de18e2a9c8b980", + "86ea9ee23ce96ee60791d95f015ca41fa875248a2affaefd993819522f236a8a": "f90211a087a2582280b4d7a42227831d9e0ef1187cb4098b54b1035e9e454679bb107c92a0332a2d4456016702ddb1006f41648e096166eafb0b71d99a7d128cb3eb7e2235a0b8e82ebbb3709cc5db2f0916f967d88b5d552512f07917b845ff1b3041838374a023703cd79bcfefd97e1ae56bb5f5b4970a13e4669bad768ef8cfaa4dc3e9e432a087600781e6a8cd0ee0fe63da274d3a8824e682a7afc85d3807b261699d02e6e3a0b71accf4ce12b30d091958dd90dc85012bc6b23e4984c3bf6d63cd73676f7279a04dc5501633e8ccea1e372cebb8bc9cb6053f4049ccdfbab6bcdcccf1c9e5da8fa0bf9f04bb04b49c6364a2a9735d689436cb90a5f76d148e51cf4ece560036fd80a0fb0e59fb6fe6bbefa3e0cdbe856f3defdc7f77d992c60fb88c169e98c5c0acaba0764323337e773fa70a10c28aa173d2e80f6533e0eab84c08d2e14e484224445da09710d37ff455f62ef438a8d503171e82b2d6d74c976c243f4a85a71a0ac21d4ba011c6fe452c323860b77c228724e2a77fd4efef526f48c64d8834f3de7f602aa7a062577f3664a5b2a2157a2bee039da7cba8ec8fe53c74e295c7be5e5a5d87432aa0717099ae6f3509dd24a1da0a4a4efb8d9de236c825a985cf704d06ee04d1b78ca0ead3c93953d0049429baeb7ee0c4d70e672e2bf0309f13033e69b0e88db699ada0ebf36594443700c61da10b6bfabd87a1e47ffd1667c1d130acd801409da9fb8580", + "872c0395b96cda5cea44005467ff2e43a6fb00b67c3f4cc392ebef6c3b561133": "f8f1a0fc35a151c929a2ea5332aef4992209198d624abf9d6ea60fef4a50e66b80faaaa0ba0930dc348e55956a45bb218e12af8513bf61932679c1c998f71d38e8aac38b808080a067a4237ff83cdd358771da016a468372ea7fb75ae12f5537099d60f3ddc07959a056e6db01a228318cd077fbc352fd6e7ac35502fde595793c8cea5fb0a7d91691a0ccc6a372fb84c554f5b7238a6349102fa2d41af1679fde97f13b0d15766db2e5a0fac7f24b0f53d51ac134cface512b30975d6d3a7758fd50af4bdf5188d685f43808080808080a0681d1d1dfba32841dab1c3f0fff41c4659c94e07f2b2ebfb48bd75f7674e11b280", + "87aaaeea20c93567ee07ec8360304fcbca0f4880ab6f84852c1659eb6dfe5024": "f90211a0bafcf287d8901592a081d5b62d5cbfe012a66fd6d69c2a9413629eea58ee7a9da0432308718fe05dba9fdafa2510ed26e50598d0806857c203a88d1948bd777a8fa089ea5b11c2f6ec01d398ca141bb0f3a1786eaca6c457c7a7615587d85d10c9a0a0621c3e437c79bdb867ae51d7ad65fd5031c4f3db890db042d60013324a003021a02ecb6e6e2f87f0f071fb2d1668e875331363afe12ee84d85f9cf1635dc69667ba0c9ced6fb7b40088b23285ae567282b879dc6bc6de25ffda4c9d8dee0a69dc4afa0d81e37dd3361efdd6e6dd2b4ff16d1ae55dae3ab63545e0e839e0bfaa43dbd5da0369d15591c0d4e3dda41fc4f6f2074c27f7a54c52cccb4c63f9dd6703e902aeba05f5274de6587ef211a03a0dd013960cfe0739d96565e617229deeb10029ace46a0223f122ecd9246f7477aacafb7f30415a30e221ea6e18d26ea01c7d83f4e5b3ca0350eb3d74674e0bb9a6ba7ef4bfc11811819f56cbbe4d27c00e726ffb4392022a0a527b58dbf64bcd7bdfb61d1f38d7caf8e319b1833636b8c85b525d0396030d6a02e42b5333519cb0d22cd91fcdeaa031c26a1f5d6feeb94c5a50cb8a3a7b5e2b8a0a4a9a9cef2059a39cfd949aaf29a1a740f311cbcaf6db89a5721395ec855b17ca0e28ddbcff15233b7a501a670e0c6949d6ae9739cd896acb662fc637796d8b7a9a0ad27b97802f2b54b375194dc064e8faab3cf1a460ac840fd0d9d1d824590616b80", + "87aee177ce76f33974d5028589ec418f628287b45b8747a0dbf0552fd72bea57": "f8b180808080a00b3ccf856766cc501baf4f5754e552f3aa59b65f1ea00fb3512f77adff784906808080a0dde3dc4428ad3897f6546e98c77ac4b2a82a06a976d8abf4009cfdefe841d489808080a03cf2d8427fe4d1cc2ac40b138cd01392b801d831c952b8bc7cd6cb92aff92199a01e9b2124a58b14436f814f23ede5f1c563bef156e2cc6e4da73ec84814fb872d80a05f70bf279f3576da619dc1809a9c2e5e114e96bc774109bab9973557c138315a80", + "88b89ad5006e9cc3e3053457b82dfff5354cc5d119159b6f1f51e02872182f6b": "f90131a07b8024d99ab8a2d93f38bc1eeb6147abcee9aca23ea8d7c24f4a2019c6b0fd8480a017ebe6512a1c49f6ae575c9c24ebf44b31e57f22fec04fd169a50aa854ac1bd680a0a66d18c1e708306086d82e2aaac60f0df82069aa5a68458b3316b8281e8f8c238080a02c5725f31f8ae62abc5c4e10567af3b7c46ecdcfbed5f49228df1af60f60bb6480a07228360fabc04ab28564402c438c4c5f8a9c41ea0bed0090503ccf9e91e4a9aea0d505ed3b98d2c10cce023c5217eca97fca14b81e545f59467e50199a13407811a040ccb52b21568223afa1f6766f4566296b0b6ef8dcb889457827e31860348b5580a0816d60b1d68673952c75d57a6e60a471f71b410b56aa3b5d1830b4cfeee51cbca0e215c92a13240706b2d7a567d424f345e59fb6c55e11c5588e464cd90a74b51b8080", + "88bc1bdf852671ef5f6248ad95d47fdb54f20c1ea213465b5f18f3981cdae7f7": "f90211a0780a034ff6b9d2e844b35c1e7f72716b8e733428befea051a4e9daa1bde7e772a0c57e29b9e81363387c0fd00118a632a6271762a9f4dc76ec9c001c4d5154f4b7a05f7b1103b3c15677d2cc7a1d57569c6d9911185251cdd0b7b877f748dc21812ba0bf01ff16c937f7a5a63646fc540f9a264b11c42856d91d40f8b0f7f2603cdc12a0a7e44fcdd0099a6ba1b386624fcd1905360f42e99b71668176fe7c9630ba61caa02c81c06a579450c70db0348bc217e6ca5e80ab8c319cca630f967fc40a3f3c03a0de6a446b251c0750543bc9290d7d0fda03fa7b85bb543e68e9a3775250e04ee9a02e9ce91e3d50c9cd363a7a7021274e02267c42a0c181a9834c2ad60bc5f8da8ba053c09b5cb8ad05a39dc02c57ff7f2dc5545ea0b86e9628fe4805529ca60b73bba08073e09d525e7baf17e447ce3317f5ca11c2bbcf58f28a560f0d71c08314a485a005a792ebfd5005509cdb75646ff73bd2c4d0be30a5091ccafaf4b016480b39f3a0545b8c19d7bc126a3fcd37885f81da4727dae1b276c8a67cd0e2dba4fac93f10a08452b0c4e0f9c37690ffee525cc6cd30db7c96d5e6cadc65b192be13b0169c17a01982d864f631d92e271746d5c3278bf491915f545bdbfd34b0f965768f14ec85a0e11e13b5335f44b71c9df3e7c086f592f43d5b07dbffcd3625140ae5c3b0999ba0fa091da37feeaafbee8f9e877a8f380762fe0b86c815a5fa7536605f92d4c0ca80", + "8945ccf44f9c4870af9c5c3d7eb559531e13700ea0912692a8a348c7d671f2a2": "f90211a06535eeca4aec2a5c096fbadbd5ac6d26f80a308facbda680cbb8cf8192c751e0a0873ad61417f43bfab98eb62c885191c84ca387f7ea835ab8d69b7ddbe8141024a0376714cd328794981fc74b9200e05e812e043a435d2a68bb25f7c0ce50e90810a0f7196a25be0817a316b4df115f367a24903d0f137ac368486a68ee0517219724a0658d1950e56ac045dfbf4b4b29dc99d8a8e8a64dd041ee604502f1ff304cc7dda0e8d9e8af23629b535b2ea1324ccbb0973e4b6537cddbbe49dc0a09cca836eb13a0b252dbd427cbe1c1c0d0ef59d21baceb1d0f630021d5dcda33bee345b4862718a064ba688e7c941cb97100767ca3cc8c11546a9c2330b4533d079ea73800896feca0797c5188c37528965406084fe9da1abc797037b0b52a076c7da0b8c55346d4c4a03378f1e2f62b856c56ef59a0c6ed0fab93527a810c82b5fdedba113dd93b6191a0b1ba507ccf61219eb08ae4267632e91d60b35b078be6504c458efc70681f8cbea0a7ca736caeda8f647c791edb32bd245ff75f2c3e2c0ef1bdcd466c3a148f8696a0ad29439acdb6834df9467480563bede98b8441b9c09495a96be4e27baafb93e9a0bf10db179b682d8574cd855b409cce3f2b4bd7ed287e64c33e89c54596c05887a00bba7e8c2bccf35c1f06730ae28aa8fb2a5d056a2c72a36f99698863387c5e63a0e6dc146d048f448f7e6e52e63fb9b35b1d36f40dac4424aa789b43434f9dd89e80", + "89a7f1ae49abc818fd35783e1f11841204a1eef679ab0b1e23887157aa795b7d": "f90211a06204a5c42fb08592f7597417dac1964b78e78ea419b768321b89ef62c8712468a03c887d9622f38722157ba99b7fa4c295228ae20c3e36b4ca4328d734cfaf8f6aa02294a7edf4c0e3191a66de67060ac20542c574fbfcebaddc8b37e8deb811f791a0483e00ccdc953f42698574c0a25aab56a37d9d059ed7e744ae4100a341b98bc1a09c167eaf3af02fd89365d44c00a514b303faefce0cea722bd597121981003c80a0deae42e7fd83263b7c4576f08ba3ada5e559322ba7bc2ba1fd245c76914546e9a0fbbdea86bf51e19849a7fd048093767c4cbf4e8803649911ecc6c53bcb90b6d2a0f9b6dfabc5e5783fad593c36510427d354e202947af66e1c8f0a39cd69a9f23aa090ff1a734fb3b0eb5f5d8f3cc3d88572a9cfe3e7542cc617d14203d9fa88453ca0e7298ce3e911be4733802112faf46e2a781d77d6eb5bbeff12a0187c843a24d3a07eb1690351200ed0b50d1e531f326e0c6c43725867728d90adcb684dfeb62a93a0f4715214f5f145734acd28b7a4abdc718e39c5c50458026e3e0443352c5ed276a0ead14b1f989c0b340dbd91d2e64f8a119b8c2c87c5e3b35e72e30869c77d4e48a0d783c0f3ab85e061d97cfc724a4a5e3e9e3c0675be5ce0230d8f00d303ad9c52a04e952e2af712dc2dc3c3a2b7fdca3a471acf6c3ae484794dc24e6e1711966825a0df4c4169921843d4d6ee7e5aa0222dd9c65ec61fa7d6703939abc6f5a2fec67b80", + "8afc6793f1d7b4c5aabedead8546e16d29ba44ea8978e6669055c5a6d61bd2e3": "f9011180a09006f5aa004fac3e93c08dd10d413ca3c0b3693e8b687b5884fd01825835c71e8080a0824eeb7bb94cc72c8e37fe457fdb996c62ae1244b9670c4726d4be32dc37ccc780a02a8d1a63217c65d2bd8c5b662230255aa00c5bd9ee4b0a7404916387a281b4e9a0562b81357aeda4ab3eb284b9941428badfb24481599b0274df380157f70b1a4ca087beff3760caae51cc7da2ba544d68cbcb44283afa023d3a7f8724bfbaa5b4328080a06e49a3a90d03e4a14979a68076271f6283a342a300c03e233490a8e7fef826f38080a0b48a784b7667a15a736554ac055447562101d402b866526ff83fba7817fba712a0c46029d343d14ea5fb3fd5a99bd7436f7286b655e110fa46b650880148c3aee280", + "8ba08d3d391c051c93be77599ddc7115c093bb2f76c37e72acd60a2be63aca4e": "f90211a0bfce9e1629c3f810533ca17440c874b4f62b72c0fa1e7f6d3e889e908bca8e9ca0d3d1e6bc371ddf75585422d2a59aecebfffc5ad02bc522d0b8e60bfe8d38bb19a0b646e703d93fb7657ad4376efda74e4de990b5d19ce182d8caf7ce525516cb98a012eba93fd67e28968821b436916e4995096b643a21dfbabb09e908d9eb22df6aa0d228ee05bd099b1b5e0588e47b677b58601ddb6ca13ce02f3aeaa8ba216abbaca036ce78f085c517d5ca10830811a74815e9f15ecfe3383aa4a2868c8ec2534682a0ba629ff5b91ac284dee8de77d465c3039f6c08e27d9d3f2573e9096110cfd9c2a09209478ac4b9a50c51d430fc71bd91a2c0fd17a83c6786397ac2627025d7acc2a0f20203db7c0c28908c05792752426f72e219b8cda3ea5d63fe446f658cc9391ba0d7f76b0d9db6d264dc0aa280869c109ae0a2255674f71f456908f893772816d6a0eb744cae926da4eeccf73fde8c8b358b55e8a707614750314ac320ce3f83caa9a0b7171124506ffe71b2138f547ae6d05b7fab8e13b26e03f6d4cdd8b70c7be828a01bc2b3f2165a4dcfab9613c0226cf7180fb84f31f31c5616133e6116a27cfb54a0433a861eefba97dc44525c8770d6358d26810d4d8403c0ed222b2e15bedf6ab8a06c39d2feef3aab1b0b989c4ee7cc17204825bce591235e74a0747dba8c3ab7eca080f8f5e28086155e14b049a9883f15166d15c3350bfa4a70922b94cf7b099d3680", + "8c4d037248f1e876b855c0af4998d265dca626bb3ba7ff58262373343d0fc09c": "f90211a085b82df22836ed4fa9cd266265c9c85ae4693b6604bc07777efcc7f888eb3aeda089afe631a28219bf1e8408762701067f374a77c88dbbdd46aa47e53e1ca282e8a0fd26b7c101746d96c96affcc91978bd0e987366511fffc882e509cf86a3e239aa0cf4fe3f76708518f9ff59306924248949d28da6c61344beb669a472c0eb4ccfea05a34eeb7aa2339f1b5606868e6d2238f0079f887d36e5b72aaa26ba52c7c66fda08b7937cab71e763fab265e6dee3a76c273924fe51400b463ed1ac8e8b3c13416a0925fc98131e5bf1f8d1004a2cec60703d92ae7f91422ebc6c256e4a51e7f1aefa039d5016ce1f67b7ca560a67030047e4b14a91a46dc63afcb2d87bfbfd0fec14aa05386c6fbf5d564afb63b718caa68eb7265a74d6652dc7bf7aa33fad554407457a0c68a1fe318f2aaec4181f91e31f60b9ff68f87e7c481b39fd8bb4c9eb7ead91da0aeeed8c5ed9dbd4a1518c30b7282813b955f920af32a7408ddea4e2c5aa80696a097616a55965215addff9c1f48b9e509eeeafa03561656e3f478322092cc87057a01f150ae7e2b80fe17fcbcc7e42ee93d648761849108a5cd8d6f21f7d35e527a9a06d4d703326d36a7e45511cf3e376ae05e04d7b6ca893c2e3c573fe95235c0be0a0a6f586a4eaa381247fa85cafe1f54838d20369a2983531c059ed05d1f3ca5451a09d78beb2ea85bde4445e6a1df43f9c8afb762971f94a12e41e76ae15c91199c480", + "8d25f3acae606452ecee2294429b57dd54d3897a01fa3c19d536d079c881084a": "f90211a0d25419f2a58a9fda41834fc15a5fa5d26453fbae4f5eedee58ea8ff1cf8fdae7a036364455b524367c93c95386f38e1cf8414c9d332ed2b7586222ec64d5f08033a05a7346c131af8fb746c11834a4e017e26bffb4bfabef3aabf5f26ff114682467a0ff370dd86a67f140e52a6879dcd0de7f838c1c1bb1157bd4302af03f460eb8f3a0930402d0d6d369acf8a475244e8a9b8373400fb9f3b988788429cfdfcdcd34c0a06c7ce32f2ca88562d5edba35dd57b6a3117252b3c0c809a1b888156e547fca7ba0d363257789a336fc40bff0d8946377a657b319877722d3d9b090670bc7a9fc72a031f1e4e7cdb6b3a78caebe3a95fdbe45d571104fb57393bddd7f786e6c6b185aa0cfdabe3168c8abdb2682413b6622b06cdb60be09d2699f1932201a5e2d33af40a0e809f71265778001315415f392fa26261ab2a7d19bfcb29e6f86fd842d8beeafa01730a3f6840bc084bcc3259455f4f1e4570bcd2492298cf0cd6eab7a2a715844a0cb56df6e9eff972cb1cdb773142bec1687b001422db0def8f17643596b685890a0fc0e634046b2e7eb019e0b98e852fb4f65976a42a2fcbe07850bf7ae9d8b552aa03da6b5578324976ffc79ad5ed8da300205093d0144c5228ab10f95cc0236e2cfa08c4d28996a6d344bed9c3b9a12812f1f984546dc12b573cd528565ff4713e67aa03680a2634e181efc0ff1829307a459d013c496ba049f5f3f15ce518f2dfaf1d280", + "8dd682f2190a96ad9e62c4459a96e275077a365300e8a94de3a1b9aa7fc1ab1c": "f90211a028445a417b2985fa1add35a618b2c08023562a6464f4b32826e56262b0893abba05d2ad588dac4ac021aae9638d69dacfa571d0227c2bda5083af2c67bdb550596a0e66e5b51081996b5fce0761d226259c47b2ca22d026ff42375aac1e94ded921ca0213cda86f44dfdc6e0fcc7d1c587b740cca5ebe7f0fa1525f27b94a84418e27ca095a6e8fd7a7432e7d49495e101c560e44785e0ca042823ed4b4d66e83f61acbfa0ba600cd6a494e1360233d62b03ea812e09e3fd8b5e5d34dc384f62050aa4f350a0b610b5984cdc7e9bdda569b49ad4fc19a087add17cab54d41b68729ac43e3d0fa088bc1bdf852671ef5f6248ad95d47fdb54f20c1ea213465b5f18f3981cdae7f7a0f5c86e0c8837ee359ec9543e72de446f2623176e0d1c4023cb9686fc764f8891a04f20b3751a1cb6775b3f3c980b6d0201965f7ceb3c4c50caae4b31ac49a79887a00ca563520457e8180aa348459645f75893253f29a2194c9fb5bb4c06101b3d78a07a06847a30fd4d22c3ee35ae8a7d781b6578adcb24604279f9401e29cfbf2f72a032a8aa4eae262d2b552cadc763c68c8428ccdfcd23faa756b9818678c1bb7d56a0d826860918247a8103e3d3bbb99a82af5cf37af038d18767e5957e4dd24077b4a0d26b2a8ba4dada6f8977eaf6bd17d0bcfbab102b5202682c110aabe62ce2e6e5a0e897dc018f2d1cb460021e4adca189e98a87c9bed48f024eb93351fe2243167080", + "8f7f62ee95216530263364614b74c2a1ffba4430aa4ce64ea1eebf2df64d1a8f": "f90131a09d5fb578cec8dcf55c9291a256e4cfb072860ce3415a74ab53f235b61567b91080a01aaa1b2b63c6f42f0d5811c8dd5d8562b03907bbc9de9ce65ce01fdfb6dde2cfa02b4cc1b6f85c62919d11ef193261d95de6e04d9a01a538f2ee62252aa51363c9a005e6115718929c61cf33b0a502a0764f630c1db48d26cd0c093572c4cef0e8f5808080a03aeaa8af90737f8973b1950d680da880f199a7dc100ecc0e6b78656b537df153a0f0250031acf380fc8242f2e69759abe1db020336cd441cf030a40593a3ea31d180a04d1a6667d3556ef3189bbc246fb91a07bd26da9ec8244d3dfacf80d86d6f7814a02ade0340017f57afe5459feb8a904de3adf54202356b227d186fb0ed01b44c758080a03ed6adcce86912376d85641697bb3271b43460e03b6d72543613c8e50976731280", + "8f8e14f2e64cb740402144f02891e6337134bd1a7f0ecf3af6f8f6663b3cc8a6": "f90211a0daf0ef28dce4ec1e37de886ca15767c9473ced0fde118045809c3217845eecc1a0f272422c81bb435e4192dbe6a25467f25a1332e303f9f709d9d79a8564d3a2eba0233299e13d87f02f2909deba397de4f97527c217d526d15e5ba17f3eb6781d4ba04b83fae4d3b68abbc63bae2da4508a9281159137d058fca5a44fa39e6d8db9b5a0be30540a3d3619c058c5b4b737beccdcd3e7fab650e5b276fe0c9ea0ec0137c6a0a729ccb2117dbfb341557f6d21cd5af47d2517b86841c08af2a28afd3d9cf0b8a04e064849450665abc600a39b03c4b0936722114250f24106575066a2ae8dc476a07d3fe0c192e9a91aeb569922f0c7c6a47ab37a6cc8b8a7e959ac80910ddeb504a02a531350cd2b01180e7ac0531cd0f4ff35801f8a707bd656944107b1f658db3ea0951bb780516ab49dbbcde2c1ec9dcc07d1ab69f7ffb5cb74ccb6e94f3645fd30a0f1eea5633ebb06cd38babb380ed7e9bce12e2cabfec530916755794f9f675584a019205e5fcb7c8e47a704aaebdf329ce1895aa34b5266ef35b926f73c28876bf4a0bedabe49c9526dc2ff5757a31b867c6bed9e528857e483abe69d055c2493c233a0de0c37023a08378228e45798c5ecaca2534ab080798de28af8f6a203a0bd493ca082db9b864480ac9e7307efa1b854ff40ed67f61f9d64f6e65e73a65e430149efa08ba85f00706a71cb33d1c6c312ef1244f921add0b4ba1847c1dc980c4cec11a880", + "907d0344ed23d7c7c406820615cf6020b0c3b2e9ecc3836c2c8c8f31fac09001": "f8f180a093eb447449a2c598eb2705c6c366add2d0c476064ea6ce49c4c8bdded8e66bdba02f5810ad8b280463508c8135999c3c5a2c4a969e4461f01bcba6cd33f80b2c84a0b77bf0c0f0b75a9b33f7978a1f84a3605360034cf4927dd86c43de4d5c93e62780808080a0faf5c51fb4558e9d2856a826cf97fec81e0593ba014ee81d5f988305369cbf09a0b23f1363d47c297c3dc5f9430b4c724659a9d09c785b1f4a0cdbd5fe25353b898080a0fc99038de285bf03f55e4b76e9f87c8b46af5c4f9e3bb6105a5aee5e01bcf8f58080a02502a66cef76b8fa9ee31994480f92e259313a3add2598a17f7675e45c54679f80", + "921219934ce54b3d31d7e4a680a4f62205a92813829d522334d6036e1272de6a": "f90211a09c5a76331063fc7457437258ea25074fb6b4928414cb097660a3314cf13dabffa0eb4d0b967d56149d0f49f6da2234d46d228aa102c24250b9c7c322c65e9ec100a050612b9c6ce945308ba6498e8ff598987eaf89376c82395103ca2b590d6e43dfa0921f752673401964a63a94549de945734d8131195aafe7bea93b9331754c9b45a0482afab081bb5d776597d79b3d0a8a7c9f6ec22fb848b371747d0b95045dd947a0f3cb731fd7731ca78dcb61685ac2cc0805e9a30fbc41a7a2fad9cd18a91856cba043a1be596020937c6582f151d2d6561fd536800286033baca8d8797221109cf5a024e9363e3321a6e9e830f056107318e68ddd543a23a8affdcb431fec866712f9a03c5945e94b513e35fbdc690358f1a6d3021645a0edbf137528eb634622663a9fa0bcad688ad6a6d5cfff74a8e5cbffd60c8b0f7ab31912cb71a9d496329d9abd37a0577c8f7380b564841c3a38a1a6220694dc93f9408605b5d9b95330a1fbc8ff7ea06e9ff03fddda8dce60314dcc4317246a0ed5b5b4ce360321da02277579794e6fa077309e7c4350146c40dcd95d386505e641e1a0f0d13b5905336032a3526fd56da0a2908f93e3fbf791c5a4442cbc541396cd3444ed2bca53d5aa92ff8738041b4fa080477121625573a0171f2daa2f688e06446e142fafc61f03ae66fb38c533498da03b492b126fde2d36d0a6d81b92c2f84b6b34f99f40262e911ffe4b4a0f2851b880", + "92bc5e067d52a5d08143fd5d61d007221a3a438174c0f80638b417fb082a64cc": "f8419e393e231d8305993d740240a013f91e3efe55c30441f1713582772a5c9076a1a00b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabe", + "92c3b71e20fcb176526a884e0c7e55f5c0a2009039e3dbe9a5c3be233f98c033": "f9015180a0ba571a7d84b1a9920964157f54f15a32b1d71774af6e8f54916d44605c699eeaa07a54e8267763f28f029f6222e0a9d27fca090180430cf9a49bd99890845c1b61a0e4d3854453f9e75ee922f70ff7ddd41b993805013734dabe703438899e76091f80a085e80b2932f4e99607019c755c48183f3fb791898154e04b3357a9fd3e4d2baaa09a0588cea174d42e5d30c1920dad44fe0f609d6bd469d22c09b102b101369456808080a07ce6d8bb484605454f0a046f3dfcfbf481e2c15a1ecc250721b0f97e2d7a1fb9a0a0dd128fa1b95830f2744aff2dd02831b3660a5b01606f3f282344becc7670b2a02931633858a0a1b96644a3e290a3e56372d19e068cc5292b34877f3ec68cb320a06c5468894051f896a3c89a2ddcf3fe00bb716ea30eafae4df12a49bccc1b52f0a0bbdc38ea2574cfc1f855f5068706d0f231c3bdc74b621abf50d2f064f57526348080", + "9326457b0be5d597199f4b5a52109e54928a58e9d4c335399adf0afcfe905dc6": "f90211a0bc656172578a3665590f3d2ed177a1d082d9c8ce8a2e614907fb16429d9f20b4a0976b6c7246728cd5af194112a3d2297f9ed9b76252cfa942de864b15935a0b94a0c051e4ca16da64f83a8828d910c774746dd37a179025bbff744245706ef0cf4ea00aa40977fee3e51655b6bf4dbd21e49fc6b6bc811ac89db054f83a9d3e34424fa01b6e319c7281a03fa1925daadb1af671746bd59d5393630e40e8f6e40e3b164ca0b8254115b21683cc8e54fdb80c84a0c5bddf6198138540427b889e1291ced341a0234e2665fa5e05747df4c1acc0787f1f188d4357eda518bb05ce0fd72e7ada35a04c9113feb33fc70c5f9d6a45a3e37e2e9d325eeea39df2f47341683b628a1360a077490b850e74737f70129d2de32face4e6d876ff9654df84e1c15c6ed5b500a9a04e1b98fd8025712ed1a11f68be9ef8e08c575f5b89cbc7a5c5bce4f821652b4ea053e4bc03e157aeccbfe1cfe95a050fe5f8370a36e5bf334e780addbcf410b403a011b88c102d25f0e65959ee1ac2d612b8416732aa4fd3b9a6f671a10a21226ad4a0fefda4deb91de6c34a23e891862451f16a9a925cb7fe17c5e0bac6493c962f28a099f8c5bf960ebbb92b0b005467c36618892082ed9e5523b9aa1ae5d611f67a03a0adcfcf75b3b72291737b5070d651fff197c9b4d3e3f9a05d1d286ba7779d6d53a0ea7f46bf22722a54e1012153b84038d28a084ffe870f53df448a43ff43d76da380", + "9835402d3489035116f956e324335bffd241a5f82b91eef98b6af7ece497db70": "f90211a0fdff4add4bddf1334831ce6cb5b05cb6a2ffdec9cfda5a48d56a404a1162d516a030a33120b92da29ff74cd474f0ea3a539891428903c9a1ebad30ca14538c04f9a0aed324fb9beddeb4a5bc28876d550f8700c8a5198460041e7d2113680ffa62fda0ba24766954ca1ff765b9ffc641aed61529b4792572a006fda396ca5f3268e2e1a0b8db7adfbde439783b3d69ea76d29894ae597e5ba7e0339d538da7ff7d82ddc8a067d4fecdbe4c21f6066cc12e43514d5c0ddc721fc2dcf76d789ebd1393edd363a069f7a3e92b7ea7bfcbb5968434511b12972bc0c20c00a557a47a8316a66d62cba0ed1fda6599600f47b9a8eee09c1d264fe2c8c80817f828bff6cbf6821c825a22a0d65f51df317e4bfd98adf88794e0b85647519d84b30fcbf40808a51e6ee6d797a01fcf805de8b727419bbd1a27170d99441970ce7e165c0bb9a4c0a85a25ebdc12a08d3479e2a5849df3e47798dc423d6a6a6f5ca5e759507c883df07882329bcbb0a058e24a13e84452e9787f65cd823850a33ce73355794e9b166c4d2fd4a1375344a0ea09530cac54d8858f2ca9e0b731b66a74cb1a5bc127a124a312f3bb2310ee14a055e26842778516198f78fe470033a4a0aeb6928e0cc98b3a2a8b5c1517aaaa0fa042a3d6031918ae9735dd3147bf68c723acfa66aff1ce8c56721460b8ae234d0da06ca7cc5fe9908761ec67904a0c842a08da2158a4a5b031e6ff9415a42ddceb4e80", + "98eadcb283ced6e945ac7e1384f796a911781adf30380e10ab5c99d0af6c4176": "f90211a082d9f35f03a655d92759de441ac6dc6b8a939589cc53c8555a562ea59f4b0b6da0506de7fb69f6bf9995d8671cc412dc966215ec1be0e5b1a194278e2553a849b5a062c513cf92130dbe077fd9bf98850d68ee93ad63a4e940765d55eafc5643bba8a04bbc7b5a259e3da27885dec12c5fe070260d42fd2797bca97c010d3c4d029deaa06b818bfdd45041c0cbceacb5cef1dd81786e3ad8862b285c8080f88145950fffa02008ce56d3627a99e0383dd47fb73fbd4bfc8e97f707e5d5d29940230524b018a0f0fa0cee58223ca2ff91b29017eeec65abc8b44601452db8f3c515e20a326066a005b38cad6d97d8e505040f58351f0030e4ddf5d4bb4de4934091ad90db631c2ba0298c556e66f30514ae41122e36b8b2397a6a53976df85b150e4345d95109a043a0b05e699364603253d85bbb46dece13efcca657c5e76eea7a2dd34e0e69c821e2a02999cd17dba82afe061f46a026056565a447445afc2df32c0b2624f1b7ca0d58a0c8a996ea99006e07ca8bf785070b6e3e4e857c59287d167ead9f1f63718c3488a04c7536e7b49c60051c5d7e09daee46cf1e23ac5f153546d9cee70cf2e3b9a424a0939d0a4d1f36642915fc382c1c42785dbe873c0f19c4fba9c6bf6e292d341dbfa01e5f037717a17292356a356591449bda46a9573c50fa95e864ea623bef2bffdfa0a89f38e6e7a95a3fcb75c7a983b2cfc9237bb67a842f0f15fca8f6b0c7b75b9d80", + "99793283c952f0699d67041a524c6237d6ec6e2d03190b2a35355563ff756544": "f90211a021c0ad58ab35d65b3758f5f3998ccc9c3bc01e0b876491a6e9d420dfb0287740a08dc9692ef239f47ce98df42412876eb8d6dc728122add4876597aaa658747e7ca0f8d9d9b94b9f9c9e6264da69a1b0a5ea6ee9fafe7ece9f4a36354ac08535fafda02f1c2e09cb0fb588c0c74efa9465fe1fc436f21fc29dbceae439f6abff22984ea08575f79945b4056eb6b5293b6219d9579afc4dcede34adf98508cc48c905db24a005687bba44e7e444ab611ece87ff983df6211aec05b2cd24656aa42415601bfea022f36bb6475a8a25f23ba89bb4c5357dd766c054f0bd4cc1b55b24de3175d4eba0ebbcfd18d4e0c046230a06cf70ea44b8533d00c6c96de46a75642f92b56e70c3a0dccbdd9b551476f3923258b30e1f0d1f8d171ebb490c5cd3622c6570541ec086a01dbfcdcd7d8cb88094fee842296094cbe10e7da0ac33a9f13c24ca14d0f004a0a0c464b2d744334c4094d2eae0ff9d3ee93fdf1959f6fb5ea762e5a6a17bbd6ce3a06d5636765cab50d7b7c397041c0e0ca875f7b47bd573efeb56cf263a7538ab2ca05e5c02ccccf19748364ef91d690478d026d7a57d5f0484cf6c87ee881782d7c1a035a749ebd1abf686ad6c9b1227927402bc11ea4235de5aad72e079207298de4da01719e904939d09b57ee0e0678acc0505d02045445b57c9f8276a369cf7ce224ea005b1260778079538de2e11261cf22c58bcab7122616088a45a2401e304096a4380", + "9a03b15cfd03fd8eba10b1263bcd49e3320b40dc802163f22f26e535af275a83": "f90211a0a9754c5925fa2b8204ccc3d2ef114507e4b1fc48efbbff707af64ee1c708ce36a0f3c6b1ae90edc8ebcfa211b6584a5863183e84916d910a1d9de857834b08e8a7a006cb1459bea1febd114cff98549c1b6ea3357113d39410506b98ef01fac7f9dda064b119234085ebefc3feb800042ea5b095db70ad30657ba7cb426afd25b41eaba02d697ee30aa317bd829ce5861684ef55b05e51ef32ee4636ffb77aefb70038c4a01e353cff6fc4f4ade3d5d2f46521ad5626b668315640ba5bcb1007e684820337a0ac30f591ce13fad6ecf219ef84d97e2de96057e5778f6a50e78ad6bb05a52ceaa0ada8a07da2dfb292dd536ea647684f3faa39f21848d34fbb44f28b005e4d2c9da07a2dc4b3e8478ccac78ff210203f523529d200454306d0630a0e930f0f787e88a0aed97da908f5f5b6c0f1285f9d7a1ed8771e6fc3fc4b9c14b9c8e9f3e39dbe7ba036c31989c19c67c9a1c4b610e1395701993f78c189bc84cc89a71573c8eb918ca0e30c45af08ee5230f84edb0bcce5d3370d65882c901ac4931e53c1cbda7171d6a0c6153e52fa38c4e2bc5715a51e6ccff3729b1af5e976f255d0effd5223aee0afa040acae8ac67b44fb79a17c6dbaf0ccec294d1b11994f5feded8472c8935d2950a0af1901d0c3b5ea744f2abdc95e2d0d3751430e2470dd030ededa2d2c106e139fa042ec2cfbfbad1210a6fafb527b966dd5b03a74b21b169b23772923fba456bc2780", + "9aeec713f6502b641c10d7e153ec1418b342ce5e93f3cdbfdd2128cff5e70248": "f8419e324d03a790e5cc8435209fa13ea2efe0dd969c21fd5bc84fee475a053dbfa1a0deadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10cc", + "9bebc1d8760826b3bdeaf111cae1f5d3793bee1aea2b837b6433feb872f79d59": "f90211a0ca9d7066a008f45873bb651610e549e5c3467014acfa5988afe95a9d51bee7f2a01c83c850b04c4831e00c33941cc3086bacba3ebc39c838026eb734e2dc390e81a04080cdd6db53c0baabea5f12597f025a5390bb98b54ee84a38aa35c3accd5b66a096d8041fa4f569c9d67eddc02e4efc9d0497b3619b037be01175490e4e90fbe1a0d6b774289040c92f0ca0a9111b633548bb5752929162765cd2e90d471736260ba0c6165d79a4fe9e02acdcba2b528e2a3ed721ab17df6c0c8d24e4ee29f43da711a006338a8b9ea91eddb38de1faa04e4784653e71678da5f9af483dbd1e295f623ca0ef51525a1d41ab3308db68b24bad340a1e6a5096a4ad34ce1d777e1770597c32a0dc67281822dbad3723d1eb3351868a8217f0d2a6b921e2a1f116abe441bb250da0a25a782319aed531b1dd816e5aeb83b2aea9fae802cc1668bce919bcbef202cba00eaa4ab5738a4277f8eb227fa2c8af8aa97d633645c4bc261a3f71a52c2d720ea0ab8f334d4ab74d8761e6c011d2e85d9aa63fdae4b967800088cf7462017d05a6a0b4d2f8b7f1df61ffc4fe6ccc3a7bb9ab0a76e0307cb404495f434576e48ff4a6a08f8e14f2e64cb740402144f02891e6337134bd1a7f0ecf3af6f8f6663b3cc8a6a0784141a1f17e9dfa79ab10c48df5d167645dfddb05daba0785f001e58284d2f6a0524dd3e79c66f67b29706af94f573a9b64a96623b84c4fa0ee96671d77d08b8680", + "9c385129b140428377cc02d4334d52eab433141470888ac66883e44bd64c946b": "f90211a0662ecd0c817b96c2bce45836e125bf826eb65256d4e2d4899ba7a05646f0b264a002e126ba9c57bd834cf7e9c61100895637d1f474e6a8c3f8a6b6288c62f5f785a0008d4d79ab8a4561992869cc1574434ce5dd45c3f666ae34b41fd2aaccfc44caa01f447445c3431fd0338a2b31d1e0ae49d31116a5e6f528b9c315f80de2545afba0b0244edb0f298b4e15f705a4b643b00461d4e1871036e53b32137e6a3b207bcda0daa18a3fc58dd3ee7a1757b04c1eb707b7b2e066fae99c935f0c491787c0cee3a0e412f626f76974dd0a0fa8a59645dd2b3af275049e4ca96cfb3710fa6c1c0322a09e3851ad6c4f2b6e5fd091a16597b23a23e4271b9292765873be66f275a94d43a0afcf40b6dd8281e1b2926926d7bdf03742faee61aa52a906160b61cd0e2dab20a00b280dbc3c33d7b51f70240ab01371ca210ace47ea77009c1b484f50402826bea0f442122f660e9ca203e11a1e099e50613edda675cfc2699217fe5813cd927207a01dfba633b9e9ed4fd88ee14dd334509a2610386dff2f7fd8be821ddb91ab830fa088ca387a9b28047853f94c8a96fdb1dde2b7cdca22644fdc6e9370b1ba99fe1ba05cc45dfc0498a1385ea307cef77c33685ea218dfb3c7878208c80e79cc810b13a0142133a777c99bbf34b3e5ccdfc11436cee544d239cc5bc5d527689d963bb2f1a0a45d95c34c2e909a57230ec48d290a7134946d27873500f0f97b5bb1be056d6180", + "9deb67240c6104a9a9624598e2a7e55e59b229c8ef9a0cf056bb732a97844a9a": "f8d1a05405d028fe613b6893b034a6d4de7c3f422099b1e275febc968cb22aaa79ce9d808080a0dda162cbec278f3292cd349dd8421bac2259918cab648792fd9fd371880912d3a0e53b9082e8a415d0d4fff2932d1652ba1b32bcd00ab34f948309965d336df979a043ee191f45caa96380deabf0ec8c0aab555ac109b3ca2c87bc6ba2e082f05d2a8080a0a8ad1c933c49577d8c935fcca82685968563e7e6cca18f47924981198a12c65d808080a0539bb6abe86c897995685b00b9499580a23ae7733456a9320092df93f20154c3808080", + "9e13769faf2ba1a5a8aa823925ed273803d71a2cd9997010866072d07e0c2472": "f8419e3ac6a6e0673d29cb74e62fc1609c73268b12c0ab41033b9c4eb6c6623846a1a0fbadbeeffee1deadfeedbabefeedc0deffbadd11f00dbabe000ff1ce00bab10c", + "9e7e35310f859d75bbeadc72d51134c1cc6a8cc539034a789c7fda75ee268d4a": "f90211a0b2f576066a65e2884867bfd41649f5feb9ad17e01074377a1cece8e0b3060a1ea06bf9ee89f7620e065ed26468f88d6c401939e918432d7841c9f4321077a40c31a075a4474a2f595c15b534197d59441ba2c0cd0a93843c52f8e7698abb68eb9400a0ff45142dca5da02b200623f896ebad3d1270e959998a258d31069a54f5712c18a08a6189afe908e00a08c060e71f4fddc55c6b61a161464eef72148cce3c7401c8a0891af137f4275f02c4e4bcb84b71a3806eb324556b16cd2bb9221d8060c5ba87a06d0e9eee3090da66dcdd5490683634616b4551a0b0515fe9f3e0696567df8406a09e5155295550a0873bdaf33e1f4a820b70ffdf77f82f9254dc62867f6d776f4ca04b83112744f1ba554b0692e6301dee4ab45fe4762636f73de939beac6fd54f5fa0ea738429885131b464c4d72bfccc4d118b126a406eec23c261314fcd146269f6a0968b04379ced9f1a0d6e83016e8803f719803dd6e8174c2d12e763241f9fad03a0b0ba2a778f5082b4bcddffdce767ad934b8d27a051165b50438110d1b4340615a07505aec445390d2ed08bf332976137aad8b85cb382e08f60b2dc8e1e7624de2ea05c08ac6ee585a303eb2f722861a38ee593f654b630fc6a094dafc307de98a9d0a086c87c93c851b5702b14180526f3b7032d9029092a14cfd21bc37505bde6c592a086ea9ee23ce96ee60791d95f015ca41fa875248a2affaefd993819522f236a8a80", + "9eb65b83436f844d348d3124e9b2c3ef44159c4947dfc8347f8837558925558f": "f8d1a0b0a42a8f578087614de678aa180122b2745fd15c0adcaac89976a9a4c38cdea9808080a0026a6d09c1f97f5a04c34e47625af46615b3f9c1984c99b75a8d356b7b5ab71aa09aec50c53cb68fe62fb55706ae13f2fb9cf70440ca432684dd7bd8a21312d01380a042d20835c02456b67e93f31a453a8490af69f84f18daed9b7dce4893be679c9c80808080a040c1d79b6255d5776bdacf7bcef7205b63e929aa7e096185c537c6bba6f11f548080a0c84486afd8131bf039615d8600ded2334c94a632308de277fba548e917ccee9980", + "9f0f9fd3c8d6caacaadc2c0947dae4f1f76f905da468265057b8a3dcd5d72918": "f90211a06054510ea248ca03e66a9c30451faed45c5d72fd8af1eebd88ce6572da505ab0a030cba20b2fa16674b4063e9958a82ab444f4f1b342df1b0aad139916a7224959a00a0e0e4961268408114c1df2764e4a6b8ad84ac1e1a3afb87f1cb3e722080285a02ddf54bc06f3e1618b6961043571ca20879253eab6889c1c76885138ee34b458a0ee0ce0d8d9797c07fd5e60fdea603078a51c2f6c0e060dc1109f60eb93113491a007c87662ac00b0f8d878ff73e2570e5e87f719efe3c0d7be796c9daa5b41392fa0127a3d64aa6d75abb47c80dce895f58f1395ed43813fdab7a79334c04e58839fa06cae6987ecd2428bb471e41dabebf82c5677a9ea2176f14412f39cbe5df42df0a06231af66f1381cd4388a4f6c0b2697af67d22d6a5d8ba7dfe2fe2b8a73e6e34ca0e2246feda795c32247a1aca26267764b54cf4d20f285b1e3d4b6bcd9401a303da0973bbfd48b98586b7aa126557accd8cb1f96eda37aa2e2af94f6c04e5a6658c1a039900e4f9984375e65079fb38c49961d0816cd612d9361da53326d4ba0fba1a1a0bd5456268c3e14821e9b9a23add9c87c7c8fde816af8ac69777e544b98cf4acca0c57d1d3f439d98e32de188f7d38f0729c5883935a43c298a6d18888a95245000a0d31a9915cd043b6cb9ebb25dada19686abc84bdc95ca846ccba885353c28699ea09727f7f3dc784ec29839300495239892c0f735944535d8dfb71a9043d00d9a5d80", + "9fbf100487cc3810607a8765e733294545ec457d91f203a7cdc2d2b4670abd1f": "f90211a0f990f5fc37f416b211cb15c30d1658d73e61512fbe29ea0eddc57aa024a0121ca06e3e356c219cd0246762fcec3890058fe1d2fc40ddacc467ee890ae06e6b82c1a08eb1a2140c2d1c48c4490262e8a79b86dc104a954cfd1e1b4b52f47a1ee2e01aa06c2408f18e7d22a962804d27dc31b2f66ae084c67d724589d69d3d3f70b2871ba09fd74ef2edcbfca5cc5ac770e11f605838fa4a5c53527da3b11496ff834992f0a0379cde075852914e1cf99bddcff1268b82db99f7bef98e3330a0c16f6876f0efa00f16d99b8149cdd636b00e3e5623f709399982841ab9210acbdddb06e1ac2524a0724d983542d35f9986910a8aac0fd3909c9e78f4a9450e20511e96803600aac6a0d8a798e57e3bc97885d079dfd7e4aee9526ce17cdffbddc30994d7e46d83a478a085a5c74308d06c4d2725778c384e74f64f5b99370d31a13588f966fb0bed6241a0161619213d417c5da4fb63da46b4c710b2826517e32025b92d8adb4a9adad6e9a0a867396797e6ade3c7e897a9eb1ae5b6d1ea58548ea7fce17f841555971dfebba0ab737af649406f1fb9229541a5d8d47f8541c2b24641a0424f76e0fc76bbd7dea0ce611908391933502f922626b01678aab1ffc5422e6ad39a4e475c64b97a259ca0a90b8f73d1de2507edf0cfc138637359dcef29ff9274699adb737bfb71946f8ba0084d01bbc325816f824a6a5cbe87962f9192be41c55a294ab54e5d282942830180", + "a0ceb26f746c255af4ece54c60886148fbe4028544da65fa85551dae38a88e4a": "f90211a06f4400044d6cd7ba46e2d7d8871225d707f7d8a088bae46caf65b123613c35e2a0540b2ac27db525ab2a3c511eaf47e0f0a756419bd55b44926b3e0778c5170406a0589b2230042938899c9cfdd0e63d41f8623b07e195033477f127e1ef38efc4dea0f3d5b43fd87af29d5885b00523d2964211725af1f7335b046496205e1025c354a0ef5a8f13718059121ec9bfb19d8dfe258c0ff2b2a60fe4f96a839ea679395615a046d131fce2822ef1c7d364d034ebd948435338d7edae7eacd1bd7f4c6b1123f6a09614d3fad0e0b8e4e61ae523321b24d8712cbed83aaefa0a3debd9febc6259eba0100d28dff963aed42cc0b3854bd763ad3baef21469afebac87533fa2d0397acfa0883555dd641fdb1ad00a3ac0db9070f95acf650f1cdf7150576220f2d5c6e1eea0aa966d86d1f8d50c2996158d1d4aaef9c017f2ec75cbffd78359b5ecc8d697c6a0671ca898acb09c2ea4b081e263bf931a6fd925a3c0f98a3426cad4d0234ad878a0fbe51669065bc1dd1477fb8b9ee595343c1d4b5d24a87e9adaa19085632f4c6ea0e4a30d4bfbf89933722baff5e83b285260167b58d349a2d541462e57117bd1cfa08a245742966cd8936a616e4a191d55e339fbe2042408798465af9b95b7a7fb15a0f1778e5a1b44229299048ed9f9018f9f86895ef1b824d89266289eb0e0b56dbca0dcd75f1cdc8c565c0695ff1bb6f2ce71570f10427e443c2cf3374e5e71cd05ba80", + "a1522c638612665b436e99f6b8893f30e6b1b38330a950bdbdebbd3810af281e": "f90131a04c0127ee026af7b877383ceb386a28dbc5a20d8850161a8737d698a658327d6180a03adee01c31cc04af9715fab15d10926a0d65132fc4b391149a980d18adc3ec66a049e310b589396e2b72d89336ce564c5379b6577f72dce51f36b00d1ad39f2a43a0d273288066c4a9179e388adaff674f5a4d46a2eeeb4cd65e3fd4d1fc37c86e5080a01bf07171e51c5663761b42741e474c98a8aae34b379d3307c74d70c96e91f7e5a0daa16d19d32fbde8635db7194857f962cd65163b62b06ddc2276c2c13555b916808080a0b7b0a32b025d35d821296c9b8e94a9835d103fe564d6ddf46725cd0bc2519211a0533f645772f254fc4fcc317e7bf55a3e5f9aa684ad5388a8cbd71cb7e102bbf3a0edfbbf076d9dc0e497939f5726e88eb23d95e05788c5de0bca82ec28f2cde03f808080", + "a15a461d184d3f48a58bcbb3172587ae8b6ed30e99bf5da0148ff8f460aa914a": "f90211a06985a765b8b44b91489b4b639b1db89a7fe1c29c8aa09f5544b710f3d8555729a03e40c2306fb0c552e147dc0cd7c5080c9ed303c98ae2e77ed4784287ece59b55a0ca142215e9f60f3903b1e15affb95a2ed238c778f3f419662d4abb8ee3dda877a0866af54c30650b7d14dc5f597a711166b9f9738ef5929a222f0ea91ba1107edda0b522457dba10ba47b7b81a176a39c6e19a15ea0b701a5da378a7b1d41b431723a09fd28c5a5aa223ed05e82692268be7fc8624f47a7929e24dbbd6fa5555fb1d18a0c93777e36763b2cd2ddc5694491ee19d55b8637258680583bdb584e6eca8fc2ca0c8aa39f87ab618cf6c590dd0b5cfc1640902ccfc6724274869f63e30b8637444a0b4f042a96d2044e570098dc73c67e70e207d0b982e765a020762282d34c3ee79a01efa949758a6fc78a82ac6ab910c57c6014013874163e17e54156e0b49e986daa0605a1dad4a673641adacfc97b5e0a836ab31f8c39e5c652e01ce446aa35c7685a05996a032f8544c6739744133931f7218a31054dd50ef144f62961802ad39ea5ba0b051372af79654a3bd581fa3522b556992f9974b39b981133afb20b1e03132a9a062b7c25373d2369c20a1a596d7a015bde3f08633fc28ad202076eda75dae1de6a07724c331f4d4a6f63bb7f54a2654019b903171a4992ea1241886780ba8850d50a01ddbd4506039724e4f186c474042a6c473ecc8e3b3e673ce69461bdece4a4fb480", + "a25a782319aed531b1dd816e5aeb83b2aea9fae802cc1668bce919bcbef202cb": "f90211a0caaa04234ca99fb0c8d481a62bdb442219d5016a6a5eb98cd4d122597b7e86b0a0b0a707c4b74a5ca998fbedfc248ee017db09176d6bac4fa1d1535344d5004cc2a0519fd7da0f2aff45189cd2253e34c531f840a186e21751084a0f0d8a0efef2d5a080926ba0200605c6e1cb0bb853611924719373e99c042eb8c9f50edbe5424210a0a77067d5385727a017030502da37ee8139b600d5dd0c40a253bb1a936a60535aa0d2d0dffc315aeddabfc34620fd32d26a69d2b1a29fb0b3aa5aa30521a34dc796a0be2980c5b60d3628a2fc3ae25c3559efa6d34c6f8a3e7811355b1229f2dec772a0592058d868b5105505e29546a3938fd6ac48f450049d8f6045b57ad69be44866a045ffa240ffa1c84ea18ae203beac4166f18e6f798e679886cf46ad40cfac7d4aa0461a841c8865022d1eb1709c64bb8a93471067d9c202c2118095c24f74d5b3c2a01c185bcff40e23d5ebd9de60322d6048b406a3bc1504c245be18cfe02c26fc1da05d26412aed6311ec54053fc85a35c92ccf3a176a421160ffe36506a842c8c4eea0c31ed6baa25fbe05d07c22edf254a4ff25af1621df818bfaa1f7c99ff4c0f7bea0a5d66ceb25428dd7f2fad7b6ba7982b1a9ca59e7f9fd0882fff3b62f3ee2b23ba0ac4468160a32e439a4b573de5146427f55f7669915cdfc28ede09abc32326698a05937e092eceb32126739feec7275864c5aa892236ed1082c8daf0fb929002f9f80", + "a5b9ad3b312ff578213c07cf92825266e9ced5adb18671ace9fc2af4bada0efd": "f90211a054b5b7a05f312eb11239ca33d57d07a7a8c02a090298187795104b4fc3577da5a0563134f703c688ef0aeb0e30be1a6f5f74c1110ee7cd824b25e84c910d838480a088aa5b3f0b69ab5dffd2bbe0fb252a16a1847b5f05c4ac5f3a2f0b91a9307801a0e5374bde4be096c791d5d4d42b2e419221b1b639065ee1434f99b2ee41baead7a03c67dd1c4b43d6cbe75356367c14a36ddb4682fad7bc6870c73b157161a8a4c1a0e4019c1ea46b674932716a91967160851c8b5bd84df75277900b96cdf4bdef13a05450f0c23d0c44a8907e6bfa014b80a7d067bd346b2ff1cd7b466a5303fbf31fa099952008109f2a56fc6e573aa0dec7284301a91e821c683743ea692c023464bca06785e19c00ff44309c668f2bff4fe520d15712eb7969f275791494611a7d651fa0818b80ef1b6284136a81181b9d19fe1cd8080758a8514c4ee11d5b1d4e7e1ecda080a2d2bc7ca4cb34aad776432a20fb21ff59666c348be7a62ee67755178056b6a0327d0684b68921226f54f0c45d6a67750fb689613e19202fbb4ffbfaadae012ba0f2de852c058f5f3169cbf7aff5e81730f10d17c0013c88113c0534a73f22014ba0dc7bea45bf94c64c68062646b870fd35e324b5aef69ecef78256c249e2df6ceba0182cc16311b2a2bd5b5074fbbe0110b6564f662a7dbb45bd0553c329c81796b8a09435b8e2a23e2ba181ce40ecbb776f0c1ad3161f60095d8d4c9ea1d0f5df700e80", + "a66d18c1e708306086d82e2aaac60f0df82069aa5a68458b3316b8281e8f8c23": "f8419e3fe3b7b5e9c0b5f9ab4156c9a3bb3f70101c40e7d0a60bb3051c93b34b1aa1a0defec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0de", + "a6b31a088fde8f24108538e982d30efcb835710a0c7927446fda0c73b3c356e0": "f8b180a034d9f7fbb5b4386919f7f6b75502c1c4a08b8d02ba2d1d387c4f63a8b424b9d48080a05017e007e05e7e7cbcbf30d7875695e2380670b10b1e3db65a8c00efdc0ebd19a0a39f1c90e1eb352fd8c4865dabd9f7f83b7b7a68cfc32ebcf4af7b30a873c1d98080a03eaf958e2baea967a10b70c9388eaa4a72142f4c0a143577f8854510b84f188da03ef7b9a11fc2171f2eadcc5cbccc83f2eb9525bd670c18c3790923e7f214c4df80808080808080", + "a7f2ade61b93ee1069dd096a4febce59715104cc861ce233a3a32446584a5a92": "f90211a081d22ca0fb6cfb0dc2d996e379dcaad03ef4a19769972962f219e8a62c58be1da07ceae5bf95229b808084b8b1224824f0e9323559da650eb4640e9ca91810f3a9a0e92d99fec820caf4370b15f992ff9d24df20ad4e2b2ef6501ae3a6743f5f2d06a0582d43bc1b1bc2e9fa2443e804991a7d6601cbce9dbd313785905c2abff3e9f2a095b0daffa8cfccfebb36f0c5bb7c7407db90f41e4c7cd0ae47fcba2c11f85a38a070e5cab0558785b3644534a8c33d0427644d43bb251103b19b8096c1b7c09697a0f5658b024aa060cd251ee6df10d57463fdbc1ec29ee64e2eb77d8d63a0369c9ca03db13a12eb71d23b238d7c68c6daaff0fa9d996232af6bba35a404cd24e4e7e5a011ac11f4ea57192d871d84516e6179ec082d12be7cda9cf30c9051c3f0c3f60ca0c14cb5cec4e826e4a57d6491b0c9b294c9eb68f6ba810385b9c7ddcc1b08414ba05d62679d4ba08c2a20ac49b3a25228ff57f37bc9d68f0e0d523c940f638e1d18a017ec0364c26fccf9f1244028d15408a1a98885d808a1909471b74be5b240c8d3a0ccc99a5a66a3928de1ac6ba21996b17260f68a846bba51616e89839bfec051fea0306739a90ba655154a4ee27ef02151d9ad79be550343e3282de894c3a4b2dcf6a089b84c052ac985523508226b66ac9480fc9be2394107bb20baafc9f796cb2d8ea0de6aa6cd1ad2e90314a32f71f1878483523b2b9b26c5df94c3a8bfd44616ef3880", + "a95cc8a58a5468c6f2a6cf77b2e6214b751bc7361022a5cb7b296de4b3ac3e9d": "f90131a0c8e9065c9127aff6e001039529b6aa8c96b5ec70a708223e284ac3996cd20585a0c663bd9b0f912a5fee29c8b34f7d0eef062fd440522cdf1ab7fd3ef8cdd630a4a0dcc01c9454d3937827f01cd68262a72d1d10dc3fc94336f21853c300c3519a91a0f8085bc71d2a16d0b7dec13d7d9e4a4de8b86539fb5928dcb50a7e32e942fc0a80a00a92e9fc753bfed7c064e7fb8a4422448feacc127f2ceffdacf2fb9f7d53de8f80a0aa602959a2ab1165c811a0ccd532b3a6b2389e142ac5197343874c8274df0f478080a09b26c90927dfb2c38adb236da9fbdc287d65d26684d8c0d843b134a385a9669480a0bab4b91d34e8a5d7ebbedb6f50208979d6b590e791e72cc47a4775e3df53d32780a067a374108f70ded33129518bb2f2bba19ab25d9b8c9417301a8ce38cd8369d448080", + "a9754c5925fa2b8204ccc3d2ef114507e4b1fc48efbbff707af64ee1c708ce36": "f90211a0c878667754561165dbc3ce5b567c306d2dcaa3e821df7ed0730121791afcaeaba06f940f58697e8c7671e1bf20a28554adfed2ca7e781d90519f85a86934c358c4a0fca4d03f62e86d64280eb85cd80d8e738958de3d8beab8d9ebe349565cf27fd9a0c74250c0ed316df283f21fe4484133acf27107015fa4202fb5d5afd410931b38a0d8fea56522f7a124e42e78352e9ed400bea9de3d74996288f22e66b38da15074a01292ee74c1b3cd129314cee68b64cbda4aa4817645d96db9475bbc3b34328471a027f0bb50bffa70575bb1c1a81bf1acf1b12b014dc9d1451bc8c644fa424eac3fa02f19b6bdf88006a8f8d96bade41c90093f04e015ff73df678c6368ccc23947dca0fee24299429eee0c6c4b229ee4106fcf4eb9c09595180575edeed5183cf0e2fba003d785b24c1057a79d1ada09aae526948e48144cf46e7b432e2f4fca87f8ec41a0684a107b3c20380e63a708e04775e611605f0b7f158bc2b8ea31ca5a8e318ac2a033df31e890c7f10da97a88b2bc5a56292e0ea8def1f7ac1383842b1a0132bd95a08f5842e04c76dd97c971d222e4d4511b858ebca22ca04c630f30afc4472555efa01f03b34889f5d5af87edaf183776d1a1db0121b99aeb41a654ae63b4ca58cbe0a0093d5440d5bd371d683db761b9940fc49a78bba8821630279f256ed3ccb1326ea0ccc0691dd3a1080fea65a492516eb165c6ada1b55e2f350967aa5c0bca57891280", + "aa89e2d76747298c8584cb2e39107fa067d3252be2999bb413d7f750f6a9bbf5": "f89180a075be8e36e4490bfc5b4e9413bbea32aadf08fb546e557bff546ed2e334cc48c4a0fcb475af75a8aa06dd0f3a827955770c6059f56edb8914c864c218610fceda618080808080808080a05f1dbb342b2e0817db500004b70edc5e06117226dfaf68c1aa7ea363c78bd8048080a0490133ebba6dcf6effed7209330072e44d9c0190fe6c42e7c1564a9140f1dc028080", + "ab42b8a0a4ab70cd5edbf515b6f75b1558378e49bcb847de06edf9bf2d675722": "f90211a04c65f171f051157db613af85b48ec47ca272344a2e9682800df4efd786672080a087780dfe413f4253e74a9a3b863cab13f4cb59e521288240e15eee005a63c072a0d8b6b3102e04b0733603638cb5d11175b973e6cae9594c652cb2b9b4c6b90b46a0cadc667f0559276a697eabe4b5c7f6d0ba825c8d92f22963743dddfe9396ebd5a09de0c2b932d24621bfe5375ac9dbbfe11ad78150858538cf28c51fb10f60fefea0798374be53606a2fa530ee0ddfaeab8b2651cd0e415729b1363c542e158e3af9a0b46a4da81d111638879bef6b56eef44c94b2d74a828b4c5d775fceabcf7c7628a06c1b92c85bce5b7393737f0348e12b829f234ea0746c421e3a48974e4f2a32e6a06de8aa26d335ca365b36d412e8692c19a503720232f0ad7d01e6c47dc6419633a03bfc6c61d6e8bf3efdbf07cb42cf37ee778307f73f97cee36338dd74a5a6d6c5a0491ed6af3395c485ec5d530f6adc2822e004522e2f73c747af028de61935efa7a087eb394950588aadcdc7f820df00600ca00d75803929d7a9391b3a52fa81392aa094e82f5a816b23ab8154c5198b819f0fcfe3473884eafc933f27729f9ce6c57ba011a3ea8230d1bccac0758f047416c7b4bb0003805537405af8682b53406054ffa00fa9d8b192a42b69d92aa3f62137981ad4e3a05cb62813bf8ac25a4828153d42a07a4b3b26b7de97085be14a51d1c6824574ec65f9a260646e67778702751e677f80", + "ab8f334d4ab74d8761e6c011d2e85d9aa63fdae4b967800088cf7462017d05a6": "f90211a011a8d54820f471b7af2a8fc2431cd10b8e47ebb50006e995f5d273034179db42a01d59dff245f612088a66f9dbe74d0f1e63dfbcf0b78dbb1b55976a857bd01c34a0b2b21983dfe447c7f53d1235abc73c1f51c42cd70f0b59ac225252ea94201e02a06672e5cc9c527fc4fe2bdc4944321105a413bae8992ec1610c16ba37c0523c76a01d7c6ccbf22b6e84ba70a15e7922bdc881c4f4b54f940478dbca3f8238bde5ffa002d9a94db206b92c01503a33f3bc83ddae6f30a515c27e571d15a7fea16424e1a0a716f3de6ee62ff1a6d9802c055d7b12161f85b91327f3a96296d3b160f6b5b1a057633015ed3e748c28b6d35a36a2f0ce526b34279127635929a8e6b7879838e6a0a43e0f5c229b7aa35ac43a0566704af9650d4bcba0cf11047a1184a31e5f5023a0b716e117a0879422ca0f7cd497d6486447cbf52e6c3bbbb907cf394cd6ffa052a04cb9927966f3e71b4941507d3a1376c7a2177dabfbe3d68c71602f43e2836229a09bf9bcc7aed4e7c2ac98ad840f8a230be6efafa117b115983b8703fc036ee079a0cf5341308f7dc7d0acf9362da5f40847b49b79ca10ff58433dcee9f71570ce24a0189978207b09d7dd0e9692e40169e488cbeed3e109f4211e6b25c11f2cb8f483a0d102b90e2d2abab5f934a04a068e3578d7b94359c9679992116a61a4d324b3aba0ea27b858729203a5c0cf04221c084418433da81dd37edf90ec76fdb694f18eec80", + "abd9d3ec44bc5d2068826517627794d98005456ad6c30e22eb9550c6e1a2ddcb": "f90211a056fadd9664a64a3fb3ead6219153c84135b2215f3fdf684ea995a1c972e7c3b5a0dbcfbb5d3a36c5e0e1a28dad29de7671dff3fcfaf290705c9dc02e524f2dd062a0ff9c1514ed9036da67d464bde223a03687e5cb2226dadb636d6c16ce3cc8ceb2a01f34d0b7c1c7fed6d19b82c7f008370002f1272108569f3a8a3e177dd65a0ea2a01ea1be3a80091c7126e1913feec45ae1d13e01826d0bf9a6629851caa6783675a00de1402495cd4cf792b93dd477739c355f386edd5b456392ac4666b927ab6204a0ad4da8805249735301c7b4eb24561997f0b5c11c3c79435090abbb9b2b77336aa001f4b87112d6da757d12df2465872f651e04ac747381983013ab279ff942f0c7a0f4c5b0c9415ade3383cf2616de50fe30c4a955df18127b9ff4dff4d53622f17ca028506b3a07e0304195422bb3f668f9b74882e8b61c3968186acf184e3368d6b0a04d4a497b73f396f2b00b9c600251a6469ddeb11e0056593a451bda13b94a4ecea0f2f5ed051f21664a2c24fc480c1240c56a3df2a3cadfd6f9c7ac98671dff93a1a0a430c636b733540b42f46bc5c8dbeb4f968bbd1af48bea94b0fd3fb08baebd6ba04cd75689491bbe990c23afd36c12a805ed0f08233e38885dcc24b147b8577b67a063972c80531389f3a19f6a9f9bdb33110d9fd7ef5d061ebf12a404d840e7c169a09695c4a3d32e5c1faefec9da83a053161b79c67d44c23e77c42f618fe8d600d280", + "ac3fa07afad499090ee0504149efd5ffbb692227f13ce4e711c25afbc42e6808": "f90211a0e0a0ad7cc2b1ac161f955dce45b76317570076357e47fb808c2403be8fecbe5ea0e1f98c7c00ffec5ed047edb33fb3c6c6f09342f8d0eccf8855626cdb9c0e8212a03b2b1304aed49717ab2801c9f549f75a8fa2ff2836bdc155bdc14b917b6d5658a0aad0b2d535b4f676d5f2874126abb31626f3ec351125ec3195acd7d95f5907faa0f2cd55fede94befb7123a1627697080340171ed746283f9e602471a189d0b7eda03f2ac9752cc668e5494b2d8f7cc0c77a2ef07f74349fef1308f432d97d29ecc5a0588d8d1270409561d2664cddffc7a40882736a8f04186773e882d83b0435e8eba0a78f6630fba285c7652147f8aa53090f11e13868f7da19dfbc9ecc3d6886cb89a02c8eb136b6ccaa84f14d60fc4f875ac861c295feb70f23dee63dcccaae793ed1a00b811e5197aa52071eb2d8e179eb1877b27b0f4d1fa02b05a705b78ca87239f9a0497c5287edaa225b14f901c1c2cd8f996affa13ccc4ba07e9a70c01c2845ed72a06b5cf720889edde5182558c32142e258b09776ba35fe2a6382b3ff8505ed18d5a0a631b8ba6c18f5ca5f6faf8eec96bed653c2c42263137ac833a93b3c02a6c31ba0ae5270af6324fd521c7be33c0419f9d529d4fa86b555e7e17d92854a9e3bea69a0c0cf2eb86d07fa5a5eb15e0b1417995ee53be7ccb5dce2e82fcef7cfeb6d85b0a00d65773f47bc8d6d9e38fea3c666e4d3392906e9f44ed5be6b618965b08a90f080", + "ac465f2063b68d167cba3e4ee5c9bf7989675f46db8103a38e4e5157fd3bc21d": "f90211a0f2bc25e6f615eaf171f964d9d77aea88d28e7c2daf87b0f23480692801a35b26a0b0729d86aca05af309571f89b408ef6b1ddf574a94608de103ecf57c259c7cc3a074532e5129f6d7a14bc5aa655e6f91810b4d9dea69e26df0b2ecb6be63a1e25fa0ddcafde5dc36cbdc383ea9d5fe65152a5749d3cb25681e87995870a35c5fc509a04d617c974054b1feaf8fe32b2c987f53b506925139b5d5867e57b0eae8b851d3a0e3463905e69f2035c0c59cad24524eb638b4b547a91cff6bead97f3653dbaf44a00774e8f7cf423b7ca7b0fc834ffceb4122752f19b1a0ee01613a078d03ac19d5a04c9b2d1f4327da5ec86d6c4bcf12afb6e1b132cab456d493ba9aae1c299a72eaa0cb678235d1cf7c037e991d646cce70d3fc7372aa029533f3ccd8686500f40168a0bdd6f49ed2416c54ab96d41dc62aa5ec49992af3b08f4daf83bbe4ef5e506b6aa094627767aeb7209fde351b766ef94db10c8c22acaf24013b046b2fc09f6efeb6a0560b4b810d30c59f0c0f76fff4d920b3b86f158a7d6e158051724c80482b4afaa0c4df07da964c84e14849ae7c96c1ce0d816cbd8a25331dbd224d4af7d6a41256a07f5d6256f99958039ff0f7ee12613e7d33fb823feabe225f19aa2b4600e463daa0df21f07a87990c1cf36ffc9af55e8c53be75357dab79e2b305a8ffb369c3523ea03c928e9ad2c1be43388773b4665e0594f694f626575bf0cca09b36b15a1d2dac80", + "ac87e70fc7ef7fe6389288cebc1e790e25491bfea114e9db2312ee688debcca3": "f90211a0364d76b7e3b2592165f3f230f886386a3109deea68cb89f02aa0889b35631081a09722d35a4b103a745c4457f703b4e1e75d87e687881ad5ec5bc8c4e914bb7abba0532e4f5b444817ab51c02c4a85a4c41a0105a6cfd6122617ca208c1fa5ffe9c3a0cc7b4c69c7e6c4242f46bf988afdbe9a55e5d272e44c5b4a8cc2c00e259f0f17a01bdf82c46f6eea6f0fcb36d462b6b95ba984a5b9592b75c9e5de903001faf77da072ec03de45e93b8522add47779accabcbb4fd37531102d78a83411e02cb199b3a00c0cf42208dce89d20f558d13d476a0f4974b986e9d8cb1eaecab6dc6ab4162da043e7c78ba174dd20a60619da5e1d34625ec653c153c339fda9fbed93e1c9dd1aa0faa624afab2347435e173c5ecd3cdc07d5b7125d249be305ee9b9bc910290bfaa066ebee64061ffe17e42308c65a7bcd5bca3a4e5a6c9e06c84a5075b386ba2219a0f623db5e1dba9bbd1c8d0c1a259bd73d08d22a6ce925992eeae96e7516fd655ea0f243c5ebc362e52cfdafca58dff732e9fb096a132b859e205326c6bc0463835ea064c2cf9a8e50f393525b72c2c70780dabdf34043cdbc027f1d34459caf72832fa07424ca8fae70596d056f493bdc6131be524e03d076c9052c70fc3f80e203438ca0520f4410b04f734218b8a5026f6c727bf94dba55e96fc950df287effb0b7fcdea07b9864f4d865fad4c3c4e247fb0b8d8abb6164c25d12d7e64ce47f6cb5c0127f80", + "accb7aa10bf06a11781d12757829736dd24a29ef152ed3dfda429a7911e6543e": "f9019180a0c031ced7b0362485d07d925c38d8999143e47eed221554eede6344bbebece10180a0d971489d3c532e28f8fa13a4190203823ee662109245f91a2a9f556bf6b7912ca0f1dd6739dae64f573d13765ced3793114d5d612a4db4cee07e0d6c90f44c2bd0a0ba3b50611b8d08e112f786721ab14be73cce9c08d56415cd99f462d9f7d0655680a05a91b9febc9310fa629cff24d501522817bd73784b3fb32b0a1cef0e3ca34feea0dbf9d303b1334114a61176fea25539864b5976fedd566a715651c10ad295036da049c44b47530735680f1bcbfa87cd32026655333e67249c9513cfbac298e6e02a80a02dac67af3b0bae52c153cf4292653e89797676ee05cf3f69ee0a29d3102d1e3aa01efab90c36ac52c32a48f0926b0986b02a4f417a17492ea078d17006d58c465da043d6f31c6976b88ade960ef3a47d63637f44a3179b41b7d220cab1e514559d4fa0976e1db067552c0e2d2aaddf847e5deab2857e26d1a365450f683e23066d5bdaa03c580ffd92e72346d3be71cf8abd53f2a419943a269a0425439f3f265a680bd080", + "acd4dd99d96729011fecbd6161851ae15b8e2ff619449ceb7ccac82bb6fbd0a2": "f90211a099144c1bd273efca614a1f278d62cc4a33d5d2d8d95ce7ce97dac1b7760f9258a0e1eae345d43077524d2630793ab52d9d6e69f54ef88852cf59f024ec96269c40a01a59d53bd34f51741b4b3021bbf76a0b5b27f93b8444004074ffd93590abe4fea0bf6e3560323a881341dfad581565bd18cfb4708b88b687284c7df98fba587d1ba07f8e5ec72b94204e19224851309d26c7c2e294dfed88570889d51df068fa9010a0e4eafc5915fd9f5b9a8ce6c3203f1371db5cfb93f0dc5547e7952006e7bc5da1a02f4419aef30e06b2282a49724f44b97b59202c56294ed4027402a1ff329c677fa0abd81c7bcd5cbbba8a9fca75784738679a5a10f02536e9f75b6f522b7319707aa08524023b495a8a1c50f1425e674b31223ee5887091c1466f30d80a6b8e685f44a0b35005de179668b12f7828bb1afd51cc709f6d05a3acd3573144097d442a16f1a0238bc07742627216becbdba13c4dc28de34d1a204c4f5c02d733ed9ccdb3aad8a040ff2f046c5203f41a784d99bdb3e6aff7f1f72e115d9980f042630e5f415f7da0b918228faa2bb810c79acb2959546ddd5ee7838f5d80fc0771e9fcfb8efe6cbea0a1522c638612665b436e99f6b8893f30e6b1b38330a950bdbdebbd3810af281ea02ae93a3b977584bcce03d5a1a9b17a173e5539f3b329bb5e4c4a7a23b368a8afa04ce53a372ed0fbc774237b45d8c20565d540a51ef37ee898be0d0feb654f104c80", + "ace05f43632b41dad7e1dffe274088fd9f245b1bd4964ccb1773e7f5c601aa2c": "f90111a0e21c522e7e62c0d75b3013a76af63f7638d16916855dc60234ff558e274892d080808080a05f36258fdb0565afdbbb1278286c64a542b52d766fb987fef07830f6a81c3d0fa00976838ecb5884eee898f1449ef015447145455023b7ea37d8813f97e9f70147a0e88b62a9be2a2ea43fbcee4ceba83c728ad564d6128eda8e197115365f80485a8080a0ae4e60dcf92c6ac7cdc2acccc3e622e2d062ac24cdcd5ad7c995940729abd115a0fc939cb8d8dc1e0bd0c07addf90b80ae3e2e1bb6ff3f024ed3e33637ee82f801a06df5ce8eaf3f8ed4fc76cfb3a945dd222a0ff67c83686a691860619b1a56cfe980a08de880fbc0a635b2db327141cfb6d65cded691a8c5dccd1ba92d6c8c80e2c22a8080", + "ad605d41243e74e8e4cadd453b01bf90276de82bd5abaf71a994aa398efffaa1": "f90211a0fa74736a21e33d7556204f836390493ccba824e919cff1765c5916f3f26d772da0a873b44ecad60d9a862775ceed81818554be4b3e076747e98f9a9db2fcc61c25a0c43bad2c9d0a321d8f72ae79a1d8e395f7dd4d8ef2f5dd7998e35624362bec81a002788dddd0412b9776b73bb77e9ee771f7458bd7499b4b1f0af897f885c7c6a3a0101a547f0a43bfac519164eae7049d8e71f5aff9210bf48643e8f0824070735fa045d27d8675f4ad682b40f1a0e3d7344da4a94cd01f5705aa22e896f8dd9a9a39a01843315596127eab409e9c4c2bee83fb16b07c6db948c40cf1d8581a8457eca7a09e5f037834026e9f3b4ef5c1a7e78044aa46d70c27f41564f3b18699629b75d4a0cda827398e41edeaf92e4548905559c5dc76088cb582aa79ac5b87eb26c24784a0ebffe75588dcda804ea8d403bb65d2c9cbd41d95b82036d44c1b6e0f54e017e1a0220bde82110485cfdfd1c00918cf206bc6d18efece97eab95f8f11904d65bb79a0e65cab575db2cc72ad50159495969ea543ce5bd22489af8b39fe9baa211e0f3fa018538ec0191b4f2074996f398146c701b83d31ff21bdc325a166867dea39c321a049f50fbb24a316cfcea301e6535096cc7ddc49620e0276fbc6dc73250b1ca165a04f22d78a5c1876a27f8b91ea09f447477301ee5794bd07d336fc3c05f9ee5e68a0863193da4ff2a963e9719842e27613c1275aa94affed33a0c30e133341c6db4780", + "aed97da908f5f5b6c0f1285f9d7a1ed8771e6fc3fc4b9c14b9c8e9f3e39dbe7b": "f90211a0ba85c26ba3fcbf51d1229ab39670bd30c83f6fee3ae8033309f7d1968a992833a0d2f870be900a8ca24c8b4570a8a4201d05aaad53e8c7b2f49d9ca66677a17abda0352f091cf3b2040a345f06c96e7951e62ff6080f90fe9dc01082c892e492c191a0414ef6a2c71a93ef5ba86b6973511d305b4f05b072b5f4d77f6e156547a026eea00d18db612e27e814d4ba207d1a911bbd6cd85e09eb86b1630cc552a3d95fe840a0fdf5917239b15a5fc0c011b0d14ffc734407553192e781fa0213f4330daeb60fa04cfe2f6080ab876518c32d879faf763d0b54aa131483c98f5315d75fced3e826a03c374e3588196c688a8c179245932a9c1e9849a89754bf1513fcc882cba0df3aa0f41809bfa7a366d287eb28bed71fcf3bb39da1f9061b42ae9f5dd89cffd66e07a0d6e2226f1e8062f80d891ceeb0ac2e71c9c47858c98796427fd4688d95be19ada038fbd60ee2e800e2a8cbfc378299255ebbdd427e1917c6f7401e8f201311d48fa0ff471d5ff539fdad83b45864bc3cadd728c6e69ea4af8561b02bb4d52871bf18a0111ef78c006c10f54a6402a31d3984c90a0e199c6b468693af13cc088aec970ea0904a6664852dcdc7c3a19261ef970b1c60c40e7a12635c5c25f3207a928e17b5a06364e98d6366f7d3282dd1c8242d2dda97ec1008d772a905213bac43b7fd7da0a0b17ffb03a31f33e6a0ca87745bccaed29d9c9208929e8bc8f804a74fd0e295fc80", + "af7a421a3f3f128d09d801350510cfcdd9d576c2018e6b8843bb113fd8743d8d": "f90211a088c2387501bf41d7a39980d66312be457dd9b5ef855ddc09a6e625ce1d81ae42a0ff2cbf9575f2f410a1012fc4756f000754a5840886d0ebbfb820e9bfb80a1e78a02aa04c103c11b0b6438f43d1f1f8018f9b8ddd5321d283bc796a00cf871bbab5a06bfced91f24b6d3ef1b3ca9b22e9426714374bebae18f2803c4a008c009ff1bea0e72a2fdc4c2de98ec2575b1854baefdb8c83803b99fbccd262aa211c689904d2a033b3e1c3e2d3e98ea8a6ba57071faf66808168f60bfbf1136ee8012468af4377a09b0a34781ef05d87d8be1c11f516b92943f4b9002cbf2ff4b7c7da0af2d8c71ba062214c7663622dc5ace96fc040c82da833499a692730eed3b12cb8b92c065c05a0e51eb8a91a53d9b9723020c10b9c90c9a5357683b2294c08400b3e18cfacbc31a00ddd16129b717c4bacb2f89ec055fa1ba20a1ac97a77719c14f950247fb9eed7a084276c2d0dfba711259ddbd787539fb4e8b6f821322a178451951756bf9d9624a0cee7a74be5c63b83ddffb8dfa21e1c0b888a7a5daacdc057446f1b040f9628a6a001ea2dc751637c0b1a65a56c6102d9d51153b7b95f674ad0b5a7c99c83c236dda03b22cd5215424a72f16a168694b974d6c4cb2d84575e24f32c5d4fcab90d06d5a07d7de541af4169b2b0ecb94f161619e1e6782297c719b5879df4102f3b4e616da03d211c339a3e6b614464eab38278a37d2ecd0d687971e10a5ca621f660d6f50880", + "afb26de13662effbe2f8dd309a5580206bfffa3b79654a3926552ea880538364": "f90151a0292bc7cd7ea2d4501db110abb54709436979e740fc0f01497cd18acc184bc3c780a024007160aa7bf816f352c94a8ff18e0044aaf6f81626cf5917d22229737498cc80a053c344eb44ea227fc8fb8bc94401370ea6fbc39211cd97b59dc88a2969b8699680a0665afd6a7bba8bbdb7b67b0ffdea7e0bcfbd72c73221771ac5f0b10ef70d063780a03ac01a5453ff71366038daba0073228d0063e5fc84a4963a330122ff58c8719ea00ce92d05bc4fec04a835d497cab351af480a35b914f0460234afd62f8a7538bfa0217ab6a2d535929451d74785a9562eaf02a04bdce0fe20112c35cd7f314f968280a00e4fd4bebd34b098509b5060b0750605842b1df66324da0a0043cbfbbd9815d680a0c67861c6d9481c1a7a2179d0c4dfc77de6402eb05525f7cb43355da4c8fb0f32a03166579bc3591547f89db41d2113ccd0ceb03a18b344ba5156acefe4ca891e5380", + "afc7ad54a29e704f07a6dd160d6a2a4a68c1948b61f3dfdafebbc15b4bb556db": "f90211a02278657b3a6925f6ef6a926ca1e59a4175e43f7bae07557e70d59096caf0ce51a01c0b40975b27828bc224f65076ebc6fcbc8a9af6f84224877a40c8770cb708e9a027e40f9a2705ed6b0c3c358ab6f4904557d36ca36824a31e64418fc6b04bf183a0085567c6f37decccb503d26ac30decdc924d4233e4a0ba3b6cb16718872ad448a0e53bdccae7bde822f4a4caa9c068d0a2d3f923e6cc534d76c54d55be09467950a041c0ef1e578498da13048ebe1eca4729fb6208d241358236021e085b247761cfa080109d39ba89edf3544f14ffdec453a72a9613db87ad18fa061d1b9959f6b873a05d6d005b3c90919a286b145f65ba6bad78a5c3ae54c6c8de3ac447937688863ca021320ff5b6664481e6ce309d539ea2883141c54c18b75aa7408347c9fb58cd3aa00a944c155427fb757a5071616199deae8b7271b8a36883a71920b90aa4dd4037a06e6760efc69005f443dd0252e12b4f20ce69fa53cba1f58cbd503a4f5c378b33a00bdeee122274cdd8ccee1baa43c12564a027ba6ee101231c5633aa3240fb703ca0f8b141298a73945d7dbaedd8a8a0ef422443d08d958409627b54161b1b277907a0356641ddd86e14768b0354aefb425b3e85489318c3ddb51510f4823a431e6748a06eaebdfd878f7795180b0a6f675af0ba7d2a34056da0a188503fcd92c8f908d8a0a08a8c91366534090fc85203646b89142972e1c04151c4991f8a45a72ad9735d80", + "b051372af79654a3bd581fa3522b556992f9974b39b981133afb20b1e03132a9": "f90111a0a2cf131990d149475965f8a6cd06f23283bc6c41dc10769a4d338a7135c495088080a009dcf998e05359a060336b7fb50688c6e46babd0c1a6422cd9a638f114ff3b2780a019e01f46e9141e04ef8c2289c3bac4b75e02b377ce27f910a9d0aa6709a9afa6808080a09e13769faf2ba1a5a8aa823925ed273803d71a2cd9997010866072d07e0c247280a045d4afce4a70a3c189e15e4f70737ad624c2b9f65d75c8d0e354183491f6a103a0abe1374debba3718094c814e798c37c1eb6221e9a965865981d8d496d560cd4580a06f9459742cc06142bad454f64e29ec1da59d1e1cecabc4bac4794c6bd530ea60a0237d99f73d46cfccaf3f6196fa479f966c4fdf27d203b8a09b307531c4d58b7080", + "b055d890fcdd49d7189beddcd567f7f8cab5856323958217ee72a99376cb38f0": "f8b18080a0fea658cfbc794ff7c2559da7a54c4c498df46f27749727c9e3a2fb125f01a2a1a01ae94c8661ce1bf5ca026d8b62303c9db4f4b0897c177b5089962a8d4448690a8080a0ddfd2ecd9506bde97fff232632c07636e3b4e01caca50963b6cf664ccc07f43c8080a04533e1eb133b2573c0684e09e8ad69b2f15ced7b249cc07f3f34fb03e2d588dda0fa7771f08b391fd03e69645940973cffd4f0f6a84fba13af48b4296098e9f088808080808080", + "b0846221076674fcddb287f65c4a85a2638f1b1537d58360daee74785b76b096": "f90211a007dae85f75251812faea6d70b7a61053cff818277ecb8cbda23621d8e7f2d602a0c8b7ae5f86497bd8c9256197368d2b4502775374d2adc9ded95e31632b508affa074093df1ff178ea4f4c246b4504da7c5886f108737c2d372d01aec673efeacbca0c06fca1a6ae3c25fa337beba64f24e1e333a74bb83ac52dc81ab4bce4064804da027af6270c47c1d26229e73c272398c5034e0328f88410e6522b209ac2f9aff3da0c8f22c90937671622603855f1f3a2017797904c757955946d795d0d506d18c24a0946beb7acbb7b128af3f6d8fcd1b2bc57c28730d15ca9459505418f3f5798b1da0fcfe32b73244dc9a08439634d846a39f767552ae05778cd8e52708bea25cd805a09c0018ee90f45bcfed5e76221bf3fea9557d2aadd72dc68e3c8773b9a9437d16a07c524c75dc1226f5e328345fd24648e24061fa06c122cbf6ce09386066064510a051cc0d0f4a2c99a1115419570446aaacace212bff84ec72e824bf602696cd001a065b78367b410b827fa6a340719a8dc9131a011330d3efc4c46aed330e97504a2a027d01748601b67f84204741ab93ff1927c513f58bff22bc4e1e1d22700bce5aba0c0b9ca8876e6c2f3b7d276556cbf29ef5a83c72a959b3736e795354dbc30bbaaa023d7c6aba3b6aa9be07b0159c2312d89169d99bac145d508792ae7ada145fa93a0c5ebaca42b422e4582cb723dacbd51f7552fb405befe519a6a8708c2751ca98f80", + "b0d3dfffceb8aaa35130a73b0b7152744056c0bcf01089d04f933e87db10f884": "f90211a06fa9b71376a00284b607267985d40172740743158eac1aa2eb41b5e753d9ba1fa0ad5c62cea8f5ad1c76b13b879eb096fff286f804820ff9cbe2541022d0879670a00eff46381bf4df64aa616a390dead848d2f91be172b53e371123a8ec0fae7f2ca0974927483baa2e35dab3f947f9e2fe14613b56839631d36cc3736f77a4166e30a0eef76edbb6232031dfa63fec2117ae16d9f496547b114b6fb45c7e7fe02a959fa01abf94952f2ed8edb3b172e53afb23aa1adc3ae35c253922a1a3ae396cfd4a31a02ea8f2898220d76cc68b3378120c7bd1a8081fe6dcc4258a63c2fcc053814539a097ff1299415634827d91f5adb81035bbbd6bb3418ca15005f707135e519569a1a0e70b15a8f674dde82269d6e4ac7f920c037dd18ba37d67bf14551b09e46cf7b8a03f6bae9e508061350d0b8f662d4600a378f72eb0f9afb1546e405a69c8c62e1ca095fe111109ef3b829b0b96ba779cc36d4996bb85ce18a3205b3b73ccdd7500c8a0162896179095ecec32261afd082d8dc5e3b5b1bcbe2092a1003245a84877c50da092c53aa36e8aa879e4d1faca25cf8947af394bd723437dc1e0fb68678d0fcd82a04afcab30962262eca9543282dc00e63dd315f2412e3300d63c0adf4f2803f72ba07afb23848648035eddec36ef0470f27c56f70c079e207bf8230467bd4ae8063da0f43a576071970fd464524e6b740523c17e6fef10bafc0a06abf6565b5180806880", + "b45e67d0c01bafbc49da1624308d8c120f3a730bc159177d58416f09bc1a775a": "f8718080a0091b9ae20dacc0f3735c79e897e9b8c5bccf7e95f09fcc43151a67bfd0335fe980a0c1dfdb5cbbec198a6cc3326fd825c3384cd1a0bd88c5d269049fad7a6bb8f061808080808080808080a093f1c55d62e67da9e3a442c2a2b666c1e9511673200e922e3adbaa7e12aa67638080", + "b47716d1d566bb445b41cf129322cefbde28de6a7d98101c83cf481e868c28f2": "f90131a084f3073662ca1adb60fd7e796634cff628a93ed439b8f5070c030fac1d25150680a02626fbb62c0888b06854160f1f0e5cfe2dc8e527b2d79ec75ba8264b3fd4cfb8808080a081165c7f77f5dac72e244064ee63ba03cff111332bcc83f384a33b18d29ef766808080a020aa6cd3c81a93c2d1e31bf018ecc3aade4c83bb3fd733599599f6e08bcdd712a0b43cb3319da6455328c8392f6905054f78ad688545307db68c478b9917c2a7c0a040d81393cf65ed148e01f9840794c9a71513b26dd53a9cb997a44b39abbfcb8ba09aeec713f6502b641c10d7e153ec1418b342ce5e93f3cdbfdd2128cff5e70248a0ce5142ced367c47b3c0c368e910c842d998f62fba7f613556db3ed8786ecfe47a0d69a0eb64a234c08863f798781116d82998edcefc846e21957d491f8c5e3805f80", + "b5becb50edbd55ed62f7b8440a4a590fb3954f73a76c4991f7622e0e412fa236": "f90211a08bb5313f5257a2a983ac2c853c2b792e9f59f60da3e6f3945317beae3362f882a069e1bf6b8e7da0eac1536685903de4dd6c29499a99038d3a2c69a5017bac5732a012a1318053742c441486616c1133a8cbb6c976bf91422edf64a392d16c9c02d5a01019b7a92ebdaaedf7f48e5323bc60d423be1cdde002b2f26ca67f613cbb3af2a0bff2a99536785013a8b896830dc244f17befa3ed8d0cb1b784ad081ed261fd98a02c79b0cc68ba1d4536e8c4fa310c46047334d2a47bdb3e922d63c71dbf2f6b3ba067759dabaf844e3b0df1d3d6bf5b938b975881f74035551b4f7c0c1112024dcaa0f7aa7b49feffe534a75a0b572f2dc8d5b8ce222c49db3b68939da756db2cbecba0848230fbbc03d04c007b4613e83de1d9fd189056a4a7d18be1087882ad04dca8a096bfb9703af2fe3eed16073bd69347d157bcaacf88866690e6afb3b321134527a00d15b219c7b86ae67fb35818bb6e5fdf57b61b1271533acec4ec23945ed1130ea0ae3916571ab0efc40b70373ae78f1e85e05211aad9c0d0abe473eca41dc948dea0dca1f67dd17df0f302567cbd480c9ed9de5ce1284a0bd156861be4b293f6a15ba0c92d65f3a31b77c7780cb35f8f0a63a51545c98099d2a9ce925aada272490863a00c423590db1d70ea8c104b1489b0e513288930e1246b200f50daa09aea79a466a092cd14b516c3c1ba0f8f356a69b496caae22b5e78434d91df7abbbb6d410069280", + "b6b809a7bda41fbe525c9f19a6184e565a7e7bff7520f4f8ded00cdea697f833": "f90211a0523fb9cbda8598a39df5140e7d61f5a8e51f2abb5752e57a993d18424e0b7c07a01d4d8c1c48f0836867b381f666a00f514f01e43d3182a6dda2680ca722302de4a04cbc377795a99dedc57288023f3ce5e6cef68b26a77987cb561bba4d5d829995a0f7916f5e4aee97c7eee03840857dda5a28b31a370e9140a28fe8c70cd5913eaba0fa5c7688de29efccae765b840ea9a2b155ea8619fc4e5c78ef980ad416052c96a0d4eb3296e008229bfff3e413ae9a96ff4dbcd56137ac27f66d6411d503c1d462a00f608c600456f9e47857e55f57934c463bb4d51fec3bf65c81731055b4fe3ff8a0648f00ee1a86d3d63acfdefd3bd3b6dc75f0b1ca2378f0504781a15574b0b326a0a9a47f489043c8cac87b33c8b27172b737bf2363dfdd8632f6017c359aacad7ea071ece5fbcd63b6397b0a70709d16393ea3441bd247020eedb7962c7095336699a0ed3a4c9f33819015507654ced48e2fa7dc3060d051482796732f93466246c6aba0595daf1a3c969d51952728631d7683ce44385e638908cc67830ab29f2b40dc17a08191e83562a1980d567974c1f393e7175fab24811900850794e9a68a6eb05a7fa053df309bbb50e1e754e4beb296fb35e1547a0cd094b49981d8ee303a680f24daa03f04454f868623d9dea6b79286d5d1c8232df4bee7a7c079d5eb91ef76d402b8a0cee318f4bfa0b6dbfa4b062a151940709f603c63c712bb5b8991247ead64898980", + "b79811242d6b5b05530f5ab13df4ba3288c729127a334da034bd9f8e21b7f4f3": "f8d1808080a08f729a3d50416c97f7020248757ec99fb461dedaddd50f2559ab4e94ad60cf1b80a04bc6228cbb9b536ae4d2eafa74d5d6af87712afcb41dfb4226b95c88246f1450a0259c2569faf29b24372fe6e2155333f224f75c8f13b12c08e22f8d5cacb85484808080808080a06c9c90611f68ea5c86248cf7d8f9b2d7c48db61249065257c9c6bf4239690413a040e6efd8aa0bc63817019e3353df6a5cb09e4b814570d10603f594eab130125ea075717a05796436383ff43ab3ffa3702e91734d82a948594b7307eb52c6915bd380", + "b96946d1298b0e049fdf340edf7dbe4a7748c76b5b186f84ae3c207f4d0a4a8b": "f90211a0d7934fe1aa24a28e88514b6fff7db6aa76e4260e4fa0484d10251dbff4972ef8a051f52fb837d9201143c5ed1421f05ea139a66c4f061cdaee1a431bbbd2fea523a05e66eabac805d9377d861b2f1a0a060cb8f7638ef0a2b5783ffa6df6858056dda0ebfff3286207536c9ddaf49e8aaa3f1c1be7a540dceb4806c90cd6b63b578970a05b90eb36cf49176b8f1fb328b733a42f86ee5505e35aa3477f7af245df6c5ce2a016a9579e9282345386fbf886c39f0f7646de4ba6e617e91d1f4ad8c8b68a3ea3a0a4ab073e33b49cce7cdca3a419e064d827ae81a59be903281da0ed6c39527faca0b3682926ce764ded1f16fa4d22af79cc31a83a9b3f0e930c89ecbb686324fc46a0563dcd54281ce0aa478866055f775ba2ccbc820ccaff99425a0dcd3eaca7e655a0ce2904fc08d8886b48e5960b53872109fc3db6decd0e1a88fe09cf1f418468dba00ac2a8d68e7e6467015b8e19a7f0bd48475282b0c162f41dbca2587be21660f3a0f83de6d3c2f4511d57e2b4ba91d5682b39d710475437a5ead7596820c51a0ad6a014d8b7ab51f306be060a43b7b774ede60bb19313ef0c5aa1948e0045282ce9efa06a5443c4d1b8337f515d4fdf9ab14366ab382cb1df6c15183a128e3de47083eda0ce4bba51db114f626cc5a04de2259c4c7b003ea9f099cac46e47bc2630019b8fa09f2d25813c8729df578affa442dc8e30e658b6a2e86a5bfa5771880d0200b98a80", + "b9b52c2b23480fd435b810ec53e780b07f89e1cb228d849c30c6aad542e725da": "f90131a04280c433a3a2c6a0262a5ed249a97476307e2b66fb7679de1ab10feb6f47c0c08080a07faeb39cbe70d29f79e5fe3724946322cc25ff77e04b1cf50a9573462e038c2080a02b83ee5101f0d41664c7d3248fb974bfa68b3c42917d197611501b8a12fa22d6a0ac6a74dd6c3d15c8cb54750344ad5c08a57c0c4872192022742b754e857f3ca8a0c2fbad218cb725764d78d35b2896a8b1b4a7370e15815a87a1169e5d901f3a42a07345922d5b77934f54986728a7d9f45a8eaa08ac4a8d3748e4ef036cd5d29ad280a0320b1dbafb3ee67d114fe2b0b0a971a88223bbcb7e5312a96bebf965b832e3b380a06a73cb4633bdb5b1c2e993248d2eb653642f82e9416e292ce40b8b1cc3931d78a07e3a7665e43b2a2b15590bc0e8a18ca9eada41c470db3af762ad9aa25c821c50808080", + "ba32d656c4618673b416a6f3cbe398bad96c0d77a76b7a78a10566de2f641f10": "f8d1808080a03f75da57ee6d61ee468fd53eacd5ad47c9561a1443a013df6edb5604c783ea32a0dcfeaf2911f85e5a765353ac661db8675da222ea94853ef22c1546200bdb88ed808080a089083ea92b753f1598bc604f43e987c58aaa9cf2127a06ed1a2a5c5c628cab64a0598040c2450482a597e8cdfd4e8ce460849396046a689e490a6fbccc9690760c8080a01f6785a712844e0633848b831860e08ecb84386ed311c6b2894d602c9020910280a0b45c096b751361fd8b50191c766bd4d402cad25192b3ac58c4791d7963c12ac08080", + "bb26f3635184edcabdd44fd72442ec6e617cfed8144f11a3c756031c7068d649": "f90211a043a20bc79230694968fe06c05d10ebaba63dbe0e893e7a768e42258feb00fbf6a0fd387652179b98d146b3be7a58519afacb005086b2557e9ff085797e18c30b87a0ef7862e67d698683544b265a5fe194b1a37d98010898eb67f3492bba615674e2a09e62ace1fee5f4bf681d3359232714788891388aedd50a843913650c4f08273ea0be693451e05c8f824919a9532e93e8fbdbf7b854f650434458c04051c7c02effa0f103936186fa39d7e7662df83e82bb5fe50ddebc77a61c84a13466e968875e4ca068b16ad43c0b257c9089c061d8747b3e767924b7ff2f0efaf975b688defb18f9a0a2fd1b515c6140cdd78d4bb26181fba32bf8214670de5029a333c531a153f9aaa03520da9937402d872983a4aa6b6b1643dd53ca03f77d60348230968ac300038da04652ec9c84074e28e4c970452601a9310460d303b581f89a5dacd8d09e41e819a0b3bbeb748e3ba6ad8a3e5cf1ce7fd4657b031e2e5ae5bb1565af30a610e4c8b4a0ff2d2bf9dba85c3974cec548ce36c76e451812635773b06e23da432ded98d697a031d0608e281578dce52a9906e478dad539f68c31772fe1b2634270ea8081761ea0548dfbdfc77d30b3e1a1d8ae9c4b99c27783512cb3a706179c5ff3bbb0de272ba023b6234fdd4f159710626b185b9ac47fb3b32e9b2f53625c2e3309f04cbade2da0e8e35471fb9353e0393c3378045ef523a7511722bcd612f3f0577d2ef706000980", + "bb454dfad395dfcdbaa03c923b84f83c347fa2e617d763c3613f2097c176f44d": "f8f180a0b83bd82c32dfb12efdc118893dadf5f927881a0fb0b595ec0e4418ee6a36bf23a08ad64ffbbc93b751637076cf89f37bc61ada8959a11d7908d640abe49a8e8159a062aa8ad371914643d0310452b6447a557e0c47bcc41b466cee267d9e651652a780a02afac32c48947de387fabcd2216bee9c1c88019f077504b39d979307d02f82bd80a06c082683d4a5cd200a4ddb54d868a86103aa8463496f4ecaee8094be0b7cb4498080a013279fd1390fe4f74df7542723a7ac489bf3492ba04b7fdc1e2dca9c270f0f26a054e838f0e72244a0b4622e60cbd500579a13a6615657f5d7045adaa6a7073f788080808080", + "bc656172578a3665590f3d2ed177a1d082d9c8ce8a2e614907fb16429d9f20b4": "f8b1808080a079e98be1d443145b240c379dde9af7d3f031f8a1226a0dec02f0eca3d5e35b50a0dfd3abd115196a11ae88e00daf66508f5ee4f7e5d2544daca6a9ce603101b466808080a02a35ecb3ad7819818c66bee5c71f4246e78d17f1d360bff09d1f636e917667d7a0bd9c1b7833a6571df7d62313b3c4a3a4c16a8a3b6a996668c857993c596d7eaf80808080a00510ef4c33b4342a49325a765b5c8dfcac3f565484f9e372563ca0bebc083c398080", + "bd3702c0dfc79748400d72dfb91231502e0ecbfff94c3f315cf5911c6102cdbf": "f90211a02edb707eae21a27312b6ca3f456312b08090deb1a5c34c45944741e2fe93b001a010ed615cf10952de153465bde446d994f64c1fdbfb86c7f45f94d38b60247581a02e108a5623a5d625d9c1b7269f832a0b3e1c198365a05d84f756fa282bafa306a0bc7fd6405cee95cd67118fc5c7a32f5647f02bda2f8ae4f477b48886542516f9a03855b68d0e1ab4f8f6788cf2d45d7aed1323e008ee645bd4483658f3f92ad7a9a067e0596690f75d01a92768c8e431ee93a9239ca690dfbac89ec0bd13ea971348a09108ac6e1eff8c46e705d890921f59cb06cc94f9738227afaa4e0152951887c6a0d8dc441dd4cc3bd1b4454a019efb75879eaa4151b9812b0e17337d8eb64cb489a0cb9d1844dd16bc57551c443c4eb5302d6a7bd8b11df406f6dce00b562c1a0784a0bc5868404093d29c7e6991ebcf54d575f2238c235323506807d82430a9e24a37a0565ab415f5bc4c4f54711176d8453d85e6344c7cb9d1c3c2397060d8feff6750a0ec58c2a42c437f554f70a50e1c136b7bf3d1b4759c4936f8e43b895d7a1b65c9a0be2b6f65bd279e2649f61b3da1398874aef3c341b0ec8af1010aed1ef54e60c7a08bc6cad8d92f984afb9257c2bc0b4fa31c59a8b55b1daa0ac7142ccf9d40906aa01c9a9f46c4d688a8e102e19b57cd78910cd6fcbe7a7e9e5d310abe9bc3a7ffd2a0938810a41b1a79a4677af1895c93f6c1975b6e38fd3b5348f8f406a6338fdd5880", + "bdd6f49ed2416c54ab96d41dc62aa5ec49992af3b08f4daf83bbe4ef5e506b6a": "f90211a042b86145ceb022c727612213dbb8482a7ab8c4ac835fd0fb7d779e3e6c518139a05935f2b4ab061693175619955af7ef8b5410b905d8c9617c9f14d08c87d4114ba05b46693931c3ce409ae98fbe2b3bef1481830e7d9e9d578518096ed4ffd4b2b4a096b2bd01d5cd92012ace8066460137c2e12cf2302b45c63f3478151cb143e54ea0601b16f4bd1025a16a390d80adb37d039131ef2a0f4ff437d5f8747f5220457ea092c3b71e20fcb176526a884e0c7e55f5c0a2009039e3dbe9a5c3be233f98c033a0622e78cb0e14bfa3738cecb90dcda4e6204d1ada60bb18df5e83c4928adfbfa6a04144cc9e8c620416badba803c7641f1be0dff605c7207676f109432aca2bd2d2a0584ed6005432d5f7f600dfe29597012c1b15fff259dfafd408cca2fe2825de71a08f957451fde81789d980d3ac25180100e0a9ba0ebca3bd3db5368e650464882aa097adb6ae8e3cf813fe97c55bfbf93689419b7d955d8ed193ac6e1099565535e4a025b26e4d2dad037fbe78c9e6facf94e137b6baa3b0b08b91a118be9928225a7ea087396eab37047a851faba0dde6a48b5da4c79652663b19b7772b2dbf73e2ddb3a0ddfea4b170fecd313faffb4d421fce9de71f979139a9146d336325a300616f9ea08024f062f46026fd19d43be16c4084fe489cb791bf0e3bc7fd686bba2cf19300a05b7332a568c2c2ddcb1b1bed3beac3267c24e9feeac7950954d5a9dab6a0f8dc80", + "be7fbe2def8f872d272685d83bfe1946c45c607c804555952ba75bc921e9fc47": "f8419e30b2faf697fc5dba87c94d054114918a23aecfc65f0d81e90e31e3915259a1a0dead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00d", + "c04700525cd0a1d86454ed97c41757b61dabdd9e2638600a256304164928ce05": "f90211a0c5ff471b2dbc9c62fd3177e68ff08f98f71a420bd84712877e997e10a19bad5da0352e07ff9483f3bd8f47825b23278b4d8868ca1a3f54bc4167ddc59b58c742f0a0e673dcdf8a9efe89cd446d939a02e9fce19994ba22aba83474cdecac686d5bd5a0a71fad1a858d09e900e5c7b562f3b7dc668b3cf4009fb85095a480308c00c77fa0aac65e703e8afd480a4ad7e22c4182eac9057772aef2126716c6e476e850d8ada0f8dac91ae2c8699002e9c36c963fcbe6d9e69f96b6bb1051c061ba01ae9fc896a00df072c2899efc8de1ed0d84eb8c75bde585e97bfd12b0a18f0a69e9cc8de387a0297f9daec11fe042328c78b0ccadd4c596c67d0d98563249773b74ec3448db51a0f6f25c5dcc0e1c819fdffe26576c6b7c3a80706d83b764abcacefc6d8edc8520a0ec9a595555800aaca69aae7fe55e88efb4ed202f45fc793bd22530e16c8ac7b1a0802baa295b526fd3f3afd315fd4028648a9f12f4cff95babf24a70438089bb97a033f41e319868b59872a25a3c59ae0a39120080cca49c1fa6269e8e2299c008baa013e86626b39c39ef67661eff84a49262593bf84f1039e11290534426a65b39c9a06d5dd47f8d72fa8d568f84562699bae08b0158ba2c03b79aba9267e890d7bf34a05cade5982e50026e9801b072d9b326d0057033f89148a790ce9e42c7337b0a54a081a10ff12430c04a175ad7ec506bf4e83ea2ddb7c76a92a15dbaa6e77fc6d3f780", + "c0906a846ae684eec3864a80092f59acaf47e9e080d0fa37b2b0600422a51bd4": "f90211a02b7b50779219bf40ed7384a469f8488ff661a78e6a138a6173873472dd220b9da0998cf93a0d8b93d35959b33ebd41e500252fc58e0df9188a4e1f1c53d4771929a07cb69b6a8383d8995ec6980b2bc70d81c3df0392a01cbff4d63734ecad5535e5a01f20b9f30078dd0ac3c67b8269a6870a8db581d361125d86e3799ea7324dbac8a0613b06377afbd6ae089bbf8b0fec2bf73790cc88166ee2cb5639cb1db3caf0dfa033f550f474262165b1d9df8ec692c87d6633cffe2daf24d6517bdb216b299b2da05821e56a89db565b1dceaaed00311621bb5be1f8b5d9dde5e486a741fe90cbc6a016542f514f2786aadf924c99e251da98e1195b6122774562a273318518a1ae1ea0dea914b89ff259902acca17c90d27a9cb980e5cff9b516db8d77aecafee64438a0f61eee8f71a287c8561ebb99d2327ea955b2f081dc62a4be33c8675c8d5c3727a0b95457b59983c5137b728d62bc05234ed6cb1a55f84b3b6b52a0aa49cd21a87fa0fa52e76ff1c450eb4b2582e35f0681fa1bb48502fd48d39208160e651e1fba19a0181c8834f606ccb63fdd3cb357997f5a0676646de24bc54202e554995c2f1cd8a0217ea47fd3f307ffb3a071bb720fe6aeca55c2ccae75876c165febc1a607f2eaa00819a182c07122df1df57599dc3d6227a01a2a55e6311575b0081a8f6f14c936a0984ef1bf1ff7bc25240a2925f752d2bd59ead2700bc25a7d6328ac3f976dab6980", + "c19d91c2a81180de78273b7461427b337647ff9b42e79a388433396f4fa150e1": "f90211a0443d76b89b14e2cc3bffa0d99af8695d5f69eed92a9d8ce275d540c164e7cdd1a0e20c35fa257c6357276e1a4c507e18154a61c04d0b96e3f147b8fbc9caf70e74a031a034d33813e4dfd48996739f26bfd0d1429cbffaa37c4e91c47a56d2496348a0671f1c8da030114b2d3df5a65d7be92556329ff0740513870b144166a05accb3a08f2e7dd44ce5c000a99c508e396a04a4cb8751bbe8575ea846b5fd5fe371c194a0fffd20b681d8d4d98ee5cdbd4922f4c3a0464134c4d04b927ef305922f564e7ba0e02d7981b7af38417865bbe8f8e8e0dcd6b2aecfe2f5a31aa008f22153480613a074c1aefb3b0dc4105cbc831b2380889af471739d63190e9f5d0303f87fe12e4fa0a9b2a10a3e46d898d51b5491ea07f5c9050ebb4cfe360347475d327467aca9c5a0fcafa6876857c4ed8995794d898efe1fe20d93c7e5b43fe98c283123924cc74ca0f2d006207e994befc37f78d3fdea029f37f32f9ed1544fba9d13fca775ebb719a055acf37597b7a2793b31bc8edd8a2f9686a880d3cb24ed92c925614f3ecc86aea0e7530501db2687c73e1cc9b8204cb7c29f244d20ce156b0af2fe830ec537b4cfa0386d3a8ec59db64fe270a58693099dff1f54448652b91ffda974aec2eec5536da0d55c102d2903c7657c8d729cdad9b8e19ae21180c069c9f882cfda734c819407a032816c6866cc82aeb8d5d140b409d3f0443fef72c52b93f7f8b3f2d63f614eea80", + "c464b2d744334c4094d2eae0ff9d3ee93fdf1959f6fb5ea762e5a6a17bbd6ce3": "f8f1a0724f8269597045e61528ea8aa1034eeab3e6de84a94e864904d87d45954158e6a0974c1944919f27fd85b89d488137de9a45438a71f89d6456bebc6d678e602bc380a0352bf037a7dbcac4d2517191bc3225c4b42489f15b48464bc1fabc80f4f460ae80a0759dd5e040d8ec1858591947520723eb61aeaf28cf09a403cd18b874db7d8cc1a0162fae7190ce60a18051e7f2853be0032597da1903096783ac10ec3f0240b282a0b809abcc89f9c523df3a7a37609fc593cbe61d042fdbcab5b67b00c7f1c292f280808080808080a0ddcc9f00f9be819be93e9ae1f0fecad98affe60d69c69150c99e0027bcd4be8480", + "c46ba0d152f58f060f5979ec848e23a5cb7a3a2b50072bc304e35073d80e22d4": "f90211a05ae182ffc5ad4546bd9c5cfbf53beed68774017fdd24ec3ed57fc8bee0449827a0da7a1db7389d48f3b459d9c377b6d67c564cc0189bc5b5756bbfff7fa08302a4a0bc74a7b84a775c6b71160f53062e1d3f025b30d974d839a31112159a3a62234ca0cff8bbf1cdb97dee31b6fe7fdab24e108c23647c2ae690cefdc1a53ec996d2d7a0df962edabd7b686a5097bb71db979cd93532a9e12e44a2d032ca88eb5461b618a005633f7fc790acfc41debea193d7e03bf355cb193d321c77400e01d100b12a35a03ce62750b4c32fe5b09ab958c7f6c4eb9d34924607d246e63e809eafb6b8ebe2a03d4cc00a827886e5df28555ede0e8ba93b39cd8725904c0f0fd8f0de2fcd37cea0aa81ae2e454c470362f8414848fc09607e7c43597e83bb86fdd148aa86a40c3fa0187e9557c004906a7c06b0602ae8340d3ad98047e9a7c975d3bc84e420de9772a04974257b5e51dcca4914c23091f63a0588b1d55a0e69ed6d76dd2df7edccfd6fa0cc7eeed289cc4be7813d04f499b6ec24a137da5656f2158f39349126aca0ca3da0d578575697af3ae855b5867f31557b97ad880f3cdc6c8264c15e89c389f2b67ea071962197159cc8099d6c0ad4b3b9f81f5826d0a6713d259dae503ddbb12d136fa0178cf70af82bcb0fbb8c1be4b56e89b3743896c045fa40fc555471992cdb2a38a0682b6ce8179b01b7f72d0c3692c3e33b06ab083c8bd741b9ba35cb61a1df49c980", + "c6165d79a4fe9e02acdcba2b528e2a3ed721ab17df6c0c8d24e4ee29f43da711": "f90211a09b6b7574cdc0bd6c20123b9004e271de5a764b836d26e956734e191611b2d8f6a0b84a9b8ff3eae8d41e65a9f8cebc23fb3c1f9e1d2a1d979ba2331d4bb7608ae8a0cb1336f8c9a59337ed1f0e506ea6b38d1025dd9fa8c4da0b329e3ddff6c5790da078029e322a1f4933f7f8d98fc501a684522ad5666ccb57098c5cf14c689ba309a0e9100dc84a099da7c6f7f863b9ddc3d9fd74eaf8b7f52a889252f62af65a59f4a0029c7f6e59984e1b993b72259f94c3810847d0935a47c96f9eab57eb528b3a7fa03323c8261afeccce5f88b510470b107b942864b5920726def8c9562dd05412d6a0afee9f0e625a297964894883974b3b0dfe7e69319e18802fd81b068474a966a2a00c4ddb1cd88318e80ae6668155a8794d16e0f29f5d6a28fc83fd20bdcdc17cfca05fc390a2df6fb311b2882fba4d1697c2eab5e7ad61d83f2c06e2f733bece5f78a0e209370cf77ca609d5cb9fbeabd2fd7ff0838d87de467dd834b00bdea1006ee2a092bed4e95dfd56e3c4f44a86da7c0652c5dac656b5ae5b6ebba194f7a7a33c7ba014cf330036384e5eb6de41d607533fdf51c0fc3cf373af8cf31418f291271929a0e93c48b9f894696bac2e791e43b5a4ab0040818e47b4ce029ac25a2dedfc6d01a0de34629ccbef99a22437e7c747b98bf697d7140fdaa4038379e5c8a1e4c1f27aa029c1e1fce77b4d2834ec68c2d89bd4eccbcbe09e09f56af9164526735a35371b80", + "c663bd9b0f912a5fee29c8b34f7d0eef062fd440522cdf1ab7fd3ef8cdd630a4": "f8419e3f0873f04d1e703ff874c2d0e1b0d2001312384808710248f321513b50e9a1a0cafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeaf", + "c76f34549cc95765b2f011b05e0978155d2d6d84d88a2c4006ed713521627084": "f90211a0df5b7cefad2c04bfaadf438fcb24554d7240cbb886ae121691f5ecbce2ebbddba04fca7600b4a71c4c75a0ab5131df404c0664262ea92a91f6c9f6d7b2533995ada0412ae1b5e0a127daacb414f62765ad9a682d403edf75bd1331b65953b2aa58f7a0f12dec8e72bb2cd1d32b65ac93c8f061e28c3dda4f53eb5b75ab2a6a630b9821a0f4af19a0bf2124c8acd7173ce0929336dfe3c7ac73e37c25138aafd3b9cde0d3a0db40142f7f55626d06564bd928cc85d01877a7b8b4ecced441dcb92f38673735a064c235bb18013bb68af4d0ee3c9aeebbe15d287a435c10948c70c21efc31c6d1a05b98d87e4a088e3b97bb5c92d0148e0e7c2d34f6e3b180e5dce3c830d0077f8ba0a66550bf64dbd68d8776bad8d6928a0fff6f168615703bb589a153c9207b56bea01d6ae070e7ff94fd948b839a3fd67da45f162cb8208828a5d2310cf3f422175ea051a315c5c48abff1d2cbfd41fe0d05357e4e19dd9343bdc17e3675afbf558ea8a0c533257a2d5366831d076e8b44a1e8f622b25b011125335a3074d6f223d263a9a062fb2cc7a32bfd7ba1eb47aef620f8340958d4b5af328acbec3fffdf7c6fcbd2a06c58bf2c14ae4648794451df32f677b82f3dc731bb16b5b702d84af81af63d10a00a724e73b5df0a0e020daa23805c89ccc78093a1d2796fa178a67134db1a602ca081bf4488734fa9c8ecfe00c950aa0557e712899b7455c2befac5662cba074d3880", + "c84486afd8131bf039615d8600ded2334c94a632308de277fba548e917ccee99": "f8419e3645c69bf3cc8373b32fdcaf820a41aded22ee3022772ba7ee9aa5b8c973a1a0defec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0de", + "c89e8a859b2ff542dda37467103651268be0bc72415d5b861fb8abdebb750bdf": "f90211a0dad1795e6476ce6fbb390776192abdc9601a6a977d4b5ed20024e6e2c2f8d86da0c904b305b6deefbf798cd7d51ab48e107d66cdd3768c21860c1b25747e21f0f8a052c07bb450c3a41d71074880ac2d698230b543876764f73dddbb03cd91a06a7da0f8fe55e3eca6a19272750b1a220946901e74b3d426d02517cd00c9c24083e381a075e6c85c20c2e309954c34f8fe44a617a40499879df70e2bc8ee662da9ceda36a06c51c211b9e0994dfaee26c43fb264ecbed4a8fff9557ebc5374b31f46efa888a0160198d99c0c6c367d5d068af3cdf15d70ca7234336aa1c741ac438523dd4194a00ed87f39b0e95961e32a441dde2ded948f6cb8fb6c20563a3e4bb4fd16af8b2ca02ddb13d2b76f4b5dd4ffa33e100919a50c901f56bcd8ed7cf8b8a3a4feee604aa096d0952f5fe395cacf9fea9385b0159937ddb840894766a0cc5fe830b43e3d7ea0c95cd1443392791becce6a76d5c890f96a7b4e025ad288e9554a0a51ea4eb1fba093acede0ffcec7a37b2a14fecd61cf9c963b41ba3cab2678ac1d74d0851a34bfa0c94223dc99b6c7d4f64b7f0bd4b00e3db2d66c234f9116f0f461401f683b62e6a0aa89e2d76747298c8584cb2e39107fa067d3252be2999bb413d7f750f6a9bbf5a0c043fd7308e7e86c264e3e6c9844390d7d86c9e81812ed5459bc85f38625f8caa09474f7adbac6b0abbc3786aa56059216afab9c2510274c58311fbf02e5ddd9ba80", + "c8b402c941194a37a413bfc512b4e003f79a9fadeb5b02f049fec0edb1c1705b": "f8419e377bd1cde15b166faecc7174b064d5c9aaa8d7ca865fa8807616f550bd49a1a0cafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeaf", + "c9ef4bef7715b41226d59feb20be7b511c33dc60a9ff64ffdf93f0858edddfb1": "f90211a040ae4d08698d20dd478b7a5313f033a5a9976fdda23a6b106ccc6c941caff1a1a0836cf1ed650739b81d5564d385235b51a352759462e5c853621b17743a27988fa077ff881a5e0d268c3e20fd2f735c6cdb75cadc483c90d809d823869e56dbe60ca0b49e1cc08170ce0122c56dd914068350eeb592f5d7dc5fe3b9701154b5dd2e05a0dea4848b9b977b858e8c56b38d49f4fc9621c3c2179de490d235f1a665d87ab6a0171b835c26be4e1a371684b7544212b65766c4897e704a1bbed060738fb957aba04f3d8bdea7661673c9848b8f3905fe504bca92f50308138295306bdeb6989c28a01dc5adb8c3afd19c5c0491b441f538739af9e9a0bdf1c050109de3cfc70353f1a0788431d02e7da5d3471a412a4772a44e561e2ed990510d9a021ad715978245eea035e2aa19a97f67ab742e104e1d8eaacbe1d584a6d645b2611eb587d5a31920dca09fd46207bfdbe98539457b5e9805d2bb8ca7bd3734a3ffc0bc3be10f27639489a01da84049aa01531cb34e6752ea2793ac51824aec9831b0005a7f3f84796ba06fa08945ccf44f9c4870af9c5c3d7eb559531e13700ea0912692a8a348c7d671f2a2a04857e1aea69407ee8146c93f29d7eced300e431e510d49c8a2f7e1d4a087380ea0076b6ebacb85528374d7c7cef072bc40dae020e6e42d6ec3da575fd9ee16dee9a053f49ebf16a030e2c6dc380b940b1c25cf418f9db175e0defed3f36447f2bfe280", + "ca9d7066a008f45873bb651610e549e5c3467014acfa5988afe95a9d51bee7f2": "f90211a09c34c8495fa68721b025a54a216088ede9f67d843fd7f2bb7f21a5f28da3d873a0b656ade7a30005341461a471bc829265b72b29d556bbab2d0b5ce8b92f9b82bda08b9ec008099edd404dd4dfb573f86fcef1c20c376fb92d78339ef9b3104a1bd7a0d4308701a6684eec65208e8732c9baeb7e602440ef9218dfc82990cbe8450fd5a01ff7faa5e0142c1ded0452d0965e2514e8b1d56627e3246d5ff31b6a72e6afb4a0dcdb5ba60059f1cb4190d9e5b28c51ecee4a37965dae4ebc039569d7de2e88c9a029da18b0cdc430f1ecdbe50ae98fe480d341b1f65e12c1bcb6b9f345ccbc3073a0f10ef13814196b7c42116845ddecb8fa2fee1528fa20c0bc93a353f5b3912967a07e8ef1f0bb37dad4c38a7f196c537424e42300e269f29b648969f4f6ebae392da0ed6fb76a871eac0f74717bde24db977ecb9150488f062e446a7f8cacf99ce07ea004142e4ec5315786c30e95b795d51e1df47c96eda66234732c240bc26b65579da09330d83e6ad19ccc13028c673c0f8d6fdd80a2f23e0943b143159a687cff5760a00929abc43af2390ee1594c69f8e5ebb65f1ab518c8d54d3ea740bf9943e95e04a06a842dc47ada4741343f4610ac6adb1a12e3baf5e89967f0cc9fdc9523622744a07ac4b52e2dece3b5729b48f1102022baff4f960b88bdc8a04d82af85f980a56da0f454cf1bad8bdb835ea83109dc55359d7c2ac319032c7dcb17c180ea142704d380", + "caa482827e86d181120c76dc3a387ed2ef4a060512ef069761e46dd0ae36f247": "f8d1a0dfbe9d9836a5b8e6649e36684016eeed93b3cf45c56bb716f69ed0bd124f7521a05d47be7c00f91532a144f3f15022c2a83788eb395b34bb55e0cc825584cf11e78080a0bfdf1cded03e3799041897cb33196e3c82297d2b5c4921c341a77069c1cbc4e58080808080a073688f1853da9869f39e9ac69079ae097aed51539b44c9698f2e79fd9c9092af808080a0d6a702d7fddf7d35f8e01b6ba4a45195bbe4b2ba6740b04ad7ba6ae16ce98223a04239f418b12a70b84deca6063d8394f5ae256103ab0b97c0555a48660e059f5080", + "cb3dc35fd95666fb836fd4f275fe2f8e0de6b0f4cfe5cd2140ffa7105ed1071c": "f90211a017fa439ac15220608b688e79f68de39a945d5a9fb26af3e1b264ee9b6f6aa24fa00176fe99351635424e4ad0844393a2524796cefa288625ad4e46296d9c176beea0e13343cefa47942a4da58d906ec5a39410f2b39fceeb88bc8749aa84e23e6c61a09bf60f012dafe6939f0b69fe8906209263805ba173aa315f4fb8622b091671d7a02cbd55420b6cfe39c8aa5fb977a454352cf26b90990e8f9801a6e9a23e29979ea0afc7ad54a29e704f07a6dd160d6a2a4a68c1948b61f3dfdafebbc15b4bb556dba013c75348040b32d663e809f41df7e898e327651b091cd3ded62585fa33fa55f0a0e5e38139e194a500cd74e7949887a959fa66f4414df027e165c936e0a392adf9a0a7bcfc5207ee91326041756fc184072d5a1087901c04e894eab6e6a3e4502594a081c858bb661f50f44b234b377c20c6d0eceaeb79be6ea805214465df6c41dd6ea08868c048759ceaca68e38fae64f97d6615558ada99aa86ca3de514d97cd6efc1a0032c8350b4423cf2008715f73f2fe2fcce726cd4ab2d439653338a48264f73aea0ce4e7933dc95f69a35d99f3fda2226abe040e86ed96d8d43318180224ea613cba0a6146ecfeab5d208120ed087a57f1d991188d30c154b7c284599dfe9a24559f1a0c82b43d01f58d7186725a02051ae9e90470e1d9fac1cd3ba196f8ce1b379b6d8a090dcd0ee8be9b531bfaeb0276004b5cd8a3af27f4d2420008dcaf850e05493b080", + "cb56df6e9eff972cb1cdb773142bec1687b001422db0def8f17643596b685890": "f8d18080a07924de4f0bea629d7ab12b9be8483bdb8d65c6bbb569477f8b6a216981628ee6808080a05c25f508343f930146d60a2dfa4a72ba2e034b7db247b865e48011325460f412a01d436061d2b0e261bfc6fd3cb0e209f3772c18df33b6c7b3ff82377f0ad5f0748080a021dd6e65c61b64bc87b9ac1d9704c54750552203a9498d468a170db38efb1853a012fbfe9d7cc6da5add7032a0d3e5a4083dbbe34db2acf0dec68bfe4e27c666a48080a07d0653202074bbdfc3d8cca74f3a1765e11d38b4a50b0f12d988845f6b3b2e018080", + "cc1a4df8439f81f3fabb8d66ae387cca8edf9c555e29bfc36dddaf0545acca63": "f8419e3060b17828abb7c64976fb8175954d0f3f730d7528f9b07d85b0327c0588a1a0baadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabe", + "cc5dc99deacf55ac3d75a56942c61df8fab14a7d58ac5ed051c0b180edbaf1c2": "f90171a0c5d6f66d4fadabd6f2af74d77c616efe267db6c8aee7bf0ef0808b5baa36c580a0a687caa187b67b8976372fc80192056c4780cce8eaee6732c788626f80e00281a0a42d3ee1b6067b0e76db3675ed55c727eff3f1d66dad331d811b565f3fe564118080a0b6b68059b71f51d0dac5b11954595c26d57ca9655c25c5299565235006d033d780a0be7fbe2def8f872d272685d83bfe1946c45c607c804555952ba75bc921e9fc47a0a17c81b542375bbfc12d281e05d4dadb00aeb147ac561dfcff9db4d593507818a0617947495a6319c2da8a82df0a46cccf8073326facf3b026a2182f2e0735d41da0a842b92006b8cb505d1e97a89506e92e6327b71fdadd97e815af79f55d7a590780a01ffa59eb13506aedff66f1dae6dbdecdd57979a19e65b00a7efe33a9cbb3140aa0b603361c695ebb9200d426f6ab5b3cd9c971bec1d6c033121dec3cc6bb9325a8a01da28fb42ca827d1e5e91a622e5c30086ab92fadf0b5ef455d8792965378e0c58080", + "cc7b4c69c7e6c4242f46bf988afdbe9a55e5d272e44c5b4a8cc2c00e259f0f17": "f90211a0710c16b4f2745ad4f8cc07c027f3204da3b17f2adc8f7283b17a1a19ee0fe94ba025bca3597b92ba3ed9de75b1a08afd2bb77b59487a8ef57899769e168ec0ae1ca03021e5bf2bcd69568a01f982177368000204d9c5665aa02c8574a91dec884eb9a0fe46f5d6dddb35717669faf8218ec033270ad0f78d87f056b6e315f7b5903543a0e1352c22df35dadbce9a46fc50bc7a886db546ef1062413f2d1b46495cac034ea098eadcb283ced6e945ac7e1384f796a911781adf30380e10ab5c99d0af6c4176a018fa0adac23bd42ba9abcb41bf8a43c0e0ab590328633dba88f1bfcf736a407da098a93a924334f634a84946803e5d84a7eea32f601f84735bb71a176e3ed74440a01d6da91a2b52c2961b5315bb5ce06466a002feac1b6859873fb35705f00b4f3ea017f05a52b56e5ad6407f2738f7ecff706abc00910aa6af8a0fcc88c1296844eda03b05028bac2c598e2f83a01d9061ab31bb531f0fd3baffe846cb4a6ce40915e4a08177929ac44f592c90b5bb2e7239c5a0c25c898193752c60d739ff8efaa4428ba0adc8696b377199082f4b25b841af2fc112d0037201a481195785b365665e6d57a0f5c7799531b0b748cf254cc70b1cd2c02fdbeecbc30d67864b79e0470b91cfa8a0522e231db5dfacd4e1eedcf574dc0ee9f4dbb7be17e62f1d426e67015bfa615aa05729fb884439b5e2231d2bcc5d2e0bd64090e862ff4a9bfb0b721d0ce0740cf680", + "cdc75fa9865fc40ebc29e2fe74c83f117b82b0d101934766dc142f17bbc6eb04": "f891a01e4322d8d7226263d0f8b5a7a7a7668d3f9961b9a46a8cdf6b9dba5f713f342b808080a00cbf62aa5ca7798838a04e5cf937439cc7ea06cbd74e53264f7d41b88b2ad045a095c213cbcc2dc4c26ec3f11bfbce2ad2c4bbdbe65c66259624147dba99d763338080808080a0bac246cec07bbd7342067ada0a8b3ecfa02205a431a414c08c541201d9074c8b8080808080", + "ce611908391933502f922626b01678aab1ffc5422e6ad39a4e475c64b97a259c": "f90211a03def2c24d71ce8700049d1207bce5e9f71f78b6b7c07a8c321b53adcb4d8e2cea07b5fd328fb05c1667e628dc286a9808f7c42b769005622990ba652c4f1cf159aa013f9ebf361ba60ef63f40ecce52075f06c04cffd1a0a022773c645fc788c45d7a08880cda86f85f5fb55a16cca794eba5044eee1e62ce3162bda0d5b1dc82411c0a0243735d7ad5e4857ca2efc5051b16f5a5382b7eea801ea5f0204be32762be4aea086d6e35bd591d67b348101bc3b87d40f8f81c78c60bfedc53e87b7ba4c1c432fa0de700941e15c534ffc059d9cfcdbf3d014227fd9685961736fc73850423481d5a0653eaaca48818e85e4f0e7ce841a498c4afa42287887cad28e9cb8c29103b030a00b36697f2dd15cbb2066b8c3889fed1d8a38a3afc7f5e474df1e0a82ade115a7a0903d2cd1bc51bdc720aaa7fdea70e149b319a5d8c9cfac7134f61f750dbf5beea0abed5e9dd6a9087fec7587c9b47a07522c8f29d07abba2c877bbd5602ef91e58a0e5d957849a4e5c1b7283b418216d6fff7019a610bfa13a1742becdf9eb1dceb6a09981f5b5fc8ae7cdb398a43458207fe94eaf427e9e7ac44404ae691306c1f507a0e74873c41dc9888e004df11f6c9d66d1967fc3acef24df8d03d316a51100be6ba00631a75cc4fc195c7f6f7af1962d0765947e8c1cc9865cfecfd5a096054a1d51a0621cc2f89a42fae73099559c31a2bc76bb9e39325b0845b18653bb1e051a894b80", + "cf2e13be7626659cd54237c1b756e762ead0c9feb45035f080185f3fdf502d32": "f90211a099a736af04807b1d12e0393ea474191d5d83040205d8a7cb9fcefbc76cd5c42ca02bb5287ee0f84946753841b82da3d9b1bf8b40fd0223ada77a9e68cb39316d07a058d949f334c223b860b0a0bbb5b944e4cfb89c9cd2a9ead77d5d8c5e4520312fa018d4980a6c23d5f09f39b03ddc08b03f0681ad7796815d745e288494465a74f6a06f1aaf3eeabfeae1128df69b2fcc583eb53f06ba115187e5a44f6ca449df59a4a0197d12884cfadca25e1213cdda0c9fbf18fa338c7d76da539efa8569e999ae19a03f081c4149cf2364c99a1799524172704631e39a7629078133f35c093f8f5255a0a1fdc22107c07d33e25f3a7c391888186d7d39e98daef63cff80d05265c2eefda08e8df6c58d7f8634417c65435cfeae34d9092594491c9d6c9a62d57b79caf849a015a88a51531f904cfdd61e0736d6b5ca41ef18bc5f22139f038dc532382b4387a074b4b86d2a3ebe724718084ef41e4b2366a921b901468ef42ee208312042980ea0854283a98374ed1b3e43a12d0602201f87b5108b1817e2fb9b806c903a91a970a03380e13372a399107f9cca8e45f921474f4a48f7b8ee8d8cb72e32d2e1262aaba03dcef64f8805a7feafd428126bb9f1b83b14854b5c16a367f01e505b52fd26e9a0a95cc8a58a5468c6f2a6cf77b2e6214b751bc7361022a5cb7b296de4b3ac3e9da01beb70958b13e6c1442870467a83ed172eced6533d01f38434e28f3591a39a7080", + "cf5341308f7dc7d0acf9362da5f40847b49b79ca10ff58433dcee9f71570ce24": "f90211a0adf51059066fdb3990e97b21b667b45a4fcb5ad15f148b7dc22625fd9c683b22a0ffaa0b85e04f3563f545dce886b0c135b3d882c696078ad05d343a9223e5fc62a06377107755fb77957b4df80d13ede1757a771008431072eeaf2a9db982139c61a0f54fa3f1a828906a90ac19c713d11cf3615a277e3b7195894f61b8591b8ff190a02e58ad7b17da481fd23b0787b5601e9869e3d3e0760afc096c41f91377fd7de7a099d81c345efe786eca22f8be5046b71b12b1a64c9d443359e6b10145c8475604a0846746a2a384bfccd9ed07ac984b2a4590a058f2d612c10da1060577d8887763a08b2b35fa4fe0d65e3afb4e976c63d696fd6ab3f09a6a42563ee6ed69aded4698a0e5dad2b02534a7a9676d894a2dc37f6a77b57aa17e80c9c7af88bc5e3d643575a0da0a788b4324f45f99889dc6f802e062a08cb637c99af2e79c70cc25837e5b27a02a07930c350dc4bf770642fb381412037df8a779c53d236b7ffb32967c6e12f7a00cf7dc4a683262770ea0958dd0c378be1d0f86a771cf2745be1b7b493c86c329a0bf5ab2f5073e9d276b48d75d070493e0a25fda8c7589cf6bf39cb276adb0e086a0edda5a318592c48a7ae079dedd5162a45eb5d936a8d7fd4016e9026cb0b51f24a09ec1d56b4d8e6911b31c9f4777112910b32d01088696b4c84cc7ecba36604d3ca0736cca1ee36169cead591cfb85bf3193cf3eaf0618a8e2fcf0a30bec5eed727e80", + "d1044c5c73457b4ca87ded35848516d95f8e1c3bb6afff915b2c2a03606c27be": "f9011180a0cbac136a35d1e8ce5a3f557097607d5dff6d9561234bd727b5ad8f2e91f515e08080a0833410eeed81d4f7ea100865d146e77fac969d55e9f67d857fe449e5d7084dbd8080a05dfe3df391d2aec0a7d5378f300afe20b929a4e4050941c9552f306d40294747a04102f08e6f76907c2e116475c37c66e87c4422c5223519d2ef74b3af60d5878aa041a4448ec90e2ec296f5c77838a0e3d13b6ff76b0881059f0d07ca5f9e80fed5a098334b5923617c1fcb5b5f7ce79d36a41faa59fb9ec5d486f3258f25405690e280a03b4f0fb6fdaf2960de68ac16e541328b49d12a2401305c36dc8474966b3db08f80a0526b421099cd67655e774ed5624e02333ceb573bc4c07c765bc48a42438c18b88080", + "d194f061c614e187e926b10b7401c82aabae045cb0d57ddc4c0a3ee912277229": "f90211a06ddca46c37913e5d7b1e1f2de5f352ba4e7f21bbaed9ef7b0971b099d139544ea05d28fdfdcf1f717f9306d8b47c1f1783fb1145865430f1c81c9564886ea09f62a049f369aeb42adff7636ec861e38811421989b7aea6a4c22f47bdf4b133c3a777a055c0eabc7436428504261fbc68ec93ddd9fcb85fff468b9158d24d237c5bf266a05afe7de99acf628cfa38364b4b27e9f197f2ecee4fc9c48244a8afba7f042235a0692e3ee71dc51965057d8f048aaede52463c978e0a93d1d2520037d7472730e2a05b446b0945c1cf7dd05bb76115be0dcb5503a07aa15a3171f0b50f2f75a96e75a041491c1d3fb9d46c92e9706a94fd34398690cbe61940cac9e58a1c31a0119949a06dfe58c7ff911f5abf1f570ffec92a946b912d4735414e99b94e69f5ae66ab18a0205aa4dbdb30ad03999f3c02dbf6c9ce678b8820a74703f93263d27facab4622a014a6b83ee9a4d2ba49eb6cd1632234da6927e2181d8adada9cfbbd9c318b6cd0a016a2cc1fd5312e776e7059010c7eff90b3841753baed288e38a06c177514136ba0da8c16dbedcfaedb2ea9591b8039fc84a85c9d3d68837336eab72ec0eebf997ea0d244e68354344346a4dbc9ceb4e588f401ca795d9fae2b716401e19cdfa429d3a050c5e64f457840ad57899056fe9b70b5a9809ea4c15a001c736de5679af3e66fa092768c5bfce61008d24c49e6dbf36d1b3bc6df5cc27a6daff60f8fcb1729d55c80", + "d1cd727ba27d0d1560347abb129c8103578ece7124dafb685b2b79353a9fae29": "f8f1808080a06f093c903d86eab04d1bdd9b628c59d8f0972405d25fb600992d91eb634d2347a05ec85860ec1e203c795ef0a201671b0565b89c56356675c6d2a77fb9275b3137a046aab247f16fb2913231ad0c54409643046a2db691b56aebca8979ee675cb898808080a0669961cf98917aa88b47a9e9d5c48c54b5ab16a06cb95c01c131577b4b18972ea09510ef192b49c21aaeeb892f7a5e95c49343d27ca44af0f9e390bba250aeb92fa0c88a3a42102f742399d3520b9cb8104e55f2722b370d6c0a2d2399eefb84e86b8080a0d986be733e5d42f0dc9ad48d286ebd31f1910c12b31e36a978b09b40882608d28080", + "d26b2a8ba4dada6f8977eaf6bd17d0bcfbab102b5202682c110aabe62ce2e6e5": "f90211a03372584598ea6dac89b00afac5e9ef15ad41d23a36111d908c7754659c2fc08ea02fedbc53b3d00e200e76d46ed1e33bf15b88f3b65c9beb01dffd47dc78675bd6a09326457b0be5d597199f4b5a52109e54928a58e9d4c335399adf0afcfe905dc6a066b2ebe2f04253e7a40162028fa9b7ce357a33f8f7130f4ea15eeb5eb5470beda02cd84a56ae1ceb56879a9f05498143f0df6d4f1f4bd9e0c7463cac5dbbca2124a00251fcaa592c765d789bc53aaad5d510ba354ad489e52177493047966edf450fa09924a2e8b2fd8ac5d4111bdee59089466b619d5a78a1eb0313757c328529fec9a0e888fa4f607ca747e6bb04be8c788045e2c9af49dd42aa2c452be8aa65e08b64a0426f1d656eca70b6f5403b4637f9cfcc319e73ef2c4b5e627dc4613e3b3376b3a0cb039be3a7e42e1dc3ea2584112b5f764f6b0f2f681e3dfecb0d8d3b69247477a0933c837627092e513aacac50e9556482519bd2d6bc0a9c2d00df52fee45e4626a07d00b8c5a57b7fa10c082b329c9ec5d1966186f8320d694590c632432fa3d30aa08af4ff2496d2208a46354ce83892c17b90267d19a8080291ff05cdec499e55bba075806ad1a51d0a097e944bf3d6806d88293024a800ac684a02bc0acacb31979da0a2ae25e98d131c84ec54851412e1fa4d5a8c9ee2f2efd3a8165b89c2034e23e9a0883275f0eeabda0b50367e55fcfbb103d72144e2dc02031eaef504cdcac4e0f880", + "d28c18e13afe286fe2b20c319c6baeffff9d6c267f19a3a654ba82313ee368c3": "f90131a021a807ad429b02021cb9d52626ad565af02e5cc8824e3c147750d14d8f39884d80a0b05c208a1e5a8635b65313f16e2848a6adf71d9fdbee7db581db130ef696dae180a021ff7eafda4ff664074d2806cd708fa44b6972f28fd3be42d85b38725be0d57c80a0c8a8ea5d15057ef476e126570c40d56ac3c1f1921d9dffa44669dfc9728eef9b80a0817a92cb17b7801878cef5f8f6831445a75d441a2fa8d67fb2a4d410f0378623a06c8ab3a486f09d3dc0e1f4ac9c4254b55e349d7323ba23b2fe819c88930f011080a0ffcee0c127e349bc57e90caa422dba1ea6bef18d6a0bd4b845ea80a0f028ea0380a0bff2685f2d70d70f688b155445eddc6e64f99ff7de0c2c8a67fe75d14c1e27dda0cac1b96fde52d9c7e16c922a334f9060b2b9078290ee7edc87094ef6e85619d08080", + "d2e47c44778cf1775cb363da3c200e595a3871633b4aff0d448a7de3e03fdbc7": "f90211a059cb827c864a9686c7594fd4f5582c25e0cbf33455898ae0fe1800145e1139e4a0b75cc101c1cafcb7ec520a6b495b9cada2527f431013ef78d70a464f6cc9d34ba0bb454dfad395dfcdbaa03c923b84f83c347fa2e617d763c3613f2097c176f44da00ae6517c9585825e9f3ea60629fae12818242ce5d53e4b196e6f7810d625ab6ea09a5552ff7d440a3bde9a310e900480ddb076efbaf360cf67deff5ccd98af8b6ea0576b4a52368bc71419107e2ec68997fb059c935ca3692ce241f369f38e53f754a0c5db4f3a0cd6faaa2f41dfdecfb64a00da58767c01af45f3c3c13ff5e0db00dda0450e20fe7821b955c3f424318f362977fdcd2c9033f7e4a3b3a7163912603b7fa08f0291ce7bda50f6c818af1648ac1932e0dfbf50d4d3d919acdc34ab68a93725a0a56378af292120fecd2e1e75cb3781193a0fe26fc39927936d669f522c6d4257a00b1750fadd538a2554264ae03b7545ea4b372a7b2cde6814676a854ac5fdd416a089f39938dd49c6892078230da99ab9afbfd8f0d36d48f1df2f318ffa4333b47da05061667b1133c828c45fde9059aef4cd698b003eb3ee0dc82f5ab48432d58831a0289e90be0cad23d33d842dbd4559ad92694fcecdff8dde6f2fe0e610b8854353a06fa043e8d7d61acb70085fd22c9c7f38f9357821f737888b9693004c7f1dab90a072a14fbcb89ba7d655f8afc5614e8c02d3c8b3942f61cc0c6697a1472e56337d80", + "d5626cb68f579840457a7bc4607260af2798fe34a02f1b80871b7e240eb3eea7": "f90211a073fe9bf668ea45af449da19c9ffe0a66eb8eb0630ea568e159231e80252d4f29a0233185270482e01a772775a1fd226e373cf20bd95b317d89d043829a5a011aa7a0b946a1019ee2194a5c711107623e3b67664c0c046d7625b89219dfcd0dbeb401a0cc235ac169185880a2055a37b40951992043c6d413cdad4d2aa7d7acdaa75449a0587fd1509148435cec5a2972f56c2457d173ab06c891718de31efe6407089ec3a0a8cc5087ba676f875f43028220f8a1ddc45dd8a0724a6a8c21eaafb32d3dec50a074ebb741679a5d8dff6aacd9ba632055e0060261c821fec6b1c37c19a651f756a0549556d571c086a4280ea0c8582591eca3c1d00edad3120174fc311e4338a099a0bf76f304425a0aae5c23ed7941787bb93db035f23b71efca7cf5cb3789e13d1aa0a0ad88bf39f6a00d6b5a9da2c2e3a8eeb9c20a94d3f1bb540b3783ec085c6618a0535bf09781099597eace7460b8021b09c6bc4f89151b6ff68bb7814aeac5866aa0bbe27a49309b650d65f06d045390d849355c17b08247df099f4b66b9bfc490f1a092686381fdfce4583a9638a71cd077589f8f3e1a7bbeb3ff770e73b7a25a8e7fa07ad75d94848616268aa277bad1582dac2f26f94d028321e58f532dc66369f602a0bf8ff48a6a3a35cf62f6a4ce8beee37d29c9ac2ff92f14d4ef6e1ef97bff22fca03d68775f5dee10b31d68d71e3faa7413cd5605e6d6bfa8f16e2b08c481e359f980", + "d706322a3d0cc1d9ed30c519aca353ee54e97744c2d8b19df188cc9efd89efa0": "f901318080a0b2e8b6bdd25e5c8df7f677044cd3d8da72b83e94339b575a0fbfe4ec77faded8a02f076749258f1190b54bdbf383d447c0161c1f5c859d10973e204fdf7827fd488080a03067aca1ae2e729acb8d8a9fef8a001ce63e763e8f8fd842611bc0e3fd8a0094a0589ff81e82aebaae236b21e67e88c51ce7014c2a4c831e1c7a731583618fb524a0e930015791ddfb40f0560a83903656ff8c9ec5b9e0c413879f076e74360d85a5a0398eabd316d22a87dc673801f47398c71e878f433ca65117ceac88e90100e9a680a02b095d8002754058c971bcd51f10a3ef2975970d54716ea2ee666bd55ba77b0a80a091ac33f28914ec4ee463d7b9d366a0f48a93771496ec24a6b4b7acad3e60045fa0b173412e7de1ed60ebd548833e3ea5695e25a1119e514c13d3f414c81484f5cf8080", + "d783c0f3ab85e061d97cfc724a4a5e3e9e3c0675be5ce0230d8f00d303ad9c52": "f8f180a052e18db3b80a82a7eb706b8cf4166e88518bf8d25ec6ff8e59893a4af5f33fa880a0b54d6be5a9c3afda7b304db7362b9c55df5d3f413dc3818c817609431f2d42638080a041c0a7e78598fa275a45becdfe4a3efeba7cb2b54313ad11fb812278507eb71580a0d0d1b093bbc2542625dbd5a6abc4bbfd5a0aedeb8930be0f8a7a34758cf87acca09de933dbc4bafc922a28011176ba6de6a015fadcc4fdb8a17011d52817365c9a808080a04327a611b120f0884937c2a3b86a13b71f91f3412a4d8eb3f4a82a7649a03acea0668d6b3c16c0109b54df732f0051ff33de2385b2ecb5da2c79185dc60d81138f8080", + "d81e37dd3361efdd6e6dd2b4ff16d1ae55dae3ab63545e0e839e0bfaa43dbd5d": "f90211a088c7f305f91b22654fa8d2896d75ebd92788ae53d9d45cc7599e07abe08003cea0e142d649dd96fe8380e9df94ebc362ece3335c2cd158fb3e76095ecc0d3c3e4ca0cfa209d9c9feb4b46705d8f18843ead9aab90a030942903722981a4ec040e9c1a0e1314642ca9441879353418f522053bc897c0c9117592197fe7ad9a354924cdaa0c4e7e688b90bb8582d05698430d25367505647c03bcd4be0e2a087ecd3da52e6a005066e16b0003f57913816272fa6064f5c023bd92115d40dc4b507c7b9e4ed4fa0679881e250d50de7896e20719f546c1cff5d86e1abfc4cfe79283f7364ee43a5a0e8c2e9a6690dc5c3c0edec95eb458a5f1a0bed0ce7b0b095e92350f39b80084ba0bbb91224d5f11a981f8678fe65983e60830c2fc357e3a130d2d2be2a39c939e9a05506931eb4bc56a30e39a91dbce7ceaaea9c0bc31b1014e7be84b55c294f67cca010c8144dadd55adf9b30c7122d31f0c1acb8c3f4616db3b56e511ef3ecef367ea075404c250c61cf1176ebb0b3de6eeaca54f5c36dbc212492cb870b5287465fa8a0e9477bf211f4e6033c441b71308bb962d5fa06a5d727718e56571a8443914aa6a0492b199495eb22ece7e18ee6e5a1866702beafac027dac8837e5da92e5175f40a08f3f257a70fc9d6eeee0cbb8afb8e98b75da41474a8af1dec842bbff00f6b659a01f6aac7544034dde4fc668c92321742f71fd0349165be787ae9ca19b30b0c86e80", + "d8fea56522f7a124e42e78352e9ed400bea9de3d74996288f22e66b38da15074": "f90211a059df98cd6a960fd3a170be2bc4f3a2e34a0d82da96ed885bd1c7041a9852edfba01678c376ba0565e0d38c6c17753bb0f23a19a1330f6b0878780227ce7190484ba0c236c084e8892b9f2b5e3e5b09c023285d7799e39748d33daa99b8309ecb2a75a0acba9ed77b13eb8893fd1b9b0d3ba9625417215f1076b93b9f1780cccc59c6e6a0d9670d6be535d78dfad81d23796f7b6629d13ae87f5a9911b1936cc022ba4512a084fc516c24e2952a638b255c762eb4f28ea5f969fdfb345678c704cbe84bb54aa0012b030778f32e6f836016a17333abd245152638b94e1c6fd8fc7d912d75e8a3a0c27b186e0d782d73c62a65cb179940580a6109c1ac766cac0369ccbf487c30c3a01aeaeca4d71bbc26c66a7ec4be8fcf808c9e5fda90b0fa0a5df0901aacae274ea053af391cf3919dc180db4bdc64623a5dfa6cf18c9ecacf02dff7506c0bc51c36a06d27a9966e94f1ea21971dfd9b2e7bb7cd8206c57fcb062cb305dd35ac432ee5a046fc22d6d07ba6dd611c5bffdbc2293c4c31cb228ab8a972066f30c8c64a83b8a03310cdc264b67e560164012a360da3e29c789f47865070b7ea38827c1685e40aa0c7febf529f53bf9ad26baf54048e668dcb42711e0d4adf58d7da1e48f6e23974a026d0451f40ac9abc98a2be0103f5e1a9410d67d49869a62058b1537b969f6aada00c15214956bb0f5a88e8e028c997833c6dac59818e7ca282be8192608e18234f80", + "d9670d6be535d78dfad81d23796f7b6629d13ae87f5a9911b1936cc022ba4512": "f8d1808080a04da03a5fd236544236b53971747e8fb47d6084cee6ee0b7ad9236cf6103c5d19a0cf54e1231aeb4cd9a537cdf77774c21ea2b97d147318c05cc0e604ca5d0b5707a0a4291d6922924b9ba1b8e1964c917a202ac5ba54090907d8a4736544d117ce40a0a759da580499f5a51f4dd6ac1d6b8cd32be79cf41108dc70f5afacf74cf8ae0b80a0210bb28b98bb79b93232d637920d7af4e1c7fd735aeacdc51e7459c5d50ceb8880808080a059e637746eb3b0983b8b300d2df6fce1f729227554608c0677f4db52abf9fbf6808080", + "d971489d3c532e28f8fa13a4190203823ee662109245f91a2a9f556bf6b7912c": "f8518080a0f719ffd7f9562924bcfe03021fafd2a89b8625b914d435e60c9b6e2702333c03808080808080808080a0a81fd467c66204a7aec13a098c068df51c944c8da012fc621ddca6265fd0769080808080", + "da2d58f4b9eb7a2555c49d3829ef09e7089a13286faa94d42c241107ed198600": "f8b180a0d51757dc1f2a252923992e02b6eb9c250af98d51a7076e087e29ff134cb478aaa0d466e86322b8ff25541f187186643cfc9359b49518ad206e93aa650081a83739808080a076d23daa0a31a7fd12f4305b01f68208c47c867a47e371e52101ebd0c84f06ac8080808080a0234b49e2fd87964dc7849cd79c50af5d0778db0b4349ec54f97f4ca60956cdcfa0eac1687218941e0bfe7e1fbcfbcedf244ad25f617bfd897856c38b36223a5f4c808080", + "da68687a9b35ed6f2a70b85ad12b3a045deab691b94abcd4da36555f39cb5d44": "f8f18080a0a7fc3b20ae00ae0dc2c660fa4fb2866cbec4d19d47ceabdd03c16ad63366fd5ca0597d1527517611d1724220ebfca41c9e4c3640ffac4ccbc96e86a20a01020af080a0ffc0533be8f83d4a258ad5cdc10143016f25160c0af31170257e539891461797808080a05bf04fdb6d835662530c0b455691c0733936852e57dfab7f1652f5e4fd0076fb808080a0c751fea88573c1120d7ac4d2202d31917dad4a89cf2bae4c8544b4233f7a2382a06ede77dadb3f9f98e9b30d2a33f0245ac3760a321565fd5df681e5f6e7ad599fa0a1c2fc5b45ffbea953bbf6baedb72cb9e708c46568d92844403c914c55e5d8f880", + "dc67281822dbad3723d1eb3351868a8217f0d2a6b921e2a1f116abe441bb250d": "f90211a0bd3702c0dfc79748400d72dfb91231502e0ecbfff94c3f315cf5911c6102cdbfa0461cba92d2108ffacc398c2ea26f1a463ccc83b1ce57e0dfca0d4c9838c2d3f7a0b16bc4b448c09e34236f840731f13874f7bfc73142dfc1534c41347f1d154213a058b639d7ec70a1d1eb2238aba343c4863aa84d1df2e49af8d2f396943364aba8a0955af49b8b5bcd8e3d050f1630fd90517aa20b9d3f810621348f3f653b2b4466a04ebac6c98999985c1c9a1b766bdbf0ac0885cc78246e3b893cfc139ba00673d3a0e91e5a6560d6cab596f011eca7b95b98d666de5dc3a4c5ac274e80045c9fec92a0bffb80a1d1e6487d63ceec17ec296bf7bd361c895f1f6657ac4d14da9659f422a0fb49e0c1a443c2e0260c4c14458e375b6ed07880a32e671199fbc973f91cc120a0da3a1f5319ae2faa21938b452a5d4052ff1246a5c97554afafba8eca21d823eba0932608ce5333a7f3720c20b2ec43c434f8bab97bf0427962166bfca3c690596ba0075d41a53b84ac008697ea307563199a612c2ea02c0926c168d5725724d95227a0988f5d5712ec04a260abfdc7f86ee66b8c61261c4bb296abf36df5d345fc01a0a0b82a1b38bc1ab3a803f5d43710e0139b54555a5712c1b1c6513859ed2e96124ca029b750dd7f6033d5f8a766fc04f013e2af6e31202a10452095cb395012764c36a010656c50044c8c60886d09baad3dfd7b37de5a281b82c04c4626e844971e718580", + "dcdb5ba60059f1cb4190d9e5b28c51ecee4a37965dae4ebc039569d7de2e88c9": "f90211a032ef1ac9353a5970916abaf4b8d9a986fb369309252ec8fdb7d71e79d5d40ee9a0a7e482f75f359d439d27ff5fb5ed2b6796a05ee9f5bc66c00f1d53a9cbc6336ea0facebb03314f4f39daad4aaf485b63c6f7a7947afd96b9631e82d2d9cfbb3501a0208544cc467a0bffdbdfe633973919618dccd501c8514cc5dd62e2d42c0ba215a0e3c8d618dadc597cc25f79513b63080f2d61ea4d83c59c8808a3d2ae435d882ca0286a21ce3d4bac7a178b48992c17051e9044a882b195b205e0152310c74f8d7aa05abae31e52072a09e79dca70824ead4b5aecea57ad17896d117846512323f179a02f5321575aeeb91f8da931b9b252ae053fc510fb0e18a28292d0c8562cad64aca0f40baf7a21a37608930275b07ec48828000b1f2dd09700e5c46d20bfbba7bb50a0e95409e90d6712fd2f39fb156cd39fb7378d1fe154d8dd138f119f30076a69c0a035314eb4d2410929462907f8f295e5ac58b4049f2a46f1ba8605ae69e29ccdfda039f624a3e26dfe1a041160483e9185618b209ba6fdb03efee945af328a5b112ba0f8c9d6cd875ed955580f97e52e21b32da3cc69f802e14d4b3698371890573fc4a089e89b8a6bc10bb7de5b33bd337492f110f3166b6c88e6b9c9d720453668cceba0a64015ba69129ac2f6a649348fbdcaa1139749bd8553667742c256b42a0986c5a002594b5f39c9d150eeebcafd4c2b69b76fd1a90a9e293e369613c43538f4e52280", + "de6a446b251c0750543bc9290d7d0fda03fa7b85bb543e68e9a3775250e04ee9": "f90211a0ec18088432e18321b93a3af7641423179e3ab5f2a0f5ac8054adb96e46cf26b8a01466d30e7649263168d6a913e44fd73987717f396633c8e7b69a8b526cfd3d5fa03731487bf62974358fd9927c498ba731251878e5f8767f290d4535c960061093a0c50b1d6bf8bd6e9c267ff1e7f66eaddd08736dac4f0f0aed6fc252877b0782f5a086a4d3f4b1d28a0bb5a899ac16258f5072fc2d4b3726218db944e927544db595a0f2a098252ea13413d31f84f41b9eabed0148be4100cae35328c35e483426045da034d8ad9629c4fa6d0f4a751fe12560ebe85d433c2a55d6959d18b8ff74966e00a0c3c0fc57bf1ac51187db16f054a1551ca63d8c7df070835e61ba8989335a47dfa0f33f50dc23dc9e85e47be56fd20a2e3b5bd8d1261e6d1a239fed59cbe1552d25a02a0eb724ec3ebea9af2c8b5c3216533f992cd1f1a836fd224cff79c36516afa4a015627c03bf53f559c4d3b916e0f10edd1424800bf6ccfeed2e8228b3e8d81a46a0c61f03f12fb9e3b706d389f66083262a2526d6db408afbacb11ff263912e8be6a0adf2cf3d5347de8f86c1c28b1d3934bcd120f1c283b7433c56c1a6e78392cc60a0123241cd2d7beef1be4348da5aa50a45b481d715e5fe5052d67dd86bc35424a9a08407b329c05a34d31380dd657a601d64a4bdf31a69b9828462d407b33d90d4e5a07557c94d2d3164e3e9ff6dbcf53392292a8ad291737332cfcfbfd9732375b7f580", + "dea4848b9b977b858e8c56b38d49f4fc9621c3c2179de490d235f1a665d87ab6": "f90211a0b854407bcb77713db5346d22eb60827ee771c543caa79f2f673f21c82203cd91a07707f55438e215cf961e838fed2641db7c9536843c5ea910c248c2d8163c813ea09f0d4a0696cc088e7d82960a93a8a73cc6d149b98cb3581298c3ef4fe49a4e30a0c01484df1ca6eae107468c11437bfea188562d2ba802a1573d143f331bc1200ba062e82f6ae361c1b2da99cde1f5de3834293dcd938f473b003dee56e2849ec40ea06bb2eb0a64730d3e652c228bae4b3679e828b15c27d9071fe8d4ad6082b41619a07031338ed253dd4adab3f5d5c7d5952d63d45357ecf8e7c36407820dea3fcba4a04dbb8db8c7e8920a00ec19056ffa0b1b078ca28fb237911be784092aaea19b23a081a2b3d6fee7f774fc83d723c8762211f23e3830186a3b7da624de53f82a1799a0d91136d1e0564e615d60c8a7d355af2e8238df43735a9e1ec42c88726f152f09a030c7076402f79631f52338c0bea72bb695647baa2b72c22e3b0ea7202eed9ca1a0d2390736185bcdd32d9c5a0976ec9275ebe316e1d65d546e4166dddd3157193ea0571adfadbe1e5832602cac8376e01895d4e2b5b87a102ca1bade792d427df296a03086be308c165a4fafdb4d1b03dbd90a217d07a2971f9937ca598f47d4051d08a0d2e47c44778cf1775cb363da3c200e595a3871633b4aff0d448a7de3e03fdbc7a05b384328eb29259ac93833822a5447319dd6d781fd7ccb794aa247eaed2cc2ba80", + "dea914b89ff259902acca17c90d27a9cb980e5cff9b516db8d77aecafee64438": "f90211a016ac58c68185172e8d34a0b64d94595995bcc40aed433da6b23467c743a72986a098c2bc7ab7400049ddc76177c707ff5e5192270e76e750bff3d516a778a2f67fa06e43ddfaf79c86a57f7e2f900184576994fc507f66cc80c300361ee2c921972ea0160b0be7a23770cfbd6affd3035853dd1817ee0f6cff9da9d3f143ac18c1a53ea043f4550adb8ff5d2584d2cd33a9d99e46e3a7f42c0e2b12778619ef45cfca68ca05ccfa0b18c13b56e579987c56a16b545b359d35b0dd0efff6dcd5af7bc9b9f2ea0b4fbbd80244d53ef326076cb060f2f4bbe3f5e72ac044b644cf7a5119c61ffbaa0a7f2ade61b93ee1069dd096a4febce59715104cc861ce233a3a32446584a5a92a0d2623f120154b315718b3f586872e3fb742265bcc185fa0dc1ceb2cf645e98caa0f143ceb1d07423c80ba25b514ada48f1387ef69201b9669f4c6c6e1ff3bf4227a0a8132c80dd561ab864312d697e51839f7138bae5cdc80c123d3d2a18ea125e40a0e9b38c273f0db1cd9bf262c72c774ee468b437302b2efa5b1a890c677cf9f9e1a0ad605d41243e74e8e4cadd453b01bf90276de82bd5abaf71a994aa398efffaa1a0355fed079e23106851fff677a922345ae7cfb1f25aa6d2a4ea24ceae6d509d1fa051f92f6cad19b7da764f32fbc8a00db408794dc6f1c2f1de3fed14c148614b22a0e1ae05942f0d900242a9377dda61a5ba3c4d118c3fb4310ad59032d83e0dcf0280", + "e455c9e9c13f83104d5b848239206ea5cacb2cfd5e04cdb6eec0d869c36fe076": "f90211a05b306254b380316c6d4b7188eae217793724b18bd10010f2ce575852d0fba16aa0ad1e00700c40c3d2ddb49a1c80d0ebab537bddb862224bbdc58b930736e591c1a0a24feae5d4de51cee413ab56b0a5aef3a1fed50bdf7160ba110420c7924879f2a0fa36c7abe9728e9218ede73f530f847cb9ec9e113dd5ee0c3d136425a31e294ba081cd6e1a1cadce744e53cb15636b5dd702241f1a6c9e382b31ba24dbe667ecd1a06a6217dc0e085444f4831d2ed334d065d06769d30d33af9f9d7eaf03606edd62a01494d50d60afa32c2e9e51c86e0e24c2a0dd115117bb5891e24d5a74a99a787ca0319a9dcc15e8a4e0a2a166c2a81f37693b6dade76926211e2c3f96967ac44a52a06f3546e8ad1ea7d2793341c76574e9946aab41d57d53d8299bb11080ad7e959fa09339e754a575bd75b132a118aff3161ed10b576c768a4224afda6237b66ab751a07596531c88c2844c5846ccd19f0e8344c0296e3191daf5bc15fb720d393f5145a03b69756a1be7b5d986556a802f9a9bdbd922b307d751df0687065e7093888e98a01b84dab9c1810385983d1338c4fcd83874b92d5ac5841c867db2c7e3a423e478a0c9019476527507dc7263f2cb8a2f8b5ce1d617d100794252dc3bba2d9844f9a5a06409979b958673bb9e7f1fef28d48593b58ba3eeae9b50f5122cbf2aff76ba87a07bb1727d38b0bc01c2f0b256768d7c3d081763c383649d184dbde2060f2fc16180", + "e51eb8a91a53d9b9723020c10b9c90c9a5357683b2294c08400b3e18cfacbc31": "f90211a0282b7f30d99f1f21396157977e3f545da8dddaf6a9c5c8508d4f08bcd57f733ba0c2160db198b88cf14c25e8a2bb26d66c728f9d071da682df65d65a6e715b427fa03bbf6c6535a3025f1241b51863b866240ed9931e748f1151290b4d6a653668bba01285ff0827d8f0a569292bedc7bd012ceca688c006a96d0a53dbd93b540393cfa050fa9e3075490c1ee61c904338ef0c7470a313718f6255fc3a1df0867256054fa0c3c0530d0767f43d1a9f6e43411b5e82bd30cf56cdc1225d639fc792f3120465a023d205e1165e1fc2b9cef28dd8e8ab473ca63f8b5593e2d6dd6b94417a29ec14a0ac5d893432c436047730146474a153749b626d59940ce3f358ae11d5c451583ba0e9cc306e37b166d2b8ccac44ba5866a379186c434eb10794bbfd7add2ca7f6c0a00f4aced82cea6c09bbce6cdf63dd51eb3850a251484110fd2fdddb4360e757eda031484d644416c072848bdd99c2fd292fc54b8a299901ad55b2789ae15acb055aa04258f4246c113eca21c12a271d8194ca8822f337bc370963335999ca9daff765a09b1b3410b0a2911a19beccc6efaba714f0b6d34b07df836df902c5f5a14fbcc0a063ef8dd057e1e3866d153192b61492e25959824e75d599efd2bc966e0da2513fa033de704a296b573493802fccbcd059f0fb5390303c102ca976c0f4d62a613d3ea0523e9e54a7d970a187f210a9f3b067c75cf6a44fc18e05135d52b67ffad75c7b80", + "e5374bde4be096c791d5d4d42b2e419221b1b639065ee1434f99b2ee41baead7": "f90211a06327be637fe26eadd02d937d2d69b70af3a522cfc67f0a7a954f2aafb710e74fa034143e5bc9356f9b1b7587fa417ff9f4eb4ff86a0d76478147914c7c8ee575f9a07238ef1ddf393ef8079c9a1930fd78608d2cca424142d1bf7b9cf6e89801ecf1a05ee6eefab3e33378422a1e52f21529af6d65ac2f2e51871b118676bf8d5c9519a0b79e2d89606d9506a83ed828013793622bc6920b62d7f76a6f7993e2851d038aa08541a6df2e2bff17fcfcc385fb7ea1aa78c3884f0435d8f3720f1f5749aacbe2a03a97fd82f74b8ea4861ced600d7592fea158810dfc1acf7439b8cf31ce62b7c8a08813da7d3cc7dcb5dd7b7f040ebd8ea7d7fd0424e72246697c3f3e0f511bf4cba002a4e1a0c0e8d62053ccbb0a07e3162eade8acb31f8bc6504283c6856848d7b8a036cb92ba36742f66d8b57e39e8e27fe2f97fe2d99c91d2fe3ad312cfb5d09851a0629367fa72300d95e7bb617903fc2026e63e47ad27689bcaf68340a90504452ca0d64f5dfe05b5ca777f76b0e11c41421f9f60fa2d9a43c52b5f0791c7b8d6bf21a0b984127bcf377fbd1313949923a389499750bcc3c2a3de9a084602148d60e897a0f59c5c69539506bb7180bdcdfcef631b2aa2244bbe9e1eaef282e004a773d3e7a017efd0d9bd4d115ce158015c1f2c1f4c25fbf2c5e9455587e33dabe768e30162a031e406ee7ba66980b7490592426810e1f388ba8001e8556411bc5864ea5df43880", + "e5cdac661e8411ef431da9abf0ecbe19fef7b490fd3f3adcc846e40fa9aba5e6": "f90211a0dce91de7f9c2709410aa02c055b8e964ad492e14eeb672af667826257436836da086642664b1c879170ae16882a47e61a3eab7f08e7bfb9bf18ac43e3c9aaeb4c0a08ae73395f7587731e391c800f18eb9b91b38e4ff40ac8032403334ae35423618a084097ea11e5053c8095a34f7cda7d1633ce43b0db74b20dc19db3b338ab67384a079316b96cfa23edcfe77407e4a7b9c60af0ac4b6f04896bed3ca69b72942cbb2a09115f7f69d189d3e5639eb62b484f18ee541a491d84a83a29a8694d9b9240a3ea08eedf9ae1f5f5f469179ea2c1dbb12c86b4be87828b93670b535b53cbf45125ea06db0f1c21d61beb7d027e18b51952c94f257f811273c7e3d999915e014eb6d9ea01c6e77f3f3ccdf5855aa998a44262258122dd8756ff936a7371a79fd7351dc62a0d7add808b1222d3e166620152d4d8694f0368b97225b06ed06dacfa76cc0f9bda0d419583c2711b8a4592ce7f071cd1c69b734502a4bf8f0f2c62b0874159620a8a0056d8c961e5ee897ce79ed1585ebb1281c28b85f7f3b8a1bbcefa809789975a1a02daa55e490f824ee5886f79258752d52bb432dca91757dea7d919bd8a359709ea0fb7dae6a7b88aa0a8a302ecd178b433da26fdbd02c8ddfd1dc643de305fc6017a0d6335c2f160e36a210667de4246822cf84f5fa636ac42b1120c7791fb49b88fba0df3e5541b3eef4f86dd2453f3996095df7325c3f62ca2c54d08b09a59602035280", + "e6517b1c04ff2f297604b90dcdf2d26eefb5b6c183e23e47a0bd1a98f15bd462": "f901318080a0769ff65ded9601d7d5c49c83f7270e434c427726f4e58cac6f55ce05e70066a08080a0f4794aeea59b611cd1019b6809571058d13ac3cd573721b8241dbac08caa2f3680a000a7df79be1db7e933de735cae2a7f090c2a7a9aa53d0f5f644bd09a07d1313480a04f97435e588970030f1654169f8d2041c4e19eebf0b9fe13c473f6b8727c8b2da04227b49b486ddf93361b799c84e3d4092f49a2bbd3bb6bfd985c39bf4fb601bca02a7064120dc887fd6ba3f37aad2c50c05620ab59195e5a0e2c1cfc176babdb12a0579c49b829565d9f9464b27184e8b9d30f6e20be49450ceff157df180bb4542ca0acda7636c53efb7d3ba2cc30b17c27df660ca4db889d3d0d24fb09458072d89aa0defdb1e0a06912fa405b9c8e06d53b593f0e8d64cbde17dabea5c1bd2321c8ad8080", + "e6864b9874664405d167ef15c4a0d3ca2214446ce2e51ec7d3fc07ee4f7d3be0": "f8b1a077b8e3c2d5f118c1b1b7ff361e24d5bc356827fcfd3e1b0306cd30cad93b4cc580a0c3fcfa17534945bef368ccb85d47ccf60cce90baac9e0c69345abb0e5fab36e18080808080808080a008aa78cb008c378f7f99cfd03cc1c8b3e7580759e119672fef134fabb1ae0c1ca0e334e34c8161394717a4d3e9c17bf59384d2a88bf2ca76a191df31ea464acf0680a065f6b287af5bbd4ee1dbfc8466b7af22bd865ad929ff22321131a396a71bc5228080", + "e70ca022df7793435bf43c3f3b669ebe9974f74199793b417e824c025579916a": "f90211a0ed0c18f88ef9de1d08d05681860d6a19105eaacb7d65329d568e12f047b645e3a0b4470b33249d68e221f7274ccbc7abd029f63d1326d2a6e894449a66039500e5a04ed87eae28641241a86bc76a216bd1ed5bfffdbaaa4e8473a34b22729912c07ca057c08248e120c8ff1f8a53effd76c1267ac2c0f85f64793f6bc000ec41b24f02a0ca1eb8d42a08ed15842c7c30af5d512cd3df6c6f0834026c1bf90e0b7c742abfa043e42cf5ccc16e043575bbade8e8507ad4a82b4df37f839b922c49fcef63a7e2a0e793d0940a6bd34c05928b9e519e996de7e645e20c03fd97d3a1a37cae7ffe10a0512e57096893b2de2a261c9bd048a6aa4be1c2d32cd03f227efdcbe003b53c8ba0973ddfd52865ca29561ac351d06d66c8914af8fa9e2dd7faa7786bc8a1433bf7a055a72f3779d0fcf2cbb630fb4a72ed0591f8aca661c94df186575f24a865242da03ef7419dc1347ad7ed16ee3598f97b0ac73899a1466d31a8faa6b8f3c4b092cba07e95a1fd272c8fc7f1d6bc79e4d97064806f2280fb15ced5857ebc3ae03227b3a059b409411397399a56a1c155056d7075d2b96b39678afe9374244ed012be9786a086bda51bf458420d3f537f5cdda5a2e703ea2e2266a7618c3c2fe2b08e866b8ca02e5c45014b9d39d9e7976d4006ad6476db46636360506f6331f8fd587b603b71a01d9a6ad9cc2907b5082fb787742a00a1ecb8d92ceae038fe7902668b76bdd13880", + "e84481c24cd5b58b3251009d714726852a4c0800637f09cdd7a8c62988cae67e": "f90211a0d3c8f58f2d6340f1cbbb0b8997a7b9a571c45c149208bd01c7f8dffaa55f1840a060ab34ace436e4d5edfe062f24782e24b1520ac524c73452ad164b8643478f25a03047f6408e5055f987993312a846bbd736edb6df01e841a8779977e29aa6eb5ea0d8e3fa957e6efe54a7c9d6458e37810611b136a34444fbdaec8845bd43f02260a0a177e9c2b657f026c3d7d10e437e738d9f1b25440c1d76cb73ccbb94afc80872a04c5aba4c67893b26b8d347ad29d4b2aacf7aa7d3dadcd54c0b2dcb0e8f9c0278a0439e20c8de404b259a387781ce7d662b2c94d05973ce8810684bfaf122d69860a08310dd15252489643c3f1f7043af3eaac520b68eccab92410f7f078a58c2f947a0776c94ea47a2c5573d2a1c806d5361223b28fe7f44e3bca7d652cb629178d91fa0db20529583c9b85818154f38cea096e86c43ed0d81d7f468682e730274ab558ea0a19f56424a412164ca1d7e6ed792079a5e876dbb0f01e1191f41323bfc10e3eda07cb0aea9fb7394a1131d181413d9081268d7739271e7b354d5305936cf32bd6fa06e0655c0e0a7599405856a37e6addb71a6076a58032ee0a1f514b143ebacca2ca0c0d3a75cc108beafe43a4912af3440b7eeb0bf847cffacdd3ecb9d5d2cf323dba0dd8aea9014d9309ec23b170c2eb18a9b0944b94fdccc47350fd10a63ee7c40afa0928cf1ddc71f0a79bf43c187692695814089f33b589cebb2d6d3b912bb26838080", + "e904e8981e2f78221111e7907f72c7377bbaa0b594c06494f5a272f5ab6d44df": "f8b1808080a047a9f4a8ea5162f5c0383f289d1a87c44bb0e0bb815986cc65f23de96bc7c7d9a0622c8fda554fdd583bb09bce7cd36543433d3e38be667cdd590a5351bd2283ba808080a0ca4fbf8d57c8ae4852e67ce374c82c67615981e21106ddcdb78ac5b79e95b2b18080a0aa45ebb0e3e55a1d9bcf06f2f13948b244f8192e251377a68ac0d65fe246d25b808080a0e8f8f31dcf9d04221d1907cf674fcbd2cb5a6980c73755f81e10b1a62848817480", + "e9100dc84a099da7c6f7f863b9ddc3d9fd74eaf8b7f52a889252f62af65a59f4": "f90211a0df9d2858284b58f7cc3ae837ef039b36b9723662e989425a26fad73327929ed8a03cd382be091224d7bc4a112b4cfa8aa25ee81e0f8aa6eb19f4f416b1791056d7a0a8294992db59c3687b4769b504fab98ee5889c4ed0a868e9b54d9382bae192e4a05d9d09bd83097c9313aba1d3c9169aff306d8ae1ccdee3546123402d1d49b66da0cbaa5a650c21af62bdd008fd353cf1503016bfe28b2f7c30ec343cb7b3af42a0a07d87dfe8ab06e003ac727878ccd987ead1e52a2488403ef22ae7d48213c9ca98a0e322f1749ae7cf1028ed8a3b9142db29b60ebc0f87997932e4be0770a47891a6a0752b4142aaf7f1e457737c404c8d1e5edd3dd4da21c6e9392f1bd97270512957a0987ad829cec3ff571720db51fa58319abba8589be6e8c64f817dc64655299747a089ff6575a993a95f7366d4939e121f0c7ffa5f19686495b56bdb2ed4d80e3fe0a0e5cc14b50095ece15d555ace24a72f695fe558d0872ab486655c7247ef2dbd24a03db691c2cf45267da809af1f8030a3931d99f2bc704bd097def6af781d0d17dda0b055d890fcdd49d7189beddcd567f7f8cab5856323958217ee72a99376cb38f0a081917dca950ff6d291b600265bedea6c1e4c2ce559818c42059cf70666fc0c8aa02856fadf2b840869503f463de5029804fa0ff5d74ee0fb8bae9ced357e9e3831a02f8ff6df7a041d5f8a279c1562aaa4e37e388d44649939dfdc2f14de2a5336bf80", + "ea20d5a286aaa075afe2aaac98f53de26fa250a220d0f36ab4bafcca40628e74": "f90211a07f9297e3685d80c07a9fe8ab05e49be27448a92e3862be5d7b5328d96d2ec6aba0b0d3dfffceb8aaa35130a73b0b7152744056c0bcf01089d04f933e87db10f884a066142bdf1766b8c40c8acfd1ddd50f80cd667c78d7bc9088ae7e2d2043d49511a0ad926d84f98a507288e100110956bdc4b7adbd2c117f53851502c27abaec0752a02f2763f23a11a3d316ae06226082389dc3654eb187f7d21baf9872f1f6fde290a029fe9dc212d629d113cc0c0c67303ecc02e5e28fc875e3791bb9cb8a2ab4615ba02b510d637ae30f2dd05cc376e0ce64ec7e447a9da6a876e0006c7143d6db0186a05a4100b75834827fc8a55e32abb5fd6f5aedf74d5b1055c12743700fc7a18206a0edf7fce5fc0c03ad0b8a892d973f842c2028c5e02142bd3b1cd366a4ffd12e31a04e129ff5bd6744600a1cf2001e1072867c3ac1cf5be28c8e9cd19ca356162592a034eb9bbaec30efb16ce8a26376b121120bacc721442f0ec55c5833f3b91d066da0340b2c9363b4bdb81fc896b50e874ac4daddeeda6a78800de3bb4dd97eeea526a05fcaf602bbcae650b814e7d89837b6e9036f0b6fc7f1d92b46716cdcd7ba59c0a0362e5f90c723b6f8d6a8a4c7ee1b1a5e72e39bb180942316444ac762e4b0c82ea01231fd0eec20d3eb156294e34a18d31682a79f4f4eb63eb354c55594f6cc833ca06ce9a9eb714a21f2431ebfe4edece03d5e916ef89771c8fa269b51305f815d1b80", + "ea2e3258ef3435ea0834fcfdca5b64806b062643d36ce6721d17256cb7aa7b9c": "f8419e37df00937b24ec62aeebbbbc4064f6ffea3b0561e398ecb981b827da4b04a1a0feedc0deffbadd11f00dbabe000ff1ce00bab10c1badb0028badf00dabadbabe", + "eadc924c27252102387ff446a4b4502e375438ae22b14be8c7f86006d958ddf5": "e39e36c251e6d3e3fb3224dc4d782c5c2ff76262edd8af06e63c294971f017bb83820801", + "eb5519d63a3c198af4978ef69319fe72e73c747d74dbdf1e4210070e5cbf300d": "f9015180a0b82a4c013a1f09833e61042e19acc9eeb08428b6612b852078acd8e7fadc4f08a0431e4287c47f0ae413168ec07d800ac25e754e9bec6ff0596982e543dc1432128080a0c31eb112fe4313daad570c2115931cecd628bf495bb9643b86ba6e4e3bc67bf0a077c0a5a0003dde23d568e72e1c681bee08af7cd4b1c49ccc61e206ac98120540a047b5a3011cc1c0e341309330b5370634958038c56a4980a159d93d00df7318d98080a04f4efcf750344137ab7926584483376bf4859e8329b8e6f63f4fb4140b8fc1c7a0168f8013cb82abc89c4290a5854613dfa69fe7dce4b88a9614a3a1debe3b84e4a0c4589c710643d5f836a0335046cf5eee4534c383d93e70ff0fddc285bfbbabc9a087a6aeba48866c036928d461c24e934c6739507e264cc0de663a06c79f2f80e880a0a5085dd481a307374d5f1e4b01794ca01f6ce834f208cafae8ed2383082a4e1880", + "ebd5332ca24e5ca847eb2cd1cc0d661668632aa02bf11fc096b1debe0c727236": "f90211a05a8808f5656f3ff357fa2ec77b055dcd4b3eb3f2d151e44b1156b4b57f942c3da07230ad6e84db8fef1870586de47c908ca519c9c9bf589e0ab7cc60395571249ea0ba15a1ef1ba30b1253de0c0a905c8b7aed87f0033474defbf36f4507a8ba1e02a03e2f05bf2d7cfb75012baf648b043582adcbe55addb92bfb24f36a32d5a4698da0a04d852a1016f7f2bb52521d45b0b8f07a5d5340ffcae61ae26c1219828b1e1ba05c60434e02ee8e4b0bdcc535bb0a7be1a890f8796a72a0c462090cb56e6d019fa099793283c952f0699d67041a524c6237d6ec6e2d03190b2a35355563ff756544a0b6996b3827e5337245f1ee2a8b58a14b27b9d455d3b2e381d96bc29e257b5b92a07281a3fd3fc55357b62af11a8faa1d2bbf94f855f48c9848ce61ccae45d433c5a085dc29768e3e27cd2290af8f5afc4201f3e6cc00087a00157130784212e94ed4a04226e9d66fe40d64319c12eabf51706c44015ab97c6e485ff8de18b426809ae5a035bb36b6d70d56d7ed13520c538f28c5ee9437eb7fc1d478730ba3da3dff4bc8a0b88f44dd5432ea5b3226dfcc2af8791321d1923abd7381f50672d214b81b3835a0fe9137081219e4c5f91eb9f6e5c5063ef1015a7355faeb32a4dc14fecc8f7d0ea00e4b5f0422ee8a35f19fd893a21e106ff514c907fe223e224e9e2650cfbf2affa0e12a8cc579df4f065795b86c1244692b0a6bbe5620dbf4397d811120af069d8880", + "ebfff3286207536c9ddaf49e8aaa3f1c1be7a540dceb4806c90cd6b63b578970": "f9013180a08c1d971be23db6faf04e673945fab56c7cbc72f69359b1df07a764c5cf5f3a90a05f0aca551491b22041f63c6351f960b3111d50ffad4bddac08d194ff01d2dc8580a03f1223675a324f8cf7906f690ff9c8e06327aea55a117d3442609a0ecc5c9cd980a06dcc36dd70bd6ae51dc2eff21067ad37cf9b2a89e81dfddae2037b228413ab6f8080a07fc3a34ead195b4ba3319e8ef047764e640871674d4f58871720750ded3a3359a09117a258cdfb0c0fd537c33d4b15deade7505dad5e2f794e6606d1c163868afa80a0c2576efb68cc861fcaa3fe1dcc931291e55845ca0e9f2bed6faaa3b9a2c708c180a0a8a3185d8ccce3c2390f2f93b4a8245e3d39cfd0ffae9a1336219251be9bf1baa0acb1713b120c498d5bf2b1071c7f95d19d1edad2eb0f83d0cb62f561c067e0bc80", + "ec8972f15beec00c03f1a83ba36f03c33e6b8952aaff8a81cbd08112c5f5ab92": "f90211a0ac6d5407d0f41a83aa13e1efa838eccbea8331fdb4b1e22a0243f38d4ab136cba0fe60a4bce77d097c8936a4456ba3c83144092df6c49d8f17e2e270f836eaa7eba0608e077ac7cba5bbfa0cbe8f6a3f2509a4bce7f5496d58970ad06fde63a5bd22a0e75cf0b4b4fdccecd48531097fdf468e626a32cdb22b9d60ff53730db37ce585a0788807bbb02f189198b820f71d1aaf5b4ae3e9430155a8c4cffe1d0ce2d3b2d4a016cacf9b8d699132e14c7993faca8c4e1c2222437c80cc1e64dfd6b759b849d9a0b3b62fefbf100b8144183b404c069dfce3ed10a40decda737433cc39fb94d504a03e87e0be1080a3fa22c6f60959b7c46baf16383be61d1f793776eadc738851d0a0233fe93857b5766ac96a0c2319ababcf3d3b52e9d7c12f20dda2d6d720d64b03a0cfbb2eee735a50638c4ccd016658951bd89ebced77352f1c85082e68fbaff7a6a068398141d5083756202e9d95b30a1ce3bbfc988f56a99d66942e512235aa223da019127cfb2e00353ea06e9a588a4209a3ca900560f14cddbdc3c05b90930563dba0a7e57c092f19c1ab9fd7a64e4ed69a3ba73f110f1bba341134196b77fe0ac028a03aaf2957e0101577ed193f7ee1a2ad98a14f2f1928fdf306e2f0913eb03f2efea0fade037931798fa5dabfb04c41c717dfe3231af4baa19957c97bdd9a70d5036da04507aa51988f3d73ec1c8aa12917fc4ecca368117fa5842f7d6f2549c18baa8380", + "ed0c18f88ef9de1d08d05681860d6a19105eaacb7d65329d568e12f047b645e3": "f8b180a04457c0f4fa1f50449c072f141d55640e91374c6509e2615e0efed1f08d5280f58080a0b89548612b8f18d53bd59d8e737fffbb995236457153674e5dd97f6abed46c7d808080a025b074e894f6d84b3583922721a62070ee8c1da62f92223e558bfd58a0f60bc7808080a0e2c7d190f9ddf08d3113b9394b2369ba868b8b4aabb13f37b9559a088a450db480a014f100a607ad8df72154f0e971223ac8344e8877269e05e53ac0c0989345e8448080", + "edfbbf076d9dc0e497939f5726e88eb23d95e05788c5de0bca82ec28f2cde03f": "f8419e3ef71bbd83b9277ec15f5b27ef7822c33b2e55644e95b9f1430665202976a1a0baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ff", + "ef5a162b77400a3a2513a451dd761ab2ba5c94ac8286248db5855c2e2fa788c0": "f9011180a0cc1a4df8439f81f3fabb8d66ae387cca8edf9c555e29bfc36dddaf0545acca638080a0b66ed527206bb85211b7aae938396ffaf45b1bae22d4b69fba6323d070b7de3ba03249547b7bf3ea063e2db4ca25c575ac5387d2825ec6cbac09ec9e209c0626a9a04d34d40be2f0af53b73f46bb34926b2b731460d905b1ddc530d09a12ca62ad4ea059029277c6d13eb307ddcb309ac1ef70fdb9b8b393d7b3061303028e3ae8a02e80a0af625d82d34de8b53b3f40719933cc8f32096add3a5f8c13245fdf8712de84c28080a037d7849c8f470d218a904665a7a394ab6610e27a3413e9bf8ef685823da746e58080a06009ccc99d187ee35a1436069fc6b17ea0c7590cbd83e9c4578600a601ed5b0a80", + "ef7862e67d698683544b265a5fe194b1a37d98010898eb67f3492bba615674e2": "f90211a0abd50f8bdd2de9f18072d2f0a0bd0447301841be5a36c11f1bba1041a1bf0a1fa0e5267dc3d82fdd1b5f07c6d6d302aa30ba29810c797a8058dcfbebe76fdda4eda00edc77bcfa154bb1dfbfdeb54886e5bca2500c6109cc1ab23b7f2a1d1ab395b4a03b6f32e2b9bc812d409043ba616842c6778e684fca5a61e1f0fbd13b7a4127d0a03ccda38501f18c0173ca6ff5b6993965857fa4e558decf9ec4eb029fedec35a9a0b4fcd9cab6ce1e4dd287e2ef45ff833c29f2d242071956735980382b8c5e4896a0990ea3ce3565e48bd298b94fa31a0ee138cf2a78eec2cb230e195a312b38615ca038b85a6dab7f3864ab27808bcea7afba47067f331df883f555c3b8a63f7f2708a00b4010de07890a392becd7b0a65ba025b68881338d90a8564948578ed3d603d1a0a3bd8522009985aefbda0c042cbd491ab95c64d06eec64c4f14b279d794c491ca02256aa32ff963eda317097c66085b4bbc7cbdb1b5bb3c20ffb315f8841e191f7a0defff5b730f636ddc7416f6be9eaf6093baafaf7e15ee3e1d8f286e18e813b44a0e6fcfc136e142784c9bd999f9a6bc7fb101fdb15570ab9efd843a718fcc14907a0b828dd6f14dd2342c36b9aceb643450772bea5ac0e287ace969d4825dddfa257a0b45e67d0c01bafbc49da1624308d8c120f3a730bc159177d58416f09bc1a775aa05f22ed8a7dea5bb08d7f1b21a1c4fa1877e49199bbf894dcdd78b5046699967b80", + "f0570d0215c72c80f88b99fbf3066173f08d70b1a38710d2c8f7da1b338c63af": "f8419e34c935999ef35f90638635ee1e8f18794e44ae035f5f8929d81a34d1fc30a1a0baadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabe", + "f10ef13814196b7c42116845ddecb8fa2fee1528fa20c0bc93a353f5b3912967": "f90211a0fa04d29b78fef22d5fd53c5a9c4ca3e650c6a756362dd18b48dd288193187706a0a02b5ca4d83881b35e7933ffad5a9159595399f2cc9c9da50448d603e5ee000da08fb9bf73dd8e084efc22c0b01e0587116ec5fc3b540ca48fc450b80513ca3e03a0c7d3b66013691d87e7d4130c16ccaa8857e69b8c80a0533857bfd674c44fa0aaa03fd2f67eaa309e041fd088d564283e22408a7842134597eb0da388920785ac86a0d991027b1baaff33ac1c6174871865672000765e4c62d445fa69f257ac79ea05a01a5d146c7b5b780d20e46bc5cf61a754abe46125550c5b01316e333cd84476bca06b2ec63e9156dc8fac4bf8d1ee6b7f7441c1b429ecda35655485c23f56cda40da06c6b0227675886c924ba75b8a5aea620e111a1c6524206f1356b8c96f3b9943ba0520035d0272b23419fb41de0f9be77f62f8a44483d192582b7b22ea6ec16ee2fa0a1000f88b4a667a6f276ca8a4b626b587d0506a424fb5378f7b45edd8769e907a03d76e2140cf49dfa89f0c2bf4628e7c8c5616891e2cbe915ed6e524ddae93213a052983f5967e6da52896ee86775986421891e78ab81ba803239291f64808b1cc9a06f2ae2b0b26237bc2482e73ed4beb2250e3d00d2685bbbc6795d333b2af3e93ba0825c1fd6628db8572adac976d5a460a42fa3d07cdfd2814e7a1ee1a99eb7aeaaa0185de8abf2d57dccc3663d088f441bdd1ac700b53a9c553401fe03e717a455d180", + "f118c6405ee680ac2c222ff2368b66c87460ddcc033897df266f95cad77b7997": "f90211a0998fd32083139f044c61aaf158be958d7cfd8493ecde344e30118ffe38862f55a0504651b3830cd8a8d0b94c022bbde54b5678e6e3313efc829690301481bcd35fa04474c2d3d86c2edbda92aae58878125686755a38e30361896a6b3dffcf54b7f8a0ce1a2bf6e4500c8b0829ade1f7e99fb8b6ad48c96a305f28a7ce570f88658a74a03b9bb5068e155d43d61f49cf73d0f2c3a48d96715eac3995566972741543fe7da0c46b51231790db88503a6fefe26ac33e62c6f117d942fb90600605fae4dbe098a02d07d0e31a9f3d48f7b04787294f906591c32bf4439a042d4d0fd40c4da87992a054df0667f08bacce450b0b53b8bee9636505023cb9a1714234f28efaa86dde23a060a9dfb7064ea5340ed5cc15b3e3f40a900c8353a49a2b6fd16e437d05e273e8a045c5650310b6a4e722f7e1c0175e73dbbb6128110cd04534f5a06fb9a62433e5a0ac0a6b5f0e9e90ea9366b40c99eafd71a896314e5844286866bbef9154a4f361a01fbd65b40e309118ba0598ef1fadded3fbd562a9cfb40f2894948b1e5a0a04a3a0dadf477d00c22884861a1e1194463efad63e08bab0eedc06f7e604bf2c8f6738a0b03ea0d36d753770f17a242f58dcdde49130dbfe3d5b40efaba819612a3ecedba05c3c5a620c939b9a7955a8108feb237ba7e753cf612b30b0c9c2924edcc3a43ba03482eb74340cca20d04109fe6344b6b9a7a3da5dfbf3b83cae305ee15947544880", + "f20203db7c0c28908c05792752426f72e219b8cda3ea5d63fe446f658cc9391b": "f90171a0ebaad4c587d32cd03a059a35124226c47d06ae27088fac68ca141cc6efeb4af7808080a0fb138f1a8912283842111e46828c9793eb75c4e8f69744cdece865269dc7350680a0f4538394fe09b83ef09caf47026f2cb9d68de78810e9c1fc7fa0bd14c91a828fa016a4e4db9c92746cd28aaa52ff26f0fb38bc1b6ea0f22c1239488442057d190ca0ed870120ddf293d88596d19d301217c67fb7d775b16fccd6dabf577c2865189aa05874746e23077144dce870d38383048c15defe6e2ef2b3378dec5d93b0b4dfe4a094b624f3f17bd055fd92c64df4c1a67e8c33e542e7a787cc47fedf685eb1c969a0058844e5d937fa570351a107484a39007b23c716d3d899f636dbf8d68613edc5a0af2420743f85122260f22dd2e188c218e32844176cc7c7934866a26b7b3ca04a80a063bd2f98ea7ea685ef473861d6bd51d615d103351845c7281a19ba36951aa38da0c8b402c941194a37a413bfc512b4e003f79a9fadeb5b02f049fec0edb1c1705b80", + "f294569b57edd4aa3d83bcc69bdd79db5706b11aebcfbeafb1e3df66bf46dcf4": "f90211a0d3ff089b0e10f7a78235f8282aa74396628f87db569a2701067c80cbbc530509a05b15be26263c6dd237e1e08366bd1b7e96f4922328ccee3c8977fe46b1b5a4e8a0fa38192b6f096428cb5d1a4932367cb57fd7149facafbaa8836ef369e8156177a0885c7d9922a823451bd00743e52fa04967ca16c49b7c15ba0a8e3067e22aca60a0aeb507d8d44ccaea6cd0a0257c7f0e99386032f4dfedde030c19b0cdc5bf2f4aa0d0de371dd1b1e6e3998fe0e10d70663a29a7476e14552b57fb86adc8abc35bf3a094e083746721816f5b28e80eb5f6d0038edd4e5d9e8af2a3e300299504d37e3da04471e04bb79b679ffbdea26deabbc3b0e3cd964b81c5d31173749d3f43f92f49a014878f3c01eafa72bc76aee1e56add1ab303877177a571f210c50c4e07445b80a0136cc810274b8260b29334bfa35dd204a920ef8c24414a6d4c31331c29997fa0a08f1dd67ac42b6dec334634bacabc4f402e24d03ddd5ce029b8654c7dc7f84651a07c3f9b17695cb1a630027e27d594d6def289ad7f61bb39e399d95fb1256f0bf6a0d194f061c614e187e926b10b7401c82aabae045cb0d57ddc4c0a3ee912277229a0848835fc3186c0281e6900f94ff3cc6532b85cc766acc3a45dd773dce044b4baa04e753d51a138e539d7273b5941437c65f400a37b70e6a6a53201655a54449860a0c28328d4e5a3ac84b724ff3698a137d146ed95a3d15c87839369ede67aca606780", + "f2cd55fede94befb7123a1627697080340171ed746283f9e602471a189d0b7ed": "f90211a032fcbf6c4e1b17354600caf62f9e7d1e231a55c8e1d8e4cfc298b17f07633a24a036a3492ec67091deac6aa78f8f333a980cd3fe47f991ad832d05c9a021db14efa0227651d627582de1e41356ec3f3b4916ea96b64a33648c51192b490dc7930d89a07b082c99648a62c23887956000339c5a443be80e0a6158b45c5d9b5de6e9feeaa0c70201eeeea190578fae4f7d9e6b224e654101ebb20cf21867564492129deb80a0d3ce8fe84d31470e358444d58f508b3c53c0e57782810fdaa72522222ec5dae5a00557d7c39a0b2c68233e5c3f1187016c3248aca4390daba9bbaea682ea8f0637a078e93e4015a4355e09ce4d0496a36d0656e5cc20390dc1170b7b35c1594bf5e2a08f7f62ee95216530263364614b74c2a1ffba4430aa4ce64ea1eebf2df64d1a8fa00df14e4825b9f64f7696cad46d8cb7fd066ac7e6aa2f6ba7407bfdb989f4eaf0a0ff393693b68318b23ed9e4aa4a7368596b58ba887f54a09813714db196a391dba0b825982b96bc6dac8667cbb618b67c44cffda19b07e6fe27e800f2f6e535499fa01543f6dc5d9c50a8a5ccf8f762ed9aff3ad112e60b785a1885a2026010a9fc06a03ddec9d9301bd6ab1ffadba5aba1148a52faef015faf91d90872ae403e5a65dea0483fdf8de0c666838b1342bbe5d2c3c2907255fdeedb15b94a092403d319af70a05540515cb4d16d57e64b7e1635c0e2711367c3599451da03e9951315b2855bbe80", + "f33530d450f5de1250ee98690733c01f23c79d693aa38cea35804252d754fe20": "f90111a037bdf170e872fcc8021680f15ba29821196827b4dc5399cacf38be7304e120d18080a0f7b57796c13867ff38665e7d4b287ec71c8289cd648ee0ad15f9bef7d015edb98080a09fabfc8fa48ff521e60d3b5c03f25bfe7a1ca2b89a62bd267cef8a9641e6d3b4a046d1322a23ed5109e92053273ca656d9eab1f5d8f6e1bc87eb1f421dba3f6bcda012878272e2d741d7266d3c226914d7fab192887288df93435d9b41015723a72c80a09e1f8a5c0fe7bc750327b4f12cd0134d149e8b8d7ba61e396b293e8f4490e180a0c4f3fdd4cfbec2cdcb14c71e608530d92e86fc6bf5fb4b3f1abcba76d59754fd8080a01445568a19b8311cd0cf054db908c97f9e36890ba4f36ba031e99872f8144b6f8080", + "f3b1230c6b239ae5fedfbf2e5cf3308ca97a9e7c59a952e091622f4c9f5ae62b": "f8b18080808080a06f1b2cf14b5c8f558225c7d73e4e4ee259f794199aeece1c022b5702333a667f80a05e56e3cb53a08466cf8ce98cbc9dba50b236732cf88e06dd71137536a9bb7a6480a0991797dda597c5d08cbd9e4931c42e090666410c3e0d1d10416efcbee682c682a0ef46e45ef8c5620f4351c3032d5cb7898778bb91b9e43cf065085e1ef5a51d2e8080a0c8f1f9ad4268a84ec0c5ab6f7fa6a06d1e6aad7f30866474a104c571a0ce5f5c808080", + "f424524e15bf7904d5b0ab04ece08073bbebb2fed66b58d6003d69b688ea9057": "f90211a0c63855522af2631c29ecf6153401a8b0bfc39bb6a86711c246999a06de7573b6a05f5dce43724a8db8c64c92acc9577c913a2a22a43a3b25f55f9d50a5d63b86c8a0b344eda5864a2627f92986b7d93c1b77830bc8fc7d1e6d560555645effc1f858a046c2d54a8d8a3da2146056b7d34ea3faa0e411d09ee4b3b78dbf6d8a23dc50a6a08a9b92991790073a3eca700a882e8cc47c38e9bb3efabfa4d110e33dc9dd5d47a0688f7331a005dfd72f6f1962eebd02167d1206550afddaf601c45fe993d19ed4a0567d2383b9bf835a9b36e001fde04ab59564f01e7a8b39b432dffc1abee1d834a06ee14cacf37f9397c5b4c2c4ee686cdc8cd4ac2ec65bd6cd62af787fea948c13a01fe2a8aa80ea9fb0e0b2e40463c791ec373417d9b64b83c9b7480911effa9f80a0a65a985812cee63114fd5972d56745a5fd10baffeed5b82198ff4d4823e7b801a0e20830069a41f91857663958a1302323ba5c07f817a1713229473d51095d22fea08d3c72f5b927eecafae2f50e516f8917a3ee3fb7f20ac6ae8e7b4cb68aca784ba06269ad1df6a564d20359a4c448c67745b2069148cd1fd685bf48df0f810fe1cca087df66c67ab026b2caa64b4caf44d2815673f0bcd1c7dcae0791b346af21fda7a07267889955578fdbf032b4d58c0b3153797181df9605d27d09cec4d678c2722da05d85246fdc22a0f50c39616de9aea6c57d509d497d7ba04cc7c53dcd246fbe6d80", + "f4dc42e7ded8ede43acd6e6be2bc324619b9cf93fc4432607ac2bd1855e70e75": "f8b180a04244dd9f96367c3df36102cadce07bf565fa939742928d8549ae16433551272e808080808080a02e7d7ba09b0af25e33416a4c36a16f228d24c78906574fdaa037c73baf77e7c08080a0f6da563ed87a91024274d8f8c189ba4621aaf696a3d1391886e65a1e074dfc8c80a032a23e6afb2aaa64e45a30a977ff90c744dbbf794012ad3a74b7812f72c3fc5c80a099617a8b124fb4b9f1ad1d9a476f4a1f5a7e8d4ff8fafbc9eb033ded4f35c5e780", + "f4ec1e678469e4424d59a5acd602d45f638d52aaffd744f011000105d4ac8762": "f90211a01ae78f9e84d417ff04024093cf2eaf68e7d29b6220fadb2e07962b92d30f5043a0f83e9f60ae1571b966ec9896d168af6db5e50e5de32e17976dcd49d3ef4ddc58a025431ec6e5fa481862368b3acb61d843040a06d36f1f214d07b1db11412d7adda0c9ae2745a2c72a7e0628f1a84605e24023f964bc354f36432344d2d6243c4fd8a0c54de6ec04a1fd400268eda0b8e99b9ed342802e70a4c316ec6183ab6472e8d8a03d69b5c506034c07d79a910dff5574d882ec9f5fce414521f4f0fe0d2b9fd6cfa0820c16b83efbd040b9209d695bfce7fba64f27da2830702d4dc480b2d0cb057ca0979b5fee50b78980f150ddaaeda2c6c7aab3f9ee95ec134cc911dd9273cf467ca04c16dbbe6e120ca71832b98b9c232858da8c5f25e4b5196c7f48db0ac9936b1aa0e294dd724b8d19156daccedc59bc39e0c8d854c41c315c59123a27eda709124ca00b030cfa5691ba68bee075634d5a8094c13a3b391a685ec432b2679cc01f2312a0d50053cc1e79218b7b3320ca13337067446d611c90f7ae5e2e5e328c0d9f0821a0ce073af42d991867e1130412d9d577dc30dc7337e0b1bbf8cdcf79ec34f2ebd9a0721fa772d1e234d9b750edd3bf2ce45dba762624169dc2db361e8952b9fecfc0a04d8ce7d5bf7ce9e8928016254ad4cba31aa26f5d5daa3661e13a661399caa421a08ce0975afd7f30541fdc25b20f09d00b902b316162d4457fae75a08733402edb80", + "f58dde8702ff92a6b5b794e7b21a801ccde3c6340ab800af6e649a989e1d8836": "f90211a09c877c8bd4e7d5d44a19b5b0deac6d7ec2d359c712121f911d6f87aff0c84981a06399e4cf5487b2c62460f3ab60081b9ad04fcd5bb00d18aaecb951041b7b7e4fa0ff1f178e228b642da8bf5cd10e0a088e4b988411830af742b8f5f677e0fc4a7fa083b1b61478e41c888ed108f1daeb9103303539e2d615d5de8521d0a16e85eb09a0023e05f135e193efdddbaee178977c260cefcfce0a49f16d669e09841e6abcafa0bf978483a13825b9c1aafd09adc8d59900a3f369884fad7e7add9cc9abc63f76a015c1b07ae34a89c7daf494bf971a2c1b703f7c0d917e7e06c7f8f560e85633e9a0ccdfa1a33242bba5e4667817745774f928aab98f5e81d01e81d2559f6c86d42ea0df897364c30a79cbc7cef281d6f162e8d82a15ca0e5722ac9c917cd8f44b6508a040eae84c36100956e12c7e7b3660c886d5fed95ffecce36abddc886f519d5ecda0a6b31a088fde8f24108538e982d30efcb835710a0c7927446fda0c73b3c356e0a0983ca8dec73bbd7abd714cc85dea36b027422cb079b0b7c17a451d292e437934a0a44f6df186a58727bb43c133a16f220190a79a777c6a3fdb1fb601b95318cb2ba021826ba88b2e7577ae2559f1279e90062eadef1028c43a87b68283ec72b6ab52a0255b3a2cb1bbc89af6fcd761340156e906c3b0d484a989942f2636e678856e51a0d3c046cfc9bf20a36d64ef0cc3328e53e1a235a491c5f1a8466ea6a7e557a2b780", + "f59c5c69539506bb7180bdcdfcef631b2aa2244bbe9e1eaef282e004a773d3e7": "f8d180808080808080a0d781015f668b0db517a83e15329aad2a658b0c9e7925afddba18aee8d854e29fa0e6895ed5b40be966c4eb2b44ad02d83e95daabe15049ecb4cd5ece3326e2e2a6a0ed9a49a723b2d3d8067a94aebb1ec876fbcccab0464b1c3e459677abae3763a4a0087bae9b406acdc96f279857b5c512933af2a0700bcfba754deaf4ead3ad99b780a0a91ff20634297f0bda786653895437785d7c75b5ee1a75c435d2d3cc1f0fa2268080a005e0e2a7988a763bd07f58a29bf59c85a98dd830d6dd2df444207612beb8d5d880", + "f61eee8f71a287c8561ebb99d2327ea955b2f081dc62a4be33c8675c8d5c3727": "f90211a005733e19ab2de0b62b29f29b79731374ee3dabbb17208d820261fcfadd79155da0f9844be68e0109514f428d1c8b85359a7c729f15991ea3696725412f053e2133a06857abf81c3994e4b85816c4c329b74089e9a11c24d92558bb7d42175ac3ed21a01f49db536be0f64a4cc7b25d838d64617d64b9be46ce036449fd03bf38f9d888a0051d755bb44c69e201b4e6e127a8334ac452b67e0b83cde54f96462a317c0af4a0524aeddae6fdb03d2de38466cd91ed60c9ca97d542e691309ec52a6ad807a2c5a08b0a4fb96bc270072147808b6a6176a6803742521936c21f25328c5075356a04a08cc6b4ae128971b7a6b4deacaa610397f97b40a82dcd94871374fb9b579c714ea0432d92d10e7ab1432414ed5592e91f4af06b5de7a5042ad269edfdaa1e910b70a081676d26ff6fb074ccc9ac6bc7a64d780d09837f9d812a766f58f4d3a6c4bf7fa021ed7d147a5ec4cf5a986a66f446b8593c924a3ba3715fe532f5b6c08950b86fa0e054b7c24244899d126ff967efe13d79557c919d3ddf184d4865ccae0879006ca0df097a159209efbed3344db003ec632b89b1209e46278b7993840e23106f2e31a0c76f34549cc95765b2f011b05e0978155d2d6d84d88a2c4006ed713521627084a00837352ca944c201c39059c79189623a7d3cae6534b648cd2e788c2cb117aa0ca0bee883c610a5aeee38e8fd2d65ed0077abc24c77d8b3cda49b1bc5455cc8fe8a80", + "f71305d6c27f3126aa03aed08cf4ad76173cd9339945642682df5944686b3f55": "f90211a0f0c14e20c39d0e5734cb5d3c0fe4a2ffaed086bbc3100bab3c938148b2adb9a4a0d514678a462daa77ed80bc698230b264215573fa7008a0e026f4c77083b846eba0cb6c43fde37b9930c17326fc6e86114f0053bce9291afe56ce105824745691afa0672b3941a701700f06def0d392eb7fedd49ed6a0839e57b0b1bfb510da8e500aa0453cca3ec06cde57ab5af155f45886f1c9b61fabbc16ef7b668420a2c154d39fa00b918189da8ca92002f01eb47f7037ae74dfa812b03953889d4637eca0fd118da0f6fd26adec32557a8d69eb520ab8791368cbf62e4d5ea92786805580508d3e76a086d533805a6dc4406140dfa8bc50638c4207242a6099559a1f11307ea69a767fa0f6ac8889af998ac16705b9b535e8baf3fde495faa92fbb7a8c0fb1b74cd8ece3a092f55bff6784abf10e45cf71fdc30edb1b6abada7cf9ecb0706ef8a1e97ea074a0e687e6e30b0384a60b6e08eb7afb4daab573ffb82a211de54182fe8a006e199aa0eaae4afc09649d5bcb815b81f8403b836c56e3e2f15823956d13ef5641ff97afa0547817b9b510d03ab3ea6b6d392235561844538983bc853a30d506e5d97ff431a0dd9e161b6ee5ac4a103baaf7fa62ba252138e7eb34ed793d0176bebddee5f54ba090e29537c6b72e979674411e8046de9de737344c5e1d37f82e591e119c8bfe55a044857555d501f4336ac4e46d4a79b14489e0f5d4db92c4028c56a5af6adb1b9680", + "f7196a25be0817a316b4df115f367a24903d0f137ac368486a68ee0517219724": "f90211a0cc2c5926940e1c259a24de6f96051971279ff7f6bfde76835e8b70371364c85ea0b1382de3c22addb8c29e4881ea51f0d0f55fab70182ca7278819333d3e14a54ba048ec4cb9918a99a0ab25134bf51481893c452fddfe3e9ac0a431d41eb2b114e9a03b9f979bce0c4e71b0ada08233305fb42b28cc6ea5b118a71dee59b7f4a41386a0eb2a5e36104b04868d1ad69971514966e032d55687b827af6808549cafc858aaa075e32706507a1e5fe0c69af0998a6c6af3651e519edd5887160734ade47750c4a052f67a05b24bf52d749d37e2ef41f32378f2dd4054d230064c58094a6c0a7026a0ba52d5a308ddc3f250196842a1ae830b652c09e49ba580f347f6cd24db548025a04d9ef8b5df6f04bc7c9c545a12fef81becd0ecc7ece0af3d799f5e7845cad573a078c13339cdd5d2ceaf8fdef1a6662df4e05a76341eb0274fbd7767f7b4d871baa0b687e7ae2ebae3d0f7e3aa31bf927f646a379b10a35edf6d58281d50ac6aa4fea034b24382ec00282a950dbdd248bc1dea9395eb3098f4816f36a8f649abf23a30a012a5e72350a9105737fc65a1da54c91583a1b71686fd0e24440e14c22b1d828ca0c1107cc3369108487e0295e22333807cf3a35dc596d46a4965711bfb5c564611a03536414ee0dfb7a9e5919812fe0c67b09a6531b9482252dd3f44e39c2630e792a01a9ad704f4ad0e9ae0a2020ae41a53bb6b88825c6bd7c79556f231642acb7b8680", + "f8b141298a73945d7dbaedd8a8a0ef422443d08d958409627b54161b1b277907": "f8b1a0a77545c50af6883966409114090fd0ea01da1a74baaecb60ee1ac64fec6633778080808080a0a83cb530413cecf306f0794d3536b8e61086a0f8842ea6a2e2371bdbc668030fa03c12e66ba2467e37a4348edd7e4f477993809310ec383e8194d628d733427868808080808080a081b636afc6614ba2dd78593ceb6704a03d945634a99f05c6606c7455fa3d4640a05d6e9d75e313723d9674b37a689434ebd2726ac32e78fe9a32ac7a32523f728f80", + "f9731da5be992bdce76170350f290d9d754195f3926fe8b4b65d2f9c051e9a1b": "f90111a01d714d0b1974ae27a2387f50aff075249fa9a018d33bfc5931ef246ee3734622a01947111c6e631eaa4d1776feae7e3fb964290f0b48bdf339f155a2530be2b27580a07a402c1a432509594c0175d298eab446247d4c3286d74efbe3fc64d1572d9abd8080a0b6b9907ef89dc9a7fbc10535fc1cccab7f1e8cacf8fa2f788e4ec101be3c3c26808080a073e83c417e6ee2ddcbbba356543f9dfe982fc2109a8c543ec0d91e31963a138da0e858e8dafa5aef306bd61569372950f71247d118146d3a9538830d5ea2cb3f2080a0d782ba1d8a122edfddcc7b410d72940921fc403e719db12cbaa2be1dc2a61c8280a080f5b6057bc43f0c174ea4f5fd0734a5355bbbbf1c283644a5a1be0d2a73089f80", + "fa7771f08b391fd03e69645940973cffd4f0f6a84fba13af48b4296098e9f088": "f8518080808080a0f628a54fdeab25a459830954436ac075408e63a934af90c267f5f116e669d22f808080a0595b243f37b06f53d918af6eb6972c289281603328389d06d7055a80668b756980808080808080", + "fb617882d02c69c87240a7bfc0b9edef6947702e866391241c057acc846ddf21": "f90211a033386b2b812bd72a1580bfbad0f8ea0bdac53f36bf3b8905765056b8bb314120a08d1f21f52e413ec55a5fa1bf90924b12f09399d418407006114ec6ad3efe707ca07b3c235af7ff9d547bf9faef9b64babe4faad497aca0c1236505b4c88d1a9553a070f1db9c1c22055a30198f7d0e66c7840bc3abf3a75f99c5d31d9ab80e3d11d3a0f51bffc369443b2bde8f04d220f5dea7b121ad0f6608cac2e0416c63973d7a3ca02323b5b2064814de80c3efcc3817c4f7f15a3271bfa55cafab3841fc6c556fe4a0688d5b11729a5ed1298d142b5423677a0da64515316135d155921f3de7054596a0d077465e74529e965f1823e487a96b0556001281b6c38e2dbd994d890433c156a038817e5e390810ae4a93f54a6271de2515f47b661a6ead91bd692d27021237c7a0be312c09ed679faf227eea833e1ba0f2e11278d00c9aa4b4fac99ef582f68d35a0cd0a4b9ebb8e68602212d720bcfca23278d2abc419290ccebd90273845de509ca009f99818622f2dc48357684066c75acfb77ca8b61bb91689f7cab49d0b7a7de0a076cf218022ad1af1ddeb84c2dfc6959e5edc5c32652f7baac09a3f6f6ecaef0fa0daaf9de60831301ca0f7ee9de594887ddafa1e7135a715ca26dff3748b05f5cba0c63dba659bb64880ab56b406aa8e9b063d7f9b72efd848760f19a5561815d1f7a039d1b3ab8272293b340d1bf11200610fca853b76504044e07dd2868557c4513580", + "fc6ac87d10550c904ab264584511899a12edd23e6801f80ff68b5ecd7f774de1": "f90211a0d83601909d5c211f5fc9f428b378a594e0454260ac516ac887c00a5584ebd189a01aaffc1fd7bea4e0d836cc790cb8cf32075cc55bba24eb48c33cf14e582a9c8ea08f4dd57cf3d66566e0f8db7f461da0339ba092934076bd444ea3c8d56848dc2ea058c7147ba81e83310642bf04961c3c86d78d8083b0b61b0de364ff7806bdbfe0a09bdee70790d798e6f07484bccdca7113635c1765665150271d97afb86b371f07a0fa5ace29d5ea4128f371a47ecfbcf7edcf51d442ffe35337213213e3076c3222a0fb0c42df3bca53295f6db02b7136ee4668e5385eda7bc2f74ad7f52c26009be2a011881dc233e9ab32122a8093ea06193bf95780fcb72d034db7da48d3d2a9753ca06d5b980de31253e4a2b75c241378a169a0558d9abfd4a86fcd78c7c9e3e47bd6a0b6fc66247f2e737a7b80c5ba7fe4d3b545fb9a941dc536f7a66d196f90ebdcb0a0398ff765b546f14291cdc97e6c62a12639b47588a37cdc024ffa5dfb80264014a0fa41513638ed92814369ace333d9726b6fb5504662dc800c1cd59f5b4146aa03a0b6fe1576c91375acefb6515583e60bbf5ddd29f8653c99cd62e00316ccfcfe7aa00423dfc1061903a7505e3c9bacc978d9632ec1b64fd353b28870a3056ec1c308a03b73260117e014baef0bfa9bcf0dd450817693091ed30650692fe90cd3a2c60fa0f025f2368de48972af7e44b8a96e6b27c489cceee09d0fa50899964c69d9f4ac80", + "fccac1597dbb9c323776eef714bdc7e013d0abe2d23de672ee20f1eda5846efb": "f90211a052abfaae552517380d3072cd87ae415f45305f4d42f8a4918aa91b76a496aca4a05121f84a798d2ed197bb05a3b8fb098d387126afdf85862c8f060a56543f4fa3a0a189485195cc3901705a5583bb81f10450872984bdedea50837fa4f1dc49fdf1a0488edbab0ff5603e9ced4e29282796a183d680ec678c54b96143aa0a1b368d91a07cd1dd2762f23aeff316dc47e1d92161e9f0950dda633fd4fc46740b8ea53f96a0f2b9f33e178be18097248ea1effa8b60cd79b7f7a38e1d50473b4ac955aa9638a06a57fdc70ade6076687d368526c2bebe6e574256bc2a0c3084e15de481d60076a0b8b1a4b3dacd20a77241dd79b619f63674d329587cfd7015dcf6a48ddb6e834ca07ac4c0580b08e57ecc42b204b170812e3a67a3849a4351b5a0abee34569deaf3a0240dec0ec07b508a6c800034535c21367268803d7e6951dfce14d070376d9927a03994dd7bd2ac403367c34366856f1a0aa6007ea0d031507bb4a025faa5c5bb46a00207127f88014b7dde80ed9035c4a68794e375c54871a6a4a0eaa6cca4add3dea02a462dcf2d0a1f7c76574d0a42186358f378e20d996d14ea8b0dbd73b6857260a0333b094107c4a07c7a35c4a5012359fb0546f02ab4d3d8966463165d01af560ba00c7617aa05ad6ea5dcbdbbd7d786e3b7a08d950a9dec9132849fe49c3d69226fa08510fff18d2037fee65aafcc130413d8df7b9bdbf75022645188bd2f78b079f380", + "fcef8054763af3dff0c963f8df3d06bdfe5730257341121ee24dbfe7b3f966b2": "f85180808080a080671aa571faf40034aabcb8f7f89a20f2ab48765a931493799d0dc91b1284c480808080808080808080a0c2e0b534b8a839c74108596405e4824f6038106b0d74046ea937baa0c69675ba80", + "fe46f5d6dddb35717669faf8218ec033270ad0f78d87f056b6e315f7b5903543": "f90211a0b95d3a56d750733889220e556adc1a3f3cf31fdda2c6c61af131d3b77cd6e79ea0b2a34def84a3b78192737ab9b728a0c810b510bbdc9177734b173c92393818b9a0194e3188ac44ad110de8ac12aee1d005147f4a84fdc76d48b1b094bd8e2e88a8a0384c297644b699393d3262a60809ee27bf887c1f3fa24c15d4354adb6501c203a0cd4456ac9ae6fd5582abea866ec1b5fcdaa1c1687c3f5477b70c5a71b887880da0c7224ae2a7c4cfe2562944fe6bdeedd6dd6464f2a4725b3fda4adcdbef9c962ba0665bb29b3f8f1fb9de073f632afd705b395471585ec1e305b472d1b48461a84fa0ef0984fc1c4fb87c7edf10ee5d6813fe62edd7d715fcd0133b38a55d9ec7dd76a0fef4c48c5f80bca8f752bee295f4b677579a040507a9b6e2d8174435fdb66903a088b89ad5006e9cc3e3053457b82dfff5354cc5d119159b6f1f51e02872182f6ba0a06b5a668a73a8c1f149d9200ad163e0c2d2ef7885f06798b69428c994b415baa0d4ca9b762c321ea63b26c7f3cdf9e7b3bba431fbfbb3b09f3ea3382b360277f0a08b043d2556a5d19965204fc16a02c48db58c44fce37ca29c5d941334a8db137fa06a871f79487d292c1ff7adc89716a9024fd96972f9a8e1d6e6a2b60eec3dcb92a0f8ff1b415a075489db1e6219d1c88b064b7540975e259c51c699134056844b1ca0ca5ef3c0b87e4a8d156692550fe42f9bd87882f48458ddcb72c759a14dd3bc4880", + "fe60a4bce77d097c8936a4456ba3c83144092df6c49d8f17e2e270f836eaa7eb": "f90211a09136a27f826707cd8a8217457db124c8a1c1c27a48bfec7aa936b170344288c8a06a79a9b529f01a0dea16a8c9837365b4bb69573e9c717ad9ca9a969cf0f46a2ea039c8109d4918c1a291042701adcfc5105a9d4534a93b3a168206403f4f515a50a0bf9a216203a885733eb20087abff828865b8dc65693178e84effa03a6019d572a0cd1caeca670db5c068a4b565d548e01663dff0af625ef8f8f1ad0362e4b7a89da017c5abeb1c81980f91df5518da56a24a3fef6004423123aaeb717449decfb4b2a08afc6793f1d7b4c5aabedead8546e16d29ba44ea8978e6669055c5a6d61bd2e3a098df008229cc8a9dbb13bae6f68c2227a0b163ebcf0adcf01b80c28c7ff3c430a004cb61cdf921438dd7d0a05dc2ab5279ec346963868d0d6dcc623789b291d0eaa029f7bedacef251443f02108e1bb1bb5667731b97ca78296e27cfd4ad7ab858b4a088e86d6f2d9667dfeff1673b8a3bcd86b5466ac8ccfdf49970f2d21b9e88f121a07a1868faef66b33b89ca753b4bd81588bc0f4b72106ae42b73db3283e49f4d59a07b0ee1d9b8e7bfaca8e8c799d8b6f2d7d188e6694031682970c50a08ce024d4fa079fab6b7e2ca671e8ec684a8f7dcb2a15673d9c924407f294798f2b103beb975a02a6ee492d26d305bf8dc73cb84243347351056f8c86125786fcf5c601310c15fa0c57b70e198a741b569ea565abe31feec70c5acbe5086c0b5660402f0f724bbdd80", + "ffdee49c5a0109eff7c53ce7c254ace02363105b9a17baaca3db3f8b0949f1e6": "f90211a0d2c711cedc21a246c5b122461ea78ac443e7cdc728549aaaab5c28f674218f49a0a6c4f8b091095fada898d490b719a884958842d32f60d44b34f1eabaa78cdb7ca0878a412e05c0df9d1af5170394a371d378f067cfe2b4cbf2c575da8364226408a05477345a83c623d093513140f14b3ad4363bbc40b96e354e275bc9b2bcc3e4f4a0b2233a87bbef49e1d2b54dad1d4d13f12e12f8660e84803431bf24c4cfea6ff1a01850573b263fc818381ac494fc820d74935350e54978f1db0d7fcdd335efa7f6a02d512c7518b2a42e45c998930db9e4ca1ad1ff4d054a056653caec7f589bec6ea0e9a39aa9e83ee614931590fea422de873517fb4e0a5bdf2dd744a371b79580b4a08673da46ecaa9f7aeb4b2bc140ef00bc8af5b26f5fd6681a1edc512972e85ea5a0c3a1b7540b82a4a3d7dc3b50f51d945906d64399647fad5b90f9e4a687069da3a0f3c8c89cb3ea01481f60b4e5c78e379d12f7f26edea3937d67fc6f5d1d13b117a0f79bc53c7e4e7cc4f1319f0b901d3bb87b3f5f8ba9fca4afef3d1c5371b8c2cca0839573792e04b48b69f00e79f5d563a09a1f60bfe42a256f2af9912b93ec0f01a0aed33cb7a585b9a671d894f575092c8ade7877678d4073b268f0a179ab7eb718a05c2d2aaf81986dcf7f7062c000e486ee9ef7732469755d71daea78901b489d76a062154a189e64b541c4349f49f8dbb243e052365cceec8126b23e03d7e87fb08380" + }, + "parentStateRoot": "0xcbccf9f17eecc98379ccf4a140a026a8c2585ca3b0901563e4f9a9f1b15907c7", + "transactionTraces": [ + { + "txn": "0xf904aa8248d080830ad21e946fda56c57b0acadb96ed5624ac500c0429d5942980b90444b374012b00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0deffbadd11f00dbabe000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0deffbadd11f00dbabe000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0deffbadd11f00dbabe000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0deffbadd11f00dbabe000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0deffbadd11f00dbabe000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0de820fc6a05b6c9cef6e35d76a51713b0cc5180b19059c3a0182da05f7525eac10b327a572a044fd10b9a63cd495a798d2c3d4264ff49a8c7e954e3bca63b7a7b60fe91dd20a", + "delta": { + "0x0000000000000000000000000000000000000000": { + "address": "0x0000000000000000000000000000000000000000", + "balance": 1000000000000092200000000, + "read": true + }, + "0x6FdA56C57B0Acadb96Ed5624aC500C0429d59429": { + "address": "0x6FdA56C57B0Acadb96Ed5624aC500C0429d59429", + "balance": 0, + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x00000000000000000000000000000000000000000000000000000000000048d0", + "0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bba39d": "0x0000000000000000000000000000000000000000000000000000000000000801", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e1b": "0x000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e1c": "0xbaaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ff", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e1d": "0xcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabe", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e1e": "0xdeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeed", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e1f": "0xdecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabe", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e20": "0xfeedc0deffbadd11f00dbabe000ff1ce00bab10c1badb0028badf00dabadbabe", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e21": "0xb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafecafeb0ba", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e22": "0xb0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e23": "0xdead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00d", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e24": "0xdeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeed", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e25": "0xfbadbeeffee1deadfeedbabefeedc0deffbadd11f00dbabe000ff1ce00bab10c", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e26": "0x1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00d", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e27": "0xbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabecafed00d", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e28": "0xcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeef", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e29": "0xdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8ed", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e2a": "0xd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0deffbadd11", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e2b": "0xf00dbabe000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b5", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e2c": "0x0b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabe", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e2d": "0xc00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaad", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e2e": "0xdeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10cc", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e2f": "0xdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1dead", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e30": "0xfeedbabefeedc0deffbadd11f00dbabe000ff1ce00bab10c1badb0028badf00d", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e31": "0xabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafe", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e32": "0xcafeb0bab0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5e", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e33": "0xdabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddead", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e34": "0xdeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e35": "0xfacefeedfbadbeeffee1deadfeedbabefeedc0deffbadd11f00dbabe000ff1ce", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e36": "0x00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaad", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e37": "0xbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabe", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e38": "0xcafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeaf", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e39": "0xdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbad", + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e3a": "0xdefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0de" + }, + "storage_read": { + "0x0000000000000000000000000000000000000000000000000000000000000002": {}, + "0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bba39d": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e1b": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e1c": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e1d": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e1e": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e1f": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e20": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e21": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e22": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e23": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e24": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e25": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e26": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e27": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e28": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e29": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e2a": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e2b": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e2c": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e2d": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e2e": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e2f": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e30": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e31": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e32": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e33": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e34": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e35": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e36": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e37": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e38": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e39": {}, + "0x4a27a46697da58dfe447cc2de67cbc23d5e879f136b82f2bd9034c3a30247e3a": {} + }, + "code_read": "YIBgQFI0gBVhABBXYACA/VtQYAQ2EGEEVFdgADVg4ByAY4CUf4ARYQJBV4Bjv1KcoRFhATtXgGPdm+9gEWEAw1eAY/J5yoERYQCHV4Bj8nnKgRRhEWFXgGP00fxhFGERkVeAY/WPw2oUYRHBV4Bj9rC79xRhEfFXgGP953IcFGESIVdhBFRWW4Bj3ZvvYBRhEHFXgGPel6NjFGEQoVeAY+n5s/IUYRDRV4Bj6lFB5hRhEQFXgGPt8APPFGERMVdhBFRWW4Bjzjz07xFhAQpXgGPOPPTvFGEPgVeAY9EXMgsUYQ+xV4Bj1R57WxRhD+FXgGPVP/P9FGEQEVeAY9k81VgUYRBBV2EEVFZbgGO/UpyhFGEOwVeAY8Ngq6YUYQ7xV4BjxCDrYRRhDyFXgGPEvWXVFGEPUVdhBFRWW4BjoYaDyxFhAclXgGOzdAErEWEBjVeAY7N0ASsUYQ3RV4Bjs9hH8hRhDgFXgGO3uGIHFGEOMVeAY7gcFIQUYQ5hV4Bjvch1/BRhDpFXYQRUVluAY6GGg8sUYQzzV4BjonG3IRRhDSNXgGOmChCHFGENQVeAY6ZFycIUYQ1xV4BjrK699hRhDaFXYQRUVluAY5YuTcIRYQIQV4Bjli5NwhRhDANXgGOYRW8+FGEMM1eAY5orfIEUYQxjV4BjnM58+RRhDJNXgGOgQK7GFGEMw1dhBFRWW4BjgJR/gBRhC0NXgGOIDv85FGELc1eAY5GKX80UYQujV4BjkeeydxRhC9NXYQRUVluAYzQw7AYRYQNSV4BjYOE83hFhAtpXgGNvCZyNEWECnleAY28JnI0UYQpTV4BjcdkdKBRhCoNXgGN7bgsOFGEKs1eAY3wZHSAUYQrjV4BjfejG+BRhCxNXYQRUVluAY2DhPN4UYQl1V4BjYT0KghRhCaVXgGNjE41PFGEJ1VeAY2Wbu08UYQoFV4Bjbn8f5xRhCiNXYQRUVluAY0D+JmIRYQMhV4BjQP4mYhRhCIVXgGNEzzvHFGEItVeAY0phrx8UYQjlV4BjTSx0sxRhCRVXgGNVkMLZFGEJRVdhBFRWW4BjNDDsBhRhB9dXgGM3EwPAFGEIB1eAYzpBHxIUYQglV4BjOkJd/BRhCFVXYQRUVluAYxgJO0YRYQPgV4BjIZzd6xFhA6RXgGMhnN3rFGEG51eAYyKU/H8UYQcXV4BjKHHvhRRhB0dXgGMrIe9EFGEHd1eAYy0055gUYQenV2EEVFZbgGMYCTtGFGEF91eAYxm2IdYUYQYnV4BjGroH6hRhBldXgGMd4vNDFGEGh1eAYyAHMy4UYQa3V2EEVFZbgGMLqKc7EWEEJ1eAYwuopzsUYQUZV4BjEoemjBRhBUlXgGMTXVL3FGEFZ1eAYxWBzxkUYQWXV4BjFlghUBRhBcdXYQRUVluAYwNK73EUYQRZV4BjBQCC+BRhBIlXgGMIe06EFGEEuVeAYws7mWoUYQTpV1tgAID9W2EEc2AEgDYDgQGQYQRukZBhJhFWW2ESUVZbYEBRYQSAkZBhJk1WW2BAUYCRA5DzW2EEo2AEgDYDgQGQYQSekZBhJhFWW2ESjFZbYEBRYQSwkZBhJk1WW2BAUYCRA5DzW2EE02AEgDYDgQGQYQTOkZBhJhFWW2ESx1ZbYEBRYQTgkZBhJk1WW2BAUYCRA5DzW2EFA2AEgDYDgQGQYQT+kZBhJ65WW2ETAVZbYEBRYQUQkZBhKHZWW2BAUYCRA5DzW2EFM2AEgDYDgQGQYQUukZBhJhFWW2ETKFZbYEBRYQVAkZBhJk1WW2BAUYCRA5DzW2EFUWETZFZbYEBRYQVekZBhJk1WW2BAUYCRA5DzW2EFgWAEgDYDgQGQYQV8kZBhJhFWW2ETbVZbYEBRYQWOkZBhJk1WW2BAUYCRA5DzW2EFsWAEgDYDgQGQYQWskZBhJhFWW2ETqVZbYEBRYQW+kZBhJk1WW2BAUYCRA5DzW2EF4WAEgDYDgQGQYQXckZBhJhFWW2ET5FZbYEBRYQXukZBhJk1WW2BAUYCRA5DzW2EGEWAEgDYDgQGQYQYMkZBhJhFWW2EUP1ZbYEBRYQYekZBhJk1WW2BAUYCRA5DzW2EGQWAEgDYDgQGQYQY8kZBhJhFWW2EUfVZbYEBRYQZOkZBhJk1WW2BAUYCRA5DzW2EGcWAEgDYDgQGQYQZskZBhJhFWW2EVDFZbYEBRYQZ+kZBhJk1WW2BAUYCRA5DzW2EGoWAEgDYDgQGQYQackZBhJhFWW2EVUlZbYEBRYQaukZBhJk1WW2BAUYCRA5DzW2EG0WAEgDYDgQGQYQbMkZBhJhFWW2EVkFZbYEBRYQbekZBhJk1WW2BAUYCRA5DzW2EHAWAEgDYDgQGQYQb8kZBhJhFWW2EVzFZbYEBRYQcOkZBhJk1WW2BAUYCRA5DzW2EHMWAEgDYDgQGQYQcskZBhJhFWW2EWB1ZbYEBRYQc+kZBhJk1WW2BAUYCRA5DzW2EHYWAEgDYDgQGQYQdckZBhJhFWW2EWRlZbYEBRYQdukZBhJk1WW2BAUYCRA5DzW2EHkWAEgDYDgQGQYQeMkZBhJhFWW2EWgVZbYEBRYQeekZBhJk1WW2BAUYCRA5DzW2EHwWAEgDYDgQGQYQe8kZBhJhFWW2EWvFZbYEBRYQfOkZBhJk1WW2BAUYCRA5DzW2EH8WAEgDYDgQGQYQfskZBhJhFWW2EW91ZbYEBRYQf+kZBhKHZWW2BAUYCRA5DzW2EID2EXo1ZbYEBRYQgckZBhJk1WW2BAUYCRA5DzW2EIP2AEgDYDgQGQYQg6kZBhJhFWW2EXwlZbYEBRYQhMkZBhJk1WW2BAUYCRA5DzW2EIb2AEgDYDgQGQYQhqkZBhJhFWW2EX/lZbYEBRYQh8kZBhJk1WW2BAUYCRA5DzW2EIn2AEgDYDgQGQYQiakZBhJhFWW2EYOlZbYEBRYQiskZBhJk1WW2BAUYCRA5DzW2EIz2AEgDYDgQGQYQjKkZBhJhFWW2EYeVZbYEBRYQjckZBhJk1WW2BAUYCRA5DzW2EI/2AEgDYDgQGQYQj6kZBhJhFWW2EYtFZbYEBRYQkMkZBhJk1WW2BAUYCRA5DzW2EJL2AEgDYDgQGQYQkqkZBhJhFWW2EY8lZbYEBRYQk8kZBhJk1WW2BAUYCRA5DzW2EJX2AEgDYDgQGQYQlakZBhJhFWW2EZLVZbYEBRYQlskZBhJk1WW2BAUYCRA5DzW2EJj2AEgDYDgQGQYQmKkZBhJhFWW2EZclZbYEBRYQmckZBhJk1WW2BAUYCRA5DzW2EJv2AEgDYDgQGQYQm6kZBhJ65WW2EZrlZbYEBRYQnMkZBhKHZWW2BAUYCRA5DzW2EJ72AEgDYDgQGQYQnqkZBhJ65WW2EZ4FZbYEBRYQn8kZBhKLFWW2BAUYCRA5DzW2EKDWEaDFZbYEBRYQoakZBhJk1WW2BAUYCRA5DzW2EKPWAEgDYDgQGQYQo4kZBhJhFWW2EaSFZbYEBRYQpKkZBhJk1WW2BAUYCRA5DzW2EKbWAEgDYDgQGQYQpokZBhJhFWW2EahlZbYEBRYQp6kZBhJk1WW2BAUYCRA5DzW2EKnWAEgDYDgQGQYQqYkZBhJhFWW2EawVZbYEBRYQqqkZBhJk1WW2BAUYCRA5DzW2EKzWAEgDYDgQGQYQrIkZBhJhFWW2Ea/1ZbYEBRYQrakZBhJk1WW2BAUYCRA5DzW2EK/WAEgDYDgQGQYQr4kZBhJhFWW2EbO1ZbYEBRYQsKkZBhJk1WW2BAUYCRA5DzW2ELLWAEgDYDgQGQYQsokZBhJhFWW2EbdlZbYEBRYQs6kZBhJk1WW2BAUYCRA5DzW2ELXWAEgDYDgQGQYQtYkZBhJhFWW2EbslZbYEBRYQtqkZBhJk1WW2BAUYCRA5DzW2ELjWAEgDYDgQGQYQuIkZBhJhFWW2EcD1ZbYEBRYQuakZBhJk1WW2BAUYCRA5DzW2ELvWAEgDYDgQGQYQu4kZBhJhFWW2EcTlZbYEBRYQvKkZBhJk1WW2BAUYCRA5DzW2EL7WAEgDYDgQGQYQvokZBhJhFWW2EciVZbYEBRYQv6kZBhJk1WW2BAUYCRA5DzW2EMHWAEgDYDgQGQYQwYkZBhJ65WW2Ec1VZbYEBRYQwqkZBhKHZWW2BAUYCRA5DzW2EMTWAEgDYDgQGQYQxIkZBhJhFWW2EdQ1ZbYEBRYQxakZBhJk1WW2BAUYCRA5DzW2EMfWAEgDYDgQGQYQx4kZBhJhFWW2Edg1ZbYEBRYQyKkZBhJk1WW2BAUYCRA5DzW2EMrWAEgDYDgQGQYQyokZBhJ65WW2EdvlZbYEBRYQy6kZBhKHZWW2BAUYCRA5DzW2EM3WAEgDYDgQGQYQzYkZBhJ65WW2Ed71ZbYEBRYQzqkZBhKHZWW2BAUYCRA5DzW2ENDWAEgDYDgQGQYQ0IkZBhJ65WW2EeFlZbYEBRYQ0akZBhKQ1WW2BAUYCRA5DzW2ENK2EemFZbYEBRYQ04kZBhJk1WW2BAUYCRA5DzW2ENW2AEgDYDgQGQYQ1WkZBhJhFWW2Ee41ZbYEBRYQ1okZBhJk1WW2BAUYCRA5DzW2ENi2AEgDYDgQGQYQ2GkZBhJhFWW2EfHlZbYEBRYQ2YkZBhJk1WW2BAUYCRA5DzW2ENu2AEgDYDgQGQYQ22kZBhJhFWW2EfWlZbYEBRYQ3IkZBhJk1WW2BAUYCRA5DzW2EN62AEgDYDgQGQYQ3mkZBhKYhWW2EfllZbYEBRYQ34kZBhJk1WW2BAUYCRA5DzW2EOG2AEgDYDgQGQYQ4WkZBhJhFWW2Ef5FZbYEBRYQ4okZBhJk1WW2BAUYCRA5DzW2EOS2AEgDYDgQGQYQ5GkZBhJhFWW2EgH1ZbYEBRYQ5YkZBhJk1WW2BAUYCRA5DzW2EOe2AEgDYDgQGQYQ52kZBhJhFWW2EgWlZbYEBRYQ6IkZBhJk1WW2BAUYCRA5DzW2EOq2AEgDYDgQGQYQ6mkZBhJhFWW2EglVZbYEBRYQ64kZBhJk1WW2BAUYCRA5DzW2EO22AEgDYDgQGQYQ7WkZBhJhFWW2Eg0FZbYEBRYQ7okZBhJk1WW2BAUYCRA5DzW2EPC2AEgDYDgQGQYQ8GkZBhJhFWW2EhFFZbYEBRYQ8YkZBhJk1WW2BAUYCRA5DzW2EPO2AEgDYDgQGQYQ82kZBhJhFWW2EhUFZbYEBRYQ9IkZBhJk1WW2BAUYCRA5DzW2EPa2AEgDYDgQGQYQ9mkZBhJhFWW2Ehi1ZbYEBRYQ94kZBhJk1WW2BAUYCRA5DzW2EPm2AEgDYDgQGQYQ+WkZBhJhFWW2EhyVZbYEBRYQ+okZBhJk1WW2BAUYCRA5DzW2EPy2AEgDYDgQGQYQ/GkZBhJhFWW2EiBlZbYEBRYQ/YkZBhJk1WW2BAUYCRA5DzW2EP+2AEgDYDgQGQYQ/2kZBhJhFWW2EiQFZbYEBRYRAIkZBhJk1WW2BAUYCRA5DzW2EQK2AEgDYDgQGQYRAmkZBhJhFWW2EifFZbYEBRYRA4kZBhJk1WW2BAUYCRA5DzW2EQW2AEgDYDgQGQYRBWkZBhJhFWW2EiuFZbYEBRYRBokZBhJk1WW2BAUYCRA5DzW2EQi2AEgDYDgQGQYRCGkZBhJhFWW2EjE1ZbYEBRYRCYkZBhJk1WW2BAUYCRA5DzW2EQu2AEgDYDgQGQYRC2kZBhJhFWW2EjVVZbYEBRYRDIkZBhJk1WW2BAUYCRA5DzW2EQ62AEgDYDgQGQYRDmkZBhJhFWW2EjkVZbYEBRYRD4kZBhJk1WW2BAUYCRA5DzW2ERG2AEgDYDgQGQYREWkZBhJhFWW2EjzlZbYEBRYREokZBhJk1WW2BAUYCRA5DzW2ERS2AEgDYDgQGQYRFGkZBhJ65WW2EkEFZbYEBRYRFYkZBhKHZWW2BAUYCRA5DzW2ERe2AEgDYDgQGQYRF2kZBhJhFWW2Ekf1ZbYEBRYRGIkZBhJk1WW2BAUYCRA5DzW2ERq2AEgDYDgQGQYRGmkZBhJhFWW2Eku1ZbYEBRYRG4kZBhJk1WW2BAUYCRA5DzW2ER22AEgDYDgQGQYRHWkZBhJhFWW2Ek+VZbYEBRYRHokZBhJk1WW2BAUYCRA5DzW2ESC2AEgDYDgQGQYRIGkZBhJ65WW2ElOFZbYEBRYRIYkZBhKhBWW2BAUYCRA5DzW2ESO2AEgDYDgQGQYRI2kZBhJhFWW2ElalZbYEBRYRJIkZBhJk1WW2BAUYCRA5DzW2AAYRJbYRejVltQYABl3q2+7wA2kFBgAIBbhIEQFWESgVc2kVBgAYEBkFBhEmtWW1BQgJFQUJGQUFZbYABhEpZhF6NWW1BgAGXerb7vADKQUGAAgFuEgRAVYRK8VzKRUGABgQGQUGESplZbUFCAkVBQkZBQVltgAGES0WEXo1ZbUGAAZd6tvu8AUpBQYABbg4EQFWES91eBYABSYAGBAZBQYRLgVltQgJFQUJGQUFZbYGBgAGAIkFBgQIKEUWAghgFgAIVa8YBhEyFXYACA/VtQUJGQUFZbYABhEzJhF6NWW1BgAGXerb7vAAGQUGAAW4OBEBVhE1pXYACCAZFQYAGBAZBQYRNBVltQgJFQUJGQUFZbYACAVJBQkFZbYABhE3dhF6NWW1BgAGXerb7vABeQUGAAW4OBEBVhE59XYACCF5FQYAGBAZBQYROGVltQgJFQUJGQUFZbYABhE7NhF6NWW1BgAGXerb7vADSQUGAAgFuEgRAVYRPZVzSRUGABgQGQUGETw1ZbUFCAkVBQkZBQVltgAGET7mEXo1ZbUGAAZd6tvu8ABpBQYABbg4EQFWEUNVd///////////////////////////////////////////+CBpFQYAGBAZBQYRP9VltQgJFQUJGQUFZbYABhFElhF6NWW1BgAGXerb7vABOQUGAAgFuEgRAVYRRyV2ABgxORUGABgQGQUGEUWVZbUFCAkVBQkZBQVltgAGEUh2EXo1ZbUGAAZd6tvu8AIJBQf/////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYABSYACAW4SBEBVhFNVXYARgACCRUGABgQGQUGEUu1ZbUH8pBFpZIAfQwkbvAsIiNXDalSLQzw9zKCx5obyPC7LCOIEUYRUCV2AAkVBbUICRUFCRkFBWW2AAYRUWYRejVltQYABl3q2+7wCkkFCAYBBSYABbg4EQFWEVSFdgBGADYAKDYAZgEKRgAYEBkFBhFSlWW1CAkVBQkZBQVltgAGEVXGEXo1ZbUGAAZd6tvu8AGpBQYACAW4SBEBVhFYVXgmAAGpFQYAGBAZBQYRVsVltQUICRUFCRkFBWW2AAYRWaYRejVltQYABl3q2+7wAbkFBgAFuDgRAVYRXCV4FgABuRUGABgQGQUGEVqVZbUICRUFCRkFBWW2AAYRXWYRejVltQYABl3q2+7wBCkFBgAIBbhIEQFWEV/FdCkVBgAYEBkFBhFeZWW1BQgJFQUJGQUFZbYABhFhFhF6NWW1BgAGXerb7vADGQUGAAMGAAW4WBEBVhFjpXgTGSUGABgQGQUGEWI1ZbUFBQgJFQUJGQUFZbYABhFlBhF6NWW1BgAGXerb7vAEiQUGAAgFuEgRAVYRZ2V0iRUGABgQGQUGEWYFZbUFCAkVBQkZBQVltgAGEWi2EXo1ZbUGAAZd6tvu8APZBQYACAW4SBEBVhFrFXPZFQYAGBAZBQYRabVltQUICRUFCRkFBWW2AAYRbGYRejVltQYABl3q2+7wBDkFBgAIBbhIEQFWEW7FdDkVBgAYEBkFBhFtZWW1BQgJFQUJGQUFZbYAKBgVSBEGEXB1dgAID9W5BgAFJgIGAAIAFgAJFQkFCAVGEXIpBhKlpWW4BgHwFgIICRBAJgIAFgQFGQgQFgQFKAkpGQgYFSYCABgoBUYRdOkGEqWlZbgBVhF5tXgGAfEGEXcFdhAQCAg1QEAoNSkWAgAZFhF5tWW4IBkZBgAFJgIGAAIJBbgVSBUpBgAQGQYCABgIMRYRd+V4KQA2AfFoIBkVtQUFBQUIFWW2AAYAFgAFRhF7SRkGEqulZbYACBkFVQYABUkFCQVltgAGEXzGEXo1ZbUGAAZd6tvu8ABJBQYABbg4EQFWEX9FdgAYIEkVBgAYEBkFBhF9tWW1CAkVBQkZBQVltgAGEYCGEXo1ZbUGAAZd6tvu8AN5BQYABbg4EQFWEYMFdgIGAAgDdgAYEBkFBhGBdWW1CAkVBQkZBQVltgAGEYRGEXo1ZbUGAAZd6tvu8AoJBQgGAQUmAAW4OBEBVhGG9XYAZgEKBgAYEBkFBhGFdWW1CAkVBQkZBQVltgAGEYg2EXo1ZbUGAAZd6tvu8AM5BQYACAW4SBEBVhGKlXM5FQYAGBAZBQYRiTVltQUICRUFCRkFBWW2AAYRi+YRejVltQYABl3q2+7wBTkFBgAFuDgRAVYRjoV2Perb7vYABSYAGBAZBQYRjNVltQgJFQUJGQUFZbYABhGPxhF6NWW1BgAGXerb7vADqQUGAAgFuEgRAVYRkiVzqRUGABgQGQUGEZDFZbUFCAkVBQkZBQVltgAGEZN2EXo1ZbUGAAZd6tvu8AUZBQYACBYABSYABbhIEQFWEZZFdgAFGRUGABgQGQUGEZTFZbUICRUFCAkVBQkZBQVltgAGEZfGEXo1ZbUGAAZd6tvu8AHZBQYABbg4EQFWEZpFeBYAAdkVBgAYEBkFBhGYtWW1CAkVBQkZBQVltgYGAAYAWQUGAggwGDUWBAUWAggYOFYACIWvGAYRnTV2AAgP1bgZVQUFBQUFCRkFBWW2AAgGACkFBgIIMBg1GDYCCBg4VgAIha8YBhGgJXYACA/VtQUFBQUJGQUFZbYABhGhZhF6NWW1BbYQPoWhEVYRpAV2ABgGAAgoJUYRo0kZBhKrpWW5JQUIGQVVBhGhhWW2ABVJBQkFZbYABhGlJhF6NWW1BgAGXerb7vABCQUGAAgFuEgRAVYRp7V4JgARCRUGABgQGQUGEaYlZbUFCAkVBQkZBQVltgAGEakGEXo1ZbUGAAZd6tvu8ARJBQYACAW4SBEBVhGrZXRJFQYAGBAZBQYRqgVltQUICRUFCRkFBWW2AAYRrLYRejVltQYABl3q2+7wARkFBgAIBbhIEQFWEa9FdgAYMRkVBgAYEBkFBhGttWW1BQgJFQUJGQUFZbYABhGwlhF6NWW1BgAGXerb7vAD6QUGAAW4OBEBVhGzFXYCBgAIA+YAGBAZBQYRsYVltQgJFQUJGQUFZbYABhG0VhF6NWW1BgAGXerb7vAEWQUGAAgFuEgRAVYRtrV0WRUGABgQGQUGEbVVZbUFCAkVBQkZBQVltgAGEbgGEXo1ZbUGAAZd6tvu8AApBQYABbg4EQFWEbqFdgAYICkVBgAYEBkFBhG49WW1CAkVBQkZBQVltgAGEbvGEXo1ZbUGAAZd6tvu8ACJBQYABbg4EQFWEcBVd///////////////////////////////////////////9gAIMIkVBgAYEBkFBhG8tWW1CAkVBQkZBQVltgAGEcGWEXo1ZbUGAAZd6tvu8AVJBQgGAAVWAAW4OBEBVhHERXYABUkVBgAYEBkFBhHCxWW1CAkVBQkZBQVltgAGEcWGEXo1ZbUGAAZd6tvu8AWpBQYACAW4SBEBVhHH5XWpFQYAGBAZBQYRxoVltQUICRUFCRkFBWW2AAYRyTYRejVltQYABl3q2+7wAZkFBgAFuDgRAVYRy5V4EZkVBgAYEBkFBhHKJWW1Bl3q2+7wAZgRRhHMxXgBmQUFuAkVBQkZBQVltgYICCURRhHRpXYEBRfwjDeaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgVJgBAFhHRGQYStLVltgQFGAkQOQ/VtgAGAHkFBgIIMBg1FgQISChGAAh1rxgGEdOldgAID9W1BQUFCRkFBWW2AAYR1NYRejVltQYABl3q2+7wChkFCAYBBSYABbg4EQFWEdeVeAYAZgEKFgAYEBkFBhHWBWW1CAkVBQkZBQVltgAGEdjWEXo1ZbUGAAZd6tvu8AFpBQYABbg4EQFWEdtFeBghaRUGABgQGQUGEdnFZbUICRUFCRkFBWW2BgYABgBJBQYCCDAYNRYEBRgYGDhWAAiFrxgGEd4ldgAID9W4GVUFBQUFBQkZBQVltgYGAAYAiQUGBAgoRRYCCGAWAAhVrxgGEeD1dgAID9W1BQkZBQVltgAGCAglEUYR5cV2BAUX8Iw3mgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIFSYAQBYR5TkGErt1ZbYEBRgJEDkP1bYABgAZBQYCCDAWAggQFRYB8aYCCCAVJgIGBAUWCAg2AAhlrxgGEeildgAID9W2BAUVGTUFBQUJGQUFZbYABhHqJhF6NWW1BbYQPoWhEVYR7bV2ABgGAAgoJUYR7AkZBhKrpWW5JQUIGQVVBDYAFUYR7VkZBhLAZWW1BhHqRWW2ABVJBQkFZbYABhHu1hF6NWW1BgAGXerb7vAEaQUGAAgFuEgRAVYR8TV0aRUGABgQGQUGEe/VZbUFCAkVBQkZBQVltgAGEfKGEXo1ZbUGAAZd6tvu8ABZBQYABbg4EQFWEfUFdgAYIFkVBgAYEBkFBhHzdWW1CAkVBQkZBQVltgAGEfZGEXo1ZbUGAAZd6tvu8AOZBQYABbg4EQFWEfjFdgIGAAgDlgAYEBkFBhH3NWW1CAkVBQkZBQVltgAGACg4OQkYBgAYFUAYCCVYCRUFBgAZADkGAAUmAgYAAgAWAAkJGSkJGSkJGSkJGSUJGCYR/VkpGQYS3uVltQYAKAVJBQkFCSkVBQVltgAGEf7mEXo1ZbUGAAZd6tvu8AWZBQYACAW4SBEBVhIBRXWZFQYAGBAZBQYR/+VltQUICRUFCRkFBWW2AAYSApYRejVltQYABl3q2+7wA4kFBgAIBbhIEQFWEgT1c4kVBgAYEBkFBhIDlWW1BQgJFQUJGQUFZbYABhIGRhF6NWW1BgAGXerb7vAEGQUGAAgFuEgRAVYSCKV0GRUGABgQGQUGEgdFZbUFCAkVBQkZBQVltgAGEgn2EXo1ZbUGAAZd6tvu8AMJBQYACAW4SBEBVhIMVXMJFQYAGBAZBQYSCvVltQUICRUFCRkFBWW2AAYSDaYRejVltQYABl3q2+7wCjkFCAYBBSYABbg4EQFWEhCldgA2ACgmAGYBCjYAGBAZBQYSDtVltQgJFQUJGQUFZbYABhIR5hF6NWW1BgAGXerb7vAAuQUGAAW4OBEBVhIUZXgWAgC5FQYAGBAZBQYSEtVltQgJFQUJGQUFZbYABhIVphF6NWW1BgAGXerb7vAEeQUGAAgFuEgRAVYSGAV0eRUGABgQGQUGEhalZbUFCAkVBQkZBQVltgAGEhlWEXo1ZbUGAAZd6tvu8AHJBQYACAW4SBEBVhIb5XgmAAHJJQYAGBAZBQYSGlVltQUICRUFCRkFBWW2AAYSHTYRejVltQYABl3q2+7wA1kFBgAIBbhIEQFWEh+1dgADWRUGABgQGQUGEh41ZbUFCAkVBQkZBQVltgAGEiEGEXo1ZbUGAAZd6tvu8AVZBQYABbg4EQFWEiNleBYABVYAGBAZBQYSIfVltQgJFQUJGQUFZbYABhIkphF6NWW1BgAGXerb7vABiQUGAAW4OBEBVhInJXYACCGJFQYAGBAZBQYSJZVltQgJFQUJGQUFZbYABhIoZhF6NWW1BgAGXerb7vAAOQUGAAW4OBEBVhIq5XYACCA5FQYAGBAZBQYSKVVltQgJFQUJGQUFZbYABhIsJhF6NWW1BgAGXerb7vAAeQUGAAW4OBEBVhIwlXf///////////////////////////////////////////ggeRUGABgQGQUGEi0VZbUICRUFCRkFBWW2AAYSMdYRejVltQYABl3q2+7wCikFCAYBBSYABbg4EQFWEjS1dgAoFgBmAQomABgQGQUGEjMFZbUICRUFCRkFBWW2AAYSNfYRejVltQYABl3q2+7wAKkFBgAFuDgRAVYSOHV2ABggqRUGABgQGQUGEjblZbUICRUFCRkFBWW2AAYSObYRejVltQYABl3q2+7wAUkFBgAIBbhIEQFWEjw1eCgxSRUGABgQGQUGEjq1ZbUFCAkVBQkZBQVltgAGEj2GEXo1ZbUGAAZd6tvu8AQJBQYABgAUMDYABbhYEQFWEkBFeBQJJQYAGBAZBQYSPtVltQUFCAkVBQkZBQVltgYGCAglEUYSRWV2BAUX8Iw3mgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIFSYAQBYSRNkGErS1ZbYEBRgJEDkP1bYABgBpBQYCCDAYNRYECEgoRgAIda8YBhJHZXYACA/VtQUFBQkZBQVltgAGEkiWEXo1ZbUGAAZd6tvu8AFZBQYACAW4SBEBVhJLBXghWRUGABgQGQUGEkmVZbUFCAkVBQkZBQVltgAGEkxWEXo1ZbUGAAZd6tvu8AEpBQYACAW4SBEBVhJO5XgmABEpFQYAGBAZBQYSTVVltQUICRUFCRkFBWW2AAYSUDYRejVltQYABl3q2+7wA7kFBgADBgAFuFgRAVYSUsV4E7klBgAYEBkFBhJRVWW1BQUICRUFCRkFBWW2AAgGADkFBgIIMBg1FgQFFgFIGDhWAAiFrxgGElXFdgAID9W4FRlVBQUFBQUJGQUFZbYABhJXRhF6NWW1BgAGXerb7vAAmQUGAAW4OBEBVhJb1Xf///////////////////////////////////////////YAGDCZFQYAGBAZBQYSWDVltQgJFQUJGQUFZbYABgQFGQUJBWW2AAgP1bYACA/VtgAIGQUJGQUFZbYSXugWEl21ZbgRRhJflXYACA/VtQVltgAIE1kFBhJguBYSXlVluSkVBQVltgAGAggoQDEhVhJidXYSYmYSXRVltbYABhJjWEgoUBYSX8VluRUFCSkVBQVlthJkeBYSXbVluCUlBQVltgAGAgggGQUGEmYmAAgwGEYSY+VluSkVBQVltgAID9W2AAgP1bYABgHxlgH4MBFpBQkZBQVlt/Tkh7cQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAFJgQWAEUmAkYAD9W2Emu4JhJnJWW4EBgYEQZ///////////ghEXFWEm2ldhJtlhJoNWW1uAYEBSUFBQVltgAGEm7WElx1ZbkFBhJvmCgmEmslZbkZBQVltgAGf//////////4IRFWEnGVdhJxhhJoNWW1thJyKCYSZyVluQUGAggQGQUJGQUFZbgoGDN2AAg4MBUlBQUFZbYABhJ1FhJ0yEYSb+VlthJuNWW5BQgoFSYCCBAYSEhAERFWEnbVdhJ2xhJm1WW1thJ3iEgoVhJy9WW1CTklBQUFZbYACCYB+DARJhJ5VXYSeUYSZoVltbgTVhJ6WEgmAghgFhJz5WW5FQUJKRUFBWW2AAYCCChAMSFWEnxFdhJ8NhJdFWW1tgAIIBNWf//////////4ERFWEn4ldhJ+FhJdZWW1thJ+6EgoUBYSeAVluRUFCSkVBQVltgAIFRkFCRkFBWW2AAgoJSYCCCAZBQkpFQUFZbYABbg4EQFWEoMVeAggFRgYQBUmAggQGQUGEoFlZbYACEhAFSUFBQUFZbYABhKEiCYSf3VlthKFKBhWEoAlZbk1BhKGKBhWAghgFhKBNWW2Eoa4FhJnJWW4QBkVBQkpFQUFZbYABgIIIBkFCBgQNgAIMBUmEokIGEYSg9VluQUJKRUFBWW2AAgZBQkZBQVlthKKuBYSiYVluCUlBQVltgAGAgggGQUGEoxmAAgwGEYSiiVluSkVBQVltgAHP//////////////////////////4IWkFCRkFBWW2AAYSj3gmEozFZbkFCRkFBWW2EpB4FhKOxWW4JSUFBWW2AAYCCCAZBQYSkiYACDAYRhKP5WW5KRUFBWW2AAgP1bYACA/VtgAICDYB+EARJhKUhXYSlHYSZoVltbgjWQUGf//////////4ERFWEpZVdhKWRhKShWW1tgIIMBkVCDYAGCAoMBERVhKYFXYSmAYSktVltbklCSkFBWW2AAgGAgg4UDEhVhKZ9XYSmeYSXRVltbYACDATVn//////////+BERVhKb1XYSm8YSXWVltbYSnJhYKGAWEpMlZbklCSUFCSUJKQUFZbYAB///////////////////////////8AAAAAAAAAAAAAAACCFpBQkZBQVlthKgqBYSnVVluCUlBQVltgAGAgggGQUGEqJWAAgwGEYSoBVluSkVBQVlt/Tkh7cQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAFJgImAEUmAkYAD9W2AAYAKCBJBQYAGCFoBhKnJXYH+CFpFQW2AgghCBA2EqhVdhKoRhKitWW1tQkZBQVlt/Tkh7cQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAFJgEWAEUmAkYAD9W2AAYSrFgmEl21ZbkVBhKtCDYSXbVluSUIKCAZBQgIIRFWEq6FdhKudhKotWW1uSkVBQVltgAIKCUmAgggGQUJKRUFBWW39JbnZhbGlkIGlucHV0IGxlbmd0aAAAAAAAAAAAAAAAAGAAggFSUFZbYABhKzVgFINhKu5WW5FQYStAgmEq/1ZbYCCCAZBQkZBQVltgAGAgggGQUIGBA2AAgwFSYStkgWErKFZbkFCRkFBWW39JbnZhbGlkIGlucHV0IGRhdGEgbGVuZ3RoLgAAAAAAAGAAggFSUFZbYABhK6FgGoNhKu5WW5FQYSusgmEra1ZbYCCCAZBQkZBQVltgAGAgggGQUIGBA2AAgwFSYSvQgWErlFZbkFCRkFBWW39OSHtxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAUmASYARSYCRgAP1bYABhLBGCYSXbVluRUGEsHINhJdtWW5JQgmEsLFdhLCthK9dWW1uCggaQUJKRUFBWW2AAgpBQkpFQUFZbYACBkFCBYABSYCBgACCQUJGQUFZbYABgIGAfgwEEkFCRkFBWW2AAgoIbkFCSkVBQVltgAGAIgwJhLKR///////////////////////////////////////////+CYSxnVlthLK6Gg2EsZ1ZblVCAGYQWk1CAhhaEF5JQUFCTklBQUFZbYACBkFCRkFBWW2AAYSzrYSzmYSzhhGEl21ZbYSzGVlthJdtWW5BQkZBQVltgAIGQUJGQUFZbYS0Fg2Es0FZbYS0ZYS0RgmEs8lZbhIRUYSx0VluCVVBQUFBWW2AAkFZbYS0uYS0hVlthLTmBhIRhLPxWW1BQUFZbW4GBEBVhLV1XYS1SYACCYS0mVltgAYEBkFBhLT9WW1BQVltgH4IRFWEtoldhLXOBYSxCVlthLXyEYSxXVluBAWAghRAVYS2LV4GQUFthLZ9hLZeFYSxXVluDAYJhLT5WW1BQW1BQUFZbYACCghyQUJKRUFBWW2AAYS3FYAAZhGAIAmEtp1ZbGYCDFpFQUJKRUFBWW2AAYS3eg4NhLbRWW5FQgmACAoIXkFCSkVBQVlthLfiDg2EsN1ZbZ///////////gREVYS4RV2EuEGEmg1ZbW2EuG4JUYSpaVlthLiaCgoVhLWFWW2AAYB+DEWABgRRhLlVXYACEFWEuQ1eChwE1kFBbYS5NhYJhLdJWW4ZVUGEutVZbYB8ZhBZhLmOGYSxCVltgAFuCgRAVYS6LV4SJATWCVWABggGRUGAghQGUUGAggQGQUGEuZlZbhoMQFWEuqFeEiQE1YS6kYB+JFoJhLbRWW4NVUFtgAWACiAIBiFVQUFBbUFBQUFBQUFb+omRpcGZzWCISIDEkITSIwvH8pZaHh/DD6W+6hGkSmoB5jhHudSkDtL/cZHNvbGNDAAgTADM=", + "touched": true, + "read": true + }, + "0x85dA99c8a7C2C95964c8EfD687E95E632Fc533D6": { + "address": "0x85dA99c8a7C2C95964c8EfD687E95E632Fc533D6", + "balance": 1e+27, + "nonce": 18641, + "read": true + }, + "0xe4f2Dea6e117FCBa4eC4FDd1D090245110763Dd9": { + "address": "0xe4f2Dea6e117FCBa4eC4FDd1D090245110763Dd9", + "balance": 1e+24, + "read": true + } + } + }, + { + "txn": "0xf904aa8248d180830ad21e946fda56c57b0acadb96ed5624ac500c0429d5942980b90444b374012b00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0deffbadd11f00dbabe000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0deffbadd11f00dbabe000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0deffbadd11f00dbabe000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0deffbadd11f00dbabe000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0deffbadd11f00dbabe000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0de820fc5a0679af9c447e4b6bb929d52a99b2ce1fda507ecf8ee1008fb28b67b4a28195168a029c35951e3e7e4916b0481cb6e2a726876ece8fbb052058086228d78117a6efc", + "delta": { + "0x0000000000000000000000000000000000000000": { + "address": "0x0000000000000000000000000000000000000000", + "balance": 1000000000000092200000000, + "read": true + }, + "0x6FdA56C57B0Acadb96Ed5624aC500C0429d59429": { + "address": "0x6FdA56C57B0Acadb96Ed5624aC500C0429d59429", + "balance": 0, + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x00000000000000000000000000000000000000000000000000000000000048d1", + "0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bba39e": "0x0000000000000000000000000000000000000000000000000000000000000801", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a64b": "0x000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a64c": "0xbaaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ff", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a64d": "0xcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabe", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a64e": "0xdeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeed", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a64f": "0xdecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabe", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a650": "0xfeedc0deffbadd11f00dbabe000ff1ce00bab10c1badb0028badf00dabadbabe", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a651": "0xb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafecafeb0ba", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a652": "0xb0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a653": "0xdead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00d", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a654": "0xdeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeed", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a655": "0xfbadbeeffee1deadfeedbabefeedc0deffbadd11f00dbabe000ff1ce00bab10c", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a656": "0x1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00d", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a657": "0xbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabecafed00d", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a658": "0xcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeef", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a659": "0xdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8ed", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a65a": "0xd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0deffbadd11", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a65b": "0xf00dbabe000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b5", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a65c": "0x0b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabe", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a65d": "0xc00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaad", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a65e": "0xdeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10cc", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a65f": "0xdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1dead", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a660": "0xfeedbabefeedc0deffbadd11f00dbabe000ff1ce00bab10c1badb0028badf00d", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a661": "0xabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafe", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a662": "0xcafeb0bab0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5e", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a663": "0xdabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddead", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a664": "0xdeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a665": "0xfacefeedfbadbeeffee1deadfeedbabefeedc0deffbadd11f00dbabe000ff1ce", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a666": "0x00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaad", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a667": "0xbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabe", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a668": "0xcafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeaf", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a669": "0xdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbad", + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a66a": "0xdefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0de" + }, + "storage_read": { + "0x0000000000000000000000000000000000000000000000000000000000000002": {}, + "0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bba39e": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a64b": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a64c": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a64d": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a64e": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a64f": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a650": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a651": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a652": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a653": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a654": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a655": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a656": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a657": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a658": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a659": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a65a": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a65b": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a65c": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a65d": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a65e": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a65f": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a660": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a661": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a662": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a663": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a664": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a665": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a666": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a667": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a668": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a669": {}, + "0xea7df19a8b53839bd1a13079a19ef91aa56e3bdb5a6bf15ff454e5037bc1a66a": {} + }, + "code_read": "YIBgQFI0gBVhABBXYACA/VtQYAQ2EGEEVFdgADVg4ByAY4CUf4ARYQJBV4Bjv1KcoRFhATtXgGPdm+9gEWEAw1eAY/J5yoERYQCHV4Bj8nnKgRRhEWFXgGP00fxhFGERkVeAY/WPw2oUYRHBV4Bj9rC79xRhEfFXgGP953IcFGESIVdhBFRWW4Bj3ZvvYBRhEHFXgGPel6NjFGEQoVeAY+n5s/IUYRDRV4Bj6lFB5hRhEQFXgGPt8APPFGERMVdhBFRWW4Bjzjz07xFhAQpXgGPOPPTvFGEPgVeAY9EXMgsUYQ+xV4Bj1R57WxRhD+FXgGPVP/P9FGEQEVeAY9k81VgUYRBBV2EEVFZbgGO/UpyhFGEOwVeAY8Ngq6YUYQ7xV4BjxCDrYRRhDyFXgGPEvWXVFGEPUVdhBFRWW4BjoYaDyxFhAclXgGOzdAErEWEBjVeAY7N0ASsUYQ3RV4Bjs9hH8hRhDgFXgGO3uGIHFGEOMVeAY7gcFIQUYQ5hV4Bjvch1/BRhDpFXYQRUVluAY6GGg8sUYQzzV4BjonG3IRRhDSNXgGOmChCHFGENQVeAY6ZFycIUYQ1xV4BjrK699hRhDaFXYQRUVluAY5YuTcIRYQIQV4Bjli5NwhRhDANXgGOYRW8+FGEMM1eAY5orfIEUYQxjV4BjnM58+RRhDJNXgGOgQK7GFGEMw1dhBFRWW4BjgJR/gBRhC0NXgGOIDv85FGELc1eAY5GKX80UYQujV4BjkeeydxRhC9NXYQRUVluAYzQw7AYRYQNSV4BjYOE83hFhAtpXgGNvCZyNEWECnleAY28JnI0UYQpTV4BjcdkdKBRhCoNXgGN7bgsOFGEKs1eAY3wZHSAUYQrjV4BjfejG+BRhCxNXYQRUVluAY2DhPN4UYQl1V4BjYT0KghRhCaVXgGNjE41PFGEJ1VeAY2Wbu08UYQoFV4Bjbn8f5xRhCiNXYQRUVluAY0D+JmIRYQMhV4BjQP4mYhRhCIVXgGNEzzvHFGEItVeAY0phrx8UYQjlV4BjTSx0sxRhCRVXgGNVkMLZFGEJRVdhBFRWW4BjNDDsBhRhB9dXgGM3EwPAFGEIB1eAYzpBHxIUYQglV4BjOkJd/BRhCFVXYQRUVluAYxgJO0YRYQPgV4BjIZzd6xFhA6RXgGMhnN3rFGEG51eAYyKU/H8UYQcXV4BjKHHvhRRhB0dXgGMrIe9EFGEHd1eAYy0055gUYQenV2EEVFZbgGMYCTtGFGEF91eAYxm2IdYUYQYnV4BjGroH6hRhBldXgGMd4vNDFGEGh1eAYyAHMy4UYQa3V2EEVFZbgGMLqKc7EWEEJ1eAYwuopzsUYQUZV4BjEoemjBRhBUlXgGMTXVL3FGEFZ1eAYxWBzxkUYQWXV4BjFlghUBRhBcdXYQRUVluAYwNK73EUYQRZV4BjBQCC+BRhBIlXgGMIe06EFGEEuVeAYws7mWoUYQTpV1tgAID9W2EEc2AEgDYDgQGQYQRukZBhJhFWW2ESUVZbYEBRYQSAkZBhJk1WW2BAUYCRA5DzW2EEo2AEgDYDgQGQYQSekZBhJhFWW2ESjFZbYEBRYQSwkZBhJk1WW2BAUYCRA5DzW2EE02AEgDYDgQGQYQTOkZBhJhFWW2ESx1ZbYEBRYQTgkZBhJk1WW2BAUYCRA5DzW2EFA2AEgDYDgQGQYQT+kZBhJ65WW2ETAVZbYEBRYQUQkZBhKHZWW2BAUYCRA5DzW2EFM2AEgDYDgQGQYQUukZBhJhFWW2ETKFZbYEBRYQVAkZBhJk1WW2BAUYCRA5DzW2EFUWETZFZbYEBRYQVekZBhJk1WW2BAUYCRA5DzW2EFgWAEgDYDgQGQYQV8kZBhJhFWW2ETbVZbYEBRYQWOkZBhJk1WW2BAUYCRA5DzW2EFsWAEgDYDgQGQYQWskZBhJhFWW2ETqVZbYEBRYQW+kZBhJk1WW2BAUYCRA5DzW2EF4WAEgDYDgQGQYQXckZBhJhFWW2ET5FZbYEBRYQXukZBhJk1WW2BAUYCRA5DzW2EGEWAEgDYDgQGQYQYMkZBhJhFWW2EUP1ZbYEBRYQYekZBhJk1WW2BAUYCRA5DzW2EGQWAEgDYDgQGQYQY8kZBhJhFWW2EUfVZbYEBRYQZOkZBhJk1WW2BAUYCRA5DzW2EGcWAEgDYDgQGQYQZskZBhJhFWW2EVDFZbYEBRYQZ+kZBhJk1WW2BAUYCRA5DzW2EGoWAEgDYDgQGQYQackZBhJhFWW2EVUlZbYEBRYQaukZBhJk1WW2BAUYCRA5DzW2EG0WAEgDYDgQGQYQbMkZBhJhFWW2EVkFZbYEBRYQbekZBhJk1WW2BAUYCRA5DzW2EHAWAEgDYDgQGQYQb8kZBhJhFWW2EVzFZbYEBRYQcOkZBhJk1WW2BAUYCRA5DzW2EHMWAEgDYDgQGQYQcskZBhJhFWW2EWB1ZbYEBRYQc+kZBhJk1WW2BAUYCRA5DzW2EHYWAEgDYDgQGQYQdckZBhJhFWW2EWRlZbYEBRYQdukZBhJk1WW2BAUYCRA5DzW2EHkWAEgDYDgQGQYQeMkZBhJhFWW2EWgVZbYEBRYQeekZBhJk1WW2BAUYCRA5DzW2EHwWAEgDYDgQGQYQe8kZBhJhFWW2EWvFZbYEBRYQfOkZBhJk1WW2BAUYCRA5DzW2EH8WAEgDYDgQGQYQfskZBhJhFWW2EW91ZbYEBRYQf+kZBhKHZWW2BAUYCRA5DzW2EID2EXo1ZbYEBRYQgckZBhJk1WW2BAUYCRA5DzW2EIP2AEgDYDgQGQYQg6kZBhJhFWW2EXwlZbYEBRYQhMkZBhJk1WW2BAUYCRA5DzW2EIb2AEgDYDgQGQYQhqkZBhJhFWW2EX/lZbYEBRYQh8kZBhJk1WW2BAUYCRA5DzW2EIn2AEgDYDgQGQYQiakZBhJhFWW2EYOlZbYEBRYQiskZBhJk1WW2BAUYCRA5DzW2EIz2AEgDYDgQGQYQjKkZBhJhFWW2EYeVZbYEBRYQjckZBhJk1WW2BAUYCRA5DzW2EI/2AEgDYDgQGQYQj6kZBhJhFWW2EYtFZbYEBRYQkMkZBhJk1WW2BAUYCRA5DzW2EJL2AEgDYDgQGQYQkqkZBhJhFWW2EY8lZbYEBRYQk8kZBhJk1WW2BAUYCRA5DzW2EJX2AEgDYDgQGQYQlakZBhJhFWW2EZLVZbYEBRYQlskZBhJk1WW2BAUYCRA5DzW2EJj2AEgDYDgQGQYQmKkZBhJhFWW2EZclZbYEBRYQmckZBhJk1WW2BAUYCRA5DzW2EJv2AEgDYDgQGQYQm6kZBhJ65WW2EZrlZbYEBRYQnMkZBhKHZWW2BAUYCRA5DzW2EJ72AEgDYDgQGQYQnqkZBhJ65WW2EZ4FZbYEBRYQn8kZBhKLFWW2BAUYCRA5DzW2EKDWEaDFZbYEBRYQoakZBhJk1WW2BAUYCRA5DzW2EKPWAEgDYDgQGQYQo4kZBhJhFWW2EaSFZbYEBRYQpKkZBhJk1WW2BAUYCRA5DzW2EKbWAEgDYDgQGQYQpokZBhJhFWW2EahlZbYEBRYQp6kZBhJk1WW2BAUYCRA5DzW2EKnWAEgDYDgQGQYQqYkZBhJhFWW2EawVZbYEBRYQqqkZBhJk1WW2BAUYCRA5DzW2EKzWAEgDYDgQGQYQrIkZBhJhFWW2Ea/1ZbYEBRYQrakZBhJk1WW2BAUYCRA5DzW2EK/WAEgDYDgQGQYQr4kZBhJhFWW2EbO1ZbYEBRYQsKkZBhJk1WW2BAUYCRA5DzW2ELLWAEgDYDgQGQYQsokZBhJhFWW2EbdlZbYEBRYQs6kZBhJk1WW2BAUYCRA5DzW2ELXWAEgDYDgQGQYQtYkZBhJhFWW2EbslZbYEBRYQtqkZBhJk1WW2BAUYCRA5DzW2ELjWAEgDYDgQGQYQuIkZBhJhFWW2EcD1ZbYEBRYQuakZBhJk1WW2BAUYCRA5DzW2ELvWAEgDYDgQGQYQu4kZBhJhFWW2EcTlZbYEBRYQvKkZBhJk1WW2BAUYCRA5DzW2EL7WAEgDYDgQGQYQvokZBhJhFWW2EciVZbYEBRYQv6kZBhJk1WW2BAUYCRA5DzW2EMHWAEgDYDgQGQYQwYkZBhJ65WW2Ec1VZbYEBRYQwqkZBhKHZWW2BAUYCRA5DzW2EMTWAEgDYDgQGQYQxIkZBhJhFWW2EdQ1ZbYEBRYQxakZBhJk1WW2BAUYCRA5DzW2EMfWAEgDYDgQGQYQx4kZBhJhFWW2Edg1ZbYEBRYQyKkZBhJk1WW2BAUYCRA5DzW2EMrWAEgDYDgQGQYQyokZBhJ65WW2EdvlZbYEBRYQy6kZBhKHZWW2BAUYCRA5DzW2EM3WAEgDYDgQGQYQzYkZBhJ65WW2Ed71ZbYEBRYQzqkZBhKHZWW2BAUYCRA5DzW2ENDWAEgDYDgQGQYQ0IkZBhJ65WW2EeFlZbYEBRYQ0akZBhKQ1WW2BAUYCRA5DzW2ENK2EemFZbYEBRYQ04kZBhJk1WW2BAUYCRA5DzW2ENW2AEgDYDgQGQYQ1WkZBhJhFWW2Ee41ZbYEBRYQ1okZBhJk1WW2BAUYCRA5DzW2ENi2AEgDYDgQGQYQ2GkZBhJhFWW2EfHlZbYEBRYQ2YkZBhJk1WW2BAUYCRA5DzW2ENu2AEgDYDgQGQYQ22kZBhJhFWW2EfWlZbYEBRYQ3IkZBhJk1WW2BAUYCRA5DzW2EN62AEgDYDgQGQYQ3mkZBhKYhWW2EfllZbYEBRYQ34kZBhJk1WW2BAUYCRA5DzW2EOG2AEgDYDgQGQYQ4WkZBhJhFWW2Ef5FZbYEBRYQ4okZBhJk1WW2BAUYCRA5DzW2EOS2AEgDYDgQGQYQ5GkZBhJhFWW2EgH1ZbYEBRYQ5YkZBhJk1WW2BAUYCRA5DzW2EOe2AEgDYDgQGQYQ52kZBhJhFWW2EgWlZbYEBRYQ6IkZBhJk1WW2BAUYCRA5DzW2EOq2AEgDYDgQGQYQ6mkZBhJhFWW2EglVZbYEBRYQ64kZBhJk1WW2BAUYCRA5DzW2EO22AEgDYDgQGQYQ7WkZBhJhFWW2Eg0FZbYEBRYQ7okZBhJk1WW2BAUYCRA5DzW2EPC2AEgDYDgQGQYQ8GkZBhJhFWW2EhFFZbYEBRYQ8YkZBhJk1WW2BAUYCRA5DzW2EPO2AEgDYDgQGQYQ82kZBhJhFWW2EhUFZbYEBRYQ9IkZBhJk1WW2BAUYCRA5DzW2EPa2AEgDYDgQGQYQ9mkZBhJhFWW2Ehi1ZbYEBRYQ94kZBhJk1WW2BAUYCRA5DzW2EPm2AEgDYDgQGQYQ+WkZBhJhFWW2EhyVZbYEBRYQ+okZBhJk1WW2BAUYCRA5DzW2EPy2AEgDYDgQGQYQ/GkZBhJhFWW2EiBlZbYEBRYQ/YkZBhJk1WW2BAUYCRA5DzW2EP+2AEgDYDgQGQYQ/2kZBhJhFWW2EiQFZbYEBRYRAIkZBhJk1WW2BAUYCRA5DzW2EQK2AEgDYDgQGQYRAmkZBhJhFWW2EifFZbYEBRYRA4kZBhJk1WW2BAUYCRA5DzW2EQW2AEgDYDgQGQYRBWkZBhJhFWW2EiuFZbYEBRYRBokZBhJk1WW2BAUYCRA5DzW2EQi2AEgDYDgQGQYRCGkZBhJhFWW2EjE1ZbYEBRYRCYkZBhJk1WW2BAUYCRA5DzW2EQu2AEgDYDgQGQYRC2kZBhJhFWW2EjVVZbYEBRYRDIkZBhJk1WW2BAUYCRA5DzW2EQ62AEgDYDgQGQYRDmkZBhJhFWW2EjkVZbYEBRYRD4kZBhJk1WW2BAUYCRA5DzW2ERG2AEgDYDgQGQYREWkZBhJhFWW2EjzlZbYEBRYREokZBhJk1WW2BAUYCRA5DzW2ERS2AEgDYDgQGQYRFGkZBhJ65WW2EkEFZbYEBRYRFYkZBhKHZWW2BAUYCRA5DzW2ERe2AEgDYDgQGQYRF2kZBhJhFWW2Ekf1ZbYEBRYRGIkZBhJk1WW2BAUYCRA5DzW2ERq2AEgDYDgQGQYRGmkZBhJhFWW2Eku1ZbYEBRYRG4kZBhJk1WW2BAUYCRA5DzW2ER22AEgDYDgQGQYRHWkZBhJhFWW2Ek+VZbYEBRYRHokZBhJk1WW2BAUYCRA5DzW2ESC2AEgDYDgQGQYRIGkZBhJ65WW2ElOFZbYEBRYRIYkZBhKhBWW2BAUYCRA5DzW2ESO2AEgDYDgQGQYRI2kZBhJhFWW2ElalZbYEBRYRJIkZBhJk1WW2BAUYCRA5DzW2AAYRJbYRejVltQYABl3q2+7wA2kFBgAIBbhIEQFWESgVc2kVBgAYEBkFBhEmtWW1BQgJFQUJGQUFZbYABhEpZhF6NWW1BgAGXerb7vADKQUGAAgFuEgRAVYRK8VzKRUGABgQGQUGESplZbUFCAkVBQkZBQVltgAGES0WEXo1ZbUGAAZd6tvu8AUpBQYABbg4EQFWES91eBYABSYAGBAZBQYRLgVltQgJFQUJGQUFZbYGBgAGAIkFBgQIKEUWAghgFgAIVa8YBhEyFXYACA/VtQUJGQUFZbYABhEzJhF6NWW1BgAGXerb7vAAGQUGAAW4OBEBVhE1pXYACCAZFQYAGBAZBQYRNBVltQgJFQUJGQUFZbYACAVJBQkFZbYABhE3dhF6NWW1BgAGXerb7vABeQUGAAW4OBEBVhE59XYACCF5FQYAGBAZBQYROGVltQgJFQUJGQUFZbYABhE7NhF6NWW1BgAGXerb7vADSQUGAAgFuEgRAVYRPZVzSRUGABgQGQUGETw1ZbUFCAkVBQkZBQVltgAGET7mEXo1ZbUGAAZd6tvu8ABpBQYABbg4EQFWEUNVd///////////////////////////////////////////+CBpFQYAGBAZBQYRP9VltQgJFQUJGQUFZbYABhFElhF6NWW1BgAGXerb7vABOQUGAAgFuEgRAVYRRyV2ABgxORUGABgQGQUGEUWVZbUFCAkVBQkZBQVltgAGEUh2EXo1ZbUGAAZd6tvu8AIJBQf/////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYABSYACAW4SBEBVhFNVXYARgACCRUGABgQGQUGEUu1ZbUH8pBFpZIAfQwkbvAsIiNXDalSLQzw9zKCx5obyPC7LCOIEUYRUCV2AAkVBbUICRUFCRkFBWW2AAYRUWYRejVltQYABl3q2+7wCkkFCAYBBSYABbg4EQFWEVSFdgBGADYAKDYAZgEKRgAYEBkFBhFSlWW1CAkVBQkZBQVltgAGEVXGEXo1ZbUGAAZd6tvu8AGpBQYACAW4SBEBVhFYVXgmAAGpFQYAGBAZBQYRVsVltQUICRUFCRkFBWW2AAYRWaYRejVltQYABl3q2+7wAbkFBgAFuDgRAVYRXCV4FgABuRUGABgQGQUGEVqVZbUICRUFCRkFBWW2AAYRXWYRejVltQYABl3q2+7wBCkFBgAIBbhIEQFWEV/FdCkVBgAYEBkFBhFeZWW1BQgJFQUJGQUFZbYABhFhFhF6NWW1BgAGXerb7vADGQUGAAMGAAW4WBEBVhFjpXgTGSUGABgQGQUGEWI1ZbUFBQgJFQUJGQUFZbYABhFlBhF6NWW1BgAGXerb7vAEiQUGAAgFuEgRAVYRZ2V0iRUGABgQGQUGEWYFZbUFCAkVBQkZBQVltgAGEWi2EXo1ZbUGAAZd6tvu8APZBQYACAW4SBEBVhFrFXPZFQYAGBAZBQYRabVltQUICRUFCRkFBWW2AAYRbGYRejVltQYABl3q2+7wBDkFBgAIBbhIEQFWEW7FdDkVBgAYEBkFBhFtZWW1BQgJFQUJGQUFZbYAKBgVSBEGEXB1dgAID9W5BgAFJgIGAAIAFgAJFQkFCAVGEXIpBhKlpWW4BgHwFgIICRBAJgIAFgQFGQgQFgQFKAkpGQgYFSYCABgoBUYRdOkGEqWlZbgBVhF5tXgGAfEGEXcFdhAQCAg1QEAoNSkWAgAZFhF5tWW4IBkZBgAFJgIGAAIJBbgVSBUpBgAQGQYCABgIMRYRd+V4KQA2AfFoIBkVtQUFBQUIFWW2AAYAFgAFRhF7SRkGEqulZbYACBkFVQYABUkFCQVltgAGEXzGEXo1ZbUGAAZd6tvu8ABJBQYABbg4EQFWEX9FdgAYIEkVBgAYEBkFBhF9tWW1CAkVBQkZBQVltgAGEYCGEXo1ZbUGAAZd6tvu8AN5BQYABbg4EQFWEYMFdgIGAAgDdgAYEBkFBhGBdWW1CAkVBQkZBQVltgAGEYRGEXo1ZbUGAAZd6tvu8AoJBQgGAQUmAAW4OBEBVhGG9XYAZgEKBgAYEBkFBhGFdWW1CAkVBQkZBQVltgAGEYg2EXo1ZbUGAAZd6tvu8AM5BQYACAW4SBEBVhGKlXM5FQYAGBAZBQYRiTVltQUICRUFCRkFBWW2AAYRi+YRejVltQYABl3q2+7wBTkFBgAFuDgRAVYRjoV2Perb7vYABSYAGBAZBQYRjNVltQgJFQUJGQUFZbYABhGPxhF6NWW1BgAGXerb7vADqQUGAAgFuEgRAVYRkiVzqRUGABgQGQUGEZDFZbUFCAkVBQkZBQVltgAGEZN2EXo1ZbUGAAZd6tvu8AUZBQYACBYABSYABbhIEQFWEZZFdgAFGRUGABgQGQUGEZTFZbUICRUFCAkVBQkZBQVltgAGEZfGEXo1ZbUGAAZd6tvu8AHZBQYABbg4EQFWEZpFeBYAAdkVBgAYEBkFBhGYtWW1CAkVBQkZBQVltgYGAAYAWQUGAggwGDUWBAUWAggYOFYACIWvGAYRnTV2AAgP1bgZVQUFBQUFCRkFBWW2AAgGACkFBgIIMBg1GDYCCBg4VgAIha8YBhGgJXYACA/VtQUFBQUJGQUFZbYABhGhZhF6NWW1BbYQPoWhEVYRpAV2ABgGAAgoJUYRo0kZBhKrpWW5JQUIGQVVBhGhhWW2ABVJBQkFZbYABhGlJhF6NWW1BgAGXerb7vABCQUGAAgFuEgRAVYRp7V4JgARCRUGABgQGQUGEaYlZbUFCAkVBQkZBQVltgAGEakGEXo1ZbUGAAZd6tvu8ARJBQYACAW4SBEBVhGrZXRJFQYAGBAZBQYRqgVltQUICRUFCRkFBWW2AAYRrLYRejVltQYABl3q2+7wARkFBgAIBbhIEQFWEa9FdgAYMRkVBgAYEBkFBhGttWW1BQgJFQUJGQUFZbYABhGwlhF6NWW1BgAGXerb7vAD6QUGAAW4OBEBVhGzFXYCBgAIA+YAGBAZBQYRsYVltQgJFQUJGQUFZbYABhG0VhF6NWW1BgAGXerb7vAEWQUGAAgFuEgRAVYRtrV0WRUGABgQGQUGEbVVZbUFCAkVBQkZBQVltgAGEbgGEXo1ZbUGAAZd6tvu8AApBQYABbg4EQFWEbqFdgAYICkVBgAYEBkFBhG49WW1CAkVBQkZBQVltgAGEbvGEXo1ZbUGAAZd6tvu8ACJBQYABbg4EQFWEcBVd///////////////////////////////////////////9gAIMIkVBgAYEBkFBhG8tWW1CAkVBQkZBQVltgAGEcGWEXo1ZbUGAAZd6tvu8AVJBQgGAAVWAAW4OBEBVhHERXYABUkVBgAYEBkFBhHCxWW1CAkVBQkZBQVltgAGEcWGEXo1ZbUGAAZd6tvu8AWpBQYACAW4SBEBVhHH5XWpFQYAGBAZBQYRxoVltQUICRUFCRkFBWW2AAYRyTYRejVltQYABl3q2+7wAZkFBgAFuDgRAVYRy5V4EZkVBgAYEBkFBhHKJWW1Bl3q2+7wAZgRRhHMxXgBmQUFuAkVBQkZBQVltgYICCURRhHRpXYEBRfwjDeaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgVJgBAFhHRGQYStLVltgQFGAkQOQ/VtgAGAHkFBgIIMBg1FgQISChGAAh1rxgGEdOldgAID9W1BQUFCRkFBWW2AAYR1NYRejVltQYABl3q2+7wChkFCAYBBSYABbg4EQFWEdeVeAYAZgEKFgAYEBkFBhHWBWW1CAkVBQkZBQVltgAGEdjWEXo1ZbUGAAZd6tvu8AFpBQYABbg4EQFWEdtFeBghaRUGABgQGQUGEdnFZbUICRUFCRkFBWW2BgYABgBJBQYCCDAYNRYEBRgYGDhWAAiFrxgGEd4ldgAID9W4GVUFBQUFBQkZBQVltgYGAAYAiQUGBAgoRRYCCGAWAAhVrxgGEeD1dgAID9W1BQkZBQVltgAGCAglEUYR5cV2BAUX8Iw3mgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIFSYAQBYR5TkGErt1ZbYEBRgJEDkP1bYABgAZBQYCCDAWAggQFRYB8aYCCCAVJgIGBAUWCAg2AAhlrxgGEeildgAID9W2BAUVGTUFBQUJGQUFZbYABhHqJhF6NWW1BbYQPoWhEVYR7bV2ABgGAAgoJUYR7AkZBhKrpWW5JQUIGQVVBDYAFUYR7VkZBhLAZWW1BhHqRWW2ABVJBQkFZbYABhHu1hF6NWW1BgAGXerb7vAEaQUGAAgFuEgRAVYR8TV0aRUGABgQGQUGEe/VZbUFCAkVBQkZBQVltgAGEfKGEXo1ZbUGAAZd6tvu8ABZBQYABbg4EQFWEfUFdgAYIFkVBgAYEBkFBhHzdWW1CAkVBQkZBQVltgAGEfZGEXo1ZbUGAAZd6tvu8AOZBQYABbg4EQFWEfjFdgIGAAgDlgAYEBkFBhH3NWW1CAkVBQkZBQVltgAGACg4OQkYBgAYFUAYCCVYCRUFBgAZADkGAAUmAgYAAgAWAAkJGSkJGSkJGSkJGSUJGCYR/VkpGQYS3uVltQYAKAVJBQkFCSkVBQVltgAGEf7mEXo1ZbUGAAZd6tvu8AWZBQYACAW4SBEBVhIBRXWZFQYAGBAZBQYR/+VltQUICRUFCRkFBWW2AAYSApYRejVltQYABl3q2+7wA4kFBgAIBbhIEQFWEgT1c4kVBgAYEBkFBhIDlWW1BQgJFQUJGQUFZbYABhIGRhF6NWW1BgAGXerb7vAEGQUGAAgFuEgRAVYSCKV0GRUGABgQGQUGEgdFZbUFCAkVBQkZBQVltgAGEgn2EXo1ZbUGAAZd6tvu8AMJBQYACAW4SBEBVhIMVXMJFQYAGBAZBQYSCvVltQUICRUFCRkFBWW2AAYSDaYRejVltQYABl3q2+7wCjkFCAYBBSYABbg4EQFWEhCldgA2ACgmAGYBCjYAGBAZBQYSDtVltQgJFQUJGQUFZbYABhIR5hF6NWW1BgAGXerb7vAAuQUGAAW4OBEBVhIUZXgWAgC5FQYAGBAZBQYSEtVltQgJFQUJGQUFZbYABhIVphF6NWW1BgAGXerb7vAEeQUGAAgFuEgRAVYSGAV0eRUGABgQGQUGEhalZbUFCAkVBQkZBQVltgAGEhlWEXo1ZbUGAAZd6tvu8AHJBQYACAW4SBEBVhIb5XgmAAHJJQYAGBAZBQYSGlVltQUICRUFCRkFBWW2AAYSHTYRejVltQYABl3q2+7wA1kFBgAIBbhIEQFWEh+1dgADWRUGABgQGQUGEh41ZbUFCAkVBQkZBQVltgAGEiEGEXo1ZbUGAAZd6tvu8AVZBQYABbg4EQFWEiNleBYABVYAGBAZBQYSIfVltQgJFQUJGQUFZbYABhIkphF6NWW1BgAGXerb7vABiQUGAAW4OBEBVhInJXYACCGJFQYAGBAZBQYSJZVltQgJFQUJGQUFZbYABhIoZhF6NWW1BgAGXerb7vAAOQUGAAW4OBEBVhIq5XYACCA5FQYAGBAZBQYSKVVltQgJFQUJGQUFZbYABhIsJhF6NWW1BgAGXerb7vAAeQUGAAW4OBEBVhIwlXf///////////////////////////////////////////ggeRUGABgQGQUGEi0VZbUICRUFCRkFBWW2AAYSMdYRejVltQYABl3q2+7wCikFCAYBBSYABbg4EQFWEjS1dgAoFgBmAQomABgQGQUGEjMFZbUICRUFCRkFBWW2AAYSNfYRejVltQYABl3q2+7wAKkFBgAFuDgRAVYSOHV2ABggqRUGABgQGQUGEjblZbUICRUFCRkFBWW2AAYSObYRejVltQYABl3q2+7wAUkFBgAIBbhIEQFWEjw1eCgxSRUGABgQGQUGEjq1ZbUFCAkVBQkZBQVltgAGEj2GEXo1ZbUGAAZd6tvu8AQJBQYABgAUMDYABbhYEQFWEkBFeBQJJQYAGBAZBQYSPtVltQUFCAkVBQkZBQVltgYGCAglEUYSRWV2BAUX8Iw3mgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIFSYAQBYSRNkGErS1ZbYEBRgJEDkP1bYABgBpBQYCCDAYNRYECEgoRgAIda8YBhJHZXYACA/VtQUFBQkZBQVltgAGEkiWEXo1ZbUGAAZd6tvu8AFZBQYACAW4SBEBVhJLBXghWRUGABgQGQUGEkmVZbUFCAkVBQkZBQVltgAGEkxWEXo1ZbUGAAZd6tvu8AEpBQYACAW4SBEBVhJO5XgmABEpFQYAGBAZBQYSTVVltQUICRUFCRkFBWW2AAYSUDYRejVltQYABl3q2+7wA7kFBgADBgAFuFgRAVYSUsV4E7klBgAYEBkFBhJRVWW1BQUICRUFCRkFBWW2AAgGADkFBgIIMBg1FgQFFgFIGDhWAAiFrxgGElXFdgAID9W4FRlVBQUFBQUJGQUFZbYABhJXRhF6NWW1BgAGXerb7vAAmQUGAAW4OBEBVhJb1Xf///////////////////////////////////////////YAGDCZFQYAGBAZBQYSWDVltQgJFQUJGQUFZbYABgQFGQUJBWW2AAgP1bYACA/VtgAIGQUJGQUFZbYSXugWEl21ZbgRRhJflXYACA/VtQVltgAIE1kFBhJguBYSXlVluSkVBQVltgAGAggoQDEhVhJidXYSYmYSXRVltbYABhJjWEgoUBYSX8VluRUFCSkVBQVlthJkeBYSXbVluCUlBQVltgAGAgggGQUGEmYmAAgwGEYSY+VluSkVBQVltgAID9W2AAgP1bYABgHxlgH4MBFpBQkZBQVlt/Tkh7cQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAFJgQWAEUmAkYAD9W2Emu4JhJnJWW4EBgYEQZ///////////ghEXFWEm2ldhJtlhJoNWW1uAYEBSUFBQVltgAGEm7WElx1ZbkFBhJvmCgmEmslZbkZBQVltgAGf//////////4IRFWEnGVdhJxhhJoNWW1thJyKCYSZyVluQUGAggQGQUJGQUFZbgoGDN2AAg4MBUlBQUFZbYABhJ1FhJ0yEYSb+VlthJuNWW5BQgoFSYCCBAYSEhAERFWEnbVdhJ2xhJm1WW1thJ3iEgoVhJy9WW1CTklBQUFZbYACCYB+DARJhJ5VXYSeUYSZoVltbgTVhJ6WEgmAghgFhJz5WW5FQUJKRUFBWW2AAYCCChAMSFWEnxFdhJ8NhJdFWW1tgAIIBNWf//////////4ERFWEn4ldhJ+FhJdZWW1thJ+6EgoUBYSeAVluRUFCSkVBQVltgAIFRkFCRkFBWW2AAgoJSYCCCAZBQkpFQUFZbYABbg4EQFWEoMVeAggFRgYQBUmAggQGQUGEoFlZbYACEhAFSUFBQUFZbYABhKEiCYSf3VlthKFKBhWEoAlZbk1BhKGKBhWAghgFhKBNWW2Eoa4FhJnJWW4QBkVBQkpFQUFZbYABgIIIBkFCBgQNgAIMBUmEokIGEYSg9VluQUJKRUFBWW2AAgZBQkZBQVlthKKuBYSiYVluCUlBQVltgAGAgggGQUGEoxmAAgwGEYSiiVluSkVBQVltgAHP//////////////////////////4IWkFCRkFBWW2AAYSj3gmEozFZbkFCRkFBWW2EpB4FhKOxWW4JSUFBWW2AAYCCCAZBQYSkiYACDAYRhKP5WW5KRUFBWW2AAgP1bYACA/VtgAICDYB+EARJhKUhXYSlHYSZoVltbgjWQUGf//////////4ERFWEpZVdhKWRhKShWW1tgIIMBkVCDYAGCAoMBERVhKYFXYSmAYSktVltbklCSkFBWW2AAgGAgg4UDEhVhKZ9XYSmeYSXRVltbYACDATVn//////////+BERVhKb1XYSm8YSXWVltbYSnJhYKGAWEpMlZbklCSUFCSUJKQUFZbYAB///////////////////////////8AAAAAAAAAAAAAAACCFpBQkZBQVlthKgqBYSnVVluCUlBQVltgAGAgggGQUGEqJWAAgwGEYSoBVluSkVBQVlt/Tkh7cQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAFJgImAEUmAkYAD9W2AAYAKCBJBQYAGCFoBhKnJXYH+CFpFQW2AgghCBA2EqhVdhKoRhKitWW1tQkZBQVlt/Tkh7cQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAFJgEWAEUmAkYAD9W2AAYSrFgmEl21ZbkVBhKtCDYSXbVluSUIKCAZBQgIIRFWEq6FdhKudhKotWW1uSkVBQVltgAIKCUmAgggGQUJKRUFBWW39JbnZhbGlkIGlucHV0IGxlbmd0aAAAAAAAAAAAAAAAAGAAggFSUFZbYABhKzVgFINhKu5WW5FQYStAgmEq/1ZbYCCCAZBQkZBQVltgAGAgggGQUIGBA2AAgwFSYStkgWErKFZbkFCRkFBWW39JbnZhbGlkIGlucHV0IGRhdGEgbGVuZ3RoLgAAAAAAAGAAggFSUFZbYABhK6FgGoNhKu5WW5FQYSusgmEra1ZbYCCCAZBQkZBQVltgAGAgggGQUIGBA2AAgwFSYSvQgWErlFZbkFCRkFBWW39OSHtxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAUmASYARSYCRgAP1bYABhLBGCYSXbVluRUGEsHINhJdtWW5JQgmEsLFdhLCthK9dWW1uCggaQUJKRUFBWW2AAgpBQkpFQUFZbYACBkFCBYABSYCBgACCQUJGQUFZbYABgIGAfgwEEkFCRkFBWW2AAgoIbkFCSkVBQVltgAGAIgwJhLKR///////////////////////////////////////////+CYSxnVlthLK6Gg2EsZ1ZblVCAGYQWk1CAhhaEF5JQUFCTklBQUFZbYACBkFCRkFBWW2AAYSzrYSzmYSzhhGEl21ZbYSzGVlthJdtWW5BQkZBQVltgAIGQUJGQUFZbYS0Fg2Es0FZbYS0ZYS0RgmEs8lZbhIRUYSx0VluCVVBQUFBWW2AAkFZbYS0uYS0hVlthLTmBhIRhLPxWW1BQUFZbW4GBEBVhLV1XYS1SYACCYS0mVltgAYEBkFBhLT9WW1BQVltgH4IRFWEtoldhLXOBYSxCVlthLXyEYSxXVluBAWAghRAVYS2LV4GQUFthLZ9hLZeFYSxXVluDAYJhLT5WW1BQW1BQUFZbYACCghyQUJKRUFBWW2AAYS3FYAAZhGAIAmEtp1ZbGYCDFpFQUJKRUFBWW2AAYS3eg4NhLbRWW5FQgmACAoIXkFCSkVBQVlthLfiDg2EsN1ZbZ///////////gREVYS4RV2EuEGEmg1ZbW2EuG4JUYSpaVlthLiaCgoVhLWFWW2AAYB+DEWABgRRhLlVXYACEFWEuQ1eChwE1kFBbYS5NhYJhLdJWW4ZVUGEutVZbYB8ZhBZhLmOGYSxCVltgAFuCgRAVYS6LV4SJATWCVWABggGRUGAghQGUUGAggQGQUGEuZlZbhoMQFWEuqFeEiQE1YS6kYB+JFoJhLbRWW4NVUFtgAWACiAIBiFVQUFBbUFBQUFBQUFb+omRpcGZzWCISIDEkITSIwvH8pZaHh/DD6W+6hGkSmoB5jhHudSkDtL/cZHNvbGNDAAgTADM=", + "touched": true, + "read": true + }, + "0x85dA99c8a7C2C95964c8EfD687E95E632Fc533D6": { + "address": "0x85dA99c8a7C2C95964c8EfD687E95E632Fc533D6", + "balance": 1e+27, + "nonce": 18642, + "read": true + }, + "0xe4f2Dea6e117FCBa4eC4FDd1D090245110763Dd9": { + "address": "0xe4f2Dea6e117FCBa4eC4FDd1D090245110763Dd9", + "balance": 1e+24, + "read": true + } + } + }, + { + "txn": "0xf904aa8248d280830ad21e946fda56c57b0acadb96ed5624ac500c0429d5942980b90444b374012b00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0deffbadd11f00dbabe000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0deffbadd11f00dbabe000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0deffbadd11f00dbabe000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0deffbadd11f00dbabe000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0deffbadd11f00dbabe000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0de820fc5a02e7447cfb47da129cc74d577531ab6c794351fc0add960ac570483f82a3e0b94a01da25789ee38a368d3316ffe9f74b85fa41f70f11739ab054a00f2f460b053d5", + "delta": { + "0x0000000000000000000000000000000000000000": { + "address": "0x0000000000000000000000000000000000000000", + "balance": 1000000000000092200000000, + "read": true + }, + "0x6FdA56C57B0Acadb96Ed5624aC500C0429d59429": { + "address": "0x6FdA56C57B0Acadb96Ed5624aC500C0429d59429", + "balance": 0, + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x00000000000000000000000000000000000000000000000000000000000048d2", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b08": "0x000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b09": "0xbaaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ff", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b0a": "0xcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabe", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b0b": "0xdeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeed", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b0c": "0xdecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabe", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b0d": "0xfeedc0deffbadd11f00dbabe000ff1ce00bab10c1badb0028badf00dabadbabe", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b0e": "0xb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafecafeb0ba", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b0f": "0xb0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b10": "0xdead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00d", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b11": "0xdeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeed", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b12": "0xfbadbeeffee1deadfeedbabefeedc0deffbadd11f00dbabe000ff1ce00bab10c", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b13": "0x1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00d", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b14": "0xbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabecafed00d", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b15": "0xcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeef", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b16": "0xdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8ed", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b17": "0xd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0deffbadd11", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b18": "0xf00dbabe000ff1ce00bab10c1badb0028badf00dabadbabeb105f00db16b00b5", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b19": "0x0b00b135baaaaaadbaadf00dbad22222baddcafecafeb0bab0bababebeefbabe", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b1a": "0xc00010ffcafebabecafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaad", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b1b": "0xdeadbabedeadbeafdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10cc", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b1c": "0xdeadfeeddecafbaddefec8edd0d0cacae011cfd0facefeedfbadbeeffee1dead", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b1d": "0xfeedbabefeedc0deffbadd11f00dbabe000ff1ce00bab10c1badb0028badf00d", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b1e": "0xabadbabeb105f00db16b00b50b00b135baaaaaadbaadf00dbad22222baddcafe", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b1f": "0xcafeb0bab0bababebeefbabec00010ffcafebabecafed00dcefaedfe0d15ea5e", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b20": "0xdabbad00dead2baddeadbaaddeadbabedeadbeafdeadbeefdeadc0dedeaddead", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b21": "0xdeadd00ddeadfa11dead10ccdeadfeeddecafbaddefec8edd0d0cacae011cfd0", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b22": "0xfacefeedfbadbeeffee1deadfeedbabefeedc0deffbadd11f00dbabe000ff1ce", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b23": "0x00bab10c1badb0028badf00dabadbabeb105f00db16b00b50b00b135baaaaaad", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b24": "0xbaadf00dbad22222baddcafecafeb0bab0bababebeefbabec00010ffcafebabe", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b25": "0xcafed00dcefaedfe0d15ea5edabbad00dead2baddeadbaaddeadbabedeadbeaf", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b26": "0xdeadbeefdeadc0dedeaddeaddeadd00ddeadfa11dead10ccdeadfeeddecafbad", + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b27": "0xdefec8edd0d0cacae011cfd0facefeedfbadbeeffee1deadfeedbabefeedc0de", + "0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bba39f": "0x0000000000000000000000000000000000000000000000000000000000000801" + }, + "storage_read": { + "0x0000000000000000000000000000000000000000000000000000000000000002": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b08": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b09": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b0a": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b0b": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b0c": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b0d": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b0e": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b0f": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b10": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b11": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b12": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b13": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b14": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b15": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b16": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b17": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b18": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b19": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b1a": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b1b": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b1c": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b1d": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b1e": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b1f": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b20": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b21": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b22": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b23": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b24": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b25": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b26": {}, + "0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b27": {}, + "0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bba39f": {} + }, + "code_read": "YIBgQFI0gBVhABBXYACA/VtQYAQ2EGEEVFdgADVg4ByAY4CUf4ARYQJBV4Bjv1KcoRFhATtXgGPdm+9gEWEAw1eAY/J5yoERYQCHV4Bj8nnKgRRhEWFXgGP00fxhFGERkVeAY/WPw2oUYRHBV4Bj9rC79xRhEfFXgGP953IcFGESIVdhBFRWW4Bj3ZvvYBRhEHFXgGPel6NjFGEQoVeAY+n5s/IUYRDRV4Bj6lFB5hRhEQFXgGPt8APPFGERMVdhBFRWW4Bjzjz07xFhAQpXgGPOPPTvFGEPgVeAY9EXMgsUYQ+xV4Bj1R57WxRhD+FXgGPVP/P9FGEQEVeAY9k81VgUYRBBV2EEVFZbgGO/UpyhFGEOwVeAY8Ngq6YUYQ7xV4BjxCDrYRRhDyFXgGPEvWXVFGEPUVdhBFRWW4BjoYaDyxFhAclXgGOzdAErEWEBjVeAY7N0ASsUYQ3RV4Bjs9hH8hRhDgFXgGO3uGIHFGEOMVeAY7gcFIQUYQ5hV4Bjvch1/BRhDpFXYQRUVluAY6GGg8sUYQzzV4BjonG3IRRhDSNXgGOmChCHFGENQVeAY6ZFycIUYQ1xV4BjrK699hRhDaFXYQRUVluAY5YuTcIRYQIQV4Bjli5NwhRhDANXgGOYRW8+FGEMM1eAY5orfIEUYQxjV4BjnM58+RRhDJNXgGOgQK7GFGEMw1dhBFRWW4BjgJR/gBRhC0NXgGOIDv85FGELc1eAY5GKX80UYQujV4BjkeeydxRhC9NXYQRUVluAYzQw7AYRYQNSV4BjYOE83hFhAtpXgGNvCZyNEWECnleAY28JnI0UYQpTV4BjcdkdKBRhCoNXgGN7bgsOFGEKs1eAY3wZHSAUYQrjV4BjfejG+BRhCxNXYQRUVluAY2DhPN4UYQl1V4BjYT0KghRhCaVXgGNjE41PFGEJ1VeAY2Wbu08UYQoFV4Bjbn8f5xRhCiNXYQRUVluAY0D+JmIRYQMhV4BjQP4mYhRhCIVXgGNEzzvHFGEItVeAY0phrx8UYQjlV4BjTSx0sxRhCRVXgGNVkMLZFGEJRVdhBFRWW4BjNDDsBhRhB9dXgGM3EwPAFGEIB1eAYzpBHxIUYQglV4BjOkJd/BRhCFVXYQRUVluAYxgJO0YRYQPgV4BjIZzd6xFhA6RXgGMhnN3rFGEG51eAYyKU/H8UYQcXV4BjKHHvhRRhB0dXgGMrIe9EFGEHd1eAYy0055gUYQenV2EEVFZbgGMYCTtGFGEF91eAYxm2IdYUYQYnV4BjGroH6hRhBldXgGMd4vNDFGEGh1eAYyAHMy4UYQa3V2EEVFZbgGMLqKc7EWEEJ1eAYwuopzsUYQUZV4BjEoemjBRhBUlXgGMTXVL3FGEFZ1eAYxWBzxkUYQWXV4BjFlghUBRhBcdXYQRUVluAYwNK73EUYQRZV4BjBQCC+BRhBIlXgGMIe06EFGEEuVeAYws7mWoUYQTpV1tgAID9W2EEc2AEgDYDgQGQYQRukZBhJhFWW2ESUVZbYEBRYQSAkZBhJk1WW2BAUYCRA5DzW2EEo2AEgDYDgQGQYQSekZBhJhFWW2ESjFZbYEBRYQSwkZBhJk1WW2BAUYCRA5DzW2EE02AEgDYDgQGQYQTOkZBhJhFWW2ESx1ZbYEBRYQTgkZBhJk1WW2BAUYCRA5DzW2EFA2AEgDYDgQGQYQT+kZBhJ65WW2ETAVZbYEBRYQUQkZBhKHZWW2BAUYCRA5DzW2EFM2AEgDYDgQGQYQUukZBhJhFWW2ETKFZbYEBRYQVAkZBhJk1WW2BAUYCRA5DzW2EFUWETZFZbYEBRYQVekZBhJk1WW2BAUYCRA5DzW2EFgWAEgDYDgQGQYQV8kZBhJhFWW2ETbVZbYEBRYQWOkZBhJk1WW2BAUYCRA5DzW2EFsWAEgDYDgQGQYQWskZBhJhFWW2ETqVZbYEBRYQW+kZBhJk1WW2BAUYCRA5DzW2EF4WAEgDYDgQGQYQXckZBhJhFWW2ET5FZbYEBRYQXukZBhJk1WW2BAUYCRA5DzW2EGEWAEgDYDgQGQYQYMkZBhJhFWW2EUP1ZbYEBRYQYekZBhJk1WW2BAUYCRA5DzW2EGQWAEgDYDgQGQYQY8kZBhJhFWW2EUfVZbYEBRYQZOkZBhJk1WW2BAUYCRA5DzW2EGcWAEgDYDgQGQYQZskZBhJhFWW2EVDFZbYEBRYQZ+kZBhJk1WW2BAUYCRA5DzW2EGoWAEgDYDgQGQYQackZBhJhFWW2EVUlZbYEBRYQaukZBhJk1WW2BAUYCRA5DzW2EG0WAEgDYDgQGQYQbMkZBhJhFWW2EVkFZbYEBRYQbekZBhJk1WW2BAUYCRA5DzW2EHAWAEgDYDgQGQYQb8kZBhJhFWW2EVzFZbYEBRYQcOkZBhJk1WW2BAUYCRA5DzW2EHMWAEgDYDgQGQYQcskZBhJhFWW2EWB1ZbYEBRYQc+kZBhJk1WW2BAUYCRA5DzW2EHYWAEgDYDgQGQYQdckZBhJhFWW2EWRlZbYEBRYQdukZBhJk1WW2BAUYCRA5DzW2EHkWAEgDYDgQGQYQeMkZBhJhFWW2EWgVZbYEBRYQeekZBhJk1WW2BAUYCRA5DzW2EHwWAEgDYDgQGQYQe8kZBhJhFWW2EWvFZbYEBRYQfOkZBhJk1WW2BAUYCRA5DzW2EH8WAEgDYDgQGQYQfskZBhJhFWW2EW91ZbYEBRYQf+kZBhKHZWW2BAUYCRA5DzW2EID2EXo1ZbYEBRYQgckZBhJk1WW2BAUYCRA5DzW2EIP2AEgDYDgQGQYQg6kZBhJhFWW2EXwlZbYEBRYQhMkZBhJk1WW2BAUYCRA5DzW2EIb2AEgDYDgQGQYQhqkZBhJhFWW2EX/lZbYEBRYQh8kZBhJk1WW2BAUYCRA5DzW2EIn2AEgDYDgQGQYQiakZBhJhFWW2EYOlZbYEBRYQiskZBhJk1WW2BAUYCRA5DzW2EIz2AEgDYDgQGQYQjKkZBhJhFWW2EYeVZbYEBRYQjckZBhJk1WW2BAUYCRA5DzW2EI/2AEgDYDgQGQYQj6kZBhJhFWW2EYtFZbYEBRYQkMkZBhJk1WW2BAUYCRA5DzW2EJL2AEgDYDgQGQYQkqkZBhJhFWW2EY8lZbYEBRYQk8kZBhJk1WW2BAUYCRA5DzW2EJX2AEgDYDgQGQYQlakZBhJhFWW2EZLVZbYEBRYQlskZBhJk1WW2BAUYCRA5DzW2EJj2AEgDYDgQGQYQmKkZBhJhFWW2EZclZbYEBRYQmckZBhJk1WW2BAUYCRA5DzW2EJv2AEgDYDgQGQYQm6kZBhJ65WW2EZrlZbYEBRYQnMkZBhKHZWW2BAUYCRA5DzW2EJ72AEgDYDgQGQYQnqkZBhJ65WW2EZ4FZbYEBRYQn8kZBhKLFWW2BAUYCRA5DzW2EKDWEaDFZbYEBRYQoakZBhJk1WW2BAUYCRA5DzW2EKPWAEgDYDgQGQYQo4kZBhJhFWW2EaSFZbYEBRYQpKkZBhJk1WW2BAUYCRA5DzW2EKbWAEgDYDgQGQYQpokZBhJhFWW2EahlZbYEBRYQp6kZBhJk1WW2BAUYCRA5DzW2EKnWAEgDYDgQGQYQqYkZBhJhFWW2EawVZbYEBRYQqqkZBhJk1WW2BAUYCRA5DzW2EKzWAEgDYDgQGQYQrIkZBhJhFWW2Ea/1ZbYEBRYQrakZBhJk1WW2BAUYCRA5DzW2EK/WAEgDYDgQGQYQr4kZBhJhFWW2EbO1ZbYEBRYQsKkZBhJk1WW2BAUYCRA5DzW2ELLWAEgDYDgQGQYQsokZBhJhFWW2EbdlZbYEBRYQs6kZBhJk1WW2BAUYCRA5DzW2ELXWAEgDYDgQGQYQtYkZBhJhFWW2EbslZbYEBRYQtqkZBhJk1WW2BAUYCRA5DzW2ELjWAEgDYDgQGQYQuIkZBhJhFWW2EcD1ZbYEBRYQuakZBhJk1WW2BAUYCRA5DzW2ELvWAEgDYDgQGQYQu4kZBhJhFWW2EcTlZbYEBRYQvKkZBhJk1WW2BAUYCRA5DzW2EL7WAEgDYDgQGQYQvokZBhJhFWW2EciVZbYEBRYQv6kZBhJk1WW2BAUYCRA5DzW2EMHWAEgDYDgQGQYQwYkZBhJ65WW2Ec1VZbYEBRYQwqkZBhKHZWW2BAUYCRA5DzW2EMTWAEgDYDgQGQYQxIkZBhJhFWW2EdQ1ZbYEBRYQxakZBhJk1WW2BAUYCRA5DzW2EMfWAEgDYDgQGQYQx4kZBhJhFWW2Edg1ZbYEBRYQyKkZBhJk1WW2BAUYCRA5DzW2EMrWAEgDYDgQGQYQyokZBhJ65WW2EdvlZbYEBRYQy6kZBhKHZWW2BAUYCRA5DzW2EM3WAEgDYDgQGQYQzYkZBhJ65WW2Ed71ZbYEBRYQzqkZBhKHZWW2BAUYCRA5DzW2ENDWAEgDYDgQGQYQ0IkZBhJ65WW2EeFlZbYEBRYQ0akZBhKQ1WW2BAUYCRA5DzW2ENK2EemFZbYEBRYQ04kZBhJk1WW2BAUYCRA5DzW2ENW2AEgDYDgQGQYQ1WkZBhJhFWW2Ee41ZbYEBRYQ1okZBhJk1WW2BAUYCRA5DzW2ENi2AEgDYDgQGQYQ2GkZBhJhFWW2EfHlZbYEBRYQ2YkZBhJk1WW2BAUYCRA5DzW2ENu2AEgDYDgQGQYQ22kZBhJhFWW2EfWlZbYEBRYQ3IkZBhJk1WW2BAUYCRA5DzW2EN62AEgDYDgQGQYQ3mkZBhKYhWW2EfllZbYEBRYQ34kZBhJk1WW2BAUYCRA5DzW2EOG2AEgDYDgQGQYQ4WkZBhJhFWW2Ef5FZbYEBRYQ4okZBhJk1WW2BAUYCRA5DzW2EOS2AEgDYDgQGQYQ5GkZBhJhFWW2EgH1ZbYEBRYQ5YkZBhJk1WW2BAUYCRA5DzW2EOe2AEgDYDgQGQYQ52kZBhJhFWW2EgWlZbYEBRYQ6IkZBhJk1WW2BAUYCRA5DzW2EOq2AEgDYDgQGQYQ6mkZBhJhFWW2EglVZbYEBRYQ64kZBhJk1WW2BAUYCRA5DzW2EO22AEgDYDgQGQYQ7WkZBhJhFWW2Eg0FZbYEBRYQ7okZBhJk1WW2BAUYCRA5DzW2EPC2AEgDYDgQGQYQ8GkZBhJhFWW2EhFFZbYEBRYQ8YkZBhJk1WW2BAUYCRA5DzW2EPO2AEgDYDgQGQYQ82kZBhJhFWW2EhUFZbYEBRYQ9IkZBhJk1WW2BAUYCRA5DzW2EPa2AEgDYDgQGQYQ9mkZBhJhFWW2Ehi1ZbYEBRYQ94kZBhJk1WW2BAUYCRA5DzW2EPm2AEgDYDgQGQYQ+WkZBhJhFWW2EhyVZbYEBRYQ+okZBhJk1WW2BAUYCRA5DzW2EPy2AEgDYDgQGQYQ/GkZBhJhFWW2EiBlZbYEBRYQ/YkZBhJk1WW2BAUYCRA5DzW2EP+2AEgDYDgQGQYQ/2kZBhJhFWW2EiQFZbYEBRYRAIkZBhJk1WW2BAUYCRA5DzW2EQK2AEgDYDgQGQYRAmkZBhJhFWW2EifFZbYEBRYRA4kZBhJk1WW2BAUYCRA5DzW2EQW2AEgDYDgQGQYRBWkZBhJhFWW2EiuFZbYEBRYRBokZBhJk1WW2BAUYCRA5DzW2EQi2AEgDYDgQGQYRCGkZBhJhFWW2EjE1ZbYEBRYRCYkZBhJk1WW2BAUYCRA5DzW2EQu2AEgDYDgQGQYRC2kZBhJhFWW2EjVVZbYEBRYRDIkZBhJk1WW2BAUYCRA5DzW2EQ62AEgDYDgQGQYRDmkZBhJhFWW2EjkVZbYEBRYRD4kZBhJk1WW2BAUYCRA5DzW2ERG2AEgDYDgQGQYREWkZBhJhFWW2EjzlZbYEBRYREokZBhJk1WW2BAUYCRA5DzW2ERS2AEgDYDgQGQYRFGkZBhJ65WW2EkEFZbYEBRYRFYkZBhKHZWW2BAUYCRA5DzW2ERe2AEgDYDgQGQYRF2kZBhJhFWW2Ekf1ZbYEBRYRGIkZBhJk1WW2BAUYCRA5DzW2ERq2AEgDYDgQGQYRGmkZBhJhFWW2Eku1ZbYEBRYRG4kZBhJk1WW2BAUYCRA5DzW2ER22AEgDYDgQGQYRHWkZBhJhFWW2Ek+VZbYEBRYRHokZBhJk1WW2BAUYCRA5DzW2ESC2AEgDYDgQGQYRIGkZBhJ65WW2ElOFZbYEBRYRIYkZBhKhBWW2BAUYCRA5DzW2ESO2AEgDYDgQGQYRI2kZBhJhFWW2ElalZbYEBRYRJIkZBhJk1WW2BAUYCRA5DzW2AAYRJbYRejVltQYABl3q2+7wA2kFBgAIBbhIEQFWESgVc2kVBgAYEBkFBhEmtWW1BQgJFQUJGQUFZbYABhEpZhF6NWW1BgAGXerb7vADKQUGAAgFuEgRAVYRK8VzKRUGABgQGQUGESplZbUFCAkVBQkZBQVltgAGES0WEXo1ZbUGAAZd6tvu8AUpBQYABbg4EQFWES91eBYABSYAGBAZBQYRLgVltQgJFQUJGQUFZbYGBgAGAIkFBgQIKEUWAghgFgAIVa8YBhEyFXYACA/VtQUJGQUFZbYABhEzJhF6NWW1BgAGXerb7vAAGQUGAAW4OBEBVhE1pXYACCAZFQYAGBAZBQYRNBVltQgJFQUJGQUFZbYACAVJBQkFZbYABhE3dhF6NWW1BgAGXerb7vABeQUGAAW4OBEBVhE59XYACCF5FQYAGBAZBQYROGVltQgJFQUJGQUFZbYABhE7NhF6NWW1BgAGXerb7vADSQUGAAgFuEgRAVYRPZVzSRUGABgQGQUGETw1ZbUFCAkVBQkZBQVltgAGET7mEXo1ZbUGAAZd6tvu8ABpBQYABbg4EQFWEUNVd///////////////////////////////////////////+CBpFQYAGBAZBQYRP9VltQgJFQUJGQUFZbYABhFElhF6NWW1BgAGXerb7vABOQUGAAgFuEgRAVYRRyV2ABgxORUGABgQGQUGEUWVZbUFCAkVBQkZBQVltgAGEUh2EXo1ZbUGAAZd6tvu8AIJBQf/////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYABSYACAW4SBEBVhFNVXYARgACCRUGABgQGQUGEUu1ZbUH8pBFpZIAfQwkbvAsIiNXDalSLQzw9zKCx5obyPC7LCOIEUYRUCV2AAkVBbUICRUFCRkFBWW2AAYRUWYRejVltQYABl3q2+7wCkkFCAYBBSYABbg4EQFWEVSFdgBGADYAKDYAZgEKRgAYEBkFBhFSlWW1CAkVBQkZBQVltgAGEVXGEXo1ZbUGAAZd6tvu8AGpBQYACAW4SBEBVhFYVXgmAAGpFQYAGBAZBQYRVsVltQUICRUFCRkFBWW2AAYRWaYRejVltQYABl3q2+7wAbkFBgAFuDgRAVYRXCV4FgABuRUGABgQGQUGEVqVZbUICRUFCRkFBWW2AAYRXWYRejVltQYABl3q2+7wBCkFBgAIBbhIEQFWEV/FdCkVBgAYEBkFBhFeZWW1BQgJFQUJGQUFZbYABhFhFhF6NWW1BgAGXerb7vADGQUGAAMGAAW4WBEBVhFjpXgTGSUGABgQGQUGEWI1ZbUFBQgJFQUJGQUFZbYABhFlBhF6NWW1BgAGXerb7vAEiQUGAAgFuEgRAVYRZ2V0iRUGABgQGQUGEWYFZbUFCAkVBQkZBQVltgAGEWi2EXo1ZbUGAAZd6tvu8APZBQYACAW4SBEBVhFrFXPZFQYAGBAZBQYRabVltQUICRUFCRkFBWW2AAYRbGYRejVltQYABl3q2+7wBDkFBgAIBbhIEQFWEW7FdDkVBgAYEBkFBhFtZWW1BQgJFQUJGQUFZbYAKBgVSBEGEXB1dgAID9W5BgAFJgIGAAIAFgAJFQkFCAVGEXIpBhKlpWW4BgHwFgIICRBAJgIAFgQFGQgQFgQFKAkpGQgYFSYCABgoBUYRdOkGEqWlZbgBVhF5tXgGAfEGEXcFdhAQCAg1QEAoNSkWAgAZFhF5tWW4IBkZBgAFJgIGAAIJBbgVSBUpBgAQGQYCABgIMRYRd+V4KQA2AfFoIBkVtQUFBQUIFWW2AAYAFgAFRhF7SRkGEqulZbYACBkFVQYABUkFCQVltgAGEXzGEXo1ZbUGAAZd6tvu8ABJBQYABbg4EQFWEX9FdgAYIEkVBgAYEBkFBhF9tWW1CAkVBQkZBQVltgAGEYCGEXo1ZbUGAAZd6tvu8AN5BQYABbg4EQFWEYMFdgIGAAgDdgAYEBkFBhGBdWW1CAkVBQkZBQVltgAGEYRGEXo1ZbUGAAZd6tvu8AoJBQgGAQUmAAW4OBEBVhGG9XYAZgEKBgAYEBkFBhGFdWW1CAkVBQkZBQVltgAGEYg2EXo1ZbUGAAZd6tvu8AM5BQYACAW4SBEBVhGKlXM5FQYAGBAZBQYRiTVltQUICRUFCRkFBWW2AAYRi+YRejVltQYABl3q2+7wBTkFBgAFuDgRAVYRjoV2Perb7vYABSYAGBAZBQYRjNVltQgJFQUJGQUFZbYABhGPxhF6NWW1BgAGXerb7vADqQUGAAgFuEgRAVYRkiVzqRUGABgQGQUGEZDFZbUFCAkVBQkZBQVltgAGEZN2EXo1ZbUGAAZd6tvu8AUZBQYACBYABSYABbhIEQFWEZZFdgAFGRUGABgQGQUGEZTFZbUICRUFCAkVBQkZBQVltgAGEZfGEXo1ZbUGAAZd6tvu8AHZBQYABbg4EQFWEZpFeBYAAdkVBgAYEBkFBhGYtWW1CAkVBQkZBQVltgYGAAYAWQUGAggwGDUWBAUWAggYOFYACIWvGAYRnTV2AAgP1bgZVQUFBQUFCRkFBWW2AAgGACkFBgIIMBg1GDYCCBg4VgAIha8YBhGgJXYACA/VtQUFBQUJGQUFZbYABhGhZhF6NWW1BbYQPoWhEVYRpAV2ABgGAAgoJUYRo0kZBhKrpWW5JQUIGQVVBhGhhWW2ABVJBQkFZbYABhGlJhF6NWW1BgAGXerb7vABCQUGAAgFuEgRAVYRp7V4JgARCRUGABgQGQUGEaYlZbUFCAkVBQkZBQVltgAGEakGEXo1ZbUGAAZd6tvu8ARJBQYACAW4SBEBVhGrZXRJFQYAGBAZBQYRqgVltQUICRUFCRkFBWW2AAYRrLYRejVltQYABl3q2+7wARkFBgAIBbhIEQFWEa9FdgAYMRkVBgAYEBkFBhGttWW1BQgJFQUJGQUFZbYABhGwlhF6NWW1BgAGXerb7vAD6QUGAAW4OBEBVhGzFXYCBgAIA+YAGBAZBQYRsYVltQgJFQUJGQUFZbYABhG0VhF6NWW1BgAGXerb7vAEWQUGAAgFuEgRAVYRtrV0WRUGABgQGQUGEbVVZbUFCAkVBQkZBQVltgAGEbgGEXo1ZbUGAAZd6tvu8AApBQYABbg4EQFWEbqFdgAYICkVBgAYEBkFBhG49WW1CAkVBQkZBQVltgAGEbvGEXo1ZbUGAAZd6tvu8ACJBQYABbg4EQFWEcBVd///////////////////////////////////////////9gAIMIkVBgAYEBkFBhG8tWW1CAkVBQkZBQVltgAGEcGWEXo1ZbUGAAZd6tvu8AVJBQgGAAVWAAW4OBEBVhHERXYABUkVBgAYEBkFBhHCxWW1CAkVBQkZBQVltgAGEcWGEXo1ZbUGAAZd6tvu8AWpBQYACAW4SBEBVhHH5XWpFQYAGBAZBQYRxoVltQUICRUFCRkFBWW2AAYRyTYRejVltQYABl3q2+7wAZkFBgAFuDgRAVYRy5V4EZkVBgAYEBkFBhHKJWW1Bl3q2+7wAZgRRhHMxXgBmQUFuAkVBQkZBQVltgYICCURRhHRpXYEBRfwjDeaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgVJgBAFhHRGQYStLVltgQFGAkQOQ/VtgAGAHkFBgIIMBg1FgQISChGAAh1rxgGEdOldgAID9W1BQUFCRkFBWW2AAYR1NYRejVltQYABl3q2+7wChkFCAYBBSYABbg4EQFWEdeVeAYAZgEKFgAYEBkFBhHWBWW1CAkVBQkZBQVltgAGEdjWEXo1ZbUGAAZd6tvu8AFpBQYABbg4EQFWEdtFeBghaRUGABgQGQUGEdnFZbUICRUFCRkFBWW2BgYABgBJBQYCCDAYNRYEBRgYGDhWAAiFrxgGEd4ldgAID9W4GVUFBQUFBQkZBQVltgYGAAYAiQUGBAgoRRYCCGAWAAhVrxgGEeD1dgAID9W1BQkZBQVltgAGCAglEUYR5cV2BAUX8Iw3mgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIFSYAQBYR5TkGErt1ZbYEBRgJEDkP1bYABgAZBQYCCDAWAggQFRYB8aYCCCAVJgIGBAUWCAg2AAhlrxgGEeildgAID9W2BAUVGTUFBQUJGQUFZbYABhHqJhF6NWW1BbYQPoWhEVYR7bV2ABgGAAgoJUYR7AkZBhKrpWW5JQUIGQVVBDYAFUYR7VkZBhLAZWW1BhHqRWW2ABVJBQkFZbYABhHu1hF6NWW1BgAGXerb7vAEaQUGAAgFuEgRAVYR8TV0aRUGABgQGQUGEe/VZbUFCAkVBQkZBQVltgAGEfKGEXo1ZbUGAAZd6tvu8ABZBQYABbg4EQFWEfUFdgAYIFkVBgAYEBkFBhHzdWW1CAkVBQkZBQVltgAGEfZGEXo1ZbUGAAZd6tvu8AOZBQYABbg4EQFWEfjFdgIGAAgDlgAYEBkFBhH3NWW1CAkVBQkZBQVltgAGACg4OQkYBgAYFUAYCCVYCRUFBgAZADkGAAUmAgYAAgAWAAkJGSkJGSkJGSkJGSUJGCYR/VkpGQYS3uVltQYAKAVJBQkFCSkVBQVltgAGEf7mEXo1ZbUGAAZd6tvu8AWZBQYACAW4SBEBVhIBRXWZFQYAGBAZBQYR/+VltQUICRUFCRkFBWW2AAYSApYRejVltQYABl3q2+7wA4kFBgAIBbhIEQFWEgT1c4kVBgAYEBkFBhIDlWW1BQgJFQUJGQUFZbYABhIGRhF6NWW1BgAGXerb7vAEGQUGAAgFuEgRAVYSCKV0GRUGABgQGQUGEgdFZbUFCAkVBQkZBQVltgAGEgn2EXo1ZbUGAAZd6tvu8AMJBQYACAW4SBEBVhIMVXMJFQYAGBAZBQYSCvVltQUICRUFCRkFBWW2AAYSDaYRejVltQYABl3q2+7wCjkFCAYBBSYABbg4EQFWEhCldgA2ACgmAGYBCjYAGBAZBQYSDtVltQgJFQUJGQUFZbYABhIR5hF6NWW1BgAGXerb7vAAuQUGAAW4OBEBVhIUZXgWAgC5FQYAGBAZBQYSEtVltQgJFQUJGQUFZbYABhIVphF6NWW1BgAGXerb7vAEeQUGAAgFuEgRAVYSGAV0eRUGABgQGQUGEhalZbUFCAkVBQkZBQVltgAGEhlWEXo1ZbUGAAZd6tvu8AHJBQYACAW4SBEBVhIb5XgmAAHJJQYAGBAZBQYSGlVltQUICRUFCRkFBWW2AAYSHTYRejVltQYABl3q2+7wA1kFBgAIBbhIEQFWEh+1dgADWRUGABgQGQUGEh41ZbUFCAkVBQkZBQVltgAGEiEGEXo1ZbUGAAZd6tvu8AVZBQYABbg4EQFWEiNleBYABVYAGBAZBQYSIfVltQgJFQUJGQUFZbYABhIkphF6NWW1BgAGXerb7vABiQUGAAW4OBEBVhInJXYACCGJFQYAGBAZBQYSJZVltQgJFQUJGQUFZbYABhIoZhF6NWW1BgAGXerb7vAAOQUGAAW4OBEBVhIq5XYACCA5FQYAGBAZBQYSKVVltQgJFQUJGQUFZbYABhIsJhF6NWW1BgAGXerb7vAAeQUGAAW4OBEBVhIwlXf///////////////////////////////////////////ggeRUGABgQGQUGEi0VZbUICRUFCRkFBWW2AAYSMdYRejVltQYABl3q2+7wCikFCAYBBSYABbg4EQFWEjS1dgAoFgBmAQomABgQGQUGEjMFZbUICRUFCRkFBWW2AAYSNfYRejVltQYABl3q2+7wAKkFBgAFuDgRAVYSOHV2ABggqRUGABgQGQUGEjblZbUICRUFCRkFBWW2AAYSObYRejVltQYABl3q2+7wAUkFBgAIBbhIEQFWEjw1eCgxSRUGABgQGQUGEjq1ZbUFCAkVBQkZBQVltgAGEj2GEXo1ZbUGAAZd6tvu8AQJBQYABgAUMDYABbhYEQFWEkBFeBQJJQYAGBAZBQYSPtVltQUFCAkVBQkZBQVltgYGCAglEUYSRWV2BAUX8Iw3mgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIFSYAQBYSRNkGErS1ZbYEBRgJEDkP1bYABgBpBQYCCDAYNRYECEgoRgAIda8YBhJHZXYACA/VtQUFBQkZBQVltgAGEkiWEXo1ZbUGAAZd6tvu8AFZBQYACAW4SBEBVhJLBXghWRUGABgQGQUGEkmVZbUFCAkVBQkZBQVltgAGEkxWEXo1ZbUGAAZd6tvu8AEpBQYACAW4SBEBVhJO5XgmABEpFQYAGBAZBQYSTVVltQUICRUFCRkFBWW2AAYSUDYRejVltQYABl3q2+7wA7kFBgADBgAFuFgRAVYSUsV4E7klBgAYEBkFBhJRVWW1BQUICRUFCRkFBWW2AAgGADkFBgIIMBg1FgQFFgFIGDhWAAiFrxgGElXFdgAID9W4FRlVBQUFBQUJGQUFZbYABhJXRhF6NWW1BgAGXerb7vAAmQUGAAW4OBEBVhJb1Xf///////////////////////////////////////////YAGDCZFQYAGBAZBQYSWDVltQgJFQUJGQUFZbYABgQFGQUJBWW2AAgP1bYACA/VtgAIGQUJGQUFZbYSXugWEl21ZbgRRhJflXYACA/VtQVltgAIE1kFBhJguBYSXlVluSkVBQVltgAGAggoQDEhVhJidXYSYmYSXRVltbYABhJjWEgoUBYSX8VluRUFCSkVBQVlthJkeBYSXbVluCUlBQVltgAGAgggGQUGEmYmAAgwGEYSY+VluSkVBQVltgAID9W2AAgP1bYABgHxlgH4MBFpBQkZBQVlt/Tkh7cQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAFJgQWAEUmAkYAD9W2Emu4JhJnJWW4EBgYEQZ///////////ghEXFWEm2ldhJtlhJoNWW1uAYEBSUFBQVltgAGEm7WElx1ZbkFBhJvmCgmEmslZbkZBQVltgAGf//////////4IRFWEnGVdhJxhhJoNWW1thJyKCYSZyVluQUGAggQGQUJGQUFZbgoGDN2AAg4MBUlBQUFZbYABhJ1FhJ0yEYSb+VlthJuNWW5BQgoFSYCCBAYSEhAERFWEnbVdhJ2xhJm1WW1thJ3iEgoVhJy9WW1CTklBQUFZbYACCYB+DARJhJ5VXYSeUYSZoVltbgTVhJ6WEgmAghgFhJz5WW5FQUJKRUFBWW2AAYCCChAMSFWEnxFdhJ8NhJdFWW1tgAIIBNWf//////////4ERFWEn4ldhJ+FhJdZWW1thJ+6EgoUBYSeAVluRUFCSkVBQVltgAIFRkFCRkFBWW2AAgoJSYCCCAZBQkpFQUFZbYABbg4EQFWEoMVeAggFRgYQBUmAggQGQUGEoFlZbYACEhAFSUFBQUFZbYABhKEiCYSf3VlthKFKBhWEoAlZbk1BhKGKBhWAghgFhKBNWW2Eoa4FhJnJWW4QBkVBQkpFQUFZbYABgIIIBkFCBgQNgAIMBUmEokIGEYSg9VluQUJKRUFBWW2AAgZBQkZBQVlthKKuBYSiYVluCUlBQVltgAGAgggGQUGEoxmAAgwGEYSiiVluSkVBQVltgAHP//////////////////////////4IWkFCRkFBWW2AAYSj3gmEozFZbkFCRkFBWW2EpB4FhKOxWW4JSUFBWW2AAYCCCAZBQYSkiYACDAYRhKP5WW5KRUFBWW2AAgP1bYACA/VtgAICDYB+EARJhKUhXYSlHYSZoVltbgjWQUGf//////////4ERFWEpZVdhKWRhKShWW1tgIIMBkVCDYAGCAoMBERVhKYFXYSmAYSktVltbklCSkFBWW2AAgGAgg4UDEhVhKZ9XYSmeYSXRVltbYACDATVn//////////+BERVhKb1XYSm8YSXWVltbYSnJhYKGAWEpMlZbklCSUFCSUJKQUFZbYAB///////////////////////////8AAAAAAAAAAAAAAACCFpBQkZBQVlthKgqBYSnVVluCUlBQVltgAGAgggGQUGEqJWAAgwGEYSoBVluSkVBQVlt/Tkh7cQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAFJgImAEUmAkYAD9W2AAYAKCBJBQYAGCFoBhKnJXYH+CFpFQW2AgghCBA2EqhVdhKoRhKitWW1tQkZBQVlt/Tkh7cQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAFJgEWAEUmAkYAD9W2AAYSrFgmEl21ZbkVBhKtCDYSXbVluSUIKCAZBQgIIRFWEq6FdhKudhKotWW1uSkVBQVltgAIKCUmAgggGQUJKRUFBWW39JbnZhbGlkIGlucHV0IGxlbmd0aAAAAAAAAAAAAAAAAGAAggFSUFZbYABhKzVgFINhKu5WW5FQYStAgmEq/1ZbYCCCAZBQkZBQVltgAGAgggGQUIGBA2AAgwFSYStkgWErKFZbkFCRkFBWW39JbnZhbGlkIGlucHV0IGRhdGEgbGVuZ3RoLgAAAAAAAGAAggFSUFZbYABhK6FgGoNhKu5WW5FQYSusgmEra1ZbYCCCAZBQkZBQVltgAGAgggGQUIGBA2AAgwFSYSvQgWErlFZbkFCRkFBWW39OSHtxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAUmASYARSYCRgAP1bYABhLBGCYSXbVluRUGEsHINhJdtWW5JQgmEsLFdhLCthK9dWW1uCggaQUJKRUFBWW2AAgpBQkpFQUFZbYACBkFCBYABSYCBgACCQUJGQUFZbYABgIGAfgwEEkFCRkFBWW2AAgoIbkFCSkVBQVltgAGAIgwJhLKR///////////////////////////////////////////+CYSxnVlthLK6Gg2EsZ1ZblVCAGYQWk1CAhhaEF5JQUFCTklBQUFZbYACBkFCRkFBWW2AAYSzrYSzmYSzhhGEl21ZbYSzGVlthJdtWW5BQkZBQVltgAIGQUJGQUFZbYS0Fg2Es0FZbYS0ZYS0RgmEs8lZbhIRUYSx0VluCVVBQUFBWW2AAkFZbYS0uYS0hVlthLTmBhIRhLPxWW1BQUFZbW4GBEBVhLV1XYS1SYACCYS0mVltgAYEBkFBhLT9WW1BQVltgH4IRFWEtoldhLXOBYSxCVlthLXyEYSxXVluBAWAghRAVYS2LV4GQUFthLZ9hLZeFYSxXVluDAYJhLT5WW1BQW1BQUFZbYACCghyQUJKRUFBWW2AAYS3FYAAZhGAIAmEtp1ZbGYCDFpFQUJKRUFBWW2AAYS3eg4NhLbRWW5FQgmACAoIXkFCSkVBQVlthLfiDg2EsN1ZbZ///////////gREVYS4RV2EuEGEmg1ZbW2EuG4JUYSpaVlthLiaCgoVhLWFWW2AAYB+DEWABgRRhLlVXYACEFWEuQ1eChwE1kFBbYS5NhYJhLdJWW4ZVUGEutVZbYB8ZhBZhLmOGYSxCVltgAFuCgRAVYS6LV4SJATWCVWABggGRUGAghQGUUGAggQGQUGEuZlZbhoMQFWEuqFeEiQE1YS6kYB+JFoJhLbRWW4NVUFtgAWACiAIBiFVQUFBbUFBQUFBQUFb+omRpcGZzWCISIDEkITSIwvH8pZaHh/DD6W+6hGkSmoB5jhHudSkDtL/cZHNvbGNDAAgTADM=", + "touched": true, + "read": true + }, + "0x85dA99c8a7C2C95964c8EfD687E95E632Fc533D6": { + "address": "0x85dA99c8a7C2C95964c8EfD687E95E632Fc533D6", + "balance": 1e+27, + "nonce": 18643, + "read": true + }, + "0xe4f2Dea6e117FCBa4eC4FDd1D090245110763Dd9": { + "address": "0xe4f2Dea6e117FCBa4eC4FDd1D090245110763Dd9", + "balance": 1e+24, + "read": true + } + } + } + ] +} diff --git a/state/immutable-trie/hasher.go b/state/immutable-trie/hasher.go index 38ea53350c..e571a5b6b7 100644 --- a/state/immutable-trie/hasher.go +++ b/state/immutable-trie/hasher.go @@ -40,6 +40,13 @@ type hasher struct { buf []byte hash hashImpl tmp [32]byte + batch Putter +} + +func (h *hasher) WithBatch(batch Putter) *hasher { + h.batch = batch + + return h } func (h *hasher) Reset() { @@ -85,20 +92,15 @@ func (h *hasher) Hash(data []byte) []byte { return h.tmp[:] } -func (t *Txn) Hash() ([]byte, error) { - if t.root == nil { +func (h *hasher) doHash(rootNode Node) ([]byte, error) { + if rootNode == nil { return emptyRoot, nil } - h, ok := hasherPool.Get().(*hasher) - if !ok { - return nil, errors.New("invalid type assertion") - } - var root []byte arena, _ := h.AcquireArena() - val := t.hash(t.root, h, arena, 0) + val := h.hashImpl(rootNode, arena, true, 0) // REDO if val.Type() == fastrlp.TypeBytes { @@ -108,8 +110,8 @@ func (t *Txn) Hash() ([]byte, error) { root = h.hash.Sum(nil) - if t.batch != nil { - t.batch.Put(root, val.Raw()) + if h.batch != nil { + h.batch.Put(root, val.Raw()) } } else { root = make([]byte, 32) @@ -122,26 +124,45 @@ func (t *Txn) Hash() ([]byte, error) { root = h.hash.Sum(nil) - if t.batch != nil { - t.batch.Put(root, tmp) + if h.batch != nil { + h.batch.Put(root, tmp) } } h.ReleaseArenas(0) - hasherPool.Put(h) return root, nil } -func (t *Txn) hash(node Node, h *hasher, a *fastrlp.Arena, d int) *fastrlp.Value { +func (t *Txn) Hash() ([]byte, error) { + h, ok := hasherPool.Get().(*hasher) + if !ok { + return nil, errors.New("invalid type assertion") + } + + defer hasherPool.Put(h) + + h.WithBatch(t.batch) + + root, err := h.doHash(t.root) + if err != nil { + return nil, err + } + + return root, nil +} + +func (h *hasher) hashImpl(node Node, a *fastrlp.Arena, useHash bool, d int) *fastrlp.Value { var val *fastrlp.Value var aa *fastrlp.Arena var idx int - if h, ok := node.Hash(); ok { - return a.NewCopyBytes(h) + if useHash { + if h, ok := node.Hash(); ok { + return a.NewCopyBytes(h) + } } switch n := node.(type) { @@ -149,7 +170,7 @@ func (t *Txn) hash(node Node, h *hasher, a *fastrlp.Arena, d int) *fastrlp.Value return a.NewCopyBytes(n.buf) case *ShortNode: - child := t.hash(n.child, h, a, d+1) + child := h.hashImpl(n.child, a, true, d+1) val = a.NewArray() val.Set(a.NewBytes(encodeCompact(n.key))) @@ -164,7 +185,7 @@ func (t *Txn) hash(node Node, h *hasher, a *fastrlp.Arena, d int) *fastrlp.Value if i == nil { val.Set(a.NewNull()) } else { - val.Set(t.hash(i, h, aa, d+1)) + val.Set(h.hashImpl(i, aa, true, d+1)) } } @@ -172,7 +193,7 @@ func (t *Txn) hash(node Node, h *hasher, a *fastrlp.Arena, d int) *fastrlp.Value if n.value == nil { val.Set(a.NewNull()) } else { - val.Set(t.hash(n.value, h, a, d+1)) + val.Set(h.hashImpl(n.value, a, true, d+1)) } default: @@ -194,8 +215,8 @@ func (t *Txn) hash(node Node, h *hasher, a *fastrlp.Arena, d int) *fastrlp.Value hh := node.SetHash(tmp) // Write data - if t.batch != nil { - t.batch.Put(tmp, h.buf) + if h.batch != nil { + h.batch.Put(tmp, h.buf) } return a.NewCopyBytes(hh) diff --git a/state/immutable-trie/snapshot.go b/state/immutable-trie/snapshot.go index 935fc52da4..31ba52ae26 100644 --- a/state/immutable-trie/snapshot.go +++ b/state/immutable-trie/snapshot.go @@ -2,6 +2,7 @@ package itrie import ( "bytes" + "encoding/hex" "github.com/0xPolygon/polygon-edge/crypto" "github.com/0xPolygon/polygon-edge/state" @@ -12,10 +13,27 @@ import ( type Snapshot struct { state *State trie *Trie + + // tracers is the list of tracers executed, one for each trie + tracers []*tracer + + // trace is the object that holds the traces + trace *types.Trace } var emptyStateHash = types.StringToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") +func (s *Snapshot) createTracer(isAccountTrie bool) *tracer { + if s.tracers == nil { + s.tracers = []*tracer{} + } + + tr := &tracer{isAccountTrie: isAccountTrie, trace: s.trace} + s.tracers = append(s.tracers, tr) + + return tr +} + func (s *Snapshot) GetStorage(addr types.Address, root types.Hash, rawkey types.Hash) types.Hash { var ( err error @@ -31,6 +49,8 @@ func (s *Snapshot) GetStorage(addr types.Address, root types.Hash, rawkey types. } } + trie.tracer = s.createTracer(false) + key := crypto.Keccak256(rawkey.Bytes()) val, ok := trie.Get(key, s.state.storage) @@ -55,6 +75,7 @@ func (s *Snapshot) GetStorage(addr types.Address, root types.Hash, rawkey types. func (s *Snapshot) GetAccount(addr types.Address) (*state.Account, error) { key := crypto.Keccak256(addr.Bytes()) + s.trie.tracer = s.createTracer(true) data, ok := s.trie.Get(key, s.state.storage) if !ok { @@ -73,17 +94,14 @@ func (s *Snapshot) GetCode(hash types.Hash) ([]byte, bool) { return s.state.GetCode(hash) } -func (s *Snapshot) Commit(objs []*state.Object) (state.Snapshot, []byte) { +func (s *Snapshot) Commit(objs []*state.Object) (state.Snapshot, *types.Trace, []byte) { batch := s.state.storage.Batch() tt := s.trie.Txn(s.state.storage) tt.batch = batch - arena := accountArenaPool.Get() - defer accountArenaPool.Put(arena) - - ar1 := stateArenaPool.Get() - defer stateArenaPool.Put(ar1) + arena := stateArenaPool.Get() + defer stateArenaPool.Put(arena) for _, obj := range objs { if obj.Deleted { @@ -110,7 +128,7 @@ func (s *Snapshot) Commit(objs []*state.Object) (state.Snapshot, []byte) { if entry.Deleted { localTxn.Delete(k) } else { - vv := ar1.NewBytes(bytes.TrimLeft(entry.Val, "\x00")) + vv := arena.NewBytes(bytes.TrimLeft(entry.Val, "\x00")) localTxn.Insert(k, vv.MarshalTo(nil)) } } @@ -145,5 +163,68 @@ func (s *Snapshot) Commit(objs []*state.Object) (state.Snapshot, []byte) { s.state.AddState(types.BytesToHash(root), nTrie) - return &Snapshot{trie: nTrie, state: s.state}, root + for _, t := range s.tracers { + t.Proof() + } + + return &Snapshot{trie: nTrie, state: s.state, trace: &types.Trace{}}, s.trace, root +} + +type tracer struct { + // isAccountTrie represents whether the trace is in an + // acount or storage trie + isAccountTrie bool + + // nodes is the list of nodes from the partial merkle trie + // accessed during the trace + nodes []Node + + // trace is the reference object to dump the traces + trace *types.Trace +} + +func (t *tracer) Trace(n Node) { + if t.nodes == nil { + t.nodes = []Node{} + } + + t.nodes = append(t.nodes, n) +} + +func (t *tracer) Proof() { + hasher, _ := hasherPool.Get().(*hasher) + defer hasherPool.Put(hasher) + + hasher.WithBatch(t) + + arena, _ := hasher.AcquireArena() + defer hasher.ReleaseArenas(0) + + for _, i := range t.nodes { + if i != nil { + hasher.hashImpl(i, arena, false, 0) + } + } +} + +func (t *tracer) Put(k, v []byte) { + kStr := hex.EncodeToString(k) + + if t.isAccountTrie { + if t.trace.AccountTrie == nil { + t.trace.AccountTrie = map[string]string{} + } + + if _, ok := t.trace.AccountTrie[kStr]; !ok { + t.trace.AccountTrie[kStr] = hex.EncodeToString(v) + } + } else { + if t.trace.StorageTrie == nil { + t.trace.StorageTrie = map[string]string{} + } + + if _, ok := t.trace.StorageTrie[kStr]; !ok { + t.trace.StorageTrie[kStr] = hex.EncodeToString(v) + } + } } diff --git a/state/immutable-trie/state.go b/state/immutable-trie/state.go index 6614604b2e..e8b9d51989 100644 --- a/state/immutable-trie/state.go +++ b/state/immutable-trie/state.go @@ -26,7 +26,7 @@ func NewState(storage Storage) *State { } func (s *State) NewSnapshot() state.Snapshot { - return &Snapshot{state: s, trie: s.newTrie()} + return &Snapshot{state: s, trace: &types.Trace{}, trie: s.newTrie()} } func (s *State) NewSnapshotAt(root types.Hash) (state.Snapshot, error) { @@ -35,7 +35,7 @@ func (s *State) NewSnapshotAt(root types.Hash) (state.Snapshot, error) { return nil, err } - return &Snapshot{state: s, trie: t}, nil + return &Snapshot{state: s, trace: &types.Trace{}, trie: t}, nil } func (s *State) newTrie() *Trie { @@ -47,6 +47,10 @@ func (s *State) SetCode(hash types.Hash, code []byte) { } func (s *State) GetCode(hash types.Hash) ([]byte, bool) { + if hash == types.EmptyCodeHash { + return []byte{}, true + } + return s.storage.GetCode(hash) } diff --git a/state/immutable-trie/state_test.go b/state/immutable-trie/state_test.go index e4e2ce4a98..566a1252d8 100644 --- a/state/immutable-trie/state_test.go +++ b/state/immutable-trie/state_test.go @@ -13,7 +13,6 @@ func TestState(t *testing.T) { func buildPreState(pre state.PreStates) state.Snapshot { storage := NewMemoryStorage() st := NewState(storage) - snap := st.NewSnapshot() - return snap + return st.NewSnapshot() } diff --git a/state/immutable-trie/trie.go b/state/immutable-trie/trie.go index 8143893306..2ae8764924 100644 --- a/state/immutable-trie/trie.go +++ b/state/immutable-trie/trie.go @@ -91,8 +91,9 @@ func (f *FullNode) getEdge(idx byte) Node { } type Trie struct { - root Node - epoch uint32 + root Node + epoch uint32 + tracer Tracer } func NewTrie() *Trie { @@ -101,6 +102,8 @@ func NewTrie() *Trie { func (t *Trie) Get(k []byte, storage Storage) ([]byte, bool) { txn := t.Txn(storage) + txn.tracer = t.tracer + res := txn.Lookup(k) return res, res != nil @@ -113,12 +116,9 @@ func hashit(k []byte) []byte { return h.Sum(nil) } -var accountArenaPool fastrlp.ArenaPool - -// TODO, Remove once we do update in fastrlp (to be fixed in EVM-528) -// -//nolint:godox -var stateArenaPool fastrlp.ArenaPool +var ( + stateArenaPool fastrlp.ArenaPool +) // Hash returns the root hash of the trie. It does not write to the // database and can be used even if the trie doesn't have one. @@ -146,11 +146,16 @@ type Putter interface { Put(k, v []byte) } +type Tracer interface { + Trace(node Node) +} + type Txn struct { root Node epoch uint32 storage Storage batch Putter + tracer Tracer } func (t *Txn) Commit() *Trie { @@ -163,7 +168,11 @@ func (t *Txn) Lookup(key []byte) []byte { return res } -func (t *Txn) lookup(node interface{}, key []byte) (Node, []byte) { +func (t *Txn) lookup(node Node, key []byte) (Node, []byte) { + if t.tracer != nil { + t.tracer.Trace(node) + } + switch n := node.(type) { case nil: return nil, nil @@ -462,6 +471,10 @@ func (t *Txn) delete(node Node, search []byte) (Node, bool) { nc = aux } + if t.tracer != nil { + t.tracer.Trace(nc) + } + obj, ok := nc.(*ShortNode) if !ok { obj := &ShortNode{} diff --git a/state/immutable-trie/trie_test.go b/state/immutable-trie/trie_test.go new file mode 100644 index 0000000000..08fa4e7f14 --- /dev/null +++ b/state/immutable-trie/trie_test.go @@ -0,0 +1,183 @@ +package itrie + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "io/ioutil" + "math/big" + "os" + "testing" + + "github.com/0xPolygon/polygon-edge/state" + "github.com/0xPolygon/polygon-edge/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/syndtr/goleveldb/leveldb" + ldbstorage "github.com/syndtr/goleveldb/leveldb/storage" + "github.com/umbracle/fastrlp" +) + +type traceStore struct { + // trace is the object that holds the traces + tr *tracer +} + +func NewTraceStore(tr *tracer) Storage { + return &traceStore{ + tr: tr, + } +} + +func (ts *traceStore) Get(k []byte) ([]byte, bool) { + var v string + if ts.tr.isAccountTrie { + v = ts.tr.trace.AccountTrie[hex.EncodeToString(k)] + } else { + v = ts.tr.trace.StorageTrie[hex.EncodeToString(k)] + // fmt.Printf("key: %s, value: %s\n", hex.EncodeToString(k), v) + } + val, _ := hex.DecodeString(v) + + if len(val) == 0 { + fmt.Printf("**** value not found for key: %s\n", hex.EncodeToString(k)) + return nil, false + } + + return val, true +} + +func (traceStore) Put(k, v []byte) {} +func (traceStore) Batch() Batch { return nil } +func (traceStore) SetCode(hash types.Hash, code []byte) {} +func (traceStore) GetCode(hash types.Hash) ([]byte, bool) { return nil, false } +func (traceStore) Close() error { return nil } + +func LoadTrace() (*types.Trace, error) { + // Load Trace structure from JSON file. + traceFile, err := os.Open("7410_readable.json") + if err != nil { + return nil, err + } + defer traceFile.Close() + + // Read JSON file and desrialize it into Trace structure. + // Read the whole file + tf, err := ioutil.ReadAll(traceFile) + if err != nil { + return nil, err + } + + trace := &types.Trace{} + err = json.Unmarshal(tf, trace) + if err != nil { + return nil, err + } + + return trace, nil +} + +func TestTrie_Proof(t *testing.T) { + acct := state.Account{ + Balance: big.NewInt(10), + } + val := acct.MarshalWith(&fastrlp.Arena{}).MarshalTo(nil) + + acct2 := state.Account{ + Balance: big.NewInt(20), + } + val2 := acct2.MarshalWith(&fastrlp.Arena{}).MarshalTo(nil) + + tt := NewTrie() + + ldbStorage := ldbstorage.NewMemStorage() + ldb, err := leveldb.Open(ldbStorage, nil) + require.NoError(t, err) + + defer ldb.Close() + + kv := NewKV(ldb) + + txn := tt.Txn(kv) + + tr := &tracer{ + isAccountTrie: true, + trace: &types.Trace{}, + } + txn.tracer = tr + + _, err = txn.Hash() + require.NoError(t, err) + + txn.Insert([]byte{0x1, 0x2}, val) + txn.Insert([]byte{0x1, 0x3}, val2) + txn.Lookup([]byte{0x1, 0x2}) + + txn.Delete([]byte{0x1, 0x3}) + + assert.IsType(t, &ShortNode{}, tr.nodes[0]) + assert.IsType(t, &FullNode{}, tr.nodes[1]) + assert.IsType(t, &ShortNode{}, tr.nodes[2]) + assert.IsType(t, &ValueNode{}, tr.nodes[3]) + _, h := tr.nodes[1].Hash() + assert.False(t, h) + + n := tr.nodes[4].(*ShortNode) + v, _ := n.child.Hash() + assert.Equal(t, val, v) + + tr.Proof() + + for k, v := range tr.trace.AccountTrie { + t.Logf("key: %s, value: %s\n", k, v) + } +} + +func TestTrie_Load(t *testing.T) { + //tt := NewTrie() + + ltr, err := LoadTrace() + require.NoError(t, err) + + accountTracer := &tracer{ + isAccountTrie: true, + trace: ltr, + } + ts := NewTraceStore(accountTracer) + s := NewState(ts) + sn, err := s.NewSnapshotAt(ltr.ParentStateRoot) + require.NoError(t, err) + + addr := types.StringToAddress("0x6FdA56C57B0Acadb96Ed5624aC500C0429d59429") + acc, err := sn.GetAccount(addr) + require.NoError(t, err) + + storageTracer := &tracer{ + isAccountTrie: false, + trace: ltr, + } + ts = NewTraceStore(storageTracer) + s = NewState(ts) + tt, err := s.newTrieAt(acc.Root) + require.NoError(t, err) + + // Load the trie from the trace. + txn := tt.Txn(ts) + + // txn.Insert(types.StringToBytes("0x0000000000000000000000000000000000000000000000000000000000000002"), types.StringToBytes("0x00000000000000000000000000000000000000000000000000000000000048d1")) + + b := txn.Lookup(types.StringToBytes("0x04e2f49b914b2b5972f4e339e6dc75455852ed61bac5676f58a2b7036def7b18")) + t.Logf("value: %s\n", hex.EncodeToString(b)) + + for _, txt := range ltr.TxnTraces { + je := txt.Delta[addr] + for slot, _ := range je.StorageRead { + v := txn.Lookup(slot.Bytes()) + if v == nil { + t.Logf("slot %s not found", slot) + } + + // assert.Equal(t, val.Bytes(), v) + } + } +} diff --git a/state/runtime/allowlist/allowlist.go b/state/runtime/addresslist/addresslist.go similarity index 69% rename from state/runtime/allowlist/allowlist.go rename to state/runtime/addresslist/addresslist.go index 6a0d362956..0046c4113d 100644 --- a/state/runtime/allowlist/allowlist.go +++ b/state/runtime/addresslist/addresslist.go @@ -1,4 +1,4 @@ -package allowlist +package addresslist import ( "bytes" @@ -10,34 +10,34 @@ import ( "github.com/umbracle/ethgo/abi" ) -// list of function methods for the allow list functionality +// list of function methods for the address list functionality var ( - SetAdminFunc = abi.MustNewMethod("function setAdmin(address)") - SetEnabledSignatureFunc = abi.MustNewMethod("function setEnabled(address)") - SetNoneFunc = abi.MustNewMethod("function setNone(address)") - ReadAllowListFunc = abi.MustNewMethod("function readAllowList(address) returns (uint256)") + SetAdminFunc = abi.MustNewMethod("function setAdmin(address)") + SetEnabledFunc = abi.MustNewMethod("function setEnabled(address)") + SetNoneFunc = abi.MustNewMethod("function setNone(address)") + ReadAddressListFunc = abi.MustNewMethod("function readAddressList(address) returns (uint256)") ) // list of gas costs for the operations var ( - writeAllowListCost = uint64(20000) - readAllowListCost = uint64(5000) + writeAddressListCost = uint64(20000) + readAddressListCost = uint64(5000) ) -type AllowList struct { +type AddressList struct { state stateRef addr types.Address } -func NewAllowList(state stateRef, addr types.Address) *AllowList { - return &AllowList{state: state, addr: addr} +func NewAddressList(state stateRef, addr types.Address) *AddressList { + return &AddressList{state: state, addr: addr} } -func (a *AllowList) Addr() types.Address { +func (a *AddressList) Addr() types.Address { return a.addr } -func (a *AllowList) Run(c *runtime.Contract, host runtime.Host, _ *chain.ForksInTime) *runtime.ExecutionResult { +func (a *AddressList) Run(c *runtime.Contract, host runtime.Host, _ *chain.ForksInTime) *runtime.ExecutionResult { ret, gasUsed, err := a.runInputCall(c.Caller, c.Input, c.Gas, c.Static) res := &runtime.ExecutionResult{ @@ -55,9 +55,10 @@ var ( errInputTooShort = fmt.Errorf("wrong input size, expected 32") errFunctionNotFound = fmt.Errorf("function not found") errWriteProtection = fmt.Errorf("write protection") + errAdminSelfRemove = fmt.Errorf("cannot remove admin role from caller") ) -func (a *AllowList) runInputCall(caller types.Address, input []byte, +func (a *AddressList) runInputCall(caller types.Address, input []byte, gas uint64, isStatic bool) ([]byte, uint64, error) { // decode the function signature from the input if len(input) < types.SignatureSize { @@ -87,8 +88,8 @@ func (a *AllowList) runInputCall(caller types.Address, input []byte, inputAddr := types.BytesToAddress(inputBytes) - if bytes.Equal(sig, ReadAllowListFunc.ID()) { - if err := consumeGas(readAllowListCost); err != nil { + if bytes.Equal(sig, ReadAddressListFunc.ID()) { + if err := consumeGas(readAddressListCost); err != nil { return nil, 0, err } @@ -102,7 +103,7 @@ func (a *AllowList) runInputCall(caller types.Address, input []byte, var updateRole Role if bytes.Equal(sig, SetAdminFunc.ID()) { updateRole = AdminRole - } else if bytes.Equal(sig, SetEnabledSignatureFunc.ID()) { + } else if bytes.Equal(sig, SetEnabledFunc.ID()) { updateRole = EnabledRole } else if bytes.Equal(sig, SetNoneFunc.ID()) { updateRole = NoRole @@ -110,7 +111,7 @@ func (a *AllowList) runInputCall(caller types.Address, input []byte, return nil, 0, errFunctionNotFound } - if err := consumeGas(writeAllowListCost); err != nil { + if err := consumeGas(writeAddressListCost); err != nil { return nil, gasUsed, err } @@ -125,16 +126,21 @@ func (a *AllowList) runInputCall(caller types.Address, input []byte, return nil, gasUsed, runtime.ErrNotAuth } + // An admin can not remove himself from the list + if addrRole == AdminRole && caller == inputAddr { + return nil, gasUsed, errAdminSelfRemove + } + a.SetRole(inputAddr, updateRole) return nil, gasUsed, nil } -func (a *AllowList) SetRole(addr types.Address, role Role) { +func (a *AddressList) SetRole(addr types.Address, role Role) { a.state.SetState(a.addr, types.BytesToHash(addr.Bytes()), types.Hash(role)) } -func (a *AllowList) GetRole(addr types.Address) Role { +func (a *AddressList) GetRole(addr types.Address) Role { res := a.state.GetStorage(a.addr, types.BytesToHash(addr.Bytes())) return Role(res) diff --git a/state/runtime/allowlist/allowlist_test.go b/state/runtime/addresslist/addresslist_test.go similarity index 71% rename from state/runtime/allowlist/allowlist_test.go rename to state/runtime/addresslist/addresslist_test.go index c8c6ad83aa..ad13e0a527 100644 --- a/state/runtime/allowlist/allowlist_test.go +++ b/state/runtime/addresslist/addresslist_test.go @@ -1,4 +1,4 @@ -package allowlist +package addresslist import ( "testing" @@ -21,16 +21,16 @@ func (m *mockState) GetStorage(addr types.Address, key types.Hash) types.Hash { return m.state[key] } -func newMockAllowList() *AllowList { +func newMockAddressList() *AddressList { state := &mockState{ state: map[types.Hash]types.Hash{}, } - return NewAllowList(state, types.Address{}) + return NewAddressList(state, types.Address{}) } -func TestAllowList_WrongInput(t *testing.T) { - a := newMockAllowList() +func TestAddressList_WrongInput(t *testing.T) { + a := newMockAddressList() input := []byte{} @@ -51,20 +51,20 @@ func TestAllowList_WrongInput(t *testing.T) { require.Equal(t, errFunctionNotFound, err) } -func TestAllowList_ReadOp_NotEnoughGas(t *testing.T) { - a := newMockAllowList() +func TestAddressList_ReadOp_NotEnoughGas(t *testing.T) { + a := newMockAddressList() - input, _ := ReadAllowListFunc.Encode([]interface{}{types.Address{}}) + input, _ := ReadAddressListFunc.Encode([]interface{}{types.Address{}}) _, _, err := a.runInputCall(types.Address{}, input, 0, false) require.Equal(t, runtime.ErrOutOfGas, err) - _, _, err = a.runInputCall(types.Address{}, input, readAllowListCost-1, false) + _, _, err = a.runInputCall(types.Address{}, input, readAddressListCost-1, false) require.Equal(t, runtime.ErrOutOfGas, err) } -func TestAllowList_ReadOp_Full(t *testing.T) { - a := newMockAllowList() +func TestAddressList_ReadOp_Full(t *testing.T) { + a := newMockAddressList() a.SetRole(types.Address{}, AdminRole) cases := []struct { @@ -84,48 +84,48 @@ func TestAllowList_ReadOp_Full(t *testing.T) { } for _, c := range cases { - input, _ := ReadAllowListFunc.Encode([]interface{}{c.addr}) - role, gasUsed, err := a.runInputCall(types.Address{}, input, readAllowListCost, false) + input, _ := ReadAddressListFunc.Encode([]interface{}{c.addr}) + role, gasUsed, err := a.runInputCall(types.Address{}, input, readAddressListCost, false) require.NoError(t, err) - require.Equal(t, gasUsed, readAllowListCost) + require.Equal(t, gasUsed, readAddressListCost) require.Equal(t, c.role.Bytes(), role) } } -func TestAllowList_WriteOp_NotEnoughGas(t *testing.T) { - a := newMockAllowList() +func TestAddressList_WriteOp_NotEnoughGas(t *testing.T) { + a := newMockAddressList() input, _ := SetAdminFunc.Encode([]interface{}{types.Address{}}) _, _, err := a.runInputCall(types.Address{}, input, 0, false) require.Equal(t, runtime.ErrOutOfGas, err) - _, _, err = a.runInputCall(types.Address{}, input, writeAllowListCost-1, false) + _, _, err = a.runInputCall(types.Address{}, input, writeAddressListCost-1, false) require.Equal(t, runtime.ErrOutOfGas, err) } -func TestAllowList_WriteOp_CannotWriteInStaticCall(t *testing.T) { - a := newMockAllowList() +func TestAddressList_WriteOp_CannotWriteInStaticCall(t *testing.T) { + a := newMockAddressList() input, _ := SetAdminFunc.Encode([]interface{}{types.Address{}}) - _, gasCost, err := a.runInputCall(types.Address{}, input, writeAllowListCost, true) - require.Equal(t, writeAllowListCost, gasCost) + _, gasCost, err := a.runInputCall(types.Address{}, input, writeAddressListCost, true) + require.Equal(t, writeAddressListCost, gasCost) require.Equal(t, err, errWriteProtection) } -func TestAllowList_WriteOp_OnlyAdminCanUpdate(t *testing.T) { - a := newMockAllowList() +func TestAddressList_WriteOp_OnlyAdminCanUpdate(t *testing.T) { + a := newMockAddressList() input, _ := SetAdminFunc.Encode([]interface{}{types.Address{}}) - _, gasCost, err := a.runInputCall(types.Address{}, input, writeAllowListCost, false) - require.Equal(t, writeAllowListCost, gasCost) + _, gasCost, err := a.runInputCall(types.Address{}, input, writeAddressListCost, false) + require.Equal(t, writeAddressListCost, gasCost) require.Equal(t, err, runtime.ErrNotAuth) } -func TestAllowList_WriteOp_Full(t *testing.T) { - a := newMockAllowList() +func TestAddressList_WriteOp_Full(t *testing.T) { + a := newMockAddressList() a.SetRole(types.Address{}, AdminRole) targetAddr := types.Address{0x1} @@ -138,15 +138,15 @@ func TestAllowList_WriteOp_Full(t *testing.T) { role Role }{ {SetAdminFunc, AdminRole}, - {SetEnabledSignatureFunc, EnabledRole}, + {SetEnabledFunc, EnabledRole}, {SetNoneFunc, NoRole}, } for _, c := range cases { input, _ := c.method.Encode([]interface{}{targetAddr}) - ret, gasCost, err := a.runInputCall(types.Address{}, input, writeAllowListCost, false) - require.Equal(t, writeAllowListCost, gasCost) + ret, gasCost, err := a.runInputCall(types.Address{}, input, writeAddressListCost, false) + require.Equal(t, writeAddressListCost, gasCost) require.NoError(t, err) require.Empty(t, ret) require.Equal(t, c.role, a.GetRole(targetAddr)) diff --git a/state/runtime/allowlist/genesis.go b/state/runtime/addresslist/genesis.go similarity index 85% rename from state/runtime/allowlist/genesis.go rename to state/runtime/addresslist/genesis.go index 025a33211a..b2b20bb805 100644 --- a/state/runtime/allowlist/genesis.go +++ b/state/runtime/addresslist/genesis.go @@ -1,4 +1,4 @@ -package allowlist +package addresslist import ( "math/big" @@ -7,9 +7,9 @@ import ( "github.com/0xPolygon/polygon-edge/types" ) -func ApplyGenesisAllocs(chain *chain.Genesis, allowListAddr types.Address, config *chain.AllowListConfig) { - allocList := &AllowList{ - addr: allowListAddr, +func ApplyGenesisAllocs(chain *chain.Genesis, addressListAddr types.Address, config *chain.AddressListConfig) { + allocList := &AddressList{ + addr: addressListAddr, state: &genesisState{chain}, } diff --git a/state/runtime/allowlist/genesis_test.go b/state/runtime/addresslist/genesis_test.go similarity index 94% rename from state/runtime/allowlist/genesis_test.go rename to state/runtime/addresslist/genesis_test.go index 64a8e34e9b..86eee51603 100644 --- a/state/runtime/allowlist/genesis_test.go +++ b/state/runtime/addresslist/genesis_test.go @@ -1,4 +1,4 @@ -package allowlist +package addresslist import ( "math/big" @@ -20,7 +20,7 @@ func TestGenesis(t *testing.T) { Alloc: map[types.Address]*chain.GenesisAccount{}, } - config := &chain.AllowListConfig{ + config := &chain.AddressListConfig{ AdminAddresses: []types.Address{ one, }, diff --git a/state/runtime/evm/dispatch_table.go b/state/runtime/evm/dispatch_table.go index 7214a18dcd..e8afeae0f5 100644 --- a/state/runtime/evm/dispatch_table.go +++ b/state/runtime/evm/dispatch_table.go @@ -123,6 +123,7 @@ func init() { register(NUMBER, handler{opNumber, 0, 2}) register(DIFFICULTY, handler{opDifficulty, 0, 2}) register(GASLIMIT, handler{opGasLimit, 0, 2}) + register(BASEFEE, handler{opBaseFee, 0, 2}) register(SELFDESTRUCT, handler{opSelfDestruct, 1, 0}) diff --git a/state/runtime/evm/evm_fuzz_test.go b/state/runtime/evm/evm_fuzz_test.go new file mode 100644 index 0000000000..31a8b66458 --- /dev/null +++ b/state/runtime/evm/evm_fuzz_test.go @@ -0,0 +1,193 @@ +package evm + +import ( + "errors" + "math/big" + "testing" + + "github.com/0xPolygon/polygon-edge/chain" + "github.com/0xPolygon/polygon-edge/state/runtime" + "github.com/0xPolygon/polygon-edge/types" + go_fuzz_utils "github.com/trailofbits/go-fuzz-utils" +) + +var _ runtime.Host = &mockHostF{} + +// mockHostF is a struct which meets the requirements of runtime.Host interface but returns naive data +type mockHostF struct { + // to use + tracer runtime.VMTracer + storage map[types.Address]map[types.Hash]types.Hash + balances map[types.Address]*big.Int + nonces map[types.Address]uint64 + + // to fuzz + refund uint64 + blockHash types.Hash +} + +func (m *mockHostF) AccountExists(addr types.Address) bool { + if _, ok := m.nonces[addr]; ok { + return true + } + + return false +} + +func (m *mockHostF) GetStorage(addr types.Address, key types.Hash) types.Hash { + if val, ok := m.storage[addr][key]; !ok { + return types.Hash{} + } else { + return val + } +} + +func (m *mockHostF) SetStorage( + addr types.Address, + key types.Hash, + value types.Hash, + config *chain.ForksInTime, +) runtime.StorageStatus { + if _, ok := m.storage[addr]; !ok { + m.storage[addr] = make(map[types.Hash]types.Hash) + } + + m.storage[addr][key] = value + + return runtime.StorageModified +} + +func (m *mockHostF) SetState(addr types.Address, key types.Hash, value types.Hash) { + return +} + +func (m *mockHostF) GetBalance(addr types.Address) *big.Int { + if b, ok := m.balances[addr]; !ok { + m.balances[addr] = big.NewInt(0) + + return m.balances[addr] + } else { + return b + } +} + +func (m *mockHostF) GetCodeSize(addr types.Address) int { + return 0 +} + +func (m *mockHostF) GetCodeHash(addr types.Address) types.Hash { + return types.Hash{} +} + +func (m *mockHostF) GetCode(addr types.Address) []byte { + return nil +} + +func (m *mockHostF) Selfdestruct(addr types.Address, beneficiary types.Address) { + return +} +func (m *mockHostF) GetTxContext() runtime.TxContext { + return runtime.TxContext{} +} + +func (m *mockHostF) GetBlockHash(number int64) types.Hash { + return m.blockHash +} + +func (m *mockHostF) EmitLog(addr types.Address, topics []types.Hash, data []byte) { + return +} + +func (m *mockHostF) Callx(c *runtime.Contract, h runtime.Host) *runtime.ExecutionResult { + return &runtime.ExecutionResult{} +} + +func (m *mockHostF) Empty(addr types.Address) bool { + return true +} + +func (m *mockHostF) GetNonce(addr types.Address) uint64 { + if nonce, ok := m.nonces[addr]; !ok { + m.nonces[addr] = 0 + + return 0 + } else { + return nonce + } +} + +func (m *mockHostF) Transfer(from types.Address, to types.Address, amount *big.Int) error { + f := m.GetBalance(from) + t := m.GetBalance(to) + + if f.Cmp(amount) < 0 { + return errors.New("not enough balance") + } + + f.Sub(f, amount) + t.Add(t, amount) + + return nil +} + +func (m *mockHostF) GetTracer() runtime.VMTracer { + return m.tracer +} + +func (m *mockHostF) GetRefund() uint64 { + return m.refund +} + +func FuzzTestEVM(f *testing.F) { + seed := []byte{ + PUSH1, 0x01, PUSH1, 0x02, ADD, + PUSH1, 0x00, MSTORE8, + PUSH1, 0x01, PUSH1, 0x00, RETURN, + } + + f.Add(seed) + + config := &chain.ForksInTime{ + Byzantium: true, + } + + evm := NewEVM() + + f.Fuzz(func(t *testing.T, input []byte) { + tp, err := go_fuzz_utils.NewTypeProvider(input) + if err != nil { + return + } + + err = tp.SetParamsSliceBounds(1, 4*1024) + if err != nil { + return + } + + refund, err := tp.GetUint64() + if err != nil { + return + } + + blockHashI, err := tp.GetNBytes(types.HashLength) + if err != nil { + return + } + + blockHash := types.BytesToHash(blockHashI) + host := &mockHostF{ + refund: refund, blockHash: blockHash, + storage: make(map[types.Address]map[types.Hash]types.Hash), + balances: make(map[types.Address]*big.Int), + nonces: make(map[types.Address]uint64), + } + + code, err := tp.GetBytes() + if err != nil { + return + } + + contract := newMockContract(big.NewInt(0), 10000000, code) + evm.Run(contract, host, config) + }) +} diff --git a/state/runtime/evm/evm_test.go b/state/runtime/evm/evm_test.go index d2e0f95a42..f22900a968 100644 --- a/state/runtime/evm/evm_test.go +++ b/state/runtime/evm/evm_test.go @@ -156,7 +156,7 @@ func TestRun(t *testing.T) { ReturnValue: nil, GasLeft: 0, GasUsed: 5000, - Err: errStackUnderflow, + Err: &runtime.StackUnderflowError{StackLen: 0, Required: 2}, }, }, { @@ -339,7 +339,7 @@ func TestRunWithTracer(t *testing.T) { "cost": uint64(2), "lastReturnData": []byte{}, "depth": 1, - "err": errStackUnderflow, + "err": &runtime.StackUnderflowError{StackLen: 0, Required: 1}, }, }, }, diff --git a/state/runtime/evm/instructions.go b/state/runtime/evm/instructions.go index 9ef721115e..4f9c798e11 100644 --- a/state/runtime/evm/instructions.go +++ b/state/runtime/evm/instructions.go @@ -907,6 +907,16 @@ func opGasLimit(c *state) { c.push1().SetInt64(c.host.GetTxContext().GasLimit) } +func opBaseFee(c *state) { + if !c.config.London { + c.exit(errOpCodeNotFound) + + return + } + + c.push(c.host.GetTxContext().BaseFee) +} + func opSelfDestruct(c *state) { if c.inStaticCall() { c.exit(errWriteProtection) @@ -984,7 +994,7 @@ func opPush(n int) instruction { func opDup(n int) instruction { return func(c *state) { if !c.stackAtLeast(n) { - c.exit(errStackUnderflow) + c.exit(&runtime.StackUnderflowError{StackLen: c.sp, Required: n}) } else { val := c.peekAt(n) c.push1().Set(val) @@ -995,7 +1005,7 @@ func opDup(n int) instruction { func opSwap(n int) instruction { return func(c *state) { if !c.stackAtLeast(n + 1) { - c.exit(errStackUnderflow) + c.exit(&runtime.StackUnderflowError{StackLen: c.sp, Required: n + 1}) } else { c.swap(n) } @@ -1013,7 +1023,7 @@ func opLog(size int) instruction { } if !c.stackAtLeast(2 + size) { - c.exit(errStackUnderflow) + c.exit(&runtime.StackUnderflowError{StackLen: c.sp, Required: 2 + size}) return } @@ -1091,7 +1101,9 @@ func opCreate(op OpCode) instruction { v := c.push1() if op == CREATE && c.config.Homestead && errors.Is(result.Err, runtime.ErrCodeStoreOutOfGas) { v.Set(zero) - } else if result.Failed() && !errors.Is(result.Err, runtime.ErrCodeStoreOutOfGas) { + } else if op == CREATE && result.Failed() && !errors.Is(result.Err, runtime.ErrCodeStoreOutOfGas) { + v.Set(zero) + } else if op == CREATE2 && result.Failed() { v.Set(zero) } else { v.SetBytes(contract.Address.Bytes()) diff --git a/state/runtime/evm/instructions_test.go b/state/runtime/evm/instructions_test.go index 2d29cf2f53..e17f79fdcc 100644 --- a/state/runtime/evm/instructions_test.go +++ b/state/runtime/evm/instructions_test.go @@ -359,6 +359,57 @@ func TestCreate(t *testing.T) { }, }, }, + { + name: "should set zero address if contract call throws any error for CREATE2", + op: CREATE2, + contract: &runtime.Contract{ + Static: false, + Address: addr1, + }, + config: &chain.ForksInTime{ + Homestead: true, + Constantinople: true, + }, + initState: &state{ + gas: 1000, + sp: 4, + stack: []*big.Int{ + big.NewInt(0x01), // salt + big.NewInt(0x01), // length + big.NewInt(0x00), // offset + big.NewInt(0x00), // value + }, + memory: []byte{ + byte(REVERT), + }, + stop: false, + err: nil, + }, + // during creation of code with length 1 for CREATE2 op code, 985 gas units are spent by buildCreateContract() + resultState: &state{ + gas: 15, + sp: 1, + stack: []*big.Int{ + big.NewInt(0x01).SetInt64(0x00), + big.NewInt(0x01), + big.NewInt(0x00), + big.NewInt(0x00), + }, + memory: []byte{ + byte(REVERT), + }, + stop: false, + err: nil, + }, + mockHost: &mockHostForInstructions{ + nonce: 0, + callxResult: &runtime.ExecutionResult{ + // if it is ErrCodeStoreOutOfGas then we set GasLeft to 0 + GasLeft: 0, + Err: runtime.ErrCodeStoreOutOfGas, + }, + }, + }, } for _, tt := range tests { diff --git a/state/runtime/evm/opcodes.go b/state/runtime/evm/opcodes.go index 85bd02d1c5..409180d4dc 100644 --- a/state/runtime/evm/opcodes.go +++ b/state/runtime/evm/opcodes.go @@ -161,6 +161,9 @@ const ( // SELFBALANCE returns the balance of the current account SELFBALANCE = 0x47 + // BASEFEE returns the current base fee value + BASEFEE = 0x48 + // POP pops a (u)int256 off the stack and discards it POP = 0x50 @@ -308,6 +311,7 @@ var opCodeToString = map[OpCode]string{ NUMBER: "NUMBER", DIFFICULTY: "DIFFICULTY", GASLIMIT: "GASLIMIT", + BASEFEE: "BASEFEE", POP: "POP", MLOAD: "MLOAD", MSTORE: "MSTORE", diff --git a/state/runtime/evm/state.go b/state/runtime/evm/state.go index 74199ca4d5..7b5ebd6cd3 100644 --- a/state/runtime/evm/state.go +++ b/state/runtime/evm/state.go @@ -38,8 +38,6 @@ const stackSize = 1024 var ( errOutOfGas = runtime.ErrOutOfGas - errStackUnderflow = runtime.ErrStackUnderflow - errStackOverflow = runtime.ErrStackOverflow errRevert = runtime.ErrExecutionReverted errGasUintOverflow = errors.New("gas uint64 overflow") errWriteProtection = errors.New("write protection") @@ -245,7 +243,7 @@ func (c *state) Run() ([]byte, error) { // check if the depth of the stack is enough for the instruction if c.sp < inst.stack { - c.exit(errStackUnderflow) + c.exit(&runtime.StackUnderflowError{StackLen: c.sp, Required: inst.stack}) c.captureExecutionError(op.String(), c.ip, gasCopy, inst.gas) break @@ -266,7 +264,7 @@ func (c *state) Run() ([]byte, error) { // check if stack size exceeds the max size if c.sp > stackSize { - c.exit(errStackOverflow) + c.exit(&runtime.StackOverflowError{StackLen: c.sp, Limit: stackSize}) break } diff --git a/state/runtime/evm/state_test.go b/state/runtime/evm/state_test.go index 5000ac1381..3bf9d05f72 100644 --- a/state/runtime/evm/state_test.go +++ b/state/runtime/evm/state_test.go @@ -3,6 +3,8 @@ package evm import ( "testing" + "github.com/0xPolygon/polygon-edge/state/runtime" + "github.com/stretchr/testify/assert" ) @@ -68,7 +70,7 @@ func TestStackOverflow(t *testing.T) { s.host = &mockHost{} _, err = s.Run() - assert.Equal(t, errStackOverflow, err) + assert.Equal(t, &runtime.StackOverflowError{StackLen: stackSize + 1, Limit: stackSize}, err) } func TestStackUnderflow(t *testing.T) { @@ -99,7 +101,8 @@ func TestStackUnderflow(t *testing.T) { s.host = &mockHost{} _, err = s.Run() - assert.Equal(t, errStackUnderflow, err) + // need at least one operation on the stack + assert.Equal(t, &runtime.StackUnderflowError{StackLen: 0, Required: 1}, err) } func TestOpcodeNotFound(t *testing.T) { diff --git a/state/runtime/precompiled/precompiled.go b/state/runtime/precompiled/precompiled.go index 2a661bba13..8b33d5eb80 100644 --- a/state/runtime/precompiled/precompiled.go +++ b/state/runtime/precompiled/precompiled.go @@ -161,8 +161,6 @@ func (p *Precompiled) Run(c *runtime.Contract, host runtime.Host, config *chain. var zeroPadding = make([]byte, 64) func (p *Precompiled) leftPad(buf []byte, n int) []byte { - //nolint:godox - // TODO, avoid buffer allocation (to be fixed in EVM-528) l := len(buf) if l > n { return buf diff --git a/state/runtime/runtime.go b/state/runtime/runtime.go index 3ba74d6d27..4ca7c2aa83 100644 --- a/state/runtime/runtime.go +++ b/state/runtime/runtime.go @@ -2,6 +2,7 @@ package runtime import ( "errors" + "fmt" "math/big" "github.com/0xPolygon/polygon-edge/chain" @@ -11,15 +12,17 @@ import ( // TxContext is the context of the transaction type TxContext struct { - GasPrice types.Hash - Origin types.Address - Coinbase types.Address - Number int64 - Timestamp int64 - GasLimit int64 - ChainID int64 - Difficulty types.Hash - Tracer tracer.Tracer + GasPrice types.Hash + Origin types.Address + Coinbase types.Address + Number int64 + Timestamp int64 + GasLimit int64 + ChainID int64 + Difficulty types.Hash + Tracer tracer.Tracer + BaseFee *big.Int + BurnContract types.Address } // StorageStatus is the status of the storage access @@ -128,20 +131,40 @@ func (r *ExecutionResult) UpdateGasUsed(gasLimit uint64, refund uint64) { var ( ErrOutOfGas = errors.New("out of gas") - ErrStackOverflow = errors.New("stack overflow") - ErrStackUnderflow = errors.New("stack underflow") ErrNotEnoughFunds = errors.New("not enough funds") ErrInsufficientBalance = errors.New("insufficient balance for transfer") - ErrMaxCodeSizeExceeded = errors.New("evm: max code size exceeded") + ErrMaxCodeSizeExceeded = errors.New("max code size exceeded") ErrContractAddressCollision = errors.New("contract address collision") ErrDepth = errors.New("max call depth exceeded") - ErrExecutionReverted = errors.New("execution was reverted") + ErrExecutionReverted = errors.New("execution reverted") ErrCodeStoreOutOfGas = errors.New("contract creation code storage out of gas") ErrUnauthorizedCaller = errors.New("unauthorized caller") ErrInvalidInputData = errors.New("invalid input data") ErrNotAuth = errors.New("not in allow list") ) +// StackUnderflowError wraps an evm error when the items on the stack less +// than the minimal requirement. +type StackUnderflowError struct { + StackLen int + Required int +} + +func (e *StackUnderflowError) Error() string { + return fmt.Sprintf("stack underflow (%d <=> %d)", e.StackLen, e.Required) +} + +// StackOverflowError wraps an evm error when the items on the stack exceeds +// the maximum allowance. +type StackOverflowError struct { + StackLen int + Limit int +} + +func (e *StackOverflowError) Error() string { + return fmt.Sprintf("stack limit reached %d (%d)", e.StackLen, e.Limit) +} + type CallType int const ( diff --git a/state/runtime/tracer/structtracer/tracer.go b/state/runtime/tracer/structtracer/tracer.go index 24260abcc7..42278912ab 100644 --- a/state/runtime/tracer/structtracer/tracer.go +++ b/state/runtime/tracer/structtracer/tracer.go @@ -55,17 +55,22 @@ type StructTracer struct { consumedGas uint64 output []byte err error - storage map[types.Address]map[types.Hash]types.Hash - currentMemory []byte - currentStack []*big.Int + storage []map[types.Address]map[types.Hash]types.Hash + currentMemory []([]byte) + currentStack []([]*big.Int) } func NewStructTracer(config Config) *StructTracer { + storage := make([](map[types.Address]map[types.Hash]types.Hash), 1) + storage[0] = make(map[types.Address]map[types.Hash]types.Hash) + return &StructTracer{ - Config: config, - cancelLock: sync.RWMutex{}, - storage: make(map[types.Address]map[types.Hash]types.Hash), + Config: config, + cancelLock: sync.RWMutex{}, + storage: storage, + currentMemory: make([]([]byte), 1), + currentStack: make([]([]*big.Int), 1), } } @@ -92,9 +97,10 @@ func (t *StructTracer) Clear() { t.consumedGas = 0 t.output = t.output[:0] t.err = nil - t.storage = make(map[types.Address]map[types.Hash]types.Hash) - t.currentMemory = t.currentMemory[:0] - t.currentStack = t.currentStack[:0] + t.storage = make([](map[types.Address]map[types.Hash]types.Hash), 1) + t.storage[0] = make(map[types.Address]map[types.Hash]types.Hash) + t.currentMemory = make([]([]byte), 1) + t.currentStack = make([]([]*big.Int), 1) } func (t *StructTracer) TxStart(gasLimit uint64) { @@ -141,9 +147,9 @@ func (t *StructTracer) CaptureState( return } - t.captureMemory(memory) + t.captureMemory(memory, opCode) - t.captureStack(stack, sp) + t.captureStack(stack, sp, opCode) t.captureStorage( stack, @@ -156,33 +162,46 @@ func (t *StructTracer) CaptureState( func (t *StructTracer) captureMemory( memory []byte, + opCode int, ) { if !t.Config.EnableMemory { return } // always allocate new space to get new reference - t.currentMemory = make([]byte, len(memory)) + currentMemory := make([]byte, len(memory)) + copy(currentMemory, memory) - copy(t.currentMemory, memory) + t.currentMemory[len(t.currentMemory)-1] = currentMemory + + if opCode == evm.CALL || opCode == evm.STATICCALL { + t.currentMemory = append(t.currentMemory, make([]byte, len(memory))) + } } func (t *StructTracer) captureStack( stack []*big.Int, sp int, + opCode int, ) { if !t.Config.EnableStack { return } - t.currentStack = make([]*big.Int, sp) + currentStack := make([]*big.Int, sp) for i, v := range stack { if i >= sp { break } - t.currentStack[i] = new(big.Int).Set(v) + currentStack[i] = new(big.Int).Set(v) + } + + t.currentStack[len(t.currentStack)-1] = currentStack + + if opCode == evm.CALL || opCode == evm.STATICCALL { + t.currentStack = append(t.currentStack, make([]*big.Int, sp)) } } @@ -193,11 +212,16 @@ func (t *StructTracer) captureStorage( sp int, host tracer.RuntimeHost, ) { + if opCode == evm.CALL || opCode == evm.STATICCALL { + t.storage = append(t.storage, make(map[types.Address]map[types.Hash]types.Hash)) + } + if !t.Config.EnableStorage || (opCode != evm.SLOAD && opCode != evm.SSTORE) { return } - _, initialized := t.storage[contractAddress] + storage := &t.storage[len(t.storage)-1] + _, initialized := (*storage)[contractAddress] switch opCode { case evm.SLOAD: @@ -206,13 +230,13 @@ func (t *StructTracer) captureStorage( } if !initialized { - t.storage[contractAddress] = make(map[types.Hash]types.Hash) + (*storage)[contractAddress] = make(map[types.Hash]types.Hash) } slot := types.BytesToHash(stack[sp-1].Bytes()) value := host.GetStorage(contractAddress, slot) - t.storage[contractAddress][slot] = value + (*storage)[contractAddress][slot] = value case evm.SSTORE: if sp < 2 { @@ -220,13 +244,13 @@ func (t *StructTracer) captureStorage( } if !initialized { - t.storage[contractAddress] = make(map[types.Hash]types.Hash) + (*storage)[contractAddress] = make(map[types.Hash]types.Hash) } - slot := types.BytesToHash(stack[sp-2].Bytes()) - value := types.BytesToHash(stack[sp-1].Bytes()) + slot := types.BytesToHash(stack[sp-1].Bytes()) + value := types.BytesToHash(stack[sp-2].Bytes()) - t.storage[contractAddress][slot] = value + (*storage)[contractAddress][slot] = value } } @@ -250,16 +274,22 @@ func (t *StructTracer) ExecuteState( ) if t.Config.EnableMemory { - memorySize = len(t.currentMemory) + if opCode == evm.OpCode(evm.CALL).String() || opCode == evm.OpCode(evm.STATICCALL).String() { + t.currentMemory = t.currentMemory[:len(t.currentMemory)-1] + } + memorySize = len(t.currentMemory[len(t.currentMemory)-1]) memory = make([]byte, memorySize) - copy(memory, t.currentMemory) + copy(memory, t.currentMemory[len(t.currentMemory)-1]) } if t.Config.EnableStack { - stack = make([]*big.Int, len(t.currentStack)) + if opCode == evm.OpCode(evm.CALL).String() || opCode == evm.OpCode(evm.STATICCALL).String() { + t.currentStack = t.currentStack[:len(t.currentStack)-1] + } - for i, v := range t.currentStack { + stack = make([]*big.Int, len(t.currentStack[len(t.currentStack)-1])) + for i, v := range t.currentStack[len(t.currentStack)-1] { stack[i] = new(big.Int).Set(v) } } @@ -271,7 +301,12 @@ func (t *StructTracer) ExecuteState( } if t.Config.EnableStorage { - contractStorage, ok := t.storage[contractAddress] + if opCode == evm.OpCode(evm.CALL).String() || opCode == evm.OpCode(evm.STATICCALL).String() { + t.storage = t.storage[:len(t.storage)-1] + } + + contractStorage, ok := t.storage[len(t.storage)-1][contractAddress] + if ok { storage = make(map[types.Hash]types.Hash, len(contractStorage)) diff --git a/state/runtime/tracer/structtracer/tracer_test.go b/state/runtime/tracer/structtracer/tracer_test.go index f2660faedb..abbca4884d 100644 --- a/state/runtime/tracer/structtracer/tracer_test.go +++ b/state/runtime/tracer/structtracer/tracer_test.go @@ -131,16 +131,18 @@ func TestStructTracerClear(t *testing.T) { consumedGas: 512, output: []byte("output example"), err: runtime.ErrInsufficientBalance, - storage: map[types.Address]map[types.Hash]types.Hash{ - types.StringToAddress("1"): { - types.StringToHash("2"): types.StringToHash("3"), + storage: []map[types.Address]map[types.Hash]types.Hash{ + { + types.StringToAddress("1"): { + types.StringToHash("2"): types.StringToHash("3"), + }, }, }, - currentMemory: []byte("memory example"), - currentStack: []*big.Int{ + currentMemory: [][]byte{[]byte("memory example")}, + currentStack: []([]*big.Int){[]*big.Int{ new(big.Int).SetUint64(1), new(big.Int).SetUint64(2), - }, + }}, } tracer.Clear() @@ -154,16 +156,18 @@ func TestStructTracerClear(t *testing.T) { EnableStorage: true, EnableReturnData: true, }, - reason: nil, - interrupt: false, - logs: []StructLog{}, - gasLimit: 0, - consumedGas: 0, - output: []byte{}, - err: nil, - storage: map[types.Address]map[types.Hash]types.Hash{}, - currentMemory: []byte{}, - currentStack: []*big.Int{}, + reason: nil, + interrupt: false, + logs: []StructLog{}, + gasLimit: 0, + consumedGas: 0, + output: []byte{}, + err: nil, + storage: []map[types.Address]map[types.Hash]types.Hash{ + make(map[types.Address]map[types.Hash]types.Hash), + }, + currentMemory: make([]([]byte), 1), + currentStack: make([]([]*big.Int), 1), }, tracer, ) @@ -183,9 +187,13 @@ func TestStructTracerTxStart(t *testing.T) { assert.Equal( t, &StructTracer{ - Config: testEmptyConfig, - storage: make(map[types.Address]map[types.Hash]types.Hash), - gasLimit: gasLimit, + Config: testEmptyConfig, + storage: []map[types.Address]map[types.Hash]types.Hash{ + make(map[types.Address]map[types.Hash]types.Hash), + }, + gasLimit: gasLimit, + currentMemory: make([]([]byte), 1), + currentStack: make([]([]*big.Int), 1), }, tracer, ) @@ -207,10 +215,14 @@ func TestStructTracerTxEnd(t *testing.T) { assert.Equal( t, &StructTracer{ - Config: testEmptyConfig, - storage: make(map[types.Address]map[types.Hash]types.Hash), - gasLimit: gasLimit, - consumedGas: gasLimit - gasLeft, + Config: testEmptyConfig, + storage: []map[types.Address]map[types.Hash]types.Hash{ + make(map[types.Address]map[types.Hash]types.Hash), + }, + gasLimit: gasLimit, + consumedGas: gasLimit - gasLeft, + currentMemory: make([]([]byte), 1), + currentStack: make([]([]*big.Int), 1), }, tracer, ) @@ -260,10 +272,14 @@ func TestStructTracerCallEnd(t *testing.T) { output: output, err: err, expected: &StructTracer{ - Config: testEmptyConfig, - storage: make(map[types.Address]map[types.Hash]types.Hash), - output: output, - err: err, + Config: testEmptyConfig, + storage: []map[types.Address]map[types.Hash]types.Hash{ + make(map[types.Address]map[types.Hash]types.Hash), + }, + output: output, + err: err, + currentMemory: make([]([]byte), 1), + currentStack: make([]([]*big.Int), 1), }, }, { @@ -272,8 +288,12 @@ func TestStructTracerCallEnd(t *testing.T) { output: output, err: err, expected: &StructTracer{ - Config: testEmptyConfig, - storage: make(map[types.Address]map[types.Hash]types.Hash), + Config: testEmptyConfig, + storage: []map[types.Address]map[types.Hash]types.Hash{ + make(map[types.Address]map[types.Hash]types.Hash), + }, + currentMemory: make([]([]byte), 1), + currentStack: make([]([]*big.Int), 1), }, }, } @@ -301,11 +321,11 @@ func TestStructTracerCaptureState(t *testing.T) { t.Parallel() var ( - memory = []byte("memory") - stack = []*big.Int{ - big.NewInt(1), - big.NewInt(2), - } + memory = [][]byte{[]byte("memory")} + stack = []([]*big.Int){[]*big.Int{ + big.NewInt(1), /* value */ + big.NewInt(2), /* key */ + }} contractAddress = types.StringToAddress("3") storageValue = types.StringToHash("4") ) @@ -317,8 +337,8 @@ func TestStructTracerCaptureState(t *testing.T) { tracer *StructTracer // input - memory []byte - stack []*big.Int + memory [][]byte + stack [][]*big.Int opCode int contractAddress types.Address sp int @@ -335,6 +355,7 @@ func TestStructTracerCaptureState(t *testing.T) { Config: Config{ EnableMemory: true, }, + currentMemory: make([]([]byte), 1), }, memory: memory, stack: stack, @@ -359,6 +380,7 @@ func TestStructTracerCaptureState(t *testing.T) { Config: Config{ EnableStack: true, }, + currentStack: make([]([]*big.Int), 1), }, memory: memory, stack: stack, @@ -383,7 +405,9 @@ func TestStructTracerCaptureState(t *testing.T) { Config: Config{ EnableStorage: true, }, - storage: make(map[types.Address]map[types.Hash]types.Hash), + storage: []map[types.Address]map[types.Hash]types.Hash{ + make(map[types.Address]map[types.Hash]types.Hash), + }, }, memory: memory, stack: stack, @@ -405,9 +429,11 @@ func TestStructTracerCaptureState(t *testing.T) { Config: Config{ EnableStorage: true, }, - storage: map[types.Address]map[types.Hash]types.Hash{ - contractAddress: { - types.BytesToHash(big.NewInt(2).Bytes()): storageValue, + storage: [](map[types.Address]map[types.Hash]types.Hash){ + map[types.Address]map[types.Hash]types.Hash{ + contractAddress: { + types.BytesToHash(big.NewInt(2).Bytes()): storageValue, + }, }, }, }, @@ -419,7 +445,9 @@ func TestStructTracerCaptureState(t *testing.T) { Config: Config{ EnableStorage: true, }, - storage: make(map[types.Address]map[types.Hash]types.Hash), + storage: []map[types.Address]map[types.Hash]types.Hash{ + make(map[types.Address]map[types.Hash]types.Hash), + }, }, memory: memory, stack: stack, @@ -434,12 +462,13 @@ func TestStructTracerCaptureState(t *testing.T) { Config: Config{ EnableStorage: true, }, - storage: map[types.Address]map[types.Hash]types.Hash{ - contractAddress: { - types.BytesToHash(big.NewInt(1).Bytes()): types.BytesToHash(big.NewInt(2).Bytes()), + storage: []map[types.Address]map[types.Hash]types.Hash{ + { + contractAddress: { + types.BytesToHash(big.NewInt(2).Bytes()): types.BytesToHash(big.NewInt(1).Bytes()), + }, }, - }, - }, + }}, expectedVMState: &mockState{}, }, { @@ -471,7 +500,9 @@ func TestStructTracerCaptureState(t *testing.T) { Config: Config{ EnableStorage: true, }, - storage: make(map[types.Address]map[types.Hash]types.Hash), + storage: []map[types.Address]map[types.Hash]types.Hash{ + make(map[types.Address]map[types.Hash]types.Hash), + }, }, memory: memory, stack: stack, @@ -486,7 +517,9 @@ func TestStructTracerCaptureState(t *testing.T) { Config: Config{ EnableStorage: true, }, - storage: map[types.Address]map[types.Hash]types.Hash{}, + storage: []map[types.Address]map[types.Hash]types.Hash{ + make(map[types.Address]map[types.Hash]types.Hash), + }, }, expectedVMState: &mockState{}, }, @@ -496,7 +529,9 @@ func TestStructTracerCaptureState(t *testing.T) { Config: Config{ EnableStorage: true, }, - storage: make(map[types.Address]map[types.Hash]types.Hash), + storage: []map[types.Address]map[types.Hash]types.Hash{ + make(map[types.Address]map[types.Hash]types.Hash), + }, }, memory: memory, stack: stack, @@ -511,7 +546,9 @@ func TestStructTracerCaptureState(t *testing.T) { Config: Config{ EnableStorage: true, }, - storage: map[types.Address]map[types.Hash]types.Hash{}, + storage: []map[types.Address]map[types.Hash]types.Hash{ + make(map[types.Address]map[types.Hash]types.Hash), + }, }, expectedVMState: &mockState{}, }, @@ -524,8 +561,8 @@ func TestStructTracerCaptureState(t *testing.T) { t.Parallel() test.tracer.CaptureState( - test.memory, - test.stack, + test.memory[0], + test.stack[0], test.opCode, test.contractAddress, test.sp, @@ -562,8 +599,8 @@ func TestStructTracerExecuteState(t *testing.T) { err = errors.New("err") refund = uint64(10000) - memory = []byte("memory sample") - storage = map[types.Address]map[types.Hash]types.Hash{ + memory = [][]byte{[]byte("memory sample")} + storage = []map[types.Address]map[types.Hash]types.Hash{{ contractAddress: { types.StringToHash("1"): types.StringToHash("2"), types.StringToHash("3"): types.StringToHash("4"), @@ -572,6 +609,7 @@ func TestStructTracerExecuteState(t *testing.T) { types.StringToHash("5"): types.StringToHash("6"), types.StringToHash("7"): types.StringToHash("8"), }, + }, } ) @@ -657,8 +695,8 @@ func TestStructTracerExecuteState(t *testing.T) { Op: opCode, Gas: availableGas, GasCost: cost, - Memory: memory, - MemorySize: len(memory), + Memory: memory[0], + MemorySize: len(memory[0]), Stack: nil, ReturnData: nil, Storage: nil, @@ -674,10 +712,10 @@ func TestStructTracerExecuteState(t *testing.T) { Config: Config{ EnableStack: true, }, - currentStack: []*big.Int{ + currentStack: [][]*big.Int{{ big.NewInt(1), big.NewInt(2), - }, + }}, }, contractAddress: contractAddress, ip: ip, diff --git a/state/state.go b/state/state.go index 0a2089b298..1b45ec24b5 100644 --- a/state/state.go +++ b/state/state.go @@ -8,7 +8,6 @@ import ( iradix "github.com/hashicorp/go-immutable-radix" "github.com/umbracle/fastrlp" - "github.com/0xPolygon/polygon-edge/crypto" "github.com/0xPolygon/polygon-edge/types" ) @@ -21,7 +20,7 @@ type State interface { type Snapshot interface { readSnapshot - Commit(objs []*Object) (Snapshot, []byte) + Commit(objs []*Object) (Snapshot, *types.Trace, []byte) } // Account is the account reference in the ethereum state @@ -102,8 +101,6 @@ func (a *Account) Copy() *Account { return aa } -var emptyCodeHash = crypto.Keccak256(nil) - // StateObject is the internal representation of the account type StateObject struct { Account *Account @@ -112,10 +109,16 @@ type StateObject struct { Deleted bool DirtyCode bool Txn *iradix.Txn + + // withFakeStorage signals whether the state object + // is using the override full state + withFakeStorage bool } func (s *StateObject) Empty() bool { - return s.Account.Nonce == 0 && s.Account.Balance.Sign() == 0 && bytes.Equal(s.Account.CodeHash, emptyCodeHash) + return s.Account.Nonce == 0 && + s.Account.Balance.Sign() == 0 && + bytes.Equal(s.Account.CodeHash, types.EmptyCodeHash.Bytes()) } // Copy makes a copy of the state object @@ -129,6 +132,7 @@ func (s *StateObject) Copy() *StateObject { ss.Deleted = s.Deleted ss.DirtyCode = s.DirtyCode ss.Code = s.Code + ss.withFakeStorage = s.withFakeStorage if s.Txn != nil { ss.Txn = s.Txn.CommitOnly().Txn() diff --git a/state/testing.go b/state/testing.go index 46322485d5..d5c9fcced6 100644 --- a/state/testing.go +++ b/state/testing.go @@ -5,30 +5,34 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/0xPolygon/polygon-edge/types" ) -var addr1 = types.StringToAddress("1") -var addr2 = types.StringToAddress("2") +var ( + addr1 = types.StringToAddress("1") + addr2 = types.StringToAddress("2") -var hash0 = types.StringToHash("0") -var hash1 = types.StringToHash("1") -var hash2 = types.StringToHash("2") + hash0 = types.StringToHash("0") + hash1 = types.StringToHash("1") + hash2 = types.StringToHash("2") -var defaultPreState = map[types.Address]*PreState{ - addr1: { - State: map[types.Hash]types.Hash{ - hash1: hash1, + defaultPreState = map[types.Address]*PreState{ + addr1: { + State: map[types.Hash]types.Hash{ + hash1: hash1, + }, }, - }, -} + } +) // PreState is the account prestate type PreState struct { - Nonce uint64 - Balance uint64 - State map[types.Hash]types.Hash + Nonce uint64 + Balance uint64 + State map[types.Hash]types.Hash + CodeHash []byte } // PreStates is a set of pre states @@ -41,66 +45,81 @@ func TestState(t *testing.T, buildPreState buildPreState) { t.Helper() t.Parallel() - t.Run("", func(t *testing.T) { + t.Run("write state", func(t *testing.T) { t.Parallel() testWriteState(t, buildPreState) }) - t.Run("", func(t *testing.T) { + t.Run("write empty state", func(t *testing.T) { t.Parallel() testWriteEmptyState(t, buildPreState) }) - t.Run("", func(t *testing.T) { + t.Run("update state with empty - delete empty objects", func(t *testing.T) { t.Parallel() - testUpdateStateWithEmpty(t, buildPreState) + testUpdateStateWithEmpty(t, buildPreState, true) }) - t.Run("", func(t *testing.T) { + t.Run("update state with empty - do not delete empty objects", func(t *testing.T) { + t.Parallel() + + testUpdateStateWithEmpty(t, buildPreState, false) + }) + t.Run("suicide account in pre-state", func(t *testing.T) { t.Parallel() testSuicideAccountInPreState(t, buildPreState) }) - t.Run("", func(t *testing.T) { + t.Run("suicide account", func(t *testing.T) { t.Parallel() testSuicideAccount(t, buildPreState) }) - t.Run("", func(t *testing.T) { + t.Run("suicide account with data", func(t *testing.T) { t.Parallel() testSuicideAccountWithData(t, buildPreState) }) - t.Run("", func(t *testing.T) { + t.Run("suicide coinbase", func(t *testing.T) { t.Parallel() testSuicideCoinbase(t, buildPreState) }) - t.Run("", func(t *testing.T) { + t.Run("suicide with intermediate commit", func(t *testing.T) { t.Parallel() testSuicideWithIntermediateCommit(t, buildPreState) }) - t.Run("", func(t *testing.T) { + t.Run("restart refunds", func(t *testing.T) { t.Parallel() testRestartRefunds(t, buildPreState) }) - t.Run("", func(t *testing.T) { + t.Run("change pre-state account balance to zero", func(t *testing.T) { t.Parallel() testChangePrestateAccountBalanceToZero(t, buildPreState) }) - t.Run("", func(t *testing.T) { + t.Run("change account balance to zero", func(t *testing.T) { t.Parallel() testChangeAccountBalanceToZero(t, buildPreState) }) - t.Run("", func(t *testing.T) { + t.Run("delete common state root", func(t *testing.T) { t.Parallel() testDeleteCommonStateRoot(t, buildPreState) }) + t.Run("get code empty code hash", func(t *testing.T) { + t.Parallel() + + testGetCodeEmptyCodeHash(t, buildPreState) + }) + t.Run("set and get code", func(t *testing.T) { + t.Parallel() + + testSetAndGetCode(t, buildPreState) + }) } func testDeleteCommonStateRoot(t *testing.T, buildPreState buildPreState) { @@ -119,13 +138,19 @@ func testDeleteCommonStateRoot(t *testing.T, buildPreState buildPreState) { txn.SetState(addr2, hash1, hash1) txn.SetState(addr2, hash2, hash1) - snap2, _ := snap.Commit(txn.Commit(false)) + objs, err := txn.Commit(false) + require.NoError(t, err) + + snap2, _, _ := snap.Commit(objs) txn2 := newTxn(snap2) txn2.SetState(addr1, hash0, hash0) txn2.SetState(addr1, hash1, hash0) - snap3, _ := snap2.Commit(txn2.Commit(false)) + objs, err = txn2.Commit(false) + require.NoError(t, err) + + snap3, _, _ := snap2.Commit(objs) txn3 := newTxn(snap3) assert.Equal(t, hash1, txn3.GetState(addr1, hash2)) @@ -146,7 +171,10 @@ func testWriteState(t *testing.T, buildPreState buildPreState) { assert.Equal(t, hash1, txn.GetState(addr1, hash1)) assert.Equal(t, hash2, txn.GetState(addr1, hash2)) - snap, _ = snap.Commit(txn.Commit(false)) + objs, err := txn.Commit(false) + require.NoError(t, err) + + snap, _, _ = snap.Commit(objs) txn = newTxn(snap) assert.Equal(t, hash1, txn.GetState(addr1, hash1)) @@ -161,7 +189,11 @@ func testWriteEmptyState(t *testing.T, buildPreState buildPreState) { // Without EIP150 the data is added txn.SetState(addr1, hash1, hash0) - snap, _ = snap.Commit(txn.Commit(false)) + + objs, err := txn.Commit(false) + require.NoError(t, err) + + snap, _, _ = snap.Commit(objs) txn = newTxn(snap) assert.True(t, txn.Exist(addr1)) @@ -171,13 +203,17 @@ func testWriteEmptyState(t *testing.T, buildPreState buildPreState) { // With EIP150 the empty data is removed txn.SetState(addr1, hash1, hash0) - snap, _ = snap.Commit(txn.Commit(true)) + + objs, err = txn.Commit(true) + require.NoError(t, err) + + snap, _, _ = snap.Commit(objs) txn = newTxn(snap) assert.False(t, txn.Exist(addr1)) } -func testUpdateStateWithEmpty(t *testing.T, buildPreState buildPreState) { +func testUpdateStateWithEmpty(t *testing.T, buildPreState buildPreState, deleteEmptyObjects bool) { t.Helper() // If the state (in prestate) is updated to empty it should be removed @@ -186,13 +222,38 @@ func testUpdateStateWithEmpty(t *testing.T, buildPreState buildPreState) { txn := newTxn(snap) txn.SetState(addr1, hash1, hash0) - //nolint:godox - // TODO, test with false (should not be deleted) (to be fixed in EVM-528) - // TODO, test with balance on the account and nonce (to be fixed in EVM-528) - snap, _ = snap.Commit(txn.Commit(true)) + objs, err := txn.Commit(deleteEmptyObjects) + require.NoError(t, err) + + snap, _, _ = snap.Commit(objs) txn = newTxn(snap) - assert.False(t, txn.Exist(addr1)) + assert.Equal(t, !deleteEmptyObjects, txn.Exist(addr1)) + + // if balance is set, no matter what is passed to deleteEmptyObjects, + // addr1 should exist in state objects of txn + txn.SetBalance(addr1, big.NewInt(100)) + + objs, err = txn.Commit(deleteEmptyObjects) + require.NoError(t, err) + + snap, _, _ = snap.Commit(objs) + + txn = newTxn(snap) + assert.Equal(t, true, txn.Exist(addr1)) + + // if nonce is set, no matter what is passed to deleteEmptyObjects, + // addr1 should exist in state objects of txn + txn.SetBalance(addr1, big.NewInt(0)) + txn.SetNonce(addr1, 1) + + objs, err = txn.Commit(deleteEmptyObjects) + require.NoError(t, err) + + snap, _, _ = snap.Commit(objs) + + txn = newTxn(snap) + assert.Equal(t, true, txn.Exist(addr1)) } func testSuicideAccountInPreState(t *testing.T, buildPreState buildPreState) { @@ -203,7 +264,11 @@ func testSuicideAccountInPreState(t *testing.T, buildPreState buildPreState) { txn := newTxn(snap) txn.Suicide(addr1) - snap, _ = snap.Commit(txn.Commit(true)) + + objs, err := txn.Commit(true) + require.NoError(t, err) + + snap, _, _ = snap.Commit(objs) txn = newTxn(snap) assert.False(t, txn.Exist(addr1)) @@ -221,7 +286,10 @@ func testSuicideAccount(t *testing.T, buildPreState buildPreState) { // Note, even if has commit suicide it still exists in the current txn assert.True(t, txn.Exist(addr1)) - snap, _ = snap.Commit(txn.Commit(true)) + objs, err := txn.Commit(true) + require.NoError(t, err) + + snap, _, _ = snap.Commit(objs) txn = newTxn(snap) assert.False(t, txn.Exist(addr1)) @@ -242,7 +310,11 @@ func testSuicideAccountWithData(t *testing.T, buildPreState buildPreState) { txn.SetState(addr1, hash1, hash1) txn.Suicide(addr1) - snap, _ = snap.Commit(txn.Commit(true)) + + objs, err := txn.Commit(true) + require.NoError(t, err) + + snap, _, _ = snap.Commit(objs) txn = newTxn(snap) @@ -265,7 +337,10 @@ func testSuicideCoinbase(t *testing.T, buildPreState buildPreState) { txn := newTxn(snap) txn.Suicide(addr1) txn.AddSealingReward(addr1, big.NewInt(10)) - snap, _ = snap.Commit(txn.Commit(true)) + objs, err := txn.Commit(true) + require.NoError(t, err) + + snap, _, _ = snap.Commit(objs) txn = newTxn(snap) assert.Equal(t, big.NewInt(10), txn.GetBalance(addr1)) @@ -282,10 +357,11 @@ func testSuicideWithIntermediateCommit(t *testing.T, buildPreState buildPreState assert.Equal(t, uint64(10), txn.GetNonce(addr1)) - txn.CleanDeleteObjects(true) + assert.NoError(t, txn.CleanDeleteObjects(true)) assert.Equal(t, uint64(0), txn.GetNonce(addr1)) - txn.Commit(true) + _, err := txn.Commit(true) + assert.NoError(t, err) assert.Equal(t, uint64(0), txn.GetNonce(addr1)) } @@ -300,7 +376,8 @@ func testRestartRefunds(t *testing.T, buildPreState buildPreState) { txn.AddRefund(1000) assert.Equal(t, uint64(1000), txn.GetRefund()) - txn.Commit(false) + _, err := txn.Commit(false) + assert.NoError(t, err) // refund should be empty after the commit assert.Equal(t, uint64(0), txn.GetRefund()) @@ -319,7 +396,11 @@ func testChangePrestateAccountBalanceToZero(t *testing.T, buildPreState buildPre txn := newTxn(snap) txn.SetBalance(addr1, big.NewInt(0)) - snap, _ = snap.Commit(txn.Commit(true)) + + objs, err := txn.Commit(true) + require.NoError(t, err) + + snap, _, _ = snap.Commit(objs) txn = newTxn(snap) assert.False(t, txn.Exist(addr1)) @@ -334,8 +415,43 @@ func testChangeAccountBalanceToZero(t *testing.T, buildPreState buildPreState) { txn.SetBalance(addr1, big.NewInt(10)) txn.SetBalance(addr1, big.NewInt(0)) - snap, _ = snap.Commit(txn.Commit(true)) + objs, err := txn.Commit(true) + require.NoError(t, err) + + snap, _, _ = snap.Commit(objs) txn = newTxn(snap) assert.False(t, txn.Exist(addr1)) } + +func testGetCodeEmptyCodeHash(t *testing.T, buildPreState buildPreState) { + t.Helper() + + // If empty code hash is passed, it is considered as a valid case, + // and in that case we are not retrieving it from the storage. + snap := buildPreState(nil) + + code, ok := snap.GetCode(types.EmptyCodeHash) + assert.True(t, ok) + assert.Empty(t, code) +} + +func testSetAndGetCode(t *testing.T, buildPreState buildPreState) { + t.Helper() + + testCode := []byte{0x2, 0x4, 0x6, 0x8} + snap := buildPreState(nil) + + txn := newTxn(snap) + txn.SetCode(addr1, testCode) + + affectedObjs, err := txn.Commit(true) + require.NoError(t, err) + + snap, _, _ = snap.Commit(affectedObjs) + assert.Len(t, affectedObjs, 1) + + code, ok := snap.GetCode(affectedObjs[0].CodeHash) + assert.True(t, ok) + assert.Equal(t, testCode, code) +} diff --git a/state/txn.go b/state/txn.go index 00e11364b3..ffb74b15f9 100644 --- a/state/txn.go +++ b/state/txn.go @@ -1,6 +1,8 @@ package state import ( + "errors" + "fmt" "math/big" iradix "github.com/hashicorp/go-immutable-radix" @@ -34,6 +36,9 @@ type Txn struct { snapshots []*iradix.Tree txn *iradix.Txn codeCache *lru.Cache + + // tracing + journal []*types.JournalEntry } func NewTxn(snapshot Snapshot) *Txn { @@ -54,6 +59,7 @@ func newTxn(snapshot readSnapshot) *Txn { snapshots: []*iradix.Tree{}, txn: i.Txn(), codeCache: codeCache, + journal: []*types.JournalEntry{}, } } @@ -68,13 +74,78 @@ func (txn *Txn) Snapshot() int { } // RevertToSnapshot reverts to a given snapshot -func (txn *Txn) RevertToSnapshot(id int) { - if id > len(txn.snapshots) { - panic("") //nolint:gocritic +func (txn *Txn) RevertToSnapshot(id int) error { + if id > len(txn.snapshots)-1 { + return fmt.Errorf("snapshot id %d out of the range", id) } tree := txn.snapshots[id] txn.txn = tree.Txn() + + return nil +} + +func (txn *Txn) getCompactJournal() map[types.Address]*types.JournalEntry { + // Instead of creating a new object to represent the aggregate on how + // an account has changed during the compaction, we piggyback the same + // journalEntry object for now. + res := map[types.Address]*types.JournalEntry{} + + for _, entry := range txn.journal { + obj, ok := res[entry.Addr] + if !ok { + obj = &types.JournalEntry{Addr: entry.Addr} + res[entry.Addr] = obj + } + + obj.Merge(entry) + } + + // reset the journal + txn.journal = txn.journal[:0] + + return res +} + +func (txn *Txn) addJournalEntry(j *types.JournalEntry) { + txn.journal = append(txn.journal, j) +} + +const ( + nonceChange = "nonce" + codeChange = "code" + balanceChange = "balance" +) + +func (txn *Txn) trackAccountChange(addr types.Address, changeType string, object *StateObject) { + entry := &types.JournalEntry{ + Addr: addr, + } + + if changeType == nonceChange { + // the node has changed + entry.Nonce = &object.Account.Nonce + } else if changeType == codeChange { + // the code has been initialized + entry.Code = object.Code + } else if changeType == balanceChange { + // the balance has changed + entry.Balance = object.Account.Balance + } else { + // this is covered on unit tests + panic(fmt.Sprintf("BUG: Not expected change '%s'", changeType)) //nolint:gocritic + } + + txn.addJournalEntry(entry) +} + +func (txn *Txn) trackCodeRead(addr types.Address, code []byte) { + entry := &types.JournalEntry{ + Addr: addr, + CodeRead: code, + } + + txn.addJournalEntry(entry) } // GetAccount returns an account @@ -88,6 +159,11 @@ func (txn *Txn) GetAccount(addr types.Address) (*Account, bool) { } func (txn *Txn) getStateObject(addr types.Address) (*StateObject, bool) { + txn.addJournalEntry(&types.JournalEntry{ + Addr: addr, + Read: boolTruePtr(), + }) + // Try to get state from radix tree which holds transient states during block processing first val, exists := txn.txn.Get(addr.Bytes()) if exists { @@ -121,7 +197,7 @@ func (txn *Txn) upsertAccount(addr types.Address, create bool, f func(object *St object = &StateObject{ Account: &Account{ Balance: big.NewInt(0), - CodeHash: emptyCodeHash, + CodeHash: types.EmptyCodeHash.Bytes(), Root: emptyStateHash, }, } @@ -138,11 +214,13 @@ func (txn *Txn) upsertAccount(addr types.Address, create bool, f func(object *St func (txn *Txn) AddSealingReward(addr types.Address, balance *big.Int) { txn.upsertAccount(addr, true, func(object *StateObject) { if object.Suicide { - *object = *newStateObject(txn) + *object = *newStateObject() object.Account.Balance.SetBytes(balance.Bytes()) } else { object.Account.Balance.Add(object.Account.Balance, balance) } + + txn.trackAccountChange(addr, balanceChange, object) }) } @@ -150,6 +228,8 @@ func (txn *Txn) AddSealingReward(addr types.Address, balance *big.Int) { func (txn *Txn) AddBalance(addr types.Address, balance *big.Int) { txn.upsertAccount(addr, true, func(object *StateObject) { object.Account.Balance.Add(object.Account.Balance, balance) + + txn.trackAccountChange(addr, balanceChange, object) }) } @@ -167,6 +247,8 @@ func (txn *Txn) SubBalance(addr types.Address, amount *big.Int) error { txn.upsertAccount(addr, true, func(object *StateObject) { object.Account.Balance.Sub(object.Account.Balance, amount) + + txn.trackAccountChange(addr, balanceChange, object) }) return nil @@ -176,6 +258,8 @@ func (txn *Txn) SubBalance(addr types.Address, amount *big.Int) error { func (txn *Txn) SetBalance(addr types.Address, balance *big.Int) { txn.upsertAccount(addr, true, func(object *StateObject) { object.Account.Balance.SetBytes(balance.Bytes()) + + txn.trackAccountChange(addr, balanceChange, object) }) } @@ -189,6 +273,7 @@ func (txn *Txn) GetBalance(addr types.Address) *big.Int { return object.Account.Balance } +// EmitLog appends log to logs tree storage func (txn *Txn) EmitLog(addr types.Address, topics []types.Hash, data []byte) { log := &types.Log{ Address: addr, @@ -209,25 +294,9 @@ func (txn *Txn) EmitLog(addr types.Address, topics []types.Hash, data []byte) { txn.txn.Insert(logIndex, logs) } -// AddLog adds a new log -func (txn *Txn) AddLog(log *types.Log) { - var logs []*types.Log - - data, exists := txn.txn.Get(logIndex) - if !exists { - logs = []*types.Log{} - } else { - logs = data.([]*types.Log) //nolint:forcetypeassert - } - - logs = append(logs, log) - txn.txn.Insert(logIndex, logs) -} - // State -var zeroHash types.Hash - +// SetStorage sets the storage of an address func (txn *Txn) SetStorage( addr types.Address, key types.Hash, @@ -247,9 +316,9 @@ func (txn *Txn) SetStorage( legacyGasMetering := !config.Istanbul && (config.Petersburg || !config.Constantinople) if legacyGasMetering { - if oldValue == zeroHash { + if oldValue == types.ZeroHash { return runtime.StorageAdded - } else if value == zeroHash { + } else if value == types.ZeroHash { txn.AddRefund(15000) return runtime.StorageDeleted @@ -259,11 +328,11 @@ func (txn *Txn) SetStorage( } if original == current { - if original == zeroHash { // create slot (2.1.1) + if original == types.ZeroHash { // create slot (2.1.1) return runtime.StorageAdded } - if value == zeroHash { // delete slot (2.1.2b) + if value == types.ZeroHash { // delete slot (2.1.2b) txn.AddRefund(15000) return runtime.StorageDeleted @@ -272,16 +341,16 @@ func (txn *Txn) SetStorage( return runtime.StorageModified } - if original != zeroHash { // Storage slot was populated before this transaction started - if current == zeroHash { // recreate slot (2.2.1.1) + if original != types.ZeroHash { // Storage slot was populated before this transaction started + if current == types.ZeroHash { // recreate slot (2.2.1.1) txn.SubRefund(15000) - } else if value == zeroHash { // delete slot (2.2.1.2) + } else if value == types.ZeroHash { // delete slot (2.2.1.2) txn.AddRefund(15000) } } if original == value { - if original == zeroHash { // reset to original nonexistent slot (2.2.2.1) + if original == types.ZeroHash { // reset to original nonexistent slot (2.2.2.1) // Storage was used as memory (allocation and deallocation occurred within the same contract) if config.Istanbul { txn.AddRefund(19200) @@ -311,11 +380,18 @@ func (txn *Txn) SetState( object.Txn = iradix.New().Txn() } - if value == zeroHash { + if value == types.ZeroHash { object.Txn.Insert(key.Bytes(), nil) } else { object.Txn.Insert(key.Bytes(), value.Bytes()) } + + txn.addJournalEntry(&types.JournalEntry{ + Addr: addr, + Storage: map[types.Hash]types.Hash{ + key: value, + }, + }) }) } @@ -326,6 +402,13 @@ func (txn *Txn) GetState(addr types.Address, key types.Hash) types.Hash { return types.Hash{} } + txn.addJournalEntry(&types.JournalEntry{ + Addr: addr, + StorageRead: map[types.Hash]struct{}{ + key: {}, + }, + }) + // Try to get account state from radix tree first // Because the latest account state should be in in-memory radix tree // if account state update happened in previous transactions of same block @@ -339,6 +422,10 @@ func (txn *Txn) GetState(addr types.Address, key types.Hash) types.Hash { } } + if object.withFakeStorage { + return types.Hash{} + } + return txn.snapshot.GetStorage(addr, object.Account.Root, key) } @@ -348,6 +435,8 @@ func (txn *Txn) GetState(addr types.Address, key types.Hash) types.Hash { func (txn *Txn) IncrNonce(addr types.Address) { txn.upsertAccount(addr, true, func(object *StateObject) { object.Account.Nonce++ + + txn.trackAccountChange(addr, nonceChange, object) }) } @@ -355,6 +444,8 @@ func (txn *Txn) IncrNonce(addr types.Address) { func (txn *Txn) SetNonce(addr types.Address, nonce uint64) { txn.upsertAccount(addr, true, func(object *StateObject) { object.Account.Nonce = nonce + + txn.trackAccountChange(addr, nonceChange, object) }) } @@ -376,9 +467,12 @@ func (txn *Txn) SetCode(addr types.Address, code []byte) { object.Account.CodeHash = crypto.Keccak256(code) object.DirtyCode = true object.Code = code + + txn.trackAccountChange(addr, codeChange, object) }) } +// GetCode gets the code on a given address func (txn *Txn) GetCode(addr types.Address) []byte { object, exists := txn.getStateObject(addr) if !exists { @@ -386,6 +480,8 @@ func (txn *Txn) GetCode(addr types.Address) []byte { } if object.DirtyCode { + txn.trackCodeRead(addr, object.Code) + return object.Code } //nolint:godox @@ -394,11 +490,15 @@ func (txn *Txn) GetCode(addr types.Address) []byte { if ok { //nolint:forcetypeassert - return v.([]byte) + code := v.([]byte) + txn.trackCodeRead(addr, code) + + return code } code, _ := txn.snapshot.GetCode(types.BytesToHash(object.Account.CodeHash)) txn.codeCache.Add(addr, code) + txn.trackCodeRead(addr, code) return code } @@ -416,6 +516,12 @@ func (txn *Txn) GetCodeHash(addr types.Address) types.Hash { return types.BytesToHash(object.Account.CodeHash) } +func boolTruePtr() *bool { + t := true + + return &t +} + // Suicide marks the given account as suicided func (txn *Txn) Suicide(addr types.Address) bool { var suicided bool @@ -426,6 +532,11 @@ func (txn *Txn) Suicide(addr types.Address) bool { } else { suicided = true object.Suicide = true + + txn.addJournalEntry(&types.JournalEntry{ + Addr: addr, + Suicide: boolTruePtr(), + }) } if object != nil { object.Account.Balance = new(big.Int) @@ -484,14 +595,26 @@ func (txn *Txn) GetCommittedState(addr types.Address, key types.Hash) types.Hash return txn.snapshot.GetStorage(addr, obj.Account.Root, key) } -func (txn *Txn) TouchAccount(addr types.Address) { - txn.upsertAccount(addr, true, func(obj *StateObject) { +// SetFullStorage is used to replace the full state of the address. +// Only used for debugging on the override jsonrpc endpoint. +func (txn *Txn) SetFullStorage(addr types.Address, state map[types.Hash]types.Hash) { + for k, v := range state { + txn.SetState(addr, k, v) + } + txn.upsertAccount(addr, true, func(object *StateObject) { + object.withFakeStorage = true }) } -//nolint:godox -// TODO, check panics with this ones (to be fixed in EVM-528) +func (txn *Txn) TouchAccount(addr types.Address) { + txn.upsertAccount(addr, true, func(obj *StateObject) { + txn.addJournalEntry(&types.JournalEntry{ + Addr: addr, + Touched: boolTruePtr(), + }) + }) +} func (txn *Txn) Exist(addr types.Address) bool { _, exists := txn.getStateObject(addr) @@ -508,11 +631,11 @@ func (txn *Txn) Empty(addr types.Address) bool { return obj.Empty() } -func newStateObject(txn *Txn) *StateObject { +func newStateObject() *StateObject { return &StateObject{ Account: &Account{ Balance: big.NewInt(0), - CodeHash: emptyCodeHash, + CodeHash: types.EmptyCodeHash.Bytes(), Root: emptyStateHash, }, } @@ -522,7 +645,7 @@ func (txn *Txn) CreateAccount(addr types.Address) { obj := &StateObject{ Account: &Account{ Balance: big.NewInt(0), - CodeHash: emptyCodeHash, + CodeHash: types.EmptyCodeHash.Bytes(), Root: emptyStateHash, }, } @@ -535,7 +658,7 @@ func (txn *Txn) CreateAccount(addr types.Address) { txn.txn.Insert(addr.Bytes(), obj) } -func (txn *Txn) CleanDeleteObjects(deleteEmptyObjects bool) { +func (txn *Txn) CleanDeleteObjects(deleteEmptyObjects bool) error { remove := [][]byte{} txn.txn.Root().Walk(func(k []byte, v interface{}) bool { @@ -553,13 +676,12 @@ func (txn *Txn) CleanDeleteObjects(deleteEmptyObjects bool) { for _, k := range remove { v, ok := txn.txn.Get(k) if !ok { - panic("it should not happen") //nolint:gocritic + return fmt.Errorf("failed to retrieve value for %s key", string(k)) } obj, ok := v.(*StateObject) - if !ok { - panic("it should not happen") //nolint:gocritic + return errors.New("found object is not of StateObject type") } obj2 := obj.Copy() @@ -569,10 +691,14 @@ func (txn *Txn) CleanDeleteObjects(deleteEmptyObjects bool) { // delete refunds txn.txn.Delete(refundIndex) + + return nil } -func (txn *Txn) Commit(deleteEmptyObjects bool) []*Object { - txn.CleanDeleteObjects(deleteEmptyObjects) +func (txn *Txn) Commit(deleteEmptyObjects bool) ([]*Object, error) { + if err := txn.CleanDeleteObjects(deleteEmptyObjects); err != nil { + return nil, err + } x := txn.txn.Commit() @@ -618,5 +744,5 @@ func (txn *Txn) Commit(deleteEmptyObjects bool) []*Object { return false }) - return objs + return objs, nil } diff --git a/state/txn_test.go b/state/txn_test.go index d1ff74b519..03be318501 100644 --- a/state/txn_test.go +++ b/state/txn_test.go @@ -7,6 +7,7 @@ import ( "github.com/0xPolygon/polygon-edge/types" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) type mockSnapshot struct { @@ -42,10 +43,14 @@ func (m *mockSnapshot) GetAccount(addr types.Address) (*Account, error) { } func (m *mockSnapshot) GetCode(hash types.Hash) ([]byte, bool) { - return nil, false + return nil, true } -func newStateWithPreState(preState map[types.Address]*PreState) readSnapshot { +func (m *mockSnapshot) Commit(objs []*Object) (Snapshot, *types.Trace, []byte) { + return nil, nil, nil +} + +func newStateWithPreState(preState map[types.Address]*PreState) Snapshot { return &mockSnapshot{state: preState} } @@ -63,6 +68,93 @@ func TestSnapshotUpdateData(t *testing.T) { txn.SetState(addr1, hash1, hash2) assert.Equal(t, hash2, txn.GetState(addr1, hash1)) - txn.RevertToSnapshot(ss) + assert.NoError(t, txn.RevertToSnapshot(ss)) assert.Equal(t, hash1, txn.GetState(addr1, hash1)) } + +func TestTxn_TracesCompaction(t *testing.T) { + txn := newTestTxn(defaultPreState) + + addr := types.Address{} + + txn.SetBalance(addr, big.NewInt(1)) + txn.SetBalance(addr, big.NewInt(2)) // updates + + txn.SetNonce(addr, 1) + txn.SetNonce(addr, 2) // updates + + oneHash := types.Hash{0x1} + + txn.SetState(addr, types.ZeroHash, types.ZeroHash) + txn.SetState(addr, types.ZeroHash, oneHash) // updates + txn.SetState(addr, oneHash, types.ZeroHash) + + txn.SetCode(addr, []byte{0x1}) + txn.GetCode(addr) + + txn.TouchAccount(addr) + require.Len(t, txn.journal, 20) + + trace := txn.getCompactJournal() + require.Len(t, trace, 1) + + nonce := uint64(2) + + require.Equal(t, trace[addr], &types.JournalEntry{ + Balance: big.NewInt(2), + Nonce: &nonce, + Storage: map[types.Hash]types.Hash{ + types.ZeroHash: oneHash, + oneHash: types.ZeroHash, + }, + Code: []byte{0x1}, + CodeRead: []byte{0x1}, + Touched: boolTruePtr(), + Read: boolTruePtr(), + }) +} + +func TestJournalEntry_Merge(t *testing.T) { + one := uint64(1) + + entryAllSet := func() *types.JournalEntry { + // use a function because the merge function + // modifies the caller and the test would + // have side effects. + return &types.JournalEntry{ + Nonce: &one, + Balance: big.NewInt(1), + Storage: map[types.Hash]types.Hash{ + types.ZeroHash: types.ZeroHash, + }, + Code: []byte{0x1}, + CodeRead: []byte{0x1}, + Suicide: boolTruePtr(), + Touched: boolTruePtr(), + Read: boolTruePtr(), + StorageRead: map[types.Hash]struct{}{ + types.ZeroHash: {}, + }, + } + } + + cases := []struct { + a, b, c *types.JournalEntry // a.merge(b) = c + }{ + { + &types.JournalEntry{}, + entryAllSet(), + entryAllSet(), + }, + { + entryAllSet(), + &types.JournalEntry{}, + entryAllSet(), + }, + } + + for _, c := range cases { + c.a.Merge(c.b) + require.Equal(t, c.c, c.a) + } +} diff --git a/syncer/client.go b/syncer/client.go index 916de61654..3e0c3c6029 100644 --- a/syncer/client.go +++ b/syncer/client.go @@ -14,6 +14,7 @@ import ( "github.com/0xPolygon/polygon-edge/network/event" "github.com/0xPolygon/polygon-edge/syncer/proto" "github.com/0xPolygon/polygon-edge/types" + "github.com/armon/go-metrics" "github.com/hashicorp/go-hclog" "github.com/libp2p/go-libp2p/core/peer" "google.golang.org/protobuf/types/known/emptypb" @@ -38,7 +39,10 @@ type syncPeerClient struct { shouldEmitBlocks bool // flag for emitting blocks in the topic closeCh chan struct{} - closed *uint64 // ACTIVE == 0, CLOSED == non-zero. + closed atomic.Bool + + peerStatusUpdateChLock sync.Mutex + peerStatusUpdateChClosed bool } func NewSyncPeerClient( @@ -55,14 +59,16 @@ func NewSyncPeerClient( peerConnectionUpdateCh: make(chan *event.PeerEvent, 1), shouldEmitBlocks: true, closeCh: make(chan struct{}), - closed: new(uint64), + + peerStatusUpdateChLock: sync.Mutex{}, + peerStatusUpdateChClosed: false, } } // Start processes for SyncPeerClient func (m *syncPeerClient) Start() error { // Mark client active. - atomic.StoreUint64(m.closed, 0) + m.closed.Store(false) go m.startNewBlockProcess() go m.startPeerEventProcess() @@ -76,7 +82,7 @@ func (m *syncPeerClient) Start() error { // Close terminates running processes for SyncPeerClient func (m *syncPeerClient) Close() { - if atomic.SwapUint64(m.closed, 1) > 0 { + if m.closed.Swap(true) { // Already closed. return } @@ -95,7 +101,10 @@ func (m *syncPeerClient) Close() { close(m.closeCh) } + m.peerStatusUpdateChLock.Lock() + m.peerStatusUpdateChClosed = true close(m.peerStatusUpdateCh) + m.peerStatusUpdateChLock.Unlock() } // DisablePublishingPeerStatus disables publishing own status via gossip @@ -210,16 +219,15 @@ func (m *syncPeerClient) handleStatusUpdate(obj interface{}, from peer.ID) { return } - if atomic.LoadUint64(m.closed) > 0 { - m.logger.Debug("received status from peer after client was closed, ignoring", "id", from) - - return - } + m.peerStatusUpdateChLock.Lock() + defer m.peerStatusUpdateChLock.Unlock() - m.peerStatusUpdateCh <- &NoForkPeer{ - ID: from, - Number: status.Number, - Distance: m.network.GetPeerDistance(from), + if !m.peerStatusUpdateChClosed { + m.peerStatusUpdateCh <- &NoForkPeer{ + ID: from, + Number: status.Number, + Distance: m.network.GetPeerDistance(from), + } } } @@ -373,6 +381,7 @@ func blockStreamToChannel(stream proto.SyncPeer_GetBlocksClient) (<-chan *types. } if err != nil { + metrics.IncrCounter([]string{syncerMetrics, "bad_message"}, 1) errorCh <- err break @@ -380,11 +389,14 @@ func blockStreamToChannel(stream proto.SyncPeer_GetBlocksClient) (<-chan *types. block, err := fromProto(protoBlock) if err != nil { + metrics.IncrCounter([]string{syncerMetrics, "bad_block"}, 1) errorCh <- err break } + metrics.SetGauge([]string{syncerMetrics, "ingress_bytes"}, float32(len(protoBlock.Block))) + blockCh <- block } }() diff --git a/syncer/client_test.go b/syncer/client_test.go index 9da920116e..9a35d68998 100644 --- a/syncer/client_test.go +++ b/syncer/client_test.go @@ -45,7 +45,6 @@ func newTestSyncPeerClient(network Network, blockchain Blockchain) *syncPeerClie id: network.AddrInfo().ID.String(), peerStatusUpdateCh: make(chan *NoForkPeer, 1), peerConnectionUpdateCh: make(chan *event.PeerEvent, 1), - closed: new(uint64), } // need to register protocol @@ -231,6 +230,7 @@ func TestStatusPubSub(t *testing.T) { } func TestPeerConnectionUpdateEventCh(t *testing.T) { + t.Skip() t.Parallel() var ( @@ -354,7 +354,7 @@ func TestPeerConnectionUpdateEventCh(t *testing.T) { wgForGossip.Wait() // close to terminate goroutine - close(client.peerStatusUpdateCh) + client.Close() // wait until collecting routine is done wgForConnectingStatus.Wait() @@ -577,10 +577,12 @@ func Test_EmitMultipleBlocks(t *testing.T) { waitForGossip := func(wg *sync.WaitGroup) bool { c := make(chan struct{}) + go func() { defer close(c) wg.Wait() }() + select { case <-c: return true diff --git a/syncer/service.go b/syncer/service.go index 4b88ca4192..1e874f6e85 100644 --- a/syncer/service.go +++ b/syncer/service.go @@ -7,6 +7,7 @@ import ( "github.com/0xPolygon/polygon-edge/network/grpc" "github.com/0xPolygon/polygon-edge/syncer/proto" "github.com/0xPolygon/polygon-edge/types" + "github.com/armon/go-metrics" "github.com/golang/protobuf/ptypes/empty" ) @@ -64,6 +65,7 @@ func (s *syncPeerService) GetBlocks( } resp := toProtoBlock(block) + metrics.SetGauge([]string{syncerMetrics, "egress_bytes"}, float32(len(resp.Block))) // if client closes stream, context.Canceled is given if err := stream.Send(resp); err != nil { diff --git a/syncer/syncer.go b/syncer/syncer.go index 6a3c32ffed..55ec6de554 100644 --- a/syncer/syncer.go +++ b/syncer/syncer.go @@ -8,6 +8,7 @@ import ( "github.com/0xPolygon/polygon-edge/helper/progress" "github.com/0xPolygon/polygon-edge/network/event" "github.com/0xPolygon/polygon-edge/types" + "github.com/armon/go-metrics" "github.com/hashicorp/go-hclog" "github.com/libp2p/go-libp2p/core/peer" ) @@ -240,13 +241,18 @@ func (s *syncer) bulkSyncWithPeer(peerID peer.ID, newBlockCallback func(*types.F fullBlock, err := s.blockchain.VerifyFinalizedBlock(block) if err != nil { + metrics.IncrCounter([]string{syncerMetrics, "bad_block"}, 1) + return lastReceivedNumber, false, fmt.Errorf("unable to verify block, %w", err) } if err := s.blockchain.WriteFullBlock(fullBlock, syncerName); err != nil { + metrics.IncrCounter([]string{syncerMetrics, "bad_block"}, 1) + return lastReceivedNumber, false, fmt.Errorf("failed to write block while bulk syncing: %w", err) } + updateMetrics(fullBlock) shouldTerminate = newBlockCallback(fullBlock) lastReceivedNumber = block.Number() @@ -255,3 +261,9 @@ func (s *syncer) bulkSyncWithPeer(peerID peer.ID, newBlockCallback func(*types.F } } } + +func updateMetrics(fullBlock *types.FullBlock) { + metrics.SetGauge([]string{syncerMetrics, "tx_num"}, float32(len(fullBlock.Block.Transactions))) + metrics.SetGauge([]string{syncerMetrics, "receipts_num"}, float32(len(fullBlock.Receipts))) + metrics.SetGauge([]string{syncerMetrics, "blocks_num"}, 1) +} diff --git a/syncer/types.go b/syncer/types.go index 3b4c6628d6..7fe61522da 100644 --- a/syncer/types.go +++ b/syncer/types.go @@ -16,6 +16,8 @@ import ( "google.golang.org/protobuf/proto" ) +const syncerMetrics = "syncer" + type Blockchain interface { // SubscribeEvents subscribes new blockchain event SubscribeEvents() blockchain.Subscription diff --git a/tests/evm_test.go b/tests/evm_test.go deleted file mode 100644 index eaab30ec1e..0000000000 --- a/tests/evm_test.go +++ /dev/null @@ -1,193 +0,0 @@ -package tests - -import ( - "encoding/json" - "math/big" - "os" - "strings" - "testing" - - "github.com/0xPolygon/polygon-edge/chain" - "github.com/0xPolygon/polygon-edge/crypto" - "github.com/0xPolygon/polygon-edge/helper/hex" - "github.com/0xPolygon/polygon-edge/helper/keccak" - "github.com/0xPolygon/polygon-edge/state" - "github.com/0xPolygon/polygon-edge/state/runtime" - "github.com/0xPolygon/polygon-edge/state/runtime/evm" - "github.com/0xPolygon/polygon-edge/types" - "github.com/hashicorp/go-hclog" - "github.com/umbracle/fastrlp" -) - -var mainnetChainConfig = chain.Params{ - Forks: &chain.Forks{ - Homestead: chain.NewFork(1150000), - EIP150: chain.NewFork(2463000), - EIP158: chain.NewFork(2675000), - Byzantium: chain.NewFork(4370000), - }, -} - -var vmTests = "VMTests" - -type VMCase struct { - Info *info `json:"_info"` - Env *env `json:"env"` - Exec *exec `json:"exec"` - - Gas string `json:"gas"` - Logs string `json:"logs"` - Out string `json:"out"` - - Post map[types.Address]*chain.GenesisAccount `json:"post"` - Pre map[types.Address]*chain.GenesisAccount `json:"pre"` -} - -func testVMCase(t *testing.T, name string, c *VMCase) { - t.Helper() - - env := c.Env.ToEnv(t) - env.GasPrice = types.BytesToHash(c.Exec.GasPrice.Bytes()) - env.Origin = c.Exec.Origin - - s, _, root := buildState(c.Pre) - - config := mainnetChainConfig.Forks.At(uint64(env.Number)) - - executor := state.NewExecutor(&mainnetChainConfig, s, hclog.NewNullLogger()) - executor.GetHash = func(*types.Header) func(i uint64) types.Hash { - return vmTestBlockHash - } - - e, _ := executor.BeginTxn(root, c.Env.ToHeader(t), env.Coinbase) - ctx := e.ContextPtr() - ctx.GasPrice = types.BytesToHash(env.GasPrice.Bytes()) - ctx.Origin = env.Origin - - evmR := evm.NewEVM() - - code := e.GetCode(c.Exec.Address) - contract := runtime.NewContractCall( - 1, - c.Exec.Caller, - c.Exec.Caller, - c.Exec.Address, - c.Exec.Value, - c.Exec.GasLimit, - code, - c.Exec.Data, - ) - - result := evmR.Run(contract, e, &config) - - if c.Gas == "" { - if result.Succeeded() { - t.Fatalf("gas unspecified (indicating an error), but VM returned no error") - } - - if result.GasLeft > 0 { - t.Fatalf("gas unspecified (indicating an error), but VM returned gas remaining > 0") - } - - return - } - - // check return - if c.Out == "" { - c.Out = "0x" - } - - if ret := hex.EncodeToHex(result.ReturnValue); ret != c.Out { - t.Fatalf("return mismatch: got %s, want %s", ret, c.Out) - } - - txn := e.Txn() - - // check logs - if logs := rlpHashLogs(txn.Logs()); logs != types.StringToHash(c.Logs) { - t.Fatalf("logs hash mismatch: got %x, want %x", logs, c.Logs) - } - - // check state - for addr, alloc := range c.Post { - for key, val := range alloc.Storage { - if have := txn.GetState(addr, key); have != val { - t.Fatalf("wrong storage value at %s:\n got %s\n want %s\n at address %s", key, have, val, addr) - } - } - } - - // check remaining gas - if expected := stringToUint64T(t, c.Gas); result.GasLeft != expected { - t.Fatalf("gas left mismatch: got %d want %d", result.GasLeft, expected) - } -} - -func rlpHashLogs(logs []*types.Log) (res types.Hash) { - r := &types.Receipt{ - Logs: logs, - } - - ar := &fastrlp.Arena{} - v := r.MarshalLogsWith(ar) - - keccak.Keccak256Rlp(res[:0], v) - - return -} - -func TestEVM(t *testing.T) { - t.Parallel() - - folders, err := listFolders(vmTests) - if err != nil { - t.Fatal(err) - } - - long := []string{ - "loop-", - "gasprice", - "origin", - } - - for _, folder := range folders { - files, err := listFiles(folder) - if err != nil { - t.Fatal(err) - } - - for _, file := range files { - file := file - t.Run(file, func(t *testing.T) { - t.Parallel() - - if !strings.HasSuffix(file, ".json") { - return - } - - data, err := os.ReadFile(file) - if err != nil { - t.Fatal(err) - } - - var vmcases map[string]*VMCase - if err := json.Unmarshal(data, &vmcases); err != nil { - t.Fatal(err) - } - - for name, cc := range vmcases { - if contains(long, name) && testing.Short() { - t.Skip() - - continue - } - testVMCase(t, name, cc) - } - }) - } - } -} - -func vmTestBlockHash(n uint64) types.Hash { - return types.BytesToHash(crypto.Keccak256([]byte(big.NewInt(int64(n)).String()))) -} diff --git a/tests/state_test.go b/tests/state_test.go index aa27337142..7be5b1814b 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -13,42 +13,63 @@ import ( "github.com/0xPolygon/polygon-edge/state" "github.com/0xPolygon/polygon-edge/types" "github.com/hashicorp/go-hclog" + "github.com/stretchr/testify/require" ) -var ( - stateTests = "GeneralStateTests" - legacyStateTests = "LegacyTests/Constantinople/GeneralStateTests" -) +// Currently used test cases suite version is v10.4. +// It does not include Merge hardfork test cases. -type stateCase struct { - Info *info `json:"_info"` - Env *env `json:"env"` - Pre map[types.Address]*chain.GenesisAccount `json:"pre"` - Post map[string]postState `json:"post"` - Transaction *stTransaction `json:"transaction"` -} +const ( + stateTests = "tests/GeneralStateTests" + legacyStateTests = "tests/LegacyTests/Constantinople/GeneralStateTests" + testGenesisBaseFee = 0x0a +) -var ripemd = types.StringToAddress("0000000000000000000000000000000000000003") +var ( + ripemd = types.StringToAddress("0000000000000000000000000000000000000003") +) -func RunSpecificTest(t *testing.T, file string, c stateCase, name, fork string, index int, p postEntry) { +func RunSpecificTest(t *testing.T, file string, c testCase, name, fork string, index int, p postEntry) { t.Helper() config, ok := Forks[fork] if !ok { - t.Fatalf("config %s not found", fork) + t.Skipf("%s fork is not supported", fork) + + return } env := c.Env.ToEnv(t) - msg, err := c.Transaction.At(p.Indexes) + var baseFee *big.Int + + if config.IsActive(chain.London, 0) { + if c.Env.BaseFee != "" { + baseFee = stringToBigIntT(t, c.Env.BaseFee) + } else { + // Retesteth uses `10` for genesis baseFee. Therefore, it defaults to + // parent - 2 : 0xa as the basefee for 'this' context. + baseFee = big.NewInt(testGenesisBaseFee) + } + } + + msg, err := c.Transaction.At(p.Indexes, baseFee) if err != nil { - t.Fatal(err) + t.Fatalf("failed to create transaction: %v", err) } - s, snapshot, pastRoot := buildState(c.Pre) + s, snapshot, pastRoot, err := buildState(c.Pre) + require.NoError(t, err) + forks := config.At(uint64(env.Number)) - xxx := state.NewExecutor(&chain.Params{Forks: config, ChainID: 1}, s, hclog.NewNullLogger()) + xxx := state.NewExecutor(&chain.Params{ + Forks: config, + ChainID: 1, + BurnContract: map[uint64]types.Address{ + 0: types.ZeroAddress, + }, + }, s, hclog.NewNullLogger()) xxx.PostHook = func(t *state.Transition) { if name == "failed_tx_xcf416c53" { @@ -70,9 +91,12 @@ func RunSpecificTest(t *testing.T, file string, c stateCase, name, fork string, // mining rewards txn.AddSealingReward(env.Coinbase, big.NewInt(0)) - objs := txn.Commit(forks.EIP155) - _, root := snapshot.Commit(objs) + objs, err := txn.Commit(forks.EIP155) + require.NoError(t, err) + + _, _, root := snapshot.Commit(objs) + // Check block root if !bytes.Equal(root, p.Root.Bytes()) { t.Fatalf( "root mismatch (%s %s %s %d): expected %s but found %s", @@ -85,6 +109,7 @@ func RunSpecificTest(t *testing.T, file string, c stateCase, name, fork string, ) } + // Check transaction logs if logs := rlpHashLogs(txn.Logs()); logs != p.Logs { t.Fatalf( "logs mismatch (%s, %s %d): expected %s but found %s", @@ -151,12 +176,12 @@ func TestState(t *testing.T) { t.Fatal(err) } - var c map[string]stateCase - if err := json.Unmarshal(data, &c); err != nil { - t.Fatal(err) + var testCases map[string]testCase + if err = json.Unmarshal(data, &testCases); err != nil { + t.Fatalf("failed to unmarshal %s: %v", file, err) } - for name, i := range c { + for name, i := range testCases { for fork, f := range i.Post { for indx, e := range f { RunSpecificTest(t, file, i, name, fork, indx, e) diff --git a/tests/testing.go b/tests/testing.go index 83af02c043..4031cf12fe 100644 --- a/tests/testing.go +++ b/tests/testing.go @@ -1,35 +1,38 @@ package tests import ( + "embed" "encoding/json" "fmt" + "io/fs" "math/big" "os" "path/filepath" "strings" "testing" + "github.com/umbracle/fastrlp" + "github.com/0xPolygon/polygon-edge/chain" "github.com/0xPolygon/polygon-edge/crypto" + "github.com/0xPolygon/polygon-edge/helper/common" "github.com/0xPolygon/polygon-edge/helper/hex" + "github.com/0xPolygon/polygon-edge/helper/keccak" "github.com/0xPolygon/polygon-edge/state" itrie "github.com/0xPolygon/polygon-edge/state/immutable-trie" "github.com/0xPolygon/polygon-edge/state/runtime" "github.com/0xPolygon/polygon-edge/types" ) -// TESTS is the default location of the tests folder -const TESTS = "./tests" - -type info struct { - Comment string `json:"comment"` - FilledWith string `json:"filledwith"` - LllcVersion string `json:"lllcversion"` - Source string `json:"source"` - SourceHash string `json:"sourcehash"` +type testCase struct { + Env *env `json:"env"` + Pre map[types.Address]*chain.GenesisAccount `json:"pre"` + Post map[string]postState `json:"post"` + Transaction *stTransaction `json:"transaction"` } type env struct { + BaseFee string `json:"currentBaseFee"` Coinbase string `json:"currentCoinbase"` Difficulty string `json:"currentDifficulty"` GasLimit string `json:"currentGasLimit"` @@ -81,6 +84,17 @@ func stringToBigInt(str string) (*big.Int, error) { return n, nil } +func stringToBigIntT(t *testing.T, str string) *big.Int { + t.Helper() + + number, err := stringToBigInt(str) + if err != nil { + t.Fatal(err) + } + + return number +} + func stringToAddressT(t *testing.T, str string) types.Address { t.Helper() @@ -137,10 +151,14 @@ func stringToInt64T(t *testing.T, str string) int64 { func (e *env) ToHeader(t *testing.T) *types.Header { t.Helper() - miner := stringToAddressT(t, e.Coinbase) + baseFee := uint64(0) + if e.BaseFee != "" { + baseFee = stringToUint64T(t, e.BaseFee) + } return &types.Header{ - Miner: miner[:], + Miner: stringToAddressT(t, e.Coinbase).Bytes(), + BaseFee: baseFee, Difficulty: stringToUint64T(t, e.Difficulty), GasLimit: stringToUint64T(t, e.GasLimit), Number: stringToUint64T(t, e.Number), @@ -151,8 +169,14 @@ func (e *env) ToHeader(t *testing.T) *types.Header { func (e *env) ToEnv(t *testing.T) runtime.TxContext { t.Helper() + baseFee := new(big.Int) + if e.BaseFee != "" { + baseFee = stringToBigIntT(t, e.BaseFee) + } + return runtime.TxContext{ Coinbase: stringToAddressT(t, e.Coinbase), + BaseFee: baseFee, Difficulty: stringToHashT(t, e.Difficulty), GasLimit: stringToInt64T(t, e.GasLimit), Number: stringToInt64T(t, e.Number), @@ -160,71 +184,9 @@ func (e *env) ToEnv(t *testing.T) runtime.TxContext { } } -type exec struct { - Address types.Address - Caller types.Address - Origin types.Address - Code []byte - Data []byte - Value *big.Int - GasLimit uint64 - GasPrice *big.Int -} - -func (e *exec) UnmarshalJSON(input []byte) error { - type execUnmarshall struct { - Address types.Address `json:"address"` - Caller types.Address `json:"caller"` - Origin types.Address `json:"origin"` - Code string `json:"code"` - Data string `json:"data"` - Value string `json:"value"` - Gas string `json:"gas"` - GasPrice string `json:"gasPrice"` - } - - var dec execUnmarshall - err := json.Unmarshal(input, &dec) - - if err != nil { - return err - } - - e.Address = dec.Address - e.Caller = dec.Caller - e.Origin = dec.Origin - - e.Code, err = types.ParseBytes(&dec.Code) - if err != nil { - return err - } - - e.Data, err = types.ParseBytes(&dec.Data) - if err != nil { - return err - } - - e.Value, err = types.ParseUint256orHex(&dec.Value) - if err != nil { - return err - } - - e.GasLimit, err = types.ParseUint64orHex(&dec.Gas) - if err != nil { - return err - } - - e.GasPrice, err = types.ParseUint256orHex(&dec.GasPrice) - if err != nil { - return err - } - - return nil -} - func buildState( allocs map[types.Address]*chain.GenesisAccount, -) (state.State, state.Snapshot, types.Hash) { +) (state.State, state.Snapshot, types.Hash, error) { s := itrie.NewState(itrie.NewMemoryStorage()) snap := s.NewSnapshot() @@ -244,10 +206,14 @@ func buildState( } } - objs := txn.Commit(false) - snap, root := snap.Commit(objs) + objs, err := txn.Commit(false) + if err != nil { + return nil, nil, types.ZeroHash, err + } + + snap, _, root := snap.Commit(objs) - return s, snap, types.BytesToHash(root) + return s, snap, types.BytesToHash(root), nil } type indexes struct { @@ -260,6 +226,7 @@ type postEntry struct { Root types.Hash Logs types.Hash Indexes indexes + TxBytes []byte } type postState []postEntry @@ -269,6 +236,7 @@ func (p *postEntry) UnmarshalJSON(input []byte) error { Root string `json:"hash"` Logs string `json:"logs"` Indexes indexes `json:"indexes"` + TxBytes string `json:"txbytes"` } var dec stateUnmarshall @@ -279,21 +247,24 @@ func (p *postEntry) UnmarshalJSON(input []byte) error { p.Root = types.StringToHash(dec.Root) p.Logs = types.StringToHash(dec.Logs) p.Indexes = dec.Indexes + p.TxBytes = types.StringToBytes(dec.TxBytes) return nil } type stTransaction struct { - Data []string `json:"data"` - GasLimit []uint64 `json:"gasLimit"` - Value []*big.Int `json:"value"` - GasPrice *big.Int `json:"gasPrice"` - Nonce uint64 `json:"nonce"` - From types.Address `json:"secretKey"` - To *types.Address `json:"to"` + Data []string `json:"data"` + GasLimit []uint64 `json:"gasLimit"` + Value []*big.Int `json:"value"` + GasPrice *big.Int `json:"gasPrice"` + MaxFeePerGas *big.Int `json:"maxFeePerGas"` + MaxPriorityFeePerGas *big.Int `json:"maxPriorityFeePerGas"` + Nonce uint64 `json:"nonce"` + From types.Address `json:"secretKey"` + To *types.Address `json:"to"` } -func (t *stTransaction) At(i indexes) (*types.Transaction, error) { +func (t *stTransaction) At(i indexes, baseFee *big.Int) (*types.Transaction, error) { if i.Data > len(t.Data) { return nil, fmt.Errorf("data index %d out of bounds (%d)", i.Data, len(t.Data)) } @@ -306,46 +277,65 @@ func (t *stTransaction) At(i indexes) (*types.Transaction, error) { return nil, fmt.Errorf("value index %d out of bounds (%d)", i.Value, len(t.Value)) } - msg := &types.Transaction{ - To: t.To, - Nonce: t.Nonce, - Value: new(big.Int).Set(t.Value[i.Value]), - Gas: t.GasLimit[i.Gas], - GasPrice: new(big.Int).Set(t.GasPrice), - Input: hex.MustDecodeHex(t.Data[i.Data]), - } + gasPrice := t.GasPrice + + // If baseFee provided, set gasPrice to effectiveGasPrice. + if baseFee != nil { + if t.MaxFeePerGas == nil { + t.MaxFeePerGas = gasPrice + } - msg.From = t.From + if t.MaxFeePerGas == nil { + t.MaxFeePerGas = new(big.Int) + } - return msg, nil + if t.MaxPriorityFeePerGas == nil { + t.MaxPriorityFeePerGas = t.MaxFeePerGas + } + + gasPrice = common.BigMin(new(big.Int).Add(t.MaxPriorityFeePerGas, baseFee), t.MaxFeePerGas) + } + + return &types.Transaction{ + From: t.From, + To: t.To, + Nonce: t.Nonce, + Value: new(big.Int).Set(t.Value[i.Value]), + Gas: t.GasLimit[i.Gas], + GasPrice: new(big.Int).Set(gasPrice), + GasFeeCap: t.MaxFeePerGas, + GasTipCap: t.MaxPriorityFeePerGas, + Input: hex.MustDecodeHex(t.Data[i.Data]), + }, nil } func (t *stTransaction) UnmarshalJSON(input []byte) error { type txUnmarshall struct { - Data []string `json:"data"` - GasLimit []string `json:"gasLimit"` - Value []string `json:"value"` - GasPrice string `json:"gasPrice"` - Nonce string `json:"nonce"` - SecretKey string `json:"secretKey"` - To string `json:"to"` + Data []string `json:"data,omitempty"` + GasLimit []string `json:"gasLimit,omitempty"` + Value []string `json:"value,omitempty"` + GasPrice string `json:"gasPrice,omitempty"` + MaxFeePerGas string `json:"maxFeePerGas,omitempty"` + MaxPriorityFeePerGas string `json:"maxPriorityFeePerGas,omitempty"` + Nonce string `json:"nonce,omitempty"` + SecretKey string `json:"secretKey,omitempty"` + To string `json:"to,omitempty"` } var dec txUnmarshall - err := json.Unmarshal(input, &dec) - - if err != nil { - return err + if err := json.Unmarshal(input, &dec); err != nil { + return fmt.Errorf("failed to unmarshal transaction into temporary struct: %w", err) } t.Data = dec.Data for _, i := range dec.GasLimit { - if j, err := stringToUint64(i); err != nil { - return err - } else { - t.GasLimit = append(t.GasLimit, j) + j, err := stringToUint64(i) + if err != nil { + return fmt.Errorf("failed to convert string '%s' to uint64: %w", i, err) } + + t.GasLimit = append(t.GasLimit, j) } for _, i := range dec.Value { @@ -364,14 +354,30 @@ func (t *stTransaction) UnmarshalJSON(input []byte) error { t.Value = append(t.Value, value) } - t.GasPrice, err = stringToBigInt(dec.GasPrice) - if err != nil { - return err + var err error + + if dec.GasPrice != "" { + if t.GasPrice, err = stringToBigInt(dec.GasPrice); err != nil { + return fmt.Errorf("failed to parse gas price: %w", err) + } } - t.Nonce, err = stringToUint64(dec.Nonce) - if err != nil { - return err + if dec.MaxFeePerGas != "" { + if t.MaxFeePerGas, err = stringToBigInt(dec.MaxFeePerGas); err != nil { + return fmt.Errorf("failed to parse max fee per gas: %w", err) + } + } + + if dec.MaxPriorityFeePerGas != "" { + if t.MaxPriorityFeePerGas, err = stringToBigInt(dec.MaxPriorityFeePerGas); err != nil { + return fmt.Errorf("failed to parse max priority fee per gas: %w", err) + } + } + + if dec.Nonce != "" { + if t.Nonce, err = stringToUint64(dec.Nonce); err != nil { + return fmt.Errorf("failed to parse nonce: %w", err) + } } t.From = types.Address{} @@ -379,7 +385,7 @@ func (t *stTransaction) UnmarshalJSON(input []byte) error { if len(dec.SecretKey) > 0 { secretKey, err := types.ParseBytes(&dec.SecretKey) if err != nil { - return err + return fmt.Errorf("failed to parse secret key: %w", err) } key, err := crypto.ParseECDSAPrivateKey(secretKey) @@ -403,83 +409,72 @@ func (t *stTransaction) UnmarshalJSON(input []byte) error { var Forks = map[string]*chain.Forks{ "Frontier": {}, "Homestead": { - Homestead: chain.NewFork(0), + chain.Homestead: chain.NewFork(0), }, "EIP150": { - Homestead: chain.NewFork(0), - EIP150: chain.NewFork(0), + chain.Homestead: chain.NewFork(0), + chain.EIP150: chain.NewFork(0), }, "EIP158": { - Homestead: chain.NewFork(0), - EIP150: chain.NewFork(0), - EIP155: chain.NewFork(0), - EIP158: chain.NewFork(0), + chain.Homestead: chain.NewFork(0), + chain.EIP150: chain.NewFork(0), + chain.EIP155: chain.NewFork(0), + chain.EIP158: chain.NewFork(0), }, "Byzantium": { - Homestead: chain.NewFork(0), - EIP150: chain.NewFork(0), - EIP155: chain.NewFork(0), - EIP158: chain.NewFork(0), - Byzantium: chain.NewFork(0), + chain.Homestead: chain.NewFork(0), + chain.EIP150: chain.NewFork(0), + chain.EIP155: chain.NewFork(0), + chain.EIP158: chain.NewFork(0), + chain.Byzantium: chain.NewFork(0), }, "Constantinople": { - Homestead: chain.NewFork(0), - EIP150: chain.NewFork(0), - EIP155: chain.NewFork(0), - EIP158: chain.NewFork(0), - Byzantium: chain.NewFork(0), - Constantinople: chain.NewFork(0), - }, - "Istanbul": { - Homestead: chain.NewFork(0), - EIP150: chain.NewFork(0), - EIP155: chain.NewFork(0), - EIP158: chain.NewFork(0), - Byzantium: chain.NewFork(0), - Constantinople: chain.NewFork(0), - Petersburg: chain.NewFork(0), - Istanbul: chain.NewFork(0), + chain.Homestead: chain.NewFork(0), + chain.EIP150: chain.NewFork(0), + chain.EIP155: chain.NewFork(0), + chain.EIP158: chain.NewFork(0), + chain.Byzantium: chain.NewFork(0), + chain.Constantinople: chain.NewFork(0), }, - "London": { - Homestead: chain.NewFork(0), - EIP150: chain.NewFork(0), - EIP155: chain.NewFork(0), - EIP158: chain.NewFork(0), - Byzantium: chain.NewFork(0), - Constantinople: chain.NewFork(0), - Petersburg: chain.NewFork(0), - Istanbul: chain.NewFork(0), - London: chain.NewFork(0), + "Istchain.anbul": { + chain.Homestead: chain.NewFork(0), + chain.EIP150: chain.NewFork(0), + chain.EIP155: chain.NewFork(0), + chain.EIP158: chain.NewFork(0), + chain.Byzantium: chain.NewFork(0), + chain.Constantinople: chain.NewFork(0), + chain.Petersburg: chain.NewFork(0), + chain.Istanbul: chain.NewFork(0), }, "FrontierToHomesteadAt5": { - Homestead: chain.NewFork(5), + chain.Homestead: chain.NewFork(5), }, "HomesteadToEIP150At5": { - Homestead: chain.NewFork(0), - EIP150: chain.NewFork(5), + chain.Homestead: chain.NewFork(0), + chain.EIP150: chain.NewFork(5), }, "HomesteadToDaoAt5": { - Homestead: chain.NewFork(0), + chain.Homestead: chain.NewFork(0), }, "EIP158ToByzantiumAt5": { - Homestead: chain.NewFork(0), - EIP150: chain.NewFork(0), - EIP155: chain.NewFork(0), - EIP158: chain.NewFork(0), - Byzantium: chain.NewFork(5), + chain.Homestead: chain.NewFork(0), + chain.EIP150: chain.NewFork(0), + chain.EIP155: chain.NewFork(0), + chain.EIP158: chain.NewFork(0), + chain.Byzantium: chain.NewFork(5), }, "ByzantiumToConstantinopleAt5": { - Byzantium: chain.NewFork(0), - Constantinople: chain.NewFork(5), + chain.Byzantium: chain.NewFork(0), + chain.Constantinople: chain.NewFork(5), }, "ConstantinopleFix": { - Homestead: chain.NewFork(0), - EIP150: chain.NewFork(0), - EIP155: chain.NewFork(0), - EIP158: chain.NewFork(0), - Byzantium: chain.NewFork(0), - Constantinople: chain.NewFork(0), - Petersburg: chain.NewFork(0), + chain.Homestead: chain.NewFork(0), + chain.EIP150: chain.NewFork(0), + chain.EIP155: chain.NewFork(0), + chain.EIP158: chain.NewFork(0), + chain.Byzantium: chain.NewFork(0), + chain.Constantinople: chain.NewFork(0), + chain.Petersburg: chain.NewFork(0), }, } @@ -493,37 +488,42 @@ func contains(l []string, name string) bool { return false } -func listFolders(paths ...string) ([]string, error) { - folders := []string{} +//go:embed tests +var testsFS embed.FS - for _, p := range paths { - path := filepath.Join(TESTS, p) +func listFolders(tests ...string) ([]string, error) { + var folders []string - files, err := os.ReadDir(path) - if err != nil { - return nil, err - } + for _, t := range tests { + if err := fs.WalkDir(testsFS, t, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } - for _, i := range files { - if i.IsDir() { - folders = append(folders, filepath.Join(path, i.Name())) + if d.IsDir() && t != "path" { + folders = append(folders, path) } + + return nil + }); err != nil { + return nil, err } + + // Excluding root dir + folders = folders[1:] } return folders, nil } func listFiles(folder string) ([]string, error) { - if !strings.HasPrefix(folder, filepath.Base(TESTS)) { - folder = filepath.Join(TESTS, folder) - } + var files []string - files := []string{} err := filepath.Walk(folder, func(path string, info os.FileInfo, err error) error { if err != nil { return err } + if !info.IsDir() { files = append(files, path) } @@ -533,3 +533,20 @@ func listFiles(folder string) ([]string, error) { return files, err } + +func rlpHashLogs(logs []*types.Log) (res types.Hash) { + r := &types.Receipt{ + Logs: logs, + } + + ar := &fastrlp.Arena{} + v := r.MarshalLogsWith(ar) + + keccak.Keccak256Rlp(res[:0], v) + + return +} + +func vmTestBlockHash(n uint64) types.Hash { + return types.BytesToHash(crypto.Keccak256([]byte(big.NewInt(int64(n)).String()))) +} diff --git a/tracker/event_tracker.go b/tracker/event_tracker.go index 882e7bab6e..6ecca5c926 100644 --- a/tracker/event_tracker.go +++ b/tracker/event_tracker.go @@ -2,7 +2,9 @@ package tracker import ( "context" + "time" + "github.com/0xPolygon/polygon-edge/helper/common" hcf "github.com/hashicorp/go-hclog" "github.com/umbracle/ethgo" "github.com/umbracle/ethgo/blocktracker" @@ -10,6 +12,8 @@ import ( "github.com/umbracle/ethgo/tracker" ) +const minBlockMaxBacklog = 96 + type eventSubscription interface { AddLog(log *ethgo.Log) } @@ -61,9 +65,42 @@ func (e *EventTracker) Start(ctx context.Context) error { return err } - blockMaxBacklog := e.numBlockConfirmations*2 + 1 + blockMaxBacklog := e.numBlockConfirmations * 2 + if blockMaxBacklog < minBlockMaxBacklog { + blockMaxBacklog = minBlockMaxBacklog + } + blockTracker := blocktracker.NewBlockTracker(provider.Eth(), blocktracker.WithBlockMaxBacklog(blockMaxBacklog)) + go func() { + <-ctx.Done() + blockTracker.Close() + store.Close() + }() + + // Init and start block tracker concurrently, retrying indefinitely + go common.RetryForever(ctx, time.Second, func(context.Context) error { + start := time.Now().UTC() + + if err := blockTracker.Init(); err != nil { + e.logger.Error("failed to init blocktracker", "error", err) + + return err + } + + elapsed := time.Now().UTC().Sub(start) // Calculate the elapsed time + + if err := blockTracker.Start(); err != nil { + e.logger.Error("failed to start blocktracker", "error", err) + + return err + } + + e.logger.Info("Block tracker has been started", "max backlog", blockMaxBacklog, "init time", elapsed) + + return nil + }) + tt, err := tracker.NewTracker(provider.Eth(), tracker.WithBatchSize(10), tracker.WithBlockTracker(blockTracker), @@ -79,30 +116,16 @@ func (e *EventTracker) Start(ctx context.Context) error { if err != nil { return err } - - go func() { - if err := blockTracker.Init(); err != nil { - e.logger.Error("failed to init blocktracker", "error", err) - - return - } - - if err := blockTracker.Start(); err != nil { - e.logger.Error("failed to start blocktracker", "error", err) - } - }() - - go func() { - <-ctx.Done() - blockTracker.Close() - store.Close() - }() - - go func() { + // Sync concurrently, retrying indefinitely + go common.RetryForever(ctx, time.Second, func(context.Context) error { if err := tt.Sync(ctx); err != nil { e.logger.Error("failed to sync", "error", err) + + return err } - }() + + return nil + }) return nil } diff --git a/txpool/query.go b/txpool/query.go index 7ffc45e761..8e4c9ba91f 100644 --- a/txpool/query.go +++ b/txpool/query.go @@ -1,6 +1,10 @@ package txpool -import "github.com/0xPolygon/polygon-edge/types" +import ( + "sync/atomic" + + "github.com/0xPolygon/polygon-edge/types" +) /* QUERY methods */ // Used to query the pool for specific state info. @@ -46,3 +50,8 @@ func (p *TxPool) GetTxs(inclQueued bool) ( return } + +// GetBaseFee returns current base fee +func (p *TxPool) GetBaseFee() uint64 { + return atomic.LoadUint64(&p.baseFee) +} diff --git a/txpool/queue.go b/txpool/queue_account.go similarity index 60% rename from txpool/queue.go rename to txpool/queue_account.go index 4cff31222f..63340b0b2d 100644 --- a/txpool/queue.go +++ b/txpool/queue_account.go @@ -12,7 +12,7 @@ import ( // All methods assume the (correct) lock is held. type accountQueue struct { sync.RWMutex - wLock uint32 + wLock atomic.Bool queue minNonceQueue } @@ -27,18 +27,17 @@ func newAccountQueue() *accountQueue { } func (q *accountQueue) lock(write bool) { - switch write { - case true: + if write { q.Lock() - atomic.StoreUint32(&q.wLock, 1) - case false: + } else { q.RLock() - atomic.StoreUint32(&q.wLock, 0) } + + q.wLock.Store(write) } func (q *accountQueue) unlock() { - if atomic.SwapUint32(&q.wLock, 0) == 1 { + if q.wLock.Swap(false) { q.Unlock() } else { q.RUnlock() @@ -152,90 +151,3 @@ func (q *minNonceQueue) Pop() interface{} { return x } - -type pricedQueue struct { - queue maxPriceQueue -} - -func newPricedQueue() *pricedQueue { - q := pricedQueue{ - queue: make(maxPriceQueue, 0), - } - - heap.Init(&q.queue) - - return &q -} - -// clear empties the underlying queue. -func (q *pricedQueue) clear() { - q.queue = q.queue[:0] -} - -// Pushes the given transactions onto the queue. -func (q *pricedQueue) push(tx *types.Transaction) { - heap.Push(&q.queue, tx) -} - -// Pop removes the first transaction from the queue -// or nil if the queue is empty. -func (q *pricedQueue) pop() *types.Transaction { - if q.length() == 0 { - return nil - } - - transaction, ok := heap.Pop(&q.queue).(*types.Transaction) - if !ok { - return nil - } - - return transaction -} - -// length returns the number of transactions in the queue. -func (q *pricedQueue) length() uint64 { - return uint64(q.queue.Len()) -} - -// transactions sorted by gas price (descending) -type maxPriceQueue []*types.Transaction - -/* Queue methods required by the heap interface */ - -func (q *maxPriceQueue) Peek() *types.Transaction { - if q.Len() == 0 { - return nil - } - - return (*q)[0] -} - -func (q *maxPriceQueue) Len() int { - return len(*q) -} - -func (q *maxPriceQueue) Swap(i, j int) { - (*q)[i], (*q)[j] = (*q)[j], (*q)[i] -} - -func (q *maxPriceQueue) Less(i, j int) bool { - return (*q)[i].GasPrice.Uint64() > (*q)[j].GasPrice.Uint64() -} - -func (q *maxPriceQueue) Push(x interface{}) { - transaction, ok := x.(*types.Transaction) - if !ok { - return - } - - *q = append(*q, transaction) -} - -func (q *maxPriceQueue) Pop() interface{} { - old := q - n := len(*old) - x := (*old)[n-1] - *q = (*old)[0 : n-1] - - return x -} diff --git a/txpool/queue_priced.go b/txpool/queue_priced.go new file mode 100644 index 0000000000..88390a11fd --- /dev/null +++ b/txpool/queue_priced.go @@ -0,0 +1,149 @@ +package txpool + +import ( + "container/heap" + "math/big" + "sync/atomic" + + "github.com/0xPolygon/polygon-edge/types" +) + +type pricedQueue struct { + queue *maxPriceQueue +} + +func newPricedQueue() *pricedQueue { + q := pricedQueue{ + queue: &maxPriceQueue{}, + } + + heap.Init(q.queue) + + return &q +} + +// clear empties the underlying queue. +func (q *pricedQueue) clear() { + q.queue.txs = q.queue.txs[:0] +} + +// Pushes the given transactions onto the queue. +func (q *pricedQueue) push(tx *types.Transaction) { + heap.Push(q.queue, tx) +} + +// Pop removes the first transaction from the queue +// or nil if the queue is empty. +func (q *pricedQueue) pop() *types.Transaction { + if q.length() == 0 { + return nil + } + + transaction, ok := heap.Pop(q.queue).(*types.Transaction) + if !ok { + return nil + } + + return transaction +} + +// length returns the number of transactions in the queue. +func (q *pricedQueue) length() uint64 { + return uint64(q.queue.Len()) +} + +// transactions sorted by gas price (descending) +type maxPriceQueue struct { + baseFee uint64 + txs []*types.Transaction +} + +/* Queue methods required by the heap interface */ + +func (q *maxPriceQueue) Peek() *types.Transaction { + if q.Len() == 0 { + return nil + } + + return q.txs[0] +} + +func (q *maxPriceQueue) Len() int { + return len(q.txs) +} + +func (q *maxPriceQueue) Swap(i, j int) { + q.txs[i], q.txs[j] = q.txs[j], q.txs[i] +} + +func (q *maxPriceQueue) Less(i, j int) bool { + switch q.cmp(q.txs[i], q.txs[j]) { + case -1: + return true + case 1: + return false + default: + return q.txs[i].Nonce > q.txs[j].Nonce + } +} + +func (q *maxPriceQueue) Push(x interface{}) { + transaction, ok := x.(*types.Transaction) + if !ok { + return + } + + q.txs = append(q.txs, transaction) +} + +func (q *maxPriceQueue) Pop() interface{} { + old := q.txs + n := len(old) + x := old[n-1] + q.txs = old[0 : n-1] + + return x +} + +// cmp compares the given transactions by their fees and returns: +// - 0 if they have same fees +// - 1 if a has higher fees than b +// - -1 if b has higher fees than a +func (q *maxPriceQueue) cmp(a, b *types.Transaction) int { + baseFee := atomic.LoadUint64(&q.baseFee) + effectiveTipA := a.EffectiveTip(baseFee) + effectiveTipB := b.EffectiveTip(baseFee) + + // Compare effective tips if baseFee is specified + if c := effectiveTipA.Cmp(effectiveTipB); c != 0 { + return c + } + + aGasFeeCap, bGasFeeCap := new(big.Int), new(big.Int) + + if a.GasFeeCap != nil { + aGasFeeCap = aGasFeeCap.Set(a.GasFeeCap) + } + + if b.GasFeeCap != nil { + bGasFeeCap = bGasFeeCap.Set(b.GasFeeCap) + } + + // Compare fee caps if baseFee is not specified or effective tips are equal + if c := aGasFeeCap.Cmp(bGasFeeCap); c != 0 { + return c + } + + aGasTipCap, bGasTipCap := new(big.Int), new(big.Int) + + if a.GasTipCap != nil { + aGasTipCap = aGasTipCap.Set(a.GasTipCap) + } + + if b.GasTipCap != nil { + bGasTipCap = bGasTipCap.Set(b.GasTipCap) + } + + // Compare tips if effective tips and fee caps are equal + return aGasTipCap.Cmp(bGasTipCap) +} diff --git a/txpool/queue_priced_test.go b/txpool/queue_priced_test.go new file mode 100644 index 0000000000..7e8aea3695 --- /dev/null +++ b/txpool/queue_priced_test.go @@ -0,0 +1,326 @@ +package txpool + +import ( + "math/big" + "math/rand" + "sort" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/0xPolygon/polygon-edge/types" +) + +func Test_maxPriceQueue(t *testing.T) { + t.Parallel() + + testTable := []struct { + name string + baseFee uint64 + unsorted []*types.Transaction + sorted []*types.Transaction + }{ + { + name: "sort txs by tips with base fee", + baseFee: 1000, + unsorted: []*types.Transaction{ + // Highest tx fee + { + Type: types.DynamicFeeTx, + GasPrice: big.NewInt(0), + GasFeeCap: big.NewInt(2000), + GasTipCap: big.NewInt(500), + }, + // Lowest tx fee + { + Type: types.LegacyTx, + GasPrice: big.NewInt(100), + }, + // Middle tx fee + { + Type: types.DynamicFeeTx, + GasPrice: big.NewInt(0), + GasFeeCap: big.NewInt(1500), + GasTipCap: big.NewInt(200), + }, + }, + sorted: []*types.Transaction{ + // Highest tx fee + { + Type: types.DynamicFeeTx, + GasPrice: big.NewInt(0), + GasFeeCap: big.NewInt(2000), + GasTipCap: big.NewInt(500), + }, + // Middle tx fee + { + Type: types.DynamicFeeTx, + GasPrice: big.NewInt(0), + GasFeeCap: big.NewInt(1500), + GasTipCap: big.NewInt(200), + }, + // Lowest tx fee + { + Type: types.LegacyTx, + GasPrice: big.NewInt(100), + }, + }, + }, + { + name: "sort txs by nonce with base fee", + baseFee: 1000, + unsorted: []*types.Transaction{ + // Highest tx fee + { + Type: types.DynamicFeeTx, + GasFeeCap: big.NewInt(2000), + GasTipCap: big.NewInt(500), + Nonce: 3, + }, + // Lowest tx fee + { + Type: types.DynamicFeeTx, + GasFeeCap: big.NewInt(2000), + GasTipCap: big.NewInt(500), + Nonce: 1, + }, + // Middle tx fee + { + Type: types.DynamicFeeTx, + GasFeeCap: big.NewInt(2000), + GasTipCap: big.NewInt(500), + Nonce: 2, + }, + }, + sorted: []*types.Transaction{ + // Highest tx fee + { + Type: types.DynamicFeeTx, + GasFeeCap: big.NewInt(2000), + GasTipCap: big.NewInt(500), + Nonce: 1, + }, + // Middle tx fee + { + Type: types.DynamicFeeTx, + GasFeeCap: big.NewInt(2000), + GasTipCap: big.NewInt(500), + Nonce: 2, + }, + // Lowest tx fee + { + Type: types.DynamicFeeTx, + GasFeeCap: big.NewInt(2000), + GasTipCap: big.NewInt(500), + Nonce: 3, + }, + }, + }, + { + name: "sort txs without base fee by fee cap", + baseFee: 0, + unsorted: []*types.Transaction{ + // Highest tx fee + { + GasFeeCap: big.NewInt(3000), + GasTipCap: big.NewInt(100), + }, + // Lowest tx fee + { + GasFeeCap: big.NewInt(1000), + GasTipCap: big.NewInt(100), + }, + // Middle tx fee + { + GasFeeCap: big.NewInt(2000), + GasTipCap: big.NewInt(100), + }, + }, + sorted: []*types.Transaction{ + // Highest tx fee + { + GasFeeCap: big.NewInt(3000), + GasTipCap: big.NewInt(100), + }, + // Middle tx fee + { + GasFeeCap: big.NewInt(2000), + GasTipCap: big.NewInt(100), + }, + // Lowest tx fee + { + GasFeeCap: big.NewInt(1000), + GasTipCap: big.NewInt(100), + }, + }, + }, + { + name: "sort txs without base fee by tip cap", + baseFee: 0, + unsorted: []*types.Transaction{ + // Highest tx fee + { + GasFeeCap: big.NewInt(1000), + GasTipCap: big.NewInt(300), + }, + // Lowest tx fee + { + GasFeeCap: big.NewInt(1000), + GasTipCap: big.NewInt(100), + }, + // Middle tx fee + { + GasFeeCap: big.NewInt(1000), + GasTipCap: big.NewInt(200), + }, + }, + sorted: []*types.Transaction{ + // Highest tx fee + { + GasFeeCap: big.NewInt(1000), + GasTipCap: big.NewInt(300), + }, + // Middle tx fee + { + GasFeeCap: big.NewInt(1000), + GasTipCap: big.NewInt(200), + }, + // Lowest tx fee + { + GasFeeCap: big.NewInt(1000), + GasTipCap: big.NewInt(100), + }, + }, + }, + { + name: "sort txs without base fee by gas price", + baseFee: 0, + unsorted: []*types.Transaction{ + // Highest tx fee + { + GasPrice: big.NewInt(1000), + }, + // Lowest tx fee + { + GasPrice: big.NewInt(100), + }, + // Middle tx fee + { + GasPrice: big.NewInt(500), + }, + }, + sorted: []*types.Transaction{ + // Highest tx fee + { + GasPrice: big.NewInt(1000), + }, + // Middle tx fee + { + GasPrice: big.NewInt(500), + }, + // Lowest tx fee + { + GasPrice: big.NewInt(100), + }, + }, + }, + } + + for _, tt := range testTable { + tt := tt + + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + queue := &maxPriceQueue{ + baseFee: tt.baseFee, + txs: tt.unsorted, + } + + sort.Sort(queue) + + for _, tx := range tt.sorted { + actual := queue.Pop() + assert.Equal(t, tx, actual) + } + }) + } +} + +func Benchmark_pricedQueue(t *testing.B) { + testTable := []struct { + name string + unsortedTxs []*types.Transaction + }{ + { + name: "1000 transactions", + unsortedTxs: generateTxs(1000), + }, + { + name: "10000 transactions", + unsortedTxs: generateTxs(10000), + }, + { + name: "100000 transactions", + unsortedTxs: generateTxs(100000), + }, + } + + for _, tt := range testTable { + t.Run(tt.name, func(b *testing.B) { + for i := 0; i < t.N; i++ { + q := newPricedQueue() + q.queue.baseFee = uint64(i) + + for _, tx := range tt.unsortedTxs { + q.push(tx) + } + + for q.length() > 0 { + _ = q.pop() + } + } + }) + } +} + +func generateTxs(num int) []*types.Transaction { + txs := make([]*types.Transaction, num) + + for i := 0; i < num; i++ { + txs[i] = generateTx(i + 1) + } + + return txs +} + +func generateTx(i int) *types.Transaction { + s := rand.NewSource(int64(i)) + r := rand.New(s) + + txTypes := []types.TxType{ + types.LegacyTx, + types.DynamicFeeTx, + } + + tx := &types.Transaction{ + Type: txTypes[r.Intn(len(txTypes))], + } + + switch tx.Type { + case types.LegacyTx: + minGasPrice := 1000 * i + maxGasPrice := 100000 * i + tx.GasPrice = new(big.Int).SetInt64(int64(rand.Intn(maxGasPrice-minGasPrice) + minGasPrice)) + case types.DynamicFeeTx: + minGasFeeCap := 1000 * i + maxGasFeeCap := 100000 * i + tx.GasFeeCap = new(big.Int).SetInt64(int64(rand.Intn(maxGasFeeCap-minGasFeeCap) + minGasFeeCap)) + + minGasTipCap := 100 * i + maxGasTipCap := 10000 * i + tx.GasTipCap = new(big.Int).SetInt64(int64(rand.Intn(maxGasTipCap-minGasTipCap) + minGasTipCap)) + } + + return tx +} diff --git a/txpool/slot_gauge.go b/txpool/slot_gauge.go index 4642ede4d4..2df18c6df0 100644 --- a/txpool/slot_gauge.go +++ b/txpool/slot_gauge.go @@ -4,6 +4,7 @@ import ( "sync/atomic" "github.com/0xPolygon/polygon-edge/types" + "github.com/armon/go-metrics" ) const ( @@ -23,12 +24,14 @@ func (g *slotGauge) read() uint64 { // increase increases the height of the gauge by the specified slots amount. func (g *slotGauge) increase(slots uint64) { - atomic.AddUint64(&g.height, slots) + newHeight := atomic.AddUint64(&g.height, slots) + metrics.SetGauge([]string{txPoolMetrics, "slots_used"}, float32(newHeight)) } // decrease decreases the height of the gauge by the specified slots amount. func (g *slotGauge) decrease(slots uint64) { - atomic.AddUint64(&g.height, ^(slots - 1)) + newHeight := atomic.AddUint64(&g.height, ^(slots - 1)) + metrics.SetGauge([]string{txPoolMetrics, "slots_used"}, float32(newHeight)) } // highPressure checks if the gauge level diff --git a/txpool/txpool.go b/txpool/txpool.go index d9d3b13102..57f2187edc 100644 --- a/txpool/txpool.go +++ b/txpool/txpool.go @@ -55,8 +55,10 @@ var ( ErrOversizedData = errors.New("oversized data") ErrMaxEnqueuedLimitReached = errors.New("maximum number of enqueued transactions reached") ErrRejectFutureTx = errors.New("rejected future tx due to low slots") - ErrSmartContractRestricted = errors.New("smart contract deployment restricted") ErrInvalidTxType = errors.New("invalid tx type") + ErrTipAboveFeeCap = errors.New("max priority fee per gas higher than max fee per gas") + ErrTipVeryHigh = errors.New("max priority fee per gas higher than 2^256-1") + ErrFeeCapVeryHigh = errors.New("max fee per gas higher than 2^256-1") ) // indicates origin of a transaction @@ -91,10 +93,9 @@ type signer interface { } type Config struct { - PriceLimit uint64 - MaxSlots uint64 - MaxAccountEnqueued uint64 - DeploymentWhitelist []types.Address + PriceLimit uint64 + MaxSlots uint64 + MaxAccountEnqueued uint64 } /* All requests are passed to the main loop @@ -170,14 +171,15 @@ type TxPool struct { // flag indicating if the current node is a sealer, // and should therefore gossip transactions - sealing uint32 + sealing atomic.Bool + + // baseFee is the base fee of the current head. + // This is needed to sort transactions by price + baseFee uint64 // Event manager for txpool events eventManager *eventManager - // deploymentWhitelist map - deploymentWhitelist deploymentWhitelist - // indicates which txpool operator commands should be implemented proto.UnimplementedTxnPoolOperatorServer @@ -186,41 +188,6 @@ type TxPool struct { pending int64 } -// deploymentWhitelist map which contains all addresses which can deploy contracts -// if empty anyone can -type deploymentWhitelist struct { - // Contract deployment whitelist - addresses map[string]bool -} - -// add an address to deploymentWhitelist map -func (w *deploymentWhitelist) add(addr types.Address) { - w.addresses[addr.String()] = true -} - -// allowed checks if address can deploy smart contract -func (w *deploymentWhitelist) allowed(addr types.Address) bool { - if len(w.addresses) == 0 { - return true - } - - _, ok := w.addresses[addr.String()] - - return ok -} - -func newDeploymentWhitelist(deploymentWhitelistRaw []types.Address) deploymentWhitelist { - deploymentWhitelist := deploymentWhitelist{ - addresses: map[string]bool{}, - } - - for _, addr := range deploymentWhitelistRaw { - deploymentWhitelist.add(addr) - } - - return deploymentWhitelist -} - // NewTxPool returns a new pool for processing incoming transactions. func NewTxPool( logger hclog.Logger, @@ -264,9 +231,6 @@ func NewTxPool( pool.topic = topic } - // initialize deployment whitelist - pool.deploymentWhitelist = newDeploymentWhitelist(config.DeploymentWhitelist) - if grpcServer != nil { proto.RegisterTxnPoolOperatorServer(grpcServer, pool) } @@ -331,21 +295,7 @@ func (p *TxPool) SetSigner(s signer) { // SetSealing sets the sealing flag func (p *TxPool) SetSealing(sealing bool) { - newValue := uint32(0) - if sealing { - newValue = 1 - } - - atomic.CompareAndSwapUint32( - &p.sealing, - p.sealing, - newValue, - ) -} - -// sealing returns the current set sealing flag -func (p *TxPool) getSealing() bool { - return atomic.LoadUint32(&p.sealing) == 1 + p.sealing.CompareAndSwap(p.sealing.Load(), sealing) } // AddTx adds a new transaction to the pool (sent from json-RPC/gRPC endpoints) @@ -376,12 +326,15 @@ func (p *TxPool) AddTx(tx *types.Transaction) error { // Prepare generates all the transactions // ready for execution. (primaries) -func (p *TxPool) Prepare() { +func (p *TxPool) Prepare(baseFee uint64) { // clear from previous round if p.executables.length() != 0 { p.executables.clear() } + // set base fee + p.updateBaseFee(baseFee) + // fetch primary from each account primaries := p.accounts.getPrimaries() @@ -474,11 +427,14 @@ func (p *TxPool) Drop(tx *types.Transaction) { clearAccountQueue(dropped) p.eventManager.signalEvent(proto.EventType_DROPPED, tx.Hash) - p.logger.Debug("dropped account txs", - "num", droppedCount, - "next_nonce", nextNonce, - "address", tx.From.String(), - ) + + if p.logger.IsDebug() { + p.logger.Debug("dropped account txs", + "num", droppedCount, + "next_nonce", nextNonce, + "address", tx.From.String(), + ) + } } // Demote excludes an account from being further processed during block building @@ -487,10 +443,12 @@ func (p *TxPool) Drop(tx *types.Transaction) { func (p *TxPool) Demote(tx *types.Transaction) { account := p.accounts.get(tx.From) if account.Demotions() >= maxAccountDemotions { - p.logger.Debug( - "Demote: threshold reached - dropping account", - "addr", tx.From.String(), - ) + if p.logger.IsDebug() { + p.logger.Debug( + "Demote: threshold reached - dropping account", + "addr", tx.From.String(), + ) + } p.Drop(tx) @@ -566,7 +524,7 @@ func (p *TxPool) processEvent(event *blockchain.Event) { // reset accounts with the new state p.resetAccounts(stateNonces) - if !p.getSealing() { + if !p.sealing.Load() { // only non-validator cleanup inactive accounts p.updateAccountSkipsCounts(stateNonces) } @@ -577,16 +535,22 @@ func (p *TxPool) processEvent(event *blockchain.Event) { func (p *TxPool) validateTx(tx *types.Transaction) error { // Check the transaction type. State transactions are not expected to be added to the pool if tx.Type == types.StateTx { + metrics.IncrCounter([]string{txPoolMetrics, "invalid_tx_type"}, 1) + return ErrInvalidTxType } // Check the transaction size to overcome DOS Attacks if uint64(len(tx.MarshalRLP())) > txMaxSize { + metrics.IncrCounter([]string{txPoolMetrics, "oversized_data_txs"}, 1) + return ErrOversizedData } // Check if the transaction has a strictly positive value if tx.Value.Sign() < 0 { + metrics.IncrCounter([]string{txPoolMetrics, "negative_value_tx"}, 1) + return ErrNegativeValue } @@ -595,6 +559,8 @@ func (p *TxPool) validateTx(tx *types.Transaction) error { // Extract the sender from, signerErr := p.signer.Sender(tx) if signerErr != nil { + metrics.IncrCounter([]string{txPoolMetrics, "invalid_signature_txs"}, 1) + return ErrExtractSignature } @@ -602,6 +568,8 @@ func (p *TxPool) validateTx(tx *types.Transaction) error { // it matches the signer if tx.From != types.ZeroAddress && tx.From != from { + metrics.IncrCounter([]string{txPoolMetrics, "invalid_sender_txs"}, 1) + return ErrInvalidSender } @@ -611,19 +579,58 @@ func (p *TxPool) validateTx(tx *types.Transaction) error { } // Check if transaction can deploy smart contract - if tx.IsContractCreation() { - if !p.deploymentWhitelist.allowed(tx.From) { - return ErrSmartContractRestricted + if tx.IsContractCreation() && p.forks.EIP158 && len(tx.Input) > state.TxPoolMaxInitCodeSize { + metrics.IncrCounter([]string{txPoolMetrics, "contract_deploy_too_large_txs"}, 1) + + return runtime.ErrMaxCodeSizeExceeded + } + + if tx.Type == types.DynamicFeeTx { + // Reject dynamic fee tx if london hardfork is not enabled + if !p.forks.London { + metrics.IncrCounter([]string{txPoolMetrics, "invalid_tx_type"}, 1) + + return ErrInvalidTxType } - if p.forks.EIP158 && len(tx.Input) > state.TxPoolMaxInitCodeSize { - return runtime.ErrMaxCodeSizeExceeded + // Check EIP-1559-related fields and make sure they are correct + if tx.GasFeeCap == nil || tx.GasTipCap == nil { + metrics.IncrCounter([]string{txPoolMetrics, "underpriced_tx"}, 1) + + return ErrUnderpriced } - } - // Reject underpriced transactions - if tx.IsUnderpriced(p.priceLimit) { - return ErrUnderpriced + if tx.GasFeeCap.BitLen() > 256 { + metrics.IncrCounter([]string{txPoolMetrics, "fee_cap_too_high_dynamic_tx"}, 1) + + return ErrFeeCapVeryHigh + } + + if tx.GasTipCap.BitLen() > 256 { + metrics.IncrCounter([]string{txPoolMetrics, "tip_too_high_dynamic_tx"}, 1) + + return ErrTipVeryHigh + } + + if tx.GasFeeCap.Cmp(tx.GasTipCap) < 0 { + metrics.IncrCounter([]string{txPoolMetrics, "tip_above_fee_cap_dynamic_tx"}, 1) + + return ErrTipAboveFeeCap + } + + // Reject underpriced transactions + if tx.GasFeeCap.Cmp(new(big.Int).SetUint64(p.GetBaseFee())) < 0 { + metrics.IncrCounter([]string{txPoolMetrics, "underpriced_tx"}, 1) + + return ErrUnderpriced + } + } else { + // Legacy approach to check if the given tx is not underpriced + if tx.GetGasPrice(p.GetBaseFee()).Cmp(big.NewInt(0).SetUint64(p.priceLimit)) < 0 { + metrics.IncrCounter([]string{txPoolMetrics, "underpriced_tx"}, 1) + + return ErrUnderpriced + } } // Grab the state root for the latest block @@ -631,26 +638,36 @@ func (p *TxPool) validateTx(tx *types.Transaction) error { // Check nonce ordering if p.store.GetNonce(stateRoot, tx.From) > tx.Nonce { + metrics.IncrCounter([]string{txPoolMetrics, "nonce_too_low_tx"}, 1) + return ErrNonceTooLow } accountBalance, balanceErr := p.store.GetBalance(stateRoot, tx.From) if balanceErr != nil { + metrics.IncrCounter([]string{txPoolMetrics, "invalid_account_state_tx"}, 1) + return ErrInvalidAccountState } // Check if the sender has enough funds to execute the transaction if accountBalance.Cmp(tx.Cost()) < 0 { + metrics.IncrCounter([]string{txPoolMetrics, "insufficient_funds_tx"}, 1) + return ErrInsufficientFunds } // Make sure the transaction has more gas than the basic transaction fee intrinsicGas, err := state.TransactionGasCost(tx, p.forks.Homestead, p.forks.Istanbul) if err != nil { + metrics.IncrCounter([]string{txPoolMetrics, "invalid_intrinsic_gas_tx"}, 1) + return err } if tx.Gas < intrinsicGas { + metrics.IncrCounter([]string{txPoolMetrics, "intrinsic_gas_low_tx"}, 1) + return ErrIntrinsicGas } @@ -658,6 +675,8 @@ func (p *TxPool) validateTx(tx *types.Transaction) error { latestBlockGasLimit := p.store.Header().GasLimit if tx.Gas > latestBlockGasLimit { + metrics.IncrCounter([]string{txPoolMetrics, "block_gas_limit_exceeded_tx"}, 1) + return ErrBlockLimitExceeded } @@ -704,10 +723,12 @@ func (p *TxPool) pruneAccountsWithNonceHoles() { // successful, an account is created for this address // (only once) and an enqueueRequest is signaled. func (p *TxPool) addTx(origin txOrigin, tx *types.Transaction) error { - p.logger.Debug("add tx", - "origin", origin.String(), - "hash", tx.Hash.String(), - ) + if p.logger.IsDebug() { + p.logger.Debug("add tx", + "origin", origin.String(), + "hash", tx.Hash.String(), + ) + } // validate incoming tx if err := p.validateTx(tx); err != nil { @@ -720,6 +741,8 @@ func (p *TxPool) addTx(origin txOrigin, tx *types.Transaction) error { // only accept transactions with expected nonce if account := p.accounts.get(tx.From); account != nil && tx.Nonce > account.getNonce() { + metrics.IncrCounter([]string{txPoolMetrics, "rejected_future_tx"}, 1) + return ErrRejectFutureTx } } @@ -733,6 +756,8 @@ func (p *TxPool) addTx(origin txOrigin, tx *types.Transaction) error { // add to index if ok := p.index.add(tx); !ok { + metrics.IncrCounter([]string{txPoolMetrics, "already_known_tx"}, 1) + return ErrAlreadyKnown } @@ -743,6 +768,8 @@ func (p *TxPool) addTx(origin txOrigin, tx *types.Transaction) error { p.enqueueReqCh <- enqueueRequest{tx: tx} p.eventManager.signalEvent(proto.EventType_ADDED, tx.Hash) + metrics.SetGauge([]string{txPoolMetrics, "added_tx"}, 1) + return nil } @@ -766,7 +793,9 @@ func (p *TxPool) handleEnqueueRequest(req enqueueRequest) { return } - p.logger.Debug("enqueue request", "hash", tx.Hash.String()) + if p.logger.IsDebug() { + p.logger.Debug("enqueue request", "hash", tx.Hash.String()) + } p.gauge.increase(slotsRequired(tx)) @@ -790,7 +819,9 @@ func (p *TxPool) handlePromoteRequest(req promoteRequest) { // promote enqueued txs promoted, pruned := account.promote() - p.logger.Debug("promote request", "promoted", promoted, "addr", addr.String()) + if p.logger.IsDebug() { + p.logger.Debug("promote request", "promoted", promoted, "addr", addr.String()) + } p.index.remove(pruned...) p.gauge.decrease(slotsRequired(pruned...)) @@ -804,7 +835,7 @@ func (p *TxPool) handlePromoteRequest(req promoteRequest) { // addGossipTx handles receiving transactions // gossiped by the network. func (p *TxPool) addGossipTx(obj interface{}, _ peer.ID) { - if !p.getSealing() { + if !p.sealing.Load() { return } @@ -834,7 +865,9 @@ func (p *TxPool) addGossipTx(obj interface{}, _ peer.ID) { // add tx if err := p.addTx(gossip, tx); err != nil { if errors.Is(err, ErrAlreadyKnown) { - p.logger.Debug("rejecting known tx (gossip)", "hash", tx.Hash.String()) + if p.logger.IsDebug() { + p.logger.Debug("rejecting known tx (gossip)", "hash", tx.Hash.String()) + } return } @@ -958,6 +991,12 @@ func (p *TxPool) Length() uint64 { return p.accounts.promoted() } +// updateBaseFee updates base fee in the tx pool and priced queue +func (p *TxPool) updateBaseFee(baseFee uint64) { + atomic.StoreUint64(&p.baseFee, baseFee) + atomic.StoreUint64(&p.executables.queue.baseFee, baseFee) +} + // toHash returns the hash(es) of given transaction(s) func toHash(txs ...*types.Transaction) (hashes []types.Hash) { for _, tx := range txs { diff --git a/txpool/txpool_test.go b/txpool/txpool_test.go index 2e203621c7..c19647bc23 100644 --- a/txpool/txpool_test.go +++ b/txpool/txpool_test.go @@ -31,10 +31,11 @@ const ( ) var ( - forks = &chain.Forks{ - Homestead: chain.NewFork(0), - Istanbul: chain.NewFork(0), - } + forks = (&chain.Forks{ + chain.Homestead: chain.NewFork(0), + chain.Istanbul: chain.NewFork(0), + chain.London: chain.NewFork(0), + }) ) // addresses used in tests @@ -91,10 +92,9 @@ func newTestPoolWithSlots(maxSlots uint64, mockStore ...store) (*TxPool, error) nil, nil, &Config{ - PriceLimit: defaultPriceLimit, - MaxSlots: maxSlots, - MaxAccountEnqueued: defaultMaxAccountEnqueued, - DeploymentWhitelist: []types.Address{}, + PriceLimit: defaultPriceLimit, + MaxSlots: maxSlots, + MaxAccountEnqueued: defaultMaxAccountEnqueued, }, ) } @@ -115,7 +115,7 @@ type result struct { func TestAddTxErrors(t *testing.T) { t.Parallel() - poolSigner := crypto.NewEIP155Signer(chain.AllForksEnabled.At(0), 100) + poolSigner := crypto.NewEIP155Signer(100, true) // Generate a private key and address defaultKey, defaultAddr := tests.GenerateKeyAndAddr(t) @@ -546,7 +546,7 @@ func TestAddGossipTx(t *testing.T) { t.Parallel() key, sender := tests.GenerateKeyAndAddr(t) - signer := crypto.NewEIP155Signer(chain.AllForksEnabled.At(0), uint64(100)) + signer := crypto.NewEIP155Signer(100, true) tx := newTx(types.ZeroAddress, 1, 1) t.Run("node is a validator", func(t *testing.T) { @@ -1435,7 +1435,7 @@ func TestPop(t *testing.T) { assert.Equal(t, uint64(1), pool.accounts.get(addr1).promoted.length()) // pop the tx - pool.Prepare() + pool.Prepare(0) tx := pool.Peek() pool.Pop(tx) @@ -1463,7 +1463,7 @@ func TestDrop(t *testing.T) { assert.Equal(t, uint64(1), pool.accounts.get(addr1).promoted.length()) // pop the tx - pool.Prepare() + pool.Prepare(0) tx := pool.Peek() pool.Drop(tx) @@ -1496,7 +1496,7 @@ func TestDemote(t *testing.T) { assert.Equal(t, uint64(0), pool.accounts.get(addr1).Demotions()) // call demote - pool.Prepare() + pool.Prepare(0) tx := pool.Peek() pool.Demote(tx) @@ -1532,7 +1532,7 @@ func TestDemote(t *testing.T) { pool.accounts.get(addr1).demotions = maxAccountDemotions // call demote - pool.Prepare() + pool.Prepare(0) tx := pool.Peek() pool.Demote(tx) @@ -1684,14 +1684,10 @@ func Test_updateAccountSkipsCounts(t *testing.T) { }) } -// TestPermissionSmartContractDeployment tests sending deployment tx with deployment whitelist -func TestPermissionSmartContractDeployment(t *testing.T) { +func Test_TxPool_validateTx(t *testing.T) { t.Parallel() - signer := crypto.NewEIP155Signer(chain.AllForksEnabled.At(0), uint64(100)) - - poolSigner := crypto.NewEIP155Signer(chain.AllForksEnabled.At(0), 100) - + signer := crypto.NewEIP155Signer(100, true) // Generate a private key and address defaultKey, defaultAddr := tests.GenerateKeyAndAddr(t) @@ -1707,7 +1703,7 @@ func TestPermissionSmartContractDeployment(t *testing.T) { } signTx := func(transaction *types.Transaction) *types.Transaction { - signedTx, signErr := poolSigner.SignTx(transaction, defaultKey) + signedTx, signErr := signer.SignTx(transaction, defaultKey) if signErr != nil { t.Fatalf("Unable to sign transaction, %v", signErr) } @@ -1715,76 +1711,166 @@ func TestPermissionSmartContractDeployment(t *testing.T) { return signedTx } - t.Run("contract deployment whitelist empty, anyone can deploy", func(t *testing.T) { + t.Run("tx input larger than the TxPoolMaxInitCodeSize", func(t *testing.T) { t.Parallel() pool := setupPool() + pool.forks.EIP158 = true + + input := make([]byte, state.TxPoolMaxInitCodeSize+1) + _, err := rand.Read(input) + require.NoError(t, err) tx := newTx(defaultAddr, 0, 1) tx.To = nil + tx.Input = input - assert.NoError(t, pool.validateTx(signTx(tx))) + assert.ErrorIs(t, + pool.validateTx(signTx(tx)), + runtime.ErrMaxCodeSizeExceeded, + ) }) - t.Run("Addresses inside whitelist can deploy smart contract", func(t *testing.T) { + + t.Run("tx input the same as TxPoolMaxInitCodeSize", func(t *testing.T) { t.Parallel() pool := setupPool() - pool.deploymentWhitelist.add(addr1) - pool.deploymentWhitelist.add(defaultAddr) + pool.forks.EIP158 = true + + input := make([]byte, state.TxPoolMaxInitCodeSize) + _, err := rand.Read(input) + require.NoError(t, err) tx := newTx(defaultAddr, 0, 1) tx.To = nil + tx.Input = input + + assert.NoError(t, + pool.validateTx(signTx(tx)), + runtime.ErrMaxCodeSizeExceeded, + ) + }) + + t.Run("transaction with eip-1559 fields can pass", func(t *testing.T) { + t.Parallel() + + pool := setupPool() + pool.baseFee = 1000 + + tx := newTx(defaultAddr, 0, 1) + tx.Type = types.DynamicFeeTx + tx.GasFeeCap = big.NewInt(1100) + tx.GasTipCap = big.NewInt(10) assert.NoError(t, pool.validateTx(signTx(tx))) }) - t.Run("Addresses outside whitelist can not deploy smart contract", func(t *testing.T) { + + t.Run("eip-1559 tx (gas fee cap less than base fee)", func(t *testing.T) { t.Parallel() + pool := setupPool() - pool.deploymentWhitelist.add(addr1) - pool.deploymentWhitelist.add(addr2) + pool.baseFee = 1000 tx := newTx(defaultAddr, 0, 1) - tx.To = nil + tx.Type = types.DynamicFeeTx + tx.GasFeeCap = big.NewInt(100) + tx.GasTipCap = big.NewInt(10) assert.ErrorIs(t, pool.validateTx(signTx(tx)), - ErrSmartContractRestricted, + ErrUnderpriced, ) }) - t.Run("Input larger than the TxPoolMaxInitCodeSize", func(t *testing.T) { + t.Run("eip-1559 tx (gas fee cap less than tip cap)", func(t *testing.T) { t.Parallel() - pool := setupPool() - pool.forks.EIP158 = true - input := make([]byte, state.TxPoolMaxInitCodeSize+1) - _, err := rand.Read(input) - require.NoError(t, err) + pool := setupPool() + pool.baseFee = 1000 tx := newTx(defaultAddr, 0, 1) - tx.To = nil - tx.Input = input + tx.Type = types.DynamicFeeTx + tx.GasFeeCap = big.NewInt(10000) + tx.GasTipCap = big.NewInt(100000) assert.ErrorIs(t, pool.validateTx(signTx(tx)), - runtime.ErrMaxCodeSizeExceeded, + ErrTipAboveFeeCap, ) }) - t.Run("Input the same as TxPoolMaxInitCodeSize", func(t *testing.T) { + t.Run("eip-1559 tx (gas fee cap and/or gas tip cap undefined)", func(t *testing.T) { t.Parallel() + pool := setupPool() - pool.forks.EIP158 = true + pool.baseFee = 1000 - input := make([]byte, state.TxPoolMaxInitCodeSize) - _, err := rand.Read(input) - require.NoError(t, err) + // undefined gas tip cap + tx := newTx(defaultAddr, 0, 1) + tx.Type = types.DynamicFeeTx + tx.GasFeeCap = big.NewInt(10000) + + signedTx := signTx(tx) + signedTx.GasTipCap = nil + assert.ErrorIs(t, + pool.validateTx(signedTx), + ErrUnderpriced, + ) + + // undefined gas fee cap + tx = newTx(defaultAddr, 1, 1) + tx.Type = types.DynamicFeeTx + tx.GasTipCap = big.NewInt(1000) + signedTx = signTx(tx) + signedTx.GasFeeCap = nil + + assert.ErrorIs(t, + pool.validateTx(signedTx), + ErrUnderpriced, + ) + }) + + t.Run("eip-1559 tx (gas fee cap and gas tip cap very high)", func(t *testing.T) { + t.Parallel() + + bitLength := 512 + + pool := setupPool() + pool.baseFee = 1000 + + // very high gas fee cap tx := newTx(defaultAddr, 0, 1) - tx.To = nil - tx.Input = input + tx.Type = types.DynamicFeeTx + tx.GasFeeCap = new(big.Int).SetBit(new(big.Int), bitLength, 1) - assert.NoError(t, + assert.ErrorIs(t, pool.validateTx(signTx(tx)), - runtime.ErrMaxCodeSizeExceeded, + ErrFeeCapVeryHigh, + ) + + // very high gas tip cap + tx = newTx(defaultAddr, 1, 1) + tx.Type = types.DynamicFeeTx + tx.GasTipCap = new(big.Int).SetBit(new(big.Int), bitLength, 1) + + assert.ErrorIs(t, + pool.validateTx(signTx(tx)), + ErrTipVeryHigh, + ) + }) + + t.Run("eip-1559 tx placed without eip-1559 fork enabled", func(t *testing.T) { + t.Parallel() + pool := setupPool() + pool.forks.London = false + + tx := newTx(defaultAddr, 0, 1) + tx.Type = types.DynamicFeeTx + tx.GasFeeCap = big.NewInt(10000) + tx.GasTipCap = big.NewInt(100000) + + assert.ErrorIs(t, + pool.validateTx(signTx(tx)), + ErrInvalidTxType, ) }) } @@ -1842,7 +1928,7 @@ func (e *eoa) signTx(t *testing.T, tx *types.Transaction, signer crypto.TxSigner return signedTx } -var signerEIP155 = crypto.NewEIP155Signer(chain.AllForksEnabled.At(0), 100) +var signerEIP155 = crypto.NewEIP155Signer(100, true) func TestResetAccounts_Promoted(t *testing.T) { t.Parallel() @@ -2493,7 +2579,7 @@ func TestRecovery(t *testing.T) { assert.Len(t, waitForEvents(ctx, promoteSubscription, totalTx), totalTx) func() { - pool.Prepare() + pool.Prepare(0) for { tx := pool.Peek() if tx == nil { @@ -2788,9 +2874,9 @@ func TestSetSealing(t *testing.T) { assert.NoError(t, err) // Set initial value - pool.sealing = 0 + pool.sealing.Store(false) if test.initialValue { - pool.sealing = 1 + pool.sealing.Store(true) } // call the target @@ -2800,7 +2886,7 @@ func TestSetSealing(t *testing.T) { assert.Equal( t, test.expectedValue, - pool.getSealing(), + pool.sealing.Load(), ) }) } diff --git a/txrelayer/txrelayer.go b/txrelayer/txrelayer.go index e812dae19d..aa4fe1983f 100644 --- a/txrelayer/txrelayer.go +++ b/txrelayer/txrelayer.go @@ -3,6 +3,8 @@ package txrelayer import ( "errors" "fmt" + "io" + "math/big" "sync" "time" @@ -12,7 +14,7 @@ import ( ) const ( - DefaultGasPrice = 1879048192 // 0x70000000 + defaultGasPrice = 1879048192 // 0x70000000 DefaultGasLimit = 5242880 // 0x500000 DefaultRPCAddress = "http://127.0.0.1:8545" numRetries = 1000 @@ -30,6 +32,8 @@ type TxRelayer interface { // SendTransactionLocal sends non-signed transaction // (this function is meant only for testing purposes and is about to be removed at some point) SendTransactionLocal(txn *ethgo.Transaction) (*ethgo.Receipt, error) + // Client returns jsonrpc client + Client() *jsonrpc.Client } var _ TxRelayer = (*TxRelayerImpl)(nil) @@ -40,11 +44,13 @@ type TxRelayerImpl struct { receiptTimeout time.Duration lock sync.Mutex + + writer io.Writer } func NewTxRelayer(opts ...TxRelayerOption) (TxRelayer, error) { t := &TxRelayerImpl{ - ipAddress: "http://127.0.0.1:8545", + ipAddress: DefaultRPCAddress, receiptTimeout: 50 * time.Millisecond, } for _, opt := range opts { @@ -84,10 +90,17 @@ func (t *TxRelayerImpl) SendTransaction(txn *ethgo.Transaction, key ethgo.Key) ( return t.waitForReceipt(txnHash) } +// Client returns jsonrpc client +func (t *TxRelayerImpl) Client() *jsonrpc.Client { + return t.client +} + func (t *TxRelayerImpl) sendTransactionLocked(txn *ethgo.Transaction, key ethgo.Key) (ethgo.Hash, error) { t.lock.Lock() defer t.lock.Unlock() + txn.From = key.Address() + nonce, err := t.client.Eth().GetNonce(key.Address(), ethgo.Pending) if err != nil { return ethgo.ZeroHash, err @@ -95,12 +108,24 @@ func (t *TxRelayerImpl) sendTransactionLocked(txn *ethgo.Transaction, key ethgo. txn.Nonce = nonce + txn.From = key.Address() + if txn.GasPrice == 0 { - txn.GasPrice = DefaultGasPrice + gasPrice, err := t.Client().Eth().GasPrice() + if err != nil { + return ethgo.ZeroHash, err + } + + txn.GasPrice = gasPrice } if txn.Gas == 0 { - txn.Gas = DefaultGasLimit + gasLimit, err := t.client.Eth().EstimateGas(ConvertTxnToCallMsg(txn)) + if err != nil { + return ethgo.ZeroHash, err + } + + txn.Gas = gasLimit } chainID, err := t.client.Eth().ChainID() @@ -118,6 +143,12 @@ func (t *TxRelayerImpl) sendTransactionLocked(txn *ethgo.Transaction, key ethgo. return ethgo.ZeroHash, err } + if t.writer != nil { + _, _ = t.writer.Write([]byte( + fmt.Sprintf("[TxRelayer.SendTransaction]\nFrom = %s \nGas = %d \nGas Price = %d\n", + txn.From, txn.Gas, txn.GasPrice))) + } + return t.client.Eth().SendRawTransaction(data) } @@ -134,8 +165,14 @@ func (t *TxRelayerImpl) SendTransactionLocal(txn *ethgo.Transaction) (*ethgo.Rec } txn.From = accounts[0] - txn.Gas = DefaultGasLimit - txn.GasPrice = DefaultGasPrice + + gasLimit, err := t.client.Eth().EstimateGas(ConvertTxnToCallMsg(txn)) + if err != nil { + return nil, err + } + + txn.Gas = gasLimit + txn.GasPrice = defaultGasPrice txnHash, err := t.client.Eth().SendTransaction(txn) if err != nil { @@ -169,6 +206,18 @@ func (t *TxRelayerImpl) waitForReceipt(hash ethgo.Hash) (*ethgo.Receipt, error) } } +// ConvertTxnToCallMsg converts txn instance to call message +func ConvertTxnToCallMsg(txn *ethgo.Transaction) *ethgo.CallMsg { + return ðgo.CallMsg{ + From: txn.From, + To: txn.To, + Data: txn.Input, + GasPrice: txn.GasPrice, + Value: txn.Value, + Gas: new(big.Int).SetUint64(txn.Gas), + } +} + type TxRelayerOption func(*TxRelayerImpl) func WithClient(client *jsonrpc.Client) TxRelayerOption { @@ -188,3 +237,9 @@ func WithReceiptTimeout(receiptTimeout time.Duration) TxRelayerOption { t.receiptTimeout = receiptTimeout } } + +func WithWriter(writer io.Writer) TxRelayerOption { + return func(t *TxRelayerImpl) { + t.writer = writer + } +} diff --git a/types/encoding.go b/types/encoding.go index 3f3dce4330..58dfe6618b 100644 --- a/types/encoding.go +++ b/types/encoding.go @@ -9,6 +9,10 @@ import ( "github.com/0xPolygon/polygon-edge/helper/hex" ) +// ParseUint64orHex parses the given string as uint64 in hex +// It should go to the common package from the logical perspective +// as well as avoiding cycle imports. +// DEPRECATED. Use common.ParseUint64orHex. func ParseUint64orHex(val *string) (uint64, error) { if val == nil { return 0, nil @@ -46,12 +50,6 @@ func ParseUint256orHex(val *string) (*big.Int, error) { return b, nil } -func ParseInt64orHex(val *string) (int64, error) { - i, err := ParseUint64orHex(val) - - return int64(i), err -} - func ParseBytes(val *string) ([]byte, error) { if val == nil { return []byte{}, nil diff --git a/types/header.go b/types/header.go index bf2750f05b..12e40feabc 100644 --- a/types/header.go +++ b/types/header.go @@ -26,6 +26,9 @@ type Header struct { MixHash Hash Nonce Nonce Hash Hash + + // BaseFee was added by EIP-1559 and is ignored in legacy headers. + BaseFee uint64 `json:"baseFeePerGas"` } func (h *Header) Equal(hh *Header) bool { @@ -75,6 +78,7 @@ func (h *Header) Copy() *Header { GasLimit: h.GasLimit, GasUsed: h.GasUsed, Timestamp: h.Timestamp, + BaseFee: h.BaseFee, } newHeader.Miner = make([]byte, len(h.Miner)) @@ -94,6 +98,7 @@ type Body struct { type FullBlock struct { Block *Block Receipts []*Receipt + Trace *Trace } type Block struct { @@ -102,7 +107,7 @@ type Block struct { Uncles []*Header // Cache - size atomic.Value // *uint64 + size atomic.Pointer[uint64] } func (b *Block) Hash() Hash { @@ -134,12 +139,7 @@ func (b *Block) Size() uint64 { return size } - sizeVal, ok := sizePtr.(*uint64) - if !ok { - return 0 - } - - return *sizeVal + return *sizePtr } func (b *Block) String() string { diff --git a/types/receipt.go b/types/receipt.go index 21ecd0a897..93830506a7 100644 --- a/types/receipt.go +++ b/types/receipt.go @@ -76,6 +76,7 @@ func (b Bloom) MarshalText() ([]byte, error) { // CreateBloom creates a new bloom filter from a set of receipts func CreateBloom(receipts []*Receipt) (b Bloom) { h := keccak.DefaultKeccakPool.Get() + defer keccak.DefaultKeccakPool.Put(h) for _, receipt := range receipts { for _, log := range receipt.Logs { @@ -87,8 +88,6 @@ func CreateBloom(receipts []*Receipt) (b Bloom) { } } - keccak.DefaultKeccakPool.Put(h) - return } @@ -99,36 +98,32 @@ func (b *Bloom) setEncode(hasher *keccak.Keccak, h []byte) { for i := 0; i < 6; i += 2 { // Find the global bit location - bit := (uint(buf[i+1]) + (uint(buf[i]) << 8)) & 2047 + bit := (uint(buf[i+1]) + (uint(buf[i]) << 8)) & (BloomByteLength*8 - 1) - // Find where the bit maps in the [0..255] byte array - byteLocation := 256 - 1 - bit/8 + // Find where the bit maps in the [0..BloomByteLength-1] byte array + byteLocation := BloomByteLength - 1 - bit/8 bitLocation := bit % 8 - b[byteLocation] = b[byteLocation] | (1 << bitLocation) + b[byteLocation] |= 1 << bitLocation } } // IsLogInBloom checks if the log has a possible presence in the bloom filter func (b *Bloom) IsLogInBloom(log *Log) bool { hasher := keccak.DefaultKeccakPool.Get() + defer keccak.DefaultKeccakPool.Put(hasher) // Check if the log address is present - addressPresent := b.isByteArrPresent(hasher, log.Address.Bytes()) - if !addressPresent { + if !b.isByteArrPresent(hasher, log.Address.Bytes()) { return false } // Check if all the topics are present for _, topic := range log.Topics { - topicsPresent := b.isByteArrPresent(hasher, topic.Bytes()) - - if !topicsPresent { + if !b.isByteArrPresent(hasher, topic.Bytes()) { return false } } - keccak.DefaultKeccakPool.Put(hasher) - return true } @@ -140,15 +135,12 @@ func (b *Bloom) isByteArrPresent(hasher *keccak.Keccak, data []byte) bool { for i := 0; i < 6; i += 2 { // Find the global bit location - bit := (uint(buf[i+1]) + (uint(buf[i]) << 8)) & 2047 + bit := (uint(buf[i+1]) + (uint(buf[i]) << 8)) & (BloomByteLength*8 - 1) - // Find where the bit maps in the [0..255] byte array - byteLocation := 256 - 1 - bit/8 + // Find where the bit maps in the [0..BloomByteLength-1] byte array + byteLocation := BloomByteLength - 1 - bit/8 bitLocation := bit % 8 - - referenceByte := b[byteLocation] - - isSet := uint(referenceByte & (1 << (bitLocation - 1))) + isSet := b[byteLocation] & (1 << bitLocation) if isSet == 0 { return false diff --git a/types/rlp_encoding_test.go b/types/rlp_encoding_test.go index 7e2e00c3c9..52b0170b98 100644 --- a/types/rlp_encoding_test.go +++ b/types/rlp_encoding_test.go @@ -1,6 +1,7 @@ package types import ( + "fmt" "math/big" "reflect" "testing" @@ -8,6 +9,7 @@ import ( "github.com/umbracle/fastrlp" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) type codec interface { @@ -134,35 +136,40 @@ func TestRLPMarshall_And_Unmarshall_TypedTransaction(t *testing.T) { addrTo := StringToAddress("11") addrFrom := StringToAddress("22") originalTx := &Transaction{ - Nonce: 0, - GasPrice: big.NewInt(11), - Gas: 11, - To: &addrTo, - From: addrFrom, - Value: big.NewInt(1), - Input: []byte{1, 2}, - V: big.NewInt(25), - S: big.NewInt(26), - R: big.NewInt(27), + Nonce: 0, + GasPrice: big.NewInt(11), + GasFeeCap: big.NewInt(12), + GasTipCap: big.NewInt(13), + Gas: 11, + To: &addrTo, + From: addrFrom, + Value: big.NewInt(1), + Input: []byte{1, 2}, + V: big.NewInt(25), + S: big.NewInt(26), + R: big.NewInt(27), } txTypes := []TxType{ StateTx, LegacyTx, + DynamicFeeTx, } for _, v := range txTypes { - originalTx.Type = v - originalTx.ComputeHash() + t.Run(v.String(), func(t *testing.T) { + originalTx.Type = v + originalTx.ComputeHash() - txRLP := originalTx.MarshalRLP() + txRLP := originalTx.MarshalRLP() - unmarshalledTx := new(Transaction) - assert.NoError(t, unmarshalledTx.UnmarshalRLP(txRLP)) + unmarshalledTx := new(Transaction) + assert.NoError(t, unmarshalledTx.UnmarshalRLP(txRLP)) - unmarshalledTx.ComputeHash() - assert.Equal(t, originalTx.Type, unmarshalledTx.Type) - assert.Equal(t, originalTx.Hash, unmarshalledTx.Hash) + unmarshalledTx.ComputeHash() + assert.Equal(t, originalTx.Type, unmarshalledTx.Type) + assert.Equal(t, originalTx.Hash, unmarshalledTx.Hash) + }) } } @@ -172,6 +179,7 @@ func TestRLPMarshall_Unmarshall_Missing_Data(t *testing.T) { txTypes := []TxType{ StateTx, LegacyTx, + DynamicFeeTx, } for _, txType := range txTypes { @@ -179,41 +187,54 @@ func TestRLPMarshall_Unmarshall_Missing_Data(t *testing.T) { testTable := []struct { name string expectedErr bool - ommitedValues map[string]bool + omittedValues map[string]bool fromAddrSet bool }{ { - name: "Insuficient params", + name: fmt.Sprintf("[%s] Insuficient params", txType), expectedErr: true, - ommitedValues: map[string]bool{ + omittedValues: map[string]bool{ "Nonce": true, "GasPrice": true, }, }, { - name: "Missing From", + name: fmt.Sprintf("[%s] Missing From", txType), expectedErr: false, - ommitedValues: map[string]bool{ - "From": true, + omittedValues: map[string]bool{ + "ChainID": txType != DynamicFeeTx, + "GasTipCap": txType != DynamicFeeTx, + "GasFeeCap": txType != DynamicFeeTx, + "GasPrice": txType == DynamicFeeTx, + "AccessList": txType != DynamicFeeTx, + "From": txType != StateTx, }, - fromAddrSet: false, + fromAddrSet: txType == StateTx, }, { - name: "Address set for state tx only", - expectedErr: false, - ommitedValues: map[string]bool{}, - fromAddrSet: txType == StateTx, + name: fmt.Sprintf("[%s] Address set for state tx only", txType), + expectedErr: false, + omittedValues: map[string]bool{ + "ChainID": txType != DynamicFeeTx, + "GasTipCap": txType != DynamicFeeTx, + "GasFeeCap": txType != DynamicFeeTx, + "GasPrice": txType == DynamicFeeTx, + "AccessList": txType != DynamicFeeTx, + "From": txType != StateTx, + }, + fromAddrSet: txType == StateTx, }, } for _, tt := range testTable { tt := tt + t.Run(tt.name, func(t *testing.T) { t.Parallel() arena := fastrlp.DefaultArenaPool.Get() parser := fastrlp.DefaultParserPool.Get() - testData := testRLPData(arena, tt.ommitedValues) + testData := testRLPData(arena, tt.omittedValues) v, err := parser.Parse(testData) assert.Nil(t, err) @@ -247,6 +268,10 @@ func TestRLPMarshall_And_Unmarshall_TxType(t *testing.T) { name: "LegacyTx", txType: LegacyTx, }, + { + name: "DynamicFeeTx", + txType: DynamicFeeTx, + }, { name: "undefined type", txType: TxType(0x09), @@ -269,56 +294,62 @@ func TestRLPMarshall_And_Unmarshall_TxType(t *testing.T) { } } -func testRLPData(arena *fastrlp.Arena, ommitValues map[string]bool) []byte { +func testRLPData(arena *fastrlp.Arena, omitValues map[string]bool) []byte { vv := arena.NewArray() - _, ommit := ommitValues["Nonce"] - if !ommit { + if omit, _ := omitValues["ChainID"]; !omit { + vv.Set(arena.NewBigInt(big.NewInt(0))) + } + + if omit, _ := omitValues["Nonce"]; !omit { vv.Set(arena.NewUint(10)) } - _, ommit = ommitValues["GasPrice"] - if !ommit { + if omit, _ := omitValues["GasTipCap"]; !omit { + vv.Set(arena.NewBigInt(big.NewInt(11))) + } + + if omit, _ := omitValues["GasFeeCap"]; !omit { vv.Set(arena.NewBigInt(big.NewInt(11))) } - _, ommit = ommitValues["Gas"] - if !ommit { + if omit, _ := omitValues["GasPrice"]; !omit { + vv.Set(arena.NewBigInt(big.NewInt(11))) + } + + if omit, _ := omitValues["Gas"]; !omit { vv.Set(arena.NewUint(12)) } - _, ommit = ommitValues["To"] - if !ommit { + if omit, _ := omitValues["To"]; !omit { vv.Set(arena.NewBytes((StringToAddress("13")).Bytes())) } - _, ommit = ommitValues["Value"] - if !ommit { + if omit, _ := omitValues["Value"]; !omit { vv.Set(arena.NewBigInt(big.NewInt(14))) } - _, ommit = ommitValues["Input"] - if !ommit { + if omit, _ := omitValues["Input"]; !omit { vv.Set(arena.NewCopyBytes([]byte{1, 2})) } - _, ommit = ommitValues["V"] - if !ommit { + if omit, _ := omitValues["AccessList"]; !omit { + vv.Set(arena.NewArray()) + } + + if omit, _ := omitValues["V"]; !omit { vv.Set(arena.NewBigInt(big.NewInt(15))) } - _, ommit = ommitValues["R"] - if !ommit { + if omit, _ := omitValues["R"]; !omit { vv.Set(arena.NewBigInt(big.NewInt(16))) } - _, ommit = ommitValues["S"] - if !ommit { + if omit, _ := omitValues["S"]; !omit { vv.Set(arena.NewBigInt(big.NewInt(17))) } - _, ommit = ommitValues["From"] - if !ommit { + if omit, _ := omitValues["From"]; !omit { vv.Set(arena.NewBytes((StringToAddress("18")).Bytes())) } @@ -327,3 +358,35 @@ func testRLPData(arena *fastrlp.Arena, ommitValues map[string]bool) []byte { return testData } + +func Test_MarshalCorruptedBytesArray(t *testing.T) { + t.Parallel() + + marshal := func(obj func(*fastrlp.Arena) *fastrlp.Value) []byte { + ar := fastrlp.DefaultArenaPool.Get() + defer fastrlp.DefaultArenaPool.Put(ar) + + return obj(ar).MarshalTo(nil) + } + + emptyArray := [8]byte{} + corruptedSlice := make([]byte, 32) + corruptedSlice[29], corruptedSlice[30], corruptedSlice[31] = 5, 126, 64 + intOfCorruption := uint64(18_446_744_073_709_551_615) // 2^64-1 + + marshalOne := func(ar *fastrlp.Arena) *fastrlp.Value { + return ar.NewBytes(corruptedSlice) + } + + marshalTwo := func(ar *fastrlp.Arena) *fastrlp.Value { + return ar.NewUint(intOfCorruption) + } + + marshal(marshalOne) + + require.Equal(t, emptyArray[:], corruptedSlice[:len(emptyArray)]) + + marshal(marshalTwo) // without fixing this, marshaling will cause corruption of the corrupted slice + + require.Equal(t, emptyArray[:], corruptedSlice[:len(emptyArray)]) +} diff --git a/types/rlp_marshal.go b/types/rlp_marshal.go index 7e244b9d27..be4f3693e2 100644 --- a/types/rlp_marshal.go +++ b/types/rlp_marshal.go @@ -1,6 +1,8 @@ package types import ( + "math/big" + "github.com/umbracle/fastrlp" ) @@ -40,7 +42,7 @@ func (b *Block) MarshalRLPWith(ar *fastrlp.Arena) *fastrlp.Value { v0 := ar.NewArray() for _, tx := range b.Transactions { if tx.Type != LegacyTx { - v0.Set(ar.NewBytes([]byte{byte(tx.Type)})) + v0.Set(ar.NewCopyBytes([]byte{byte(tx.Type)})) } v0.Set(tx.MarshalRLPWith(ar)) @@ -73,12 +75,12 @@ func (h *Header) MarshalRLPTo(dst []byte) []byte { func (h *Header) MarshalRLPWith(arena *fastrlp.Arena) *fastrlp.Value { vv := arena.NewArray() - vv.Set(arena.NewBytes(h.ParentHash.Bytes())) - vv.Set(arena.NewBytes(h.Sha3Uncles.Bytes())) + vv.Set(arena.NewCopyBytes(h.ParentHash.Bytes())) + vv.Set(arena.NewCopyBytes(h.Sha3Uncles.Bytes())) vv.Set(arena.NewCopyBytes(h.Miner[:])) - vv.Set(arena.NewBytes(h.StateRoot.Bytes())) - vv.Set(arena.NewBytes(h.TxRoot.Bytes())) - vv.Set(arena.NewBytes(h.ReceiptsRoot.Bytes())) + vv.Set(arena.NewCopyBytes(h.StateRoot.Bytes())) + vv.Set(arena.NewCopyBytes(h.TxRoot.Bytes())) + vv.Set(arena.NewCopyBytes(h.ReceiptsRoot.Bytes())) vv.Set(arena.NewCopyBytes(h.LogsBloom[:])) vv.Set(arena.NewUint(h.Difficulty)) @@ -88,9 +90,11 @@ func (h *Header) MarshalRLPWith(arena *fastrlp.Arena) *fastrlp.Value { vv.Set(arena.NewUint(h.Timestamp)) vv.Set(arena.NewCopyBytes(h.ExtraData)) - vv.Set(arena.NewBytes(h.MixHash.Bytes())) + vv.Set(arena.NewCopyBytes(h.MixHash.Bytes())) vv.Set(arena.NewCopyBytes(h.Nonce[:])) + vv.Set(arena.NewUint(h.BaseFee)) + return vv } @@ -103,7 +107,7 @@ func (r *Receipts) MarshalRLPWith(a *fastrlp.Arena) *fastrlp.Value { for _, rr := range *r { if !rr.IsLegacyTx() { - vv.Set(a.NewBytes([]byte{byte(rr.TransactionType)})) + vv.Set(a.NewCopyBytes([]byte{byte(rr.TransactionType)})) } vv.Set(rr.MarshalRLPWith(a)) @@ -131,7 +135,7 @@ func (r *Receipt) MarshalRLPWith(a *fastrlp.Arena) *fastrlp.Value { if r.Status != nil { vv.Set(a.NewUint(uint64(*r.Status))) } else { - vv.Set(a.NewBytes(r.Root[:])) + vv.Set(a.NewCopyBytes(r.Root[:])) } vv.Set(a.NewUint(r.CumulativeGasUsed)) @@ -159,15 +163,15 @@ func (r *Receipt) MarshalLogsWith(a *fastrlp.Arena) *fastrlp.Value { func (l *Log) MarshalRLPWith(a *fastrlp.Arena) *fastrlp.Value { v := a.NewArray() - v.Set(a.NewBytes(l.Address.Bytes())) + v.Set(a.NewCopyBytes(l.Address.Bytes())) topics := a.NewArray() for _, t := range l.Topics { - topics.Set(a.NewBytes(t.Bytes())) + topics.Set(a.NewCopyBytes(t.Bytes())) } v.Set(topics) - v.Set(a.NewBytes(l.Data)) + v.Set(a.NewCopyBytes(l.Data)) return v } @@ -188,13 +192,30 @@ func (t *Transaction) MarshalRLPTo(dst []byte) []byte { func (t *Transaction) MarshalRLPWith(arena *fastrlp.Arena) *fastrlp.Value { vv := arena.NewArray() + // Specify zero chain ID as per spec. + // This is needed to have the same format as other EVM chains do. + // There is no chain ID in the TX object, so it is always 0 here just to be compatible. + // Check Transaction1559Payload there https://eips.ethereum.org/EIPS/eip-1559#specification + if t.Type == DynamicFeeTx { + vv.Set(arena.NewBigInt(big.NewInt(0))) + } + vv.Set(arena.NewUint(t.Nonce)) - vv.Set(arena.NewBigInt(t.GasPrice)) + + if t.Type == DynamicFeeTx { + // Add EIP-1559 related fields. + // For non-dynamic-fee-tx gas price is used. + vv.Set(arena.NewBigInt(t.GasTipCap)) + vv.Set(arena.NewBigInt(t.GasFeeCap)) + } else { + vv.Set(arena.NewBigInt(t.GasPrice)) + } + vv.Set(arena.NewUint(t.Gas)) // Address may be empty if t.To != nil { - vv.Set(arena.NewBytes((*t.To).Bytes())) + vv.Set(arena.NewCopyBytes(t.To.Bytes())) } else { vv.Set(arena.NewNull()) } @@ -202,13 +223,21 @@ func (t *Transaction) MarshalRLPWith(arena *fastrlp.Arena) *fastrlp.Value { vv.Set(arena.NewBigInt(t.Value)) vv.Set(arena.NewCopyBytes(t.Input)) + // Specify access list as per spec. + // This is needed to have the same format as other EVM chains do. + // There is no access list feature here, so it is always empty just to be compatible. + // Check Transaction1559Payload there https://eips.ethereum.org/EIPS/eip-1559#specification + if t.Type == DynamicFeeTx { + vv.Set(arena.NewArray()) + } + // signature values vv.Set(arena.NewBigInt(t.V)) vv.Set(arena.NewBigInt(t.R)) vv.Set(arena.NewBigInt(t.S)) if t.Type == StateTx { - vv.Set(arena.NewBytes((t.From).Bytes())) + vv.Set(arena.NewCopyBytes(t.From.Bytes())) } return vv diff --git a/types/rlp_unmarshal.go b/types/rlp_unmarshal.go index 5177507224..b651863bb4 100644 --- a/types/rlp_unmarshal.go +++ b/types/rlp_unmarshal.go @@ -218,6 +218,14 @@ func (h *Header) unmarshalRLPFrom(_ *fastrlp.Parser, v *fastrlp.Value) error { h.SetNonce(nonce) + // basefee + // In order to be backward compatible, the len should be checked before accessing the element + if len(elems) > 15 { + if h.BaseFee, err = elems[15].GetUint64(); err != nil { + return err + } + } + // compute the hash after the decoding h.ComputeHash() @@ -376,30 +384,71 @@ func (t *Transaction) unmarshalRLPFrom(p *fastrlp.Parser, v *fastrlp.Value) erro return err } - if len(elems) < 9 { - return fmt.Errorf("incorrect number of elements to decode transaction, expected 9 but found %d", len(elems)) + getElem := func() *fastrlp.Value { + val := elems[0] + elems = elems[1:] + + return val + } + + var num int + + switch t.Type { + case LegacyTx: + num = 9 + case StateTx: + num = 10 + case DynamicFeeTx: + num = 12 + default: + return fmt.Errorf("transaction type %d not found", t.Type) + } + + if numElems := len(elems); numElems != num { + return fmt.Errorf("incorrect number of transaction elements, expected %d but found %d", num, numElems) } p.Hash(t.Hash[:0], v) + // Skipping Chain ID field since we don't support it (yet) + // This is needed to be compatible with other EVM chains and have the same format. + // Since we don't have a chain ID, just skip it here. + if t.Type == DynamicFeeTx { + _ = getElem() + } + // nonce - if t.Nonce, err = elems[0].GetUint64(); err != nil { + if t.Nonce, err = getElem().GetUint64(); err != nil { return err } - // gasPrice - t.GasPrice = new(big.Int) - if err = elems[1].GetBigInt(t.GasPrice); err != nil { - return err + if t.Type == DynamicFeeTx { + // gasTipCap + t.GasTipCap = new(big.Int) + if err = getElem().GetBigInt(t.GasTipCap); err != nil { + return err + } + + // gasFeeCap + t.GasFeeCap = new(big.Int) + if err = getElem().GetBigInt(t.GasFeeCap); err != nil { + return err + } + } else { + // gasPrice + t.GasPrice = new(big.Int) + if err = getElem().GetBigInt(t.GasPrice); err != nil { + return err + } } // gas - if t.Gas, err = elems[2].GetUint64(); err != nil { + if t.Gas, err = getElem().GetUint64(); err != nil { return err } // to - if vv, _ := v.Get(3).Bytes(); len(vv) == 20 { + if vv, _ := getElem().Bytes(); len(vv) == 20 { // address addr := BytesToAddress(vv) t.To = &addr @@ -410,45 +459,48 @@ func (t *Transaction) unmarshalRLPFrom(p *fastrlp.Parser, v *fastrlp.Value) erro // value t.Value = new(big.Int) - if err = elems[4].GetBigInt(t.Value); err != nil { + if err = getElem().GetBigInt(t.Value); err != nil { return err } // input - if t.Input, err = elems[5].GetBytes(t.Input[:0]); err != nil { + if t.Input, err = getElem().GetBytes(t.Input[:0]); err != nil { return err } + // Skipping Access List field since we don't support it. + // This is needed to be compatible with other EVM chains and have the same format. + // Since we don't have access list, just skip it here. + if t.Type == DynamicFeeTx { + _ = getElem() + } + // V t.V = new(big.Int) - if err = elems[6].GetBigInt(t.V); err != nil { + if err = getElem().GetBigInt(t.V); err != nil { return err } // R t.R = new(big.Int) - if err = elems[7].GetBigInt(t.R); err != nil { + if err = getElem().GetBigInt(t.R); err != nil { return err } // S t.S = new(big.Int) - if err = elems[8].GetBigInt(t.S); err != nil { + if err = getElem().GetBigInt(t.S); err != nil { return err } if t.Type == StateTx { - // set From with default value t.From = ZeroAddress // We need to set From field for state transaction, // because we are using unique, predefined address, for sending such transactions - // From - if len(elems) >= 10 { - if vv, err := v.Get(9).Bytes(); err == nil && len(vv) == AddressLength { - // address - t.From = BytesToAddress(vv) - } + if vv, err := getElem().Bytes(); err == nil && len(vv) == AddressLength { + // address + t.From = BytesToAddress(vv) } } diff --git a/types/state_transaction.go b/types/state_transaction.go new file mode 100644 index 0000000000..bcdc0ec378 --- /dev/null +++ b/types/state_transaction.go @@ -0,0 +1,135 @@ +package types + +import ( + "fmt" + "math/big" + + "github.com/umbracle/ethgo" + "github.com/umbracle/ethgo/abi" +) + +var ( + stateSyncABIType = abi.MustNewType( + "tuple(tuple(uint256 id, address sender, address receiver, bytes data))") + + // this will change to use the generated code, but for now, we leave it as is, because of the circular import + ExecuteStateSyncABIMethod, _ = abi.NewMethod("function execute(" + + "bytes32[] proof, " + + "tuple(uint256 id, address sender, address receiver, bytes data) obj)") +) + +const ( + abiMethodIDLength = 4 +) + +// StateSyncEvent is a bridge event from the rootchain +type StateSyncEvent struct { + // ID is the decoded 'index' field from the event + ID uint64 + // Sender is the decoded 'sender' field from the event + Sender ethgo.Address + // Receiver is the decoded 'receiver' field from the event + Receiver ethgo.Address + // Data is the decoded 'data' field from the event + Data []byte +} + +// ToMap converts StateSyncEvent to map +func (sse *StateSyncEvent) ToMap() map[string]interface{} { + return map[string]interface{}{ + "id": sse.ID, + "sender": sse.Sender, + "receiver": sse.Receiver, + "data": sse.Data, + } +} + +// ToABI converts StateSyncEvent to ABI +func (sse *StateSyncEvent) EncodeAbi() ([]byte, error) { + return stateSyncABIType.Encode([]interface{}{sse.ToMap()}) +} + +func (sse *StateSyncEvent) String() string { + return fmt.Sprintf("Id=%d, Sender=%v, Target=%v", sse.ID, sse.Sender, sse.Receiver) +} + +type StateSyncProof struct { + Proof []Hash + StateSync *StateSyncEvent +} + +// EncodeAbi contains logic for encoding given ABI data +func (ssp *StateSyncProof) EncodeAbi() ([]byte, error) { + return ExecuteStateSyncABIMethod.Encode([2]interface{}{ssp.Proof, ssp.StateSync.ToMap()}) +} + +// DecodeAbi contains logic for decoding given ABI data +func (ssp *StateSyncProof) DecodeAbi(txData []byte) error { + if len(txData) < abiMethodIDLength { + return fmt.Errorf("invalid proof data, len = %d", len(txData)) + } + + rawResult, err := ExecuteStateSyncABIMethod.Inputs.Decode(txData[abiMethodIDLength:]) + if err != nil { + return err + } + + result, isOk := rawResult.(map[string]interface{}) + if !isOk { + return fmt.Errorf("invalid proof data") + } + + stateSyncEventEncoded, isOk := result["obj"].(map[string]interface{}) + if !isOk { + return fmt.Errorf("invalid state sync data") + } + + proofEncoded, isOk := result["proof"].([][32]byte) + if !isOk { + return fmt.Errorf("invalid proof data") + } + + id, isOk := stateSyncEventEncoded["id"].(*big.Int) + if !isOk { + return fmt.Errorf("invalid state sync event id") + } + + senderEthgo, isOk := stateSyncEventEncoded["sender"].(ethgo.Address) + if !isOk { + return fmt.Errorf("invalid state sync sender field") + } + + receiverEthgo, isOk := stateSyncEventEncoded["receiver"].(ethgo.Address) + if !isOk { + return fmt.Errorf("invalid state sync receiver field") + } + + data, isOk := stateSyncEventEncoded["data"].([]byte) + if !isOk { + return fmt.Errorf("invalid state sync data field") + } + + stateSync := &StateSyncEvent{ + ID: id.Uint64(), + Sender: senderEthgo, + Receiver: receiverEthgo, + Data: data, + } + + proof := make([]Hash, len(proofEncoded)) + for i := 0; i < len(proofEncoded); i++ { + proof[i] = Hash(proofEncoded[i]) + } + + *ssp = StateSyncProof{ + Proof: proof, + StateSync: stateSync, + } + + return nil +} + +type ExitProof struct { + Proof []Hash + LeafIndex uint64 +} diff --git a/types/transaction.go b/types/transaction.go index 92d4ef5e2c..a66a94a3ba 100644 --- a/types/transaction.go +++ b/types/transaction.go @@ -5,57 +5,67 @@ import ( "math/big" "sync/atomic" + "github.com/0xPolygon/polygon-edge/helper/common" "github.com/0xPolygon/polygon-edge/helper/keccak" ) +const ( + // StateTransactionGasLimit is arbitrary default gas limit for state transactions + StateTransactionGasLimit = 1000000 +) + +// TxType is the transaction type. type TxType byte +// List of supported transaction types const ( - LegacyTx TxType = 0x0 - StateTx TxType = 0x7f - - StateTransactionGasLimit = 1000000 // some arbitrary default gas limit for state transactions + LegacyTx TxType = 0x0 + StateTx TxType = 0x7f + DynamicFeeTx TxType = 0x02 ) func txTypeFromByte(b byte) (TxType, error) { tt := TxType(b) switch tt { - case LegacyTx, StateTx: + case LegacyTx, StateTx, DynamicFeeTx: return tt, nil default: return tt, fmt.Errorf("unknown transaction type: %d", b) } } +// String returns string representation of the transaction type. func (t TxType) String() (s string) { switch t { case LegacyTx: return "LegacyTx" case StateTx: return "StateTx" + case DynamicFeeTx: + return "DynamicFeeTx" } return } type Transaction struct { - Nonce uint64 - GasPrice *big.Int - Gas uint64 - To *Address - Value *big.Int - Input []byte - V *big.Int - R *big.Int - S *big.Int - Hash Hash - From Address + Nonce uint64 + GasPrice *big.Int + GasTipCap *big.Int + GasFeeCap *big.Int + Gas uint64 + To *Address + Value *big.Int + Input []byte + V, R, S *big.Int + Hash Hash + From Address Type TxType // Cache - size atomic.Value + size atomic.Pointer[uint64] } // IsContractCreation checks if tx is contract creation @@ -86,6 +96,16 @@ func (t *Transaction) Copy() *Transaction { tt.GasPrice.Set(t.GasPrice) } + tt.GasTipCap = new(big.Int) + if t.GasTipCap != nil { + tt.GasTipCap.Set(t.GasTipCap) + } + + tt.GasFeeCap = new(big.Int) + if t.GasFeeCap != nil { + tt.GasFeeCap.Set(t.GasFeeCap) + } + tt.Value = new(big.Int) if t.Value != nil { tt.Value.Set(t.Value) @@ -109,32 +129,79 @@ func (t *Transaction) Copy() *Transaction { // Cost returns gas * gasPrice + value func (t *Transaction) Cost() *big.Int { - total := new(big.Int).Mul(t.GasPrice, new(big.Int).SetUint64(t.Gas)) - total.Add(total, t.Value) + var factor *big.Int + + if t.GasFeeCap != nil && t.GasFeeCap.BitLen() > 0 { + factor = new(big.Int).Set(t.GasFeeCap) + } else { + factor = new(big.Int).Set(t.GasPrice) + } + + total := new(big.Int).Mul(factor, new(big.Int).SetUint64(t.Gas)) + total = total.Add(total, t.Value) return total } +// GetGasPrice returns gas price if not empty, or calculates one based on +// the given EIP-1559 fields if exist +// +// Here is the logic: +// - use existing gas price if exists +// - or calculate a value with formula: min(gasFeeCap, gasTipCap * baseFee); +func (t *Transaction) GetGasPrice(baseFee uint64) *big.Int { + if t.GasPrice != nil && t.GasPrice.BitLen() > 0 { + return new(big.Int).Set(t.GasPrice) + } else if baseFee == 0 { + return new(big.Int) + } + + gasFeeCap := new(big.Int) + if t.GasFeeCap != nil { + gasFeeCap = gasFeeCap.Set(t.GasFeeCap) + } + + gasTipCap := new(big.Int) + if t.GasTipCap != nil { + gasTipCap = gasTipCap.Set(t.GasTipCap) + } + + gasPrice := new(big.Int) + if gasFeeCap.BitLen() > 0 || gasTipCap.BitLen() > 0 { + gasPrice = common.BigMin( + new(big.Int).Add( + gasTipCap, + new(big.Int).SetUint64(baseFee), + ), + new(big.Int).Set(gasFeeCap), + ) + } + + return gasPrice +} + func (t *Transaction) Size() uint64 { if size := t.size.Load(); size != nil { - sizeVal, ok := size.(uint64) - if !ok { - return 0 - } - - return sizeVal + return *size } size := uint64(len(t.MarshalRLP())) - t.size.Store(size) + t.size.Store(&size) return size } -func (t *Transaction) ExceedsBlockGasLimit(blockGasLimit uint64) bool { - return t.Gas > blockGasLimit -} +// EffectiveTip defines effective tip based on tx type. +// Spec: https://eips.ethereum.org/EIPS/eip-1559#specification +// We use EIP-1559 fields of the tx if the london hardfork is enabled. +// Effective tip be came to be either gas tip cap or (gas fee cap - current base fee) +func (t *Transaction) EffectiveTip(baseFee uint64) *big.Int { + if t.GasFeeCap != nil && t.GasTipCap != nil { + return common.BigMin( + new(big.Int).Sub(t.GasFeeCap, new(big.Int).SetUint64(baseFee)), + new(big.Int).Set(t.GasTipCap), + ) + } -func (t *Transaction) IsUnderpriced(priceLimit uint64) bool { - return t.GasPrice.Cmp(big.NewInt(0).SetUint64(priceLimit)) < 0 + return t.GetGasPrice(baseFee) } diff --git a/types/types.go b/types/types.go index 5c4b58cd1a..74f1f563ff 100644 --- a/types/types.go +++ b/types/types.go @@ -1,7 +1,9 @@ package types import ( + "bytes" "fmt" + "math/big" "strings" "unicode" @@ -9,15 +11,33 @@ import ( "github.com/0xPolygon/polygon-edge/helper/keccak" ) -var ZeroAddress = Address{} -var ZeroHash = Hash{} - const ( HashLength = 32 AddressLength = 20 + + SignatureSize = 4 ) -const SignatureSize = 4 +var ( + // ZeroAddress is the default zero address + ZeroAddress = Address{} + + // ZeroHash is the default zero hash + ZeroHash = Hash{} + + // ZeroNonce is the default empty nonce + ZeroNonce = Nonce{} + + // EmptyRootHash is the root when there are no transactions + EmptyRootHash = StringToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") + + // EmptyUncleHash is the root when there are no uncles + EmptyUncleHash = StringToHash("0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347") + + // EmptyCodeHash is the root where there is no code. + // Equivalent of: `types.BytesToHash(crypto.Keccak256(nil))` + EmptyCodeHash = StringToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470") +) type Hash [HashLength]byte @@ -121,6 +141,27 @@ func StringToBytes(str string) []byte { return b } +// IsValidAddress checks if provided string is a valid Ethereum address +func IsValidAddress(address string) error { + // remove 0x prefix if it exists + if strings.HasPrefix(address, "0x") { + address = address[2:] + } + + // decode the address + decodedAddress, err := hex.DecodeString(address) + if err != nil { + return fmt.Errorf("address %s contains invalid characters", address) + } + + // check if the address has the correct length + if len(decodedAddress) != AddressLength { + return fmt.Errorf("address %s has invalid length", address) + } + + return nil +} + // UnmarshalText parses a hash in hex syntax. func (h *Hash) UnmarshalText(input []byte) error { *h = BytesToHash(StringToBytes(string(input))) @@ -148,15 +189,166 @@ func (a Address) MarshalText() ([]byte, error) { return []byte(a.String()), nil } -var ( - // EmptyRootHash is the root when there are no transactions - EmptyRootHash = StringToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") +// TODO: Replace jsonrpc/types/argByte with this? +// Still unsure if the codification will be done on protobuf side more +// than marshaling in json and if this will become necessary. +// +//nolint:godox +type ArgBytes []byte - // EmptyUncleHash is the root when there are no uncles - EmptyUncleHash = StringToHash("0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347") -) +func (b ArgBytes) MarshalText() ([]byte, error) { + return encodeToHex(b), nil +} + +func (b *ArgBytes) UnmarshalText(input []byte) error { + hh, err := decodeToHex(input) + if err != nil { + return nil + } + + aux := make([]byte, len(hh)) + copy(aux[:], hh[:]) + *b = aux + + return nil +} + +func decodeToHex(b []byte) ([]byte, error) { + str := string(b) + str = strings.TrimPrefix(str, "0x") + + if len(str)%2 != 0 { + str = "0" + str + } + + return hex.DecodeString(str) +} + +func encodeToHex(b []byte) []byte { + str := hex.EncodeToString(b) + if len(str)%2 != 0 { + str = "0" + str + } + + return []byte("0x" + str) +} + +type Trace struct { + // AccountTrie is the partial trie for the account merkle trie touched during the block + AccountTrie map[string]string `json:"accountTrie"` + + // StorageTrie is the partial trie for the storage tries touched during the block + StorageTrie map[string]string `json:"storageTrie"` + + // ParentStateRoot is the parent state root for this block + ParentStateRoot Hash `json:"parentStateRoot"` + + // TxnTraces is the list of traces per transaction in the block + TxnTraces []*TxnTrace `json:"transactionTraces"` +} + +type TxnTrace struct { + // Transaction is the RLP encoding of the transaction + Transaction ArgBytes `json:"txn"` + + // Delta is the list of updates per account during this transaction + Delta map[Address]*JournalEntry `json:"delta"` +} + +type JournalEntry struct { + // Addr is the address of the account affected by the + // journal change + Addr Address `json:"address"` + + // Balance tracks changes in the account Balance + Balance *big.Int `json:"-"` + + // Nonce tracks changes in the account Nonce + Nonce *uint64 `json:"nonce,omitempty"` + + // Storage track changes in the storage + Storage map[Hash]Hash `json:"storage,omitempty"` + + // StorageRead is the list of storage slots read + StorageRead map[Hash]struct{} `json:"storage_read,omitempty"` + + // Code tracks the initialization of the contract Code + Code []byte `json:"code,omitempty"` + + // CodeRead tracks whether the contract Code was read + CodeRead []byte `json:"code_read,omitempty"` + + // Suicide tracks whether the contract has been self destructed + Suicide *bool `json:"suicide,omitempty"` + + // Touched tracks whether the account has been touched/created + Touched *bool `json:"touched,omitempty"` + + // Read signals whether the account was read + Read *bool `json:"read,omitempty"` +} + +func (j *JournalEntry) Merge(jj *JournalEntry) { + if jj.Nonce != nil && jj.Nonce != j.Nonce { + j.Nonce = jj.Nonce + } + + if jj.Balance != nil && jj.Balance != j.Balance { + j.Balance = jj.Balance + } + + if jj.Storage != nil { + if j.Storage == nil { + j.Storage = map[Hash]Hash{} + } + + for k, v := range jj.Storage { + j.Storage[k] = v + } + } + + if jj.Code != nil && !bytes.Equal(jj.Code, j.Code) { + j.Code = jj.Code + } + + if jj.CodeRead != nil && !bytes.Equal(jj.CodeRead, j.CodeRead) { + j.CodeRead = jj.CodeRead + } + + if jj.Suicide != nil && jj.Suicide != j.Suicide { + j.Suicide = jj.Suicide + } + + if jj.Touched != nil && jj.Touched != j.Touched { + j.Touched = jj.Touched + } + + if jj.Read != nil && jj.Read != j.Read { + j.Read = jj.Read + } + + if jj.StorageRead != nil { + if j.StorageRead == nil { + j.StorageRead = map[Hash]struct{}{} + } + + for k := range jj.StorageRead { + j.StorageRead[k] = struct{}{} + } + } +} type Proof struct { Data []Hash // the proof himself Metadata map[string]interface{} } + +type OverrideAccount struct { + Nonce *uint64 + Code []byte + Balance *big.Int + State map[Hash]Hash + StateDiff map[Hash]Hash +} + +type StateOverride map[Address]OverrideAccount diff --git a/types/types_test.go b/types/types_test.go index 82d6ae3ed6..26d1b982e7 100644 --- a/types/types_test.go +++ b/types/types_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestEIP55(t *testing.T) { @@ -68,15 +69,17 @@ func TestEIP55(t *testing.T) { func TestTransactionCopy(t *testing.T) { addrTo := StringToAddress("11") txn := &Transaction{ - Nonce: 0, - GasPrice: big.NewInt(11), - Gas: 11, - To: &addrTo, - Value: big.NewInt(1), - Input: []byte{1, 2}, - V: big.NewInt(25), - S: big.NewInt(26), - R: big.NewInt(27), + Nonce: 0, + GasTipCap: big.NewInt(11), + GasFeeCap: big.NewInt(11), + GasPrice: big.NewInt(11), + Gas: 11, + To: &addrTo, + Value: big.NewInt(1), + Input: []byte{1, 2}, + V: big.NewInt(25), + S: big.NewInt(26), + R: big.NewInt(27), } newTxn := txn.Copy() @@ -84,3 +87,28 @@ func TestTransactionCopy(t *testing.T) { t.Fatal("[ERROR] Copied transaction not equal base transaction") } } + +func TestIsValidAddress(t *testing.T) { + t.Parallel() + + cases := []struct { + address string + isValid bool + }{ + {address: "0x123", isValid: false}, + {address: "FooBar", isValid: false}, + {address: "123FooBar", isValid: false}, + {address: "0x1234567890987654321012345678909876543210", isValid: true}, + {address: "0x0000000000000000000000000000000000000000", isValid: true}, + {address: "0x1000000000000000000000000000000000000000", isValid: true}, + } + + for _, c := range cases { + err := IsValidAddress(c.address) + if c.isValid { + require.NoError(t, err) + } else { + require.Error(t, err) + } + } +} diff --git a/validators/store/contract/contract_test.go b/validators/store/contract/contract_test.go index e164538126..d0a7f72e50 100644 --- a/validators/store/contract/contract_test.go +++ b/validators/store/contract/contract_test.go @@ -4,6 +4,10 @@ import ( "errors" "testing" + "github.com/hashicorp/go-hclog" + lru "github.com/hashicorp/golang-lru" + "github.com/stretchr/testify/assert" + "github.com/0xPolygon/polygon-edge/chain" "github.com/0xPolygon/polygon-edge/contracts/staking" "github.com/0xPolygon/polygon-edge/crypto" @@ -14,9 +18,6 @@ import ( "github.com/0xPolygon/polygon-edge/types" "github.com/0xPolygon/polygon-edge/validators" "github.com/0xPolygon/polygon-edge/validators/store" - "github.com/hashicorp/go-hclog" - lru "github.com/hashicorp/golang-lru" - "github.com/stretchr/testify/assert" ) var ( @@ -82,6 +83,9 @@ func newTestTransition( ex := state.NewExecutor(&chain.Params{ Forks: chain.AllForksEnabled, + BurnContract: map[uint64]types.Address{ + 0: types.ZeroAddress, + }, }, st, hclog.NewNullLogger()) rootHash, err := ex.WriteGenesis(nil, types.Hash{})