diff --git a/.env.example b/.env.example index 16d79a745..8114ea82d 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,6 @@ -# Which type of ethereum testnet to run locally (anvil|pos) +# Which type of ethereum testnet to run locally (anvil|pos|besu-qbft|none) +# Validated Besu mode for e2e: ETH_TESTNET_TYPE=besu-qbft, ETH_LC_ON_COSMOS=attestor-native, +# COSMOS_LC_ON_ETH=sp1, SP1_PROVER=mock ETH_TESTNET_TYPE="anvil" # Preset for Ethereum PoS network configuration (minimal|mainnet) ETHEREUM_POS_NETWORK_PRESET="minimal" diff --git a/.github/workflows/abigen.yaml b/.github/workflows/abigen.yaml index b9a942eeb..1d3f1b4f2 100644 --- a/.github/workflows/abigen.yaml +++ b/.github/workflows/abigen.yaml @@ -9,7 +9,9 @@ on: pull_request: paths: - 'ibc-solidity/abi/**' + - 'ibc-solidity/solidity.just' - 'packages/go-abigen/**' + - 'e2e/interchaintestv8/types/erc20/**' - '**.sol' - 'ibc-solidity/bun.lock' push: @@ -17,7 +19,11 @@ on: - main paths: - 'ibc-solidity/abi/**' + - 'ibc-solidity/solidity.just' - 'packages/go-abigen/**' + - 'e2e/interchaintestv8/types/erc20/**' + - '**.sol' + - 'ibc-solidity/bun.lock' jobs: check: @@ -38,16 +44,18 @@ jobs: - name: Install abigen run: go install github.com/ethereum/go-ethereum/cmd/abigen@be4dc0c4be2fe316dbdd0a73e48421f64978232f # v1.17.2 - - name: Run abigen + - name: Generate contract artifacts run: just solidity::generate-abi - - name: Check for diffs in go-abigen + - name: Check generated contract artifacts run: | - if ! git diff --quiet HEAD -- packages/go-abigen; then - echo "Git diff found in the selected directory. Failing the job." + if [ -n "$(git status --short --untracked-files=all -- ibc-solidity/abi packages/go-abigen e2e/interchaintestv8/types/erc20)" ]; then + echo "Generated contract artifacts are stale." + git status --short --untracked-files=all -- ibc-solidity/abi packages/go-abigen e2e/interchaintestv8/types/erc20 + git diff --stat -- ibc-solidity/abi packages/go-abigen e2e/interchaintestv8/types/erc20 exit 1 else - echo "No changes detected in the selected directory." + echo "Generated contract artifacts are current." fi golangci: diff --git a/.github/workflows/e2e-attestor.yml b/.github/workflows/e2e-attestor.yml index 40d4f5be8..34655d294 100644 --- a/.github/workflows/e2e-attestor.yml +++ b/.github/workflows/e2e-attestor.yml @@ -104,7 +104,6 @@ jobs: fail-fast: false matrix: ${{ fromJson(needs.generate-matrix-eth-to-eth.outputs.matrix) }} name: attestor-native/${{ matrix.entrypoint }}/${{ matrix.test }} - runs-on: depot-ubuntu-24.04-4 permissions: contents: read @@ -121,6 +120,52 @@ jobs: cd e2e/interchaintestv8 go test -v -mod=readonly . -run "^${{ matrix.entrypoint }}$/${{ matrix.test }}$" -timeout 60m + e2e-besu-qbft: + needs: build-e2e-programs + name: besu-qbft/ics20-roundtrip + env: + ETH_TESTNET_TYPE: besu-qbft + ETH_LC_ON_COSMOS: attestor-native + COSMOS_LC_ON_ETH: sp1 + SP1_PROVER: mock + E2E_PROOF_TYPE: groth16 + runs-on: depot-ubuntu-24.04-4 + permissions: + contents: read + packages: read + steps: + - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + - name: Set up E2E environment + uses: ./.github/actions/e2e-setup + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + - name: Run test + run: | + cd e2e/interchaintestv8 + go test -v -mod=readonly . -run '^TestWithIbcEurekaTestSuite$/^Test_ICS20TransferERC20TokenfromEthereumToCosmosAndBack$' -timeout 60m + + e2e-besu-to-besu: + needs: build-e2e-programs + name: besu-to-besu + runs-on: depot-ubuntu-24.04-4 + permissions: + contents: read + packages: read + steps: + - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + - name: Set up E2E environment + uses: ./.github/actions/e2e-setup + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + - name: Run Go package tests + run: | + cd e2e/interchaintestv8 + go test ./e2esuite + - name: Run Besu to Besu test suite + run: | + cd e2e/interchaintestv8 + go test -v -mod=readonly . -run '^TestWithBesuToBesuTestSuite$' -timeout 60m + e2e-multi-attestor-native: needs: build-e2e-programs strategy: diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..d49ff44e6 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,23 @@ +# AGENTS.md + +This repo combines Solidity/Foundry contracts, a Rust workspace, Solana Anchor programs, and Go-based end-to-end tooling for IBC Eureka. + +Look here first: +- `README.md` +- `justfile` +- `ibc-solidity/foundry.toml` +- `Cargo.toml` +- `ibc-solidity/contracts/README.md` + +Use the smallest relevant validation from the repo root: +- Solidity: `just solidity::lint-solidity` and `just solidity::test-foundry` +- Rust workspace, relayer, operator, and shared packages: `just lint-rust` and `just test-cargo` +- Broad cross-stack changes: `just lint` +- Solana or e2e changes: use the subtree-specific commands in `ibc-solana/AGENTS.md` or `e2e/interchaintestv8/AGENTS.md` + +Hard constraints: +- Do not hand-edit generated outputs in `packages/go-abigen/`, most of `packages/go-anchor/`, `e2e/interchaintestv8/solana/go-anchor/`, or protobuf outputs under `e2e/interchaintestv8/types/`; regenerate with `just solidity::generate-abi`, `just solana::generate-solana-types`, or `just generate-buf`. +- `packages/go-anchor/ics07_tendermint_patches/` is the hand-maintained exception inside `packages/go-anchor/`; preserve it across regeneration. +- If Solidity interfaces, ABI-exposed structs, or contract types change, run `just solidity::generate-abi` before validating Go or e2e code. +- If Solana program interfaces or IDLs change, run `just solana::generate-solana-types`. +- If `.proto` files change, run `just generate-buf`. diff --git a/Cargo.lock b/Cargo.lock index ba1c33d0e..32b9fb6b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8491,6 +8491,7 @@ dependencies = [ "opentelemetry-otlp", "opentelemetry_sdk", "prometheus", + "proof-api-besu-to-eth", "proof-api-core", "proof-api-cosmos-to-cosmos", "proof-api-cosmos-to-eth", @@ -8511,6 +8512,25 @@ dependencies = [ "warp", ] +[[package]] +name = "proof-api-besu-to-eth" +version = "0.1.0" +dependencies = [ + "alloy 2.0.4", + "alloy-rlp", + "anyhow", + "ethereum-apis 0.1.0", + "ethereum-light-client 0.1.0", + "ibc-eureka-solidity-types 0.1.0", + "proof-api-core", + "proof-api-lib", + "rlp 0.6.1", + "serde", + "serde_json", + "tonic 0.13.1", + "tracing", +] + [[package]] name = "proof-api-core" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index bb12b2295..092b37d8c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ members = [ "packages/proof-api/modules/eth-to-cosmos-compat", "packages/proof-api/modules/cosmos-to-eth", "packages/proof-api/modules/eth-to-eth", + "packages/proof-api/modules/besu-to-eth", "packages/proof-api/modules/cosmos-to-cosmos", "packages/proof-api/modules/solana-to-cosmos", "packages/proof-api/modules/cosmos-to-solana", @@ -60,6 +61,7 @@ proof-api-eth-to-cosmos = { path = "packages/proof-api/modules/eth-to-cos proof-api-eth-to-cosmos-compat = { path = "packages/proof-api/modules/eth-to-cosmos-compat", default-features = false } proof-api-cosmos-to-eth = { path = "packages/proof-api/modules/cosmos-to-eth", default-features = false } proof-api-eth-to-eth = { path = "packages/proof-api/modules/eth-to-eth", default-features = false } +proof-api-besu-to-eth = { path = "packages/proof-api/modules/besu-to-eth", default-features = false } proof-api-cosmos-to-cosmos = { path = "packages/proof-api/modules/cosmos-to-cosmos", default-features = false } proof-api-solana-to-cosmos = { path = "packages/proof-api/modules/solana-to-cosmos", default-features = false } proof-api-cosmos-to-solana = { path = "packages/proof-api/modules/cosmos-to-solana", default-features = false } diff --git a/README.md b/README.md index 97e659b46..fcada31d8 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,8 @@ This project is structured with the following directories: | `ICS26Router.sol` | IBC router handles sequencing, replay protection, and timeout checks. Passes proofs to light clients for verification, and resolves `portId` for app callbacks. Provable IBC storage is stored in this contract. | ✅ | | `ICS20Transfer.sol` | IBC transfer application to send and receive tokens to/from another IBC transfer implementation. | ✅ | | `SP1ICS07Tendermint.sol` | Tendermint light client powered by SP1. The entry point for SP1 proofs. | ✅ | +| `BesuIBFT2LightClient.sol` | Besu IBFT 2.0 light client for header-validator mode with weak-subjectivity updates and EVM proof verification, following the YUI + prover sealing-header verification model. | ✅ | +| `BesuQBFTLightClient.sol` | Besu QBFT light client for header-validator mode with weak-subjectivity updates and EVM proof verification, following the YUI + prover sealing-header verification model. | ✅ | | `ICS27GMP.sol` | IBC General Message Passing via Interchain Accounts. | ✅ | | `AttestationLightClient.sol` | The multisig contract implementing IBC Light Client specs. | ✅ | | `utils/IFTBaseUpgradeable.sol` | Interchain Fungible Token standard. Mint and burn alternative to ICS-20. | ⏳ | @@ -316,6 +318,7 @@ Note: These gas benchmarks are with Groth16. IBC is a peer-to-peer, light-client-based interoperability protocol. This repository contains the following light clients: - **SP1 Tendermint Light Client** – Verifies the consensus state of a Cosmos SDK chain powered by SP1 and `tendermint-rs`. (Solidity) +- **Besu IBFT 2.0 / QBFT Light Clients** – Verify Besu BFT headers in header-validator mode, track the counterparty `ICS26Router` account storage root, and verify EVM account/storage proofs for Eureka commitments. (Solidity) - [**Ethereum Light Client**](./ibc-solidity/programs/cw-ics08-wasm-eth/README.md) – Verifies the consensus state of the Ethereum chain. (CosmWasm) - **Attestation Light Client** – A multisig that can be used if the counterparty chain does not have a light client protocol. (Solidity and Solana) - **Solana Tendermint Light Client** - Verifies the consensus state of a Cosmos SDK chain powered by `tendermint-rs`. (Solana) diff --git a/e2e/interchaintestv8/AGENTS.md b/e2e/interchaintestv8/AGENTS.md new file mode 100644 index 000000000..4dac2d3e2 --- /dev/null +++ b/e2e/interchaintestv8/AGENTS.md @@ -0,0 +1,21 @@ +# AGENTS.md + +This subtree contains the Go end-to-end test suites that drive local Ethereum, Cosmos, and Solana environments through interchaintest. + +Look here first: +- `e2e/interchaintestv8/README.md` +- `e2e/interchaintestv8/go.mod` +- the relevant suite entrypoint (`ibc_eureka_test.go`, `relayer_test.go`, `sp1_ics07_test.go`, `solana_test.go`, etc.) + +Use the smallest relevant validation from the repo root: +- Single targeted test: `just test-e2e TestWithSuite/Test_Name` +- Common wrappers: `just test-e2e-eureka`, `just test-e2e-relayer`, `just test-e2e-cosmos-relayer`, `just test-e2e-sp1-ics07` +- Solana e2e wrappers: `just test-e2e-solana`, `just test-e2e-solana-gmp`, `just test-e2e-solana-ift`, `just test-e2e-solana-upgrade`, `just test-e2e-solana-attestation` +- Go lint for this subtree lives in `just lint-go`; see `justfile` for the other suite wrappers + +Local constraints: +- Prefer the smallest targeted test; full e2e runs are slow and environment-dependent. +- Local runs expect `.env` set up from `.env.example`; `just test-e2e` installs the relayer, and `just test-e2e-sp1-ics07` also installs the operator. +- If contract interfaces or ABI-exposed types change, run `just generate-abi` before e2e validation. +- If Solana IDLs change, run `just generate-solana-types`; if `.proto` files change, run `just generate-buf`. +- Do not hand-edit generated code under `e2e/interchaintestv8/types/` or `e2e/interchaintestv8/solana/go-anchor/`. diff --git a/e2e/interchaintestv8/README.md b/e2e/interchaintestv8/README.md index 17a01aed3..e68e017dd 100644 --- a/e2e/interchaintestv8/README.md +++ b/e2e/interchaintestv8/README.md @@ -8,6 +8,8 @@ These end to end tests are designed to run in the CI, but you can also run them ### Prerequisites +Besu tests additionally require Docker Compose v2 (`docker compose`). + In the repo root: ``` @@ -29,3 +31,65 @@ just test-e2e TestWithIbcEurekaTestSuite/Test_Deploy # Alternatively: just test-e2e-eureka Test_Deploy ``` + +## Besu QBFT mode + +Set `ETH_TESTNET_TYPE=besu-qbft` to start a real 4-validator Besu QBFT network. + +### Supported in this mode + +This pass supports the following Besu configuration: + +- `ETH_TESTNET_TYPE=besu-qbft` +- `ETH_LC_ON_COSMOS=attestor-native` +- `COSMOS_LC_ON_ETH=sp1` +- `SP1_PROVER=mock` + +Validated coverage in this mode: + +- Besu chain bring-up and contract deployment +- Dockerized Ethereum attestors reading Besu RPC +- relayer startup and client creation +- full Ethereum ↔ Cosmos ICS20 transfer roundtrip + +### Not supported + +- `ETH_LC_ON_COSMOS=full` +- beacon-chain-based Ethereum verification on Cosmos + +### Focused local test commands + +From the repo root, run: + +```shell +# Full ICS20 roundtrip in the supported Besu mode +ETH_TESTNET_TYPE=besu-qbft \ +ETH_LC_ON_COSMOS=attestor-native \ +COSMOS_LC_ON_ETH=sp1 \ +SP1_PROVER=mock \ +just test-e2e TestWithIbcEurekaTestSuite/Test_ICS20TransferERC20TokenfromEthereumToCosmosAndBack +``` + +## Focused Besu ↔ Besu e2e + +This focused suite starts two independent Besu QBFT networks, deploys Eureka contracts on both, starts the Rust relayer with `besu_to_eth` in both directions, deploys and registers Besu light clients on both chains, and verifies a one-way A → B ICS20 transfer plus the B → A acknowledgement relay using real Besu proofs. + +### Focused local test commands + +From the repo root, run: + +```shell +# Dual-Besu deploy / client-registration path +just test-e2e TestWithBesuToBesuTestSuite/Test_Deploy + +# One-way Besu A -> Besu B ICS20 transfer with acknowledgement relay back to A +just test-e2e TestWithBesuToBesuTestSuite/Test_ICS20TransferERC20FromChainAToChainB + +# Regenerate the QBFT light-client fixture used by test/besu-bft/* +GENERATE_BESU_LIGHT_CLIENT_FIXTURES=true \ +just test-e2e TestWithBesuToBesuTestSuite/Test_ICS20TransferERC20FromChainAToChainB +``` + +When `GENERATE_BESU_LIGHT_CLIENT_FIXTURES=true` is set, the focused Besu↔Besu transfer test writes: + +- `ibc-solidity/test/besu-bft/fixtures/qbft.json` diff --git a/e2e/interchaintestv8/attestor/setup.go b/e2e/interchaintestv8/attestor/setup.go index 9cf930e5b..08101c754 100644 --- a/e2e/interchaintestv8/attestor/setup.go +++ b/e2e/interchaintestv8/attestor/setup.go @@ -203,6 +203,7 @@ func SetupAttestors(ctx context.Context, t *testing.T, params SetupParams) Setup // chainType should be ChainTypeEvm for PoW chains or ChainTypeCosmos for PoS chains. func SetupEthAttestors(ctx context.Context, t *testing.T, client *dockerclient.Client, networkID, ethRPC, ics26Address string, chainType ChainType) SetupResult { t.Helper() + require.NotEmpty(t, ethRPC, "Ethereum attestors require a Docker-reachable Ethereum RPC URL") return SetupAttestors(ctx, t, SetupParams{ NumAttestors: testvalues.NumAttestors, KeystorePathTemplate: testvalues.AttestorKeystorePathTemplate, diff --git a/e2e/interchaintestv8/besu_to_besu_test.go b/e2e/interchaintestv8/besu_to_besu_test.go new file mode 100644 index 000000000..624fc140e --- /dev/null +++ b/e2e/interchaintestv8/besu_to_besu_test.go @@ -0,0 +1,511 @@ +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "context" + "crypto/ecdsa" + "fmt" + "math/big" + "os" + "path/filepath" + "strconv" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/suite" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + ethcommon "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + + transfertypes "github.com/cosmos/ibc-go/v11/modules/apps/transfer/types" + + "github.com/cosmos/solidity-ibc-eureka/packages/go-abigen/ibcerc20" + "github.com/cosmos/solidity-ibc-eureka/packages/go-abigen/ics20transfer" + "github.com/cosmos/solidity-ibc-eureka/packages/go-abigen/ics26router" + + "github.com/srdtrk/solidity-ibc-eureka/e2e/v8/chainconfig" + "github.com/srdtrk/solidity-ibc-eureka/e2e/v8/e2esuite" + "github.com/srdtrk/solidity-ibc-eureka/e2e/v8/ethereum" + "github.com/srdtrk/solidity-ibc-eureka/e2e/v8/proofapi" + "github.com/srdtrk/solidity-ibc-eureka/e2e/v8/testvalues" + e2etypes "github.com/srdtrk/solidity-ibc-eureka/e2e/v8/types" + "github.com/srdtrk/solidity-ibc-eureka/e2e/v8/types/erc20" + proofapitypes "github.com/srdtrk/solidity-ibc-eureka/e2e/v8/types/proofapi" +) + +const ( + besuToBesuChainBID = 1338 + + besuToBesuClientOnA = "besu-chain-b" + besuToBesuClientOnB = "besu-chain-a" + + besuToBesuConsensusTypeQBFT = "qbft" +) + +var besuToBesuChainBIPs = [4]string{"10.43.0.2", "10.43.0.3", "10.43.0.4", "10.43.0.5"} + +type besuToBesuChainState struct { + network chainconfig.BesuQBFTChain + eth ethereum.Ethereum + contractAddresses ethereum.DeployedContracts + ics26 *ics26router.Contract + ics20 *ics20transfer.Contract + erc20 *erc20.Contract + deployer *ecdsa.PrivateKey + user *ecdsa.PrivateKey + relayerSubmitter *ecdsa.PrivateKey + clientAddress ethcommon.Address +} + +type BesuToBesuTestSuite struct { + suite.Suite + + cwd string + relayerConfigPath string + relayerProcess *os.Process + relayerClient proofapitypes.ProofApiServiceClient + besuFixtureGenerator *e2etypes.BesuFixtureGenerator + + chainA besuToBesuChainState + chainB besuToBesuChainState +} + +func TestWithBesuToBesuTestSuite(t *testing.T) { + suite.Run(t, new(BesuToBesuTestSuite)) +} + +func (s *BesuToBesuTestSuite) SetupSuite() { + s.T().Cleanup(func() { + ctx := context.Background() + + if s.T() != nil && s.T().Failed() { + _ = s.chainA.network.DumpLogs(ctx) + _ = s.chainB.network.DumpLogs(ctx) + } + + if s.relayerProcess != nil { + _ = s.relayerProcess.Kill() + } + if s.relayerConfigPath != "" { + _ = os.Remove(s.relayerConfigPath) + } + + s.chainB.network.Destroy(ctx) + s.chainA.network.Destroy(ctx) + + if s.cwd != "" { + _ = os.Chdir(s.cwd) + } + }) + ctx := context.Background() + + if os.Getenv(testvalues.EnvKeyRustLog) == "" { + os.Setenv(testvalues.EnvKeyRustLog, testvalues.EnvValueRustLog_Info) + } + + var err error + s.cwd, err = os.Getwd() + s.Require().NoError(err) + s.Require().NoError(os.Chdir("../..")) + + s.chainA = s.spinUpChain(ctx, chainconfig.DefaultBesuQBFTParams()) + + s.chainB = s.spinUpChain(ctx, chainconfig.BesuQBFTParams{ + ChainID: besuToBesuChainBID, + Subnet: "10.43.0.0/16", + Gateway: "10.43.0.1", + ValidatorIPs: besuToBesuChainBIPs, + }) + s.Require().NoError(s.chainA.network.WaitForTransactionHandling(ctx)) + + s.besuFixtureGenerator = e2etypes.NewBesuFixtureGenerator() + + s.createUsers(&s.chainA) + s.createUsers(&s.chainB) + + s.deployContracts(&s.chainA) + s.deployContracts(&s.chainB) + + s.startRelayer() + s.connectRelayer() + + s.createAndRegisterBesuClient(&s.chainB, &s.chainA, besuToBesuClientOnA, besuToBesuClientOnB) + s.createAndRegisterBesuClient(&s.chainA, &s.chainB, besuToBesuClientOnB, besuToBesuClientOnA) +} + +func (s *BesuToBesuTestSuite) Test_Deploy() { + s.Require().True(s.Run("Verify ICS26 on Chain A", func() { + transferOnA, err := s.chainA.ics26.GetIBCApp(nil, transfertypes.PortID) + s.Require().NoError(err) + s.Require().Equal(strings.ToLower(s.chainA.contractAddresses.Ics20Transfer), strings.ToLower(transferOnA.Hex())) + })) + + s.Require().True(s.Run("Verify ICS26 on Chain B", func() { + transferOnB, err := s.chainB.ics26.GetIBCApp(nil, transfertypes.PortID) + s.Require().NoError(err) + s.Require().Equal(strings.ToLower(s.chainB.contractAddresses.Ics20Transfer), strings.ToLower(transferOnB.Hex())) + })) + + s.Require().True(s.Run("Verify Besu client on Chain A", func() { + clientOnA, err := s.chainA.ics26.GetClient(nil, besuToBesuClientOnA) + s.Require().NoError(err) + s.Require().Equal(s.chainA.clientAddress, clientOnA) + + counterparty, err := s.chainA.ics26.GetCounterparty(nil, besuToBesuClientOnA) + s.Require().NoError(err) + s.Require().Equal(besuToBesuClientOnB, counterparty.ClientId) + })) + + s.Require().True(s.Run("Verify Besu client on Chain B", func() { + clientOnB, err := s.chainB.ics26.GetClient(nil, besuToBesuClientOnB) + s.Require().NoError(err) + s.Require().Equal(s.chainB.clientAddress, clientOnB) + + counterparty, err := s.chainB.ics26.GetCounterparty(nil, besuToBesuClientOnB) + s.Require().NoError(err) + s.Require().Equal(besuToBesuClientOnA, counterparty.ClientId) + })) + + s.Require().True(s.Run("Verify Proof API Info A->B", func() { + info := s.waitForRelayerInfo(s.chainA.eth.ChainID.String(), s.chainB.eth.ChainID.String()) + s.Require().Equal(s.chainA.eth.ChainID.String(), info.SourceChain.ChainId) + s.Require().Equal(s.chainB.eth.ChainID.String(), info.TargetChain.ChainId) + })) + + s.Require().True(s.Run("Verify Proof API Info B->A", func() { + info := s.waitForRelayerInfo(s.chainB.eth.ChainID.String(), s.chainA.eth.ChainID.String()) + s.Require().Equal(s.chainB.eth.ChainID.String(), info.SourceChain.ChainId) + s.Require().Equal(s.chainA.eth.ChainID.String(), info.TargetChain.ChainId) + })) +} + +func (s *BesuToBesuTestSuite) Test_ICS20TransferERC20FromChainAToChainB() { + ctx := context.Background() + transferAmount := big.NewInt(testvalues.TransferAmount) + userAddressA := crypto.PubkeyToAddress(s.chainA.user.PublicKey) + userAddressB := crypto.PubkeyToAddress(s.chainB.user.PublicKey) + ics20AddressA := ethcommon.HexToAddress(s.chainA.contractAddresses.Ics20Transfer) + ics26AddressA := ethcommon.HexToAddress(s.chainA.contractAddresses.Ics26Router) + ics26AddressB := ethcommon.HexToAddress(s.chainB.contractAddresses.Ics26Router) + erc20AddressA := ethcommon.HexToAddress(s.chainA.contractAddresses.Erc20) + + var ( + sendTxHash []byte + sendReceipt *ethtypes.Receipt + sendPacket ics26router.IICS26RouterMsgsPacket + recvReceipt *ethtypes.Receipt + ibcERC20OnB *ibcerc20.Contract + ackReceipt *ethtypes.Receipt + ) + + s.Require().True(s.Run("Fund user on Chain A", func() { + fundTx, err := s.chainA.erc20.Transfer(s.mustTransactOpts(&s.chainA, s.chainA.eth.Faucet), userAddressA, testvalues.StartingERC20Balance) + s.Require().NoError(err) + + fundReceipt, err := s.chainA.eth.GetTxReciept(ctx, fundTx.Hash()) + s.Require().NoError(err) + s.Require().Equal(ethtypes.ReceiptStatusSuccessful, fundReceipt.Status) + })) + + s.Require().True(s.Run("Approve ICS20 on Chain A", func() { + approveTx, err := s.chainA.erc20.Approve(s.mustTransactOpts(&s.chainA, s.chainA.user), ics20AddressA, transferAmount) + s.Require().NoError(err) + + approveReceipt, err := s.chainA.eth.GetTxReciept(ctx, approveTx.Hash()) + s.Require().NoError(err) + s.Require().Equal(ethtypes.ReceiptStatusSuccessful, approveReceipt.Status) + })) + + s.Require().True(s.Run("Send transfer from Chain A to Chain B", func() { + timeout := uint64(time.Now().Add(30 * time.Minute).Unix()) + sendTx, err := s.chainA.ics20.SendTransfer(s.mustTransactOpts(&s.chainA, s.chainA.user), ics20transfer.IICS20TransferMsgsSendTransferMsg{ + Denom: erc20AddressA, + Amount: transferAmount, + Receiver: strings.ToLower(userAddressB.Hex()), + TimeoutTimestamp: timeout, + SourceClient: besuToBesuClientOnA, + DestPort: transfertypes.PortID, + Memo: "", + }) + s.Require().NoError(err) + + sendReceipt, err = s.chainA.eth.GetTxReciept(ctx, sendTx.Hash()) + s.Require().NoError(err) + s.Require().Equal(ethtypes.ReceiptStatusSuccessful, sendReceipt.Status) + sendTxHash = sendTx.Hash().Bytes() + + sendEvent, err := e2esuite.GetEvmEvent(sendReceipt, s.chainA.ics26.ParseSendPacket) + s.Require().NoError(err) + sendPacket = sendEvent.Packet + })) + + s.Require().True(s.Run("Verify balances on Chain A after send", func() { + escrowAddress, err := s.chainA.ics20.GetEscrow(nil, besuToBesuClientOnA) + s.Require().NoError(err) + + escrowBalance, err := s.chainA.erc20.BalanceOf(nil, escrowAddress) + s.Require().NoError(err) + s.Require().Equal(0, transferAmount.Cmp(escrowBalance)) + + userBalanceA, err := s.chainA.erc20.BalanceOf(nil, userAddressA) + s.Require().NoError(err) + expectedBalanceA := new(big.Int).Sub(new(big.Int).Set(testvalues.StartingERC20Balance), transferAmount) + s.Require().Equal(0, expectedBalanceA.Cmp(userBalanceA)) + })) + + s.Require().True(s.Run("Relay packet to Chain B", func() { + var relayTx []byte + s.Require().True(s.Run("Retrieve relay tx", func() { + relayAB, err := s.relayerClient.RelayByTx(context.Background(), &proofapitypes.RelayByTxRequest{ + SrcChain: s.chainA.eth.ChainID.String(), + DstChain: s.chainB.eth.ChainID.String(), + SourceTxIds: [][]byte{sendTxHash}, + SrcClientId: besuToBesuClientOnA, + DstClientId: besuToBesuClientOnB, + }) + s.Require().NoError(err) + s.Require().NotEmpty(relayAB.Tx) + s.Require().Equal(strings.ToLower(s.chainB.contractAddresses.Ics26Router), strings.ToLower(relayAB.Address)) + relayTx = relayAB.Tx + })) + + s.Require().True(s.Run("Broadcast relay tx on Chain B", func() { + var err error + recvReceipt, err = s.chainB.eth.BroadcastTx(ctx, s.chainB.relayerSubmitter, 15_000_000, &ics26AddressB, relayTx) + s.Require().NoError(err) + s.Require().Equal(ethtypes.ReceiptStatusSuccessful, recvReceipt.Status) + + writeAckEvent, err := e2esuite.GetEvmEvent(recvReceipt, s.chainB.ics26.ParseWriteAcknowledgement) + s.Require().NoError(err) + + ibcDenomOnB := fmt.Sprintf( + "%s/%s/%s", + writeAckEvent.Packet.Payloads[0].DestPort, + writeAckEvent.Packet.DestClient, + strings.ToLower(erc20AddressA.Hex()), + ) + ibcERC20AddressOnB, err := s.chainB.ics20.IbcERC20Contract(nil, ibcDenomOnB) + s.Require().NoError(err) + ibcERC20OnB, err = ibcerc20.NewContract(ibcERC20AddressOnB, s.chainB.eth.RPCClient) + s.Require().NoError(err) + })) + })) + + s.Require().True(s.Run("Verify balances on Chain B after receive", func() { + userBalanceB, err := ibcERC20OnB.BalanceOf(nil, userAddressB) + s.Require().NoError(err) + s.Require().Equal(0, transferAmount.Cmp(userBalanceB)) + })) + + s.Require().True(s.Run("Relay acknowledgement to Chain A", func() { + var relayTx []byte + s.Require().True(s.Run("Retrieve acknowledgement relay tx", func() { + ackRelay, err := s.relayerClient.RelayByTx(context.Background(), &proofapitypes.RelayByTxRequest{ + SrcChain: s.chainB.eth.ChainID.String(), + DstChain: s.chainA.eth.ChainID.String(), + SourceTxIds: [][]byte{recvReceipt.TxHash.Bytes()}, + SrcClientId: besuToBesuClientOnB, + DstClientId: besuToBesuClientOnA, + }) + s.Require().NoError(err) + s.Require().NotEmpty(ackRelay.Tx) + s.Require().Equal(strings.ToLower(s.chainA.contractAddresses.Ics26Router), strings.ToLower(ackRelay.Address)) + relayTx = ackRelay.Tx + })) + + s.Require().True(s.Run("Broadcast acknowledgement relay tx on Chain A", func() { + var err error + ackReceipt, err = s.chainA.eth.BroadcastTx(ctx, s.chainA.relayerSubmitter, 15_000_000, &ics26AddressA, relayTx) + s.Require().NoError(err) + s.Require().Equal(ethtypes.ReceiptStatusSuccessful, ackReceipt.Status) + + _, err = e2esuite.GetEvmEvent(ackReceipt, s.chainA.ics26.ParseAckPacket) + s.Require().NoError(err) + })) + })) + + if s.besuFixtureGenerator.Enabled { + s.Require().True(s.Run("Generate QBFT fixture", func() { + sendHeight := sendReceipt.BlockNumber.Uint64() + s.Require().Greater(sendHeight, uint64(2)) + s.Require().Greater(ackReceipt.BlockNumber.Uint64(), sendHeight) + s.Require().NoError(s.besuFixtureGenerator.GenerateAndSaveQBFTFixture(ctx, e2etypes.GenerateQBFTFixtureParams{ + SourceChain: &s.chainA.eth, + RouterAddress: ics26AddressA, + Packet: sendPacket, + InitialTrustedHeight: sendHeight - 2, + AdjacentUpdateHeight: sendHeight - 1, + NonAdjacentUpdateHeight: sendHeight, + SyntheticSourceHeight: ackReceipt.BlockNumber.Uint64(), + TrustingPeriod: uint64(testvalues.DefaultTrustPeriod), + MaxClockDrift: uint64(testvalues.DefaultMaxClockDrift), + })) + })) + } +} + +func (s *BesuToBesuTestSuite) spinUpChain(ctx context.Context, params chainconfig.BesuQBFTParams) besuToBesuChainState { + network, err := chainconfig.SpinUpBesuQBFT(ctx, params) + s.Require().NoError(err) + + ethChain, err := ethereum.NewEthereum(ctx, network.RPC, nil, network.Faucet) + s.Require().NoError(err) + + return besuToBesuChainState{ + network: network, + eth: ethChain, + } +} + +func (s *BesuToBesuTestSuite) createUsers(chain *besuToBesuChainState) { + var err error + chain.deployer, err = chain.eth.CreateAndFundUser() + s.Require().NoError(err) + chain.user, err = chain.eth.CreateAndFundUser() + s.Require().NoError(err) + chain.relayerSubmitter, err = chain.eth.CreateAndFundUser() + s.Require().NoError(err) +} + +func (s *BesuToBesuTestSuite) deployContracts(chain *besuToBesuChainState) { + os.Setenv(testvalues.EnvKeyEthRPC, chain.eth.RPC) + + stdout, err := chain.eth.ForgeScript(chain.deployer, testvalues.E2EDeployScriptPath, "--slow") + s.Require().NoError(err) + + chain.contractAddresses, err = ethereum.GetEthContractsFromDeployOutput(string(stdout)) + s.Require().NoError(err) + + chain.ics26, err = ics26router.NewContract(ethcommon.HexToAddress(chain.contractAddresses.Ics26Router), chain.eth.RPCClient) + s.Require().NoError(err) + chain.ics20, err = ics20transfer.NewContract(ethcommon.HexToAddress(chain.contractAddresses.Ics20Transfer), chain.eth.RPCClient) + s.Require().NoError(err) + chain.erc20, err = erc20.NewContract(ethcommon.HexToAddress(chain.contractAddresses.Erc20), chain.eth.RPCClient) + s.Require().NoError(err) +} + +func (s *BesuToBesuTestSuite) startRelayer() { + config := proofapi.NewConfigBuilder(). + BesuToEth(proofapi.BesuToEthParams{ + SrcChainID: s.chainA.eth.ChainID.String(), + DstChainID: s.chainB.eth.ChainID.String(), + SrcRPC: s.chainA.eth.RPC, + DstRPC: s.chainB.eth.RPC, + SrcICS26: s.chainA.contractAddresses.Ics26Router, + DstICS26: s.chainB.contractAddresses.Ics26Router, + ConsensusType: besuToBesuConsensusTypeQBFT, + }). + BesuToEth(proofapi.BesuToEthParams{ + SrcChainID: s.chainB.eth.ChainID.String(), + DstChainID: s.chainA.eth.ChainID.String(), + SrcRPC: s.chainB.eth.RPC, + DstRPC: s.chainA.eth.RPC, + SrcICS26: s.chainB.contractAddresses.Ics26Router, + DstICS26: s.chainA.contractAddresses.Ics26Router, + ConsensusType: besuToBesuConsensusTypeQBFT, + }). + Build() + + s.relayerConfigPath = filepath.Join(os.TempDir(), fmt.Sprintf("besu-to-besu-relayer-%d.json", time.Now().UnixNano())) + s.Require().NoError(config.GenerateConfigFile(s.relayerConfigPath)) + + var err error + s.relayerProcess, err = proofapi.StartProofAPI(s.relayerConfigPath) + s.Require().NoError(err) +} + +func (s *BesuToBesuTestSuite) connectRelayer() { + var err error + s.relayerClient, err = proofapi.GetGRPCClient(proofapi.DefaultProofAPIGRPCAddress()) + s.Require().NoError(err) + + infoAB := s.waitForRelayerInfo(s.chainA.eth.ChainID.String(), s.chainB.eth.ChainID.String()) + s.Require().Equal(s.chainA.eth.ChainID.String(), infoAB.SourceChain.ChainId) + s.Require().Equal(s.chainB.eth.ChainID.String(), infoAB.TargetChain.ChainId) + + infoBA := s.waitForRelayerInfo(s.chainB.eth.ChainID.String(), s.chainA.eth.ChainID.String()) + s.Require().Equal(s.chainB.eth.ChainID.String(), infoBA.SourceChain.ChainId) + s.Require().Equal(s.chainA.eth.ChainID.String(), infoBA.TargetChain.ChainId) +} + +func (s *BesuToBesuTestSuite) waitForRelayerInfo(srcChainID, dstChainID string) *proofapitypes.InfoResponse { + var ( + info *proofapitypes.InfoResponse + err error + ) + + for range 20 { + info, err = s.relayerClient.Info(context.Background(), &proofapitypes.InfoRequest{ + SrcChain: srcChainID, + DstChain: dstChainID, + }) + if err == nil { + return info + } + time.Sleep(time.Second) + } + + s.Require().NoError(err) + return info +} + +func (s *BesuToBesuTestSuite) createAndRegisterBesuClient( + srcChain *besuToBesuChainState, + dstChain *besuToBesuChainState, + dstClientID string, + counterpartyClientID string, +) { + resp, err := s.relayerClient.CreateClient(context.Background(), &proofapitypes.CreateClientRequest{ + SrcChain: srcChain.eth.ChainID.String(), + DstChain: dstChain.eth.ChainID.String(), + Parameters: map[string]string{ + testvalues.ParameterKey_TrustingPeriod: strconv.Itoa(testvalues.DefaultTrustPeriod), + testvalues.ParameterKey_MaxClockDrift: strconv.Itoa(testvalues.DefaultMaxClockDrift), + testvalues.ParameterKey_RoleManager: dstChain.contractAddresses.Ics26Router, + }, + }) + s.Require().NoError(err) + s.Require().NotEmpty(resp.Tx) + + createClientReceipt, err := dstChain.eth.BroadcastTx(context.Background(), dstChain.relayerSubmitter, 15_000_000, nil, resp.Tx) + s.Require().NoError(err) + s.Require().Equal(ethtypes.ReceiptStatusSuccessful, createClientReceipt.Status) + s.Require().NotEqual(ethcommon.Address{}, createClientReceipt.ContractAddress) + + counterpartyInfo := ics26router.IICS02ClientMsgsCounterpartyInfo{ + ClientId: counterpartyClientID, + MerklePrefix: [][]byte{[]byte("")}, + } + addClientTx, err := dstChain.ics26.AddClient( + s.mustTransactOpts(dstChain, dstChain.deployer), + dstClientID, + counterpartyInfo, + createClientReceipt.ContractAddress, + ) + s.Require().NoError(err) + + addClientReceipt, err := dstChain.eth.GetTxReciept(context.Background(), addClientTx.Hash()) + s.Require().NoError(err) + s.Require().Equal(ethtypes.ReceiptStatusSuccessful, addClientReceipt.Status) + + addClientEvent, err := e2esuite.GetEvmEvent(addClientReceipt, dstChain.ics26.ParseICS02ClientAdded) + s.Require().NoError(err) + s.Require().Equal(dstClientID, addClientEvent.ClientId) + s.Require().Equal(createClientReceipt.ContractAddress, addClientEvent.Client) + + registeredClient, err := dstChain.ics26.GetClient(nil, dstClientID) + s.Require().NoError(err) + s.Require().Equal(createClientReceipt.ContractAddress, registeredClient) + + dstChain.clientAddress = createClientReceipt.ContractAddress +} + +func (s *BesuToBesuTestSuite) mustTransactOpts(chain *besuToBesuChainState, key *ecdsa.PrivateKey) *bind.TransactOpts { + txOpts, err := chain.eth.GetTransactOpts(key) + s.Require().NoError(err) + return txOpts +} diff --git a/e2e/interchaintestv8/chainconfig/besu_qbft.go b/e2e/interchaintestv8/chainconfig/besu_qbft.go new file mode 100644 index 000000000..a0990c5ad --- /dev/null +++ b/e2e/interchaintestv8/chainconfig/besu_qbft.go @@ -0,0 +1,393 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chainconfig + +import ( + "context" + "crypto/ecdsa" + "embed" + "encoding/json" + "fmt" + "io/fs" + "math/big" + "os" + "os/exec" + "path/filepath" + "strings" + "time" + + dockernetwork "github.com/docker/docker/api/types/network" + dockerclient "github.com/moby/moby/client" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" + + "github.com/cosmos/interchaintest/v11/testutil" + + "github.com/srdtrk/solidity-ibc-eureka/e2e/v8/testvalues" +) + +const ( + besuQBFTComposeFile = "docker-compose.yml" + besuQBFTProjectName = "besu-qbft" + + defaultBesuQBFTChainID uint64 = 1337 + defaultBesuQBFTSubnet = "10.42.0.0/16" + defaultBesuQBFTGateway = "10.42.0.1" + + besuQBFTTxProbeReceiptTimeout = 30 * time.Second +) + +var defaultBesuQBFTValidatorIPs = [4]string{"10.42.0.2", "10.42.0.3", "10.42.0.4", "10.42.0.5"} + +//go:embed testdata/besu/qbft +var besuQBFTAssets embed.FS + +var besuQBFTServices = []string{"validator1", "validator2", "validator3", "validator4"} + +type BesuQBFTParams struct { + ChainID uint64 + Subnet string + Gateway string + ValidatorIPs [4]string + DockerRPCAlias string + InterchainNetworkID string +} + +// DefaultBesuQBFTParams returns the topology from the embedded Besu fixture. +func DefaultBesuQBFTParams() BesuQBFTParams { + return BesuQBFTParams{ + ChainID: defaultBesuQBFTChainID, + Subnet: defaultBesuQBFTSubnet, + Gateway: defaultBesuQBFTGateway, + ValidatorIPs: defaultBesuQBFTValidatorIPs, + } +} + +type BesuQBFTChain struct { + RPC string + DockerRPC string + Faucet *ecdsa.PrivateKey + + projectName string + projectDir string +} + +func (c BesuQBFTChain) WaitForTransactionHandling(ctx context.Context) error { + return waitForBesuQBFTTransactionHandling(ctx, c.RPC, c.Faucet) +} + +func SpinUpBesuQBFT(ctx context.Context, params BesuQBFTParams) (chain BesuQBFTChain, err error) { + faucet, err := crypto.HexToECDSA(testvalues.E2EDeployerPrivateKeyHex) + if err != nil { + return BesuQBFTChain{}, fmt.Errorf("parse besu qbft faucet key: %w", err) + } + + projectDir, err := os.MkdirTemp("", besuQBFTProjectName+"-*") + if err != nil { + return BesuQBFTChain{}, fmt.Errorf("create besu qbft temp dir: %w", err) + } + + chain = BesuQBFTChain{ + Faucet: faucet, + projectDir: projectDir, + } + cleanupChain := BesuQBFTChain{projectDir: projectDir} + defer func() { + if err != nil { + cleanupCtx := context.Background() + if cleanupChain.projectName != "" { + if logErr := cleanupChain.DumpLogs(cleanupCtx); logErr != nil { + fmt.Printf("failed to dump besu qbft logs after startup error: %v\n", logErr) + } + } + cleanupChain.Destroy(cleanupCtx) + } + }() + + if err := materializeBesuQBFTAssets(projectDir); err != nil { + return BesuQBFTChain{}, fmt.Errorf("materialize besu qbft assets: %w", err) + } + + if err := patchBesuQBFTGenesis(filepath.Join(projectDir, "genesis.json"), params.ChainID); err != nil { + return BesuQBFTChain{}, fmt.Errorf("patch besu qbft genesis: %w", err) + } + + if err := patchBesuQBFTCompose(filepath.Join(projectDir, besuQBFTComposeFile), params); err != nil { + return BesuQBFTChain{}, fmt.Errorf("patch besu qbft compose file: %w", err) + } + + chain.projectName = filepath.Base(projectDir) + cleanupChain.projectName = chain.projectName + if _, err := chain.runCompose(ctx, "up", "--detach"); err != nil { + return BesuQBFTChain{}, fmt.Errorf("start besu qbft compose stack: %w", err) + } + + validator1Output, err := chain.runCompose(ctx, "ps", "-q", "validator1") + if err != nil { + return BesuQBFTChain{}, fmt.Errorf("get validator1 container: %w", err) + } + validator1ID := strings.TrimSpace(string(validator1Output)) + if validator1ID == "" { + return BesuQBFTChain{}, fmt.Errorf("get validator1 container: docker compose returned no container ID") + } + + dockerClient, err := dockerclient.NewClientWithOpts(dockerclient.FromEnv, dockerclient.WithAPIVersionNegotiation()) + if err != nil { + return BesuQBFTChain{}, fmt.Errorf("create docker client: %w", err) + } + defer dockerClient.Close() + + validator1, err := dockerClient.ContainerInspect(ctx, validator1ID) + if err != nil { + return BesuQBFTChain{}, fmt.Errorf("inspect validator1 container: %w", err) + } + if validator1.NetworkSettings == nil { + return BesuQBFTChain{}, fmt.Errorf("resolve validator1 rpc port: container has no network settings") + } + bindings := validator1.NetworkSettings.Ports["8545/tcp"] + if len(bindings) == 0 || bindings[0].HostPort == "" { + return BesuQBFTChain{}, fmt.Errorf("resolve validator1 rpc port: no 8545/tcp binding") + } + + chain.RPC = fmt.Sprintf("http://127.0.0.1:%s", bindings[0].HostPort) + if params.DockerRPCAlias != "" { + chain.DockerRPC = fmt.Sprintf("http://%s:8545", params.DockerRPCAlias) + } + + if params.InterchainNetworkID != "" { + settings := &dockernetwork.EndpointSettings{} + if params.DockerRPCAlias != "" { + settings.Aliases = []string{params.DockerRPCAlias} + } + if err := dockerClient.NetworkConnect(ctx, params.InterchainNetworkID, validator1ID, settings); err != nil { + return BesuQBFTChain{}, fmt.Errorf("connect besu qbft rpc container to interchain network: %w", err) + } + } + + if err := waitForBesuQBFTReady(ctx, chain.RPC); err != nil { + return BesuQBFTChain{}, fmt.Errorf("wait for besu qbft readiness: %w", err) + } + + if err := waitForBesuQBFTTransactionHandling(ctx, chain.RPC, faucet); err != nil { + return BesuQBFTChain{}, fmt.Errorf("wait for besu qbft transaction handling: %w", err) + } + + return chain, nil +} + +func (c BesuQBFTChain) Destroy(ctx context.Context) { + if c.projectName != "" && c.projectDir != "" { + if _, err := c.runCompose(ctx, "down", "--volumes", "--remove-orphans"); err != nil { + fmt.Printf("failed to tear down besu qbft stack: %v\n", err) + } + } + + if c.projectDir != "" { + if err := os.RemoveAll(c.projectDir); err != nil { + fmt.Printf("failed to remove besu qbft temp dir %s: %v\n", c.projectDir, err) + } + } +} + +func (c BesuQBFTChain) DumpLogs(ctx context.Context) error { + if c.projectName == "" || c.projectDir == "" { + return nil + } + + args := append([]string{"logs", "--no-color"}, besuQBFTServices...) + logs, err := c.runCompose(ctx, args...) + if len(logs) > 0 { + fmt.Print(string(logs)) + } + return err +} + +func (c BesuQBFTChain) runCompose(ctx context.Context, args ...string) ([]byte, error) { + composeArgs := []string{ + "compose", + "--project-name", c.projectName, + "--file", filepath.Join(c.projectDir, besuQBFTComposeFile), + } + composeArgs = append(composeArgs, args...) + + output, err := exec.CommandContext(ctx, "docker", composeArgs...).CombinedOutput() + if err != nil { + return output, fmt.Errorf("docker compose %s: %w: %s", strings.Join(args, " "), err, strings.TrimSpace(string(output))) + } + return output, nil +} + +func materializeBesuQBFTAssets(dst string) error { + sub, err := fs.Sub(besuQBFTAssets, "testdata/besu/qbft") + if err != nil { + return err + } + + return os.CopyFS(dst, sub) +} + +func patchBesuQBFTGenesis(path string, chainID uint64) error { + contents, err := os.ReadFile(path) + if err != nil { + return err + } + + var genesis map[string]any + if err := json.Unmarshal(contents, &genesis); err != nil { + return err + } + + config, ok := genesis["config"].(map[string]any) + if !ok { + return fmt.Errorf("genesis config missing or invalid") + } + config["chainId"] = chainID + + updated, err := json.MarshalIndent(genesis, "", " ") + if err != nil { + return err + } + updated = append(updated, '\n') + + // Besu reads the generated genesis file as an unprivileged container user. + return os.WriteFile(path, updated, 0o644) //nolint:gosec +} + +func patchBesuQBFTCompose(path string, params BesuQBFTParams) error { + contents, err := os.ReadFile(path) + if err != nil { + return err + } + + replacer := strings.NewReplacer( + defaultBesuQBFTSubnet, params.Subnet, + defaultBesuQBFTGateway, params.Gateway, + defaultBesuQBFTValidatorIPs[0], params.ValidatorIPs[0], + defaultBesuQBFTValidatorIPs[1], params.ValidatorIPs[1], + defaultBesuQBFTValidatorIPs[2], params.ValidatorIPs[2], + defaultBesuQBFTValidatorIPs[3], params.ValidatorIPs[3], + ) + + // Docker Compose reads this generated configuration outside the Go process. + return os.WriteFile(path, []byte(replacer.Replace(string(contents))), 0o644) //nolint:gosec +} + +func waitForBesuQBFTReady(ctx context.Context, rpcURL string) error { + client, err := ethclient.DialContext(ctx, rpcURL) + if err != nil { + return fmt.Errorf("dial readiness rpc: %w", err) + } + defer client.Close() + + var lastErr error + err = testutil.WaitForCondition(3*time.Minute, 2*time.Second, func() (bool, error) { + peerCount, err := client.PeerCount(ctx) + if err != nil { + lastErr = err + return false, nil + } + if peerCount < uint64(len(besuQBFTServices)-1) { + lastErr = fmt.Errorf("peer count %d, want at least %d", peerCount, len(besuQBFTServices)-1) + return false, nil + } + + blockNumber, err := client.BlockNumber(ctx) + if err != nil { + lastErr = err + return false, nil + } + if blockNumber == 0 { + lastErr = fmt.Errorf("block number is still zero") + return false, nil + } + + var validators []common.Address + if err := client.Client().CallContext(ctx, &validators, "qbft_getValidatorsByBlockNumber", "latest"); err != nil { + lastErr = err + return false, nil + } + + if len(validators) != len(besuQBFTServices) { + lastErr = fmt.Errorf("validator count %d, want exactly %d", len(validators), len(besuQBFTServices)) + return false, nil + } + + return true, nil + }) + if err != nil && lastErr != nil { + return fmt.Errorf("%w (last readiness observation: %v)", err, lastErr) + } + return err +} + +func waitForBesuQBFTTransactionHandling(ctx context.Context, rpcURL string, key *ecdsa.PrivateKey) error { + client, err := ethclient.DialContext(ctx, rpcURL) + if err != nil { + return fmt.Errorf("dial transaction probe rpc: %w", err) + } + defer client.Close() + + var lastErr error + err = testutil.WaitForCondition(2*time.Minute, 2*time.Second, func() (bool, error) { + txHash, err := sendBesuQBFTProbeTx(ctx, client, key) + if err != nil { + lastErr = err + return false, nil + } + + receiptCtx, cancel := context.WithTimeout(ctx, besuQBFTTxProbeReceiptTimeout) + receipt, err := bind.WaitMinedHash(receiptCtx, client, txHash) + cancel() + if err != nil { + lastErr = err + return false, nil + } + if receipt.Status != ethtypes.ReceiptStatusSuccessful { + return false, fmt.Errorf("besu qbft transaction probe failed on-chain with status %d", receipt.Status) + } + + return true, nil + }) + if err != nil && lastErr != nil { + return fmt.Errorf("%w (last transaction probe error: %v)", err, lastErr) + } + return err +} + +func sendBesuQBFTProbeTx(ctx context.Context, client *ethclient.Client, key *ecdsa.PrivateKey) (common.Hash, error) { + from := crypto.PubkeyToAddress(key.PublicKey) + + chainID, err := client.ChainID(ctx) + if err != nil { + return common.Hash{}, err + } + + nonce, err := client.PendingNonceAt(ctx, from) + if err != nil { + return common.Hash{}, err + } + + tx := ethtypes.NewTx(ðtypes.DynamicFeeTx{ + ChainID: chainID, + Nonce: nonce, + To: &from, + Value: big.NewInt(0), + Gas: 21_000, + GasFeeCap: big.NewInt(1), + GasTipCap: big.NewInt(1), + }) + + signedTx, err := ethtypes.SignTx(tx, ethtypes.LatestSignerForChainID(chainID), key) + if err != nil { + return common.Hash{}, err + } + if err := client.SendTransaction(ctx, signedTx); err != nil { + return common.Hash{}, err + } + + return signedTx.Hash(), nil +} diff --git a/e2e/interchaintestv8/chainconfig/testdata/besu/qbft/config.toml b/e2e/interchaintestv8/chainconfig/testdata/besu/qbft/config.toml new file mode 100644 index 000000000..3c5b75f9a --- /dev/null +++ b/e2e/interchaintestv8/chainconfig/testdata/besu/qbft/config.toml @@ -0,0 +1,13 @@ +genesis-file="/opt/besu/genesis.json" +data-path="/opt/besu/data" +node-private-key-file="/opt/besu/key" +data-storage-format="BONSAI" +bonsai-limit-trie-logs-enabled=false +rpc-http-enabled=true +rpc-http-host="0.0.0.0" +rpc-http-api=["ETH","NET","QBFT","WEB3","DEBUG"] +host-allowlist=["*"] +rpc-http-cors-origins=["all"] +min-gas-price=0 +sync-min-peers=1 +tx-pool="legacy" diff --git a/e2e/interchaintestv8/chainconfig/testdata/besu/qbft/docker-compose.yml b/e2e/interchaintestv8/chainconfig/testdata/besu/qbft/docker-compose.yml new file mode 100644 index 000000000..69587a47d --- /dev/null +++ b/e2e/interchaintestv8/chainconfig/testdata/besu/qbft/docker-compose.yml @@ -0,0 +1,96 @@ +# SPDX-License-Identifier: Apache-2.0 + +services: + validator1: + image: hyperledger/besu:26.4.0 + environment: + BESU_OPTS: -Xms128m -Xmx512m -XX:ActiveProcessorCount=2 + command: + - --config-file=/opt/besu/config.toml + - --identity=validator1 + - --p2p-host=10.42.0.2 + - --p2p-port=30303 + volumes: + - ./config.toml:/opt/besu/config.toml:ro + - ./genesis.json:/opt/besu/genesis.json:ro + - ./keys/validator1/key:/opt/besu/key:ro + - validator1-data:/opt/besu/data + ports: + - "8545" + networks: + qbft_testnet: + ipv4_address: 10.42.0.2 + + validator2: + image: hyperledger/besu:26.4.0 + environment: + BESU_OPTS: -Xms128m -Xmx512m -XX:ActiveProcessorCount=2 + command: + - --config-file=/opt/besu/config.toml + - --identity=validator2 + - --bootnodes=enode://ad83ac93fcc30a30f3e1bb6467623e45719167be50d13dccd8361cbca478cb540069869d1bae16de0f8b17a28f26f1c6c4dc12e71f240b366c6ff6f02f3fb93e@10.42.0.2:30303 + - --p2p-host=10.42.0.3 + - --p2p-port=30304 + volumes: + - ./config.toml:/opt/besu/config.toml:ro + - ./genesis.json:/opt/besu/genesis.json:ro + - ./keys/validator2/key:/opt/besu/key:ro + - validator2-data:/opt/besu/data + networks: + qbft_testnet: + ipv4_address: 10.42.0.3 + + validator3: + image: hyperledger/besu:26.4.0 + environment: + BESU_OPTS: -Xms128m -Xmx512m -XX:ActiveProcessorCount=2 + command: + - --config-file=/opt/besu/config.toml + - --identity=validator3 + - --bootnodes=enode://ad83ac93fcc30a30f3e1bb6467623e45719167be50d13dccd8361cbca478cb540069869d1bae16de0f8b17a28f26f1c6c4dc12e71f240b366c6ff6f02f3fb93e@10.42.0.2:30303 + - --p2p-host=10.42.0.4 + - --p2p-port=30305 + volumes: + - ./config.toml:/opt/besu/config.toml:ro + - ./genesis.json:/opt/besu/genesis.json:ro + - ./keys/validator3/key:/opt/besu/key:ro + - validator3-data:/opt/besu/data + networks: + qbft_testnet: + ipv4_address: 10.42.0.4 + + validator4: + image: hyperledger/besu:26.4.0 + environment: + BESU_OPTS: -Xms128m -Xmx512m -XX:ActiveProcessorCount=2 + command: + - --config-file=/opt/besu/config.toml + - --identity=validator4 + - --bootnodes=enode://ad83ac93fcc30a30f3e1bb6467623e45719167be50d13dccd8361cbca478cb540069869d1bae16de0f8b17a28f26f1c6c4dc12e71f240b366c6ff6f02f3fb93e@10.42.0.2:30303 + - --p2p-host=10.42.0.5 + - --p2p-port=30306 + volumes: + - ./config.toml:/opt/besu/config.toml:ro + - ./genesis.json:/opt/besu/genesis.json:ro + - ./keys/validator4/key:/opt/besu/key:ro + - validator4-data:/opt/besu/data + networks: + qbft_testnet: + ipv4_address: 10.42.0.5 + +networks: + qbft_testnet: + driver: bridge + driver_opts: + com.docker.network.enable_ipv6: "false" + ipam: + driver: default + config: + - subnet: 10.42.0.0/16 + gateway: 10.42.0.1 + +volumes: + validator1-data: + validator2-data: + validator3-data: + validator4-data: diff --git a/e2e/interchaintestv8/chainconfig/testdata/besu/qbft/genesis.json b/e2e/interchaintestv8/chainconfig/testdata/besu/qbft/genesis.json new file mode 100644 index 000000000..85f58aa50 --- /dev/null +++ b/e2e/interchaintestv8/chainconfig/testdata/besu/qbft/genesis.json @@ -0,0 +1,24 @@ +{ + "config": { + "chainId": 1337, + "cancunTime": 0, + "zeroBaseFee": true, + "qbft": { + "blockperiodseconds": 2, + "epochlength": 30000, + "requesttimeoutseconds": 4 + } + }, + "nonce": "0x0", + "timestamp": "0x58ee40ba", + "gasLimit": "0x2faf080", + "difficulty": "0x1", + "mixHash": "0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "f39fd6e51aad88f6f4ce6ab8827279cfffb92266": { + "balance": "1000000000000000000000000" + } + }, + "extraData": "0xf87aa00000000000000000000000000000000000000000000000000000000000000000f85494065f139d8a49e9926232cc4435159024cb5064fc940eb968de631abc65322ecdca5dfdf9c6296e52f494543d3796700ee35803a1c43562a69fec08e1e4239420c5edbcf6263cd9e30df395a2b914f6e939b9bac080c0" +} diff --git a/e2e/interchaintestv8/chainconfig/testdata/besu/qbft/keys/validator1/key b/e2e/interchaintestv8/chainconfig/testdata/besu/qbft/keys/validator1/key new file mode 100644 index 000000000..0a70c443d --- /dev/null +++ b/e2e/interchaintestv8/chainconfig/testdata/besu/qbft/keys/validator1/key @@ -0,0 +1 @@ +0x18fddb41c4f6316532162f1c54a0cf4c62562b499c392720f04e7d33e32e88fa diff --git a/e2e/interchaintestv8/chainconfig/testdata/besu/qbft/keys/validator2/key b/e2e/interchaintestv8/chainconfig/testdata/besu/qbft/keys/validator2/key new file mode 100644 index 000000000..43586a8fe --- /dev/null +++ b/e2e/interchaintestv8/chainconfig/testdata/besu/qbft/keys/validator2/key @@ -0,0 +1 @@ +0x9a4cc956527624fba01e932a28f982233b8169d840b72a9089cd0d3da127ccb6 diff --git a/e2e/interchaintestv8/chainconfig/testdata/besu/qbft/keys/validator3/key b/e2e/interchaintestv8/chainconfig/testdata/besu/qbft/keys/validator3/key new file mode 100644 index 000000000..b2049aeca --- /dev/null +++ b/e2e/interchaintestv8/chainconfig/testdata/besu/qbft/keys/validator3/key @@ -0,0 +1 @@ +0x2fd21d48dcb473933de188ff882fed9d3bcbc4d43af77172f1b8035f1574a19b diff --git a/e2e/interchaintestv8/chainconfig/testdata/besu/qbft/keys/validator4/key b/e2e/interchaintestv8/chainconfig/testdata/besu/qbft/keys/validator4/key new file mode 100644 index 000000000..a2903bdff --- /dev/null +++ b/e2e/interchaintestv8/chainconfig/testdata/besu/qbft/keys/validator4/key @@ -0,0 +1 @@ +0xa9b2b5406572152ceb0a5480a65f63fc562e6970402dd58ede1bec32837ae25a diff --git a/e2e/interchaintestv8/e2esuite/config.go b/e2e/interchaintestv8/e2esuite/config.go index a0693a5ad..0424d01bd 100644 --- a/e2e/interchaintestv8/e2esuite/config.go +++ b/e2e/interchaintestv8/e2esuite/config.go @@ -34,6 +34,10 @@ func (c *ethereumConfig) isAnvilBased() bool { return c.testnetType == testvalues.EthTestnetTypeAnvil } +func (c *ethereumConfig) isBesuQBFT() bool { + return c.testnetType == testvalues.EthTestnetTypeBesuQBFT +} + func (c *ethereumConfig) needsPoS() bool { return c.testnetType == testvalues.EthTestnetTypePoS } @@ -61,22 +65,29 @@ func (c *setupConfig) validate() error { ethTestnetType := c.ethereum.testnetType ethLcOnCosmos := c.cosmos.lightClientType - // Skip validation if no ethereum chain - if ethTestnetType == "" || ethTestnetType == testvalues.EthTestnetType_None { + switch ethTestnetType { + case "", testvalues.EthTestnetType_None: return nil + case testvalues.EthTestnetTypeAnvil: + if c.ethereum.anvilCount > 1 { + return nil + } + if ethLcOnCosmos == testvalues.EthLCOnCosmosTypeDummyWasm || ethLcOnCosmos == testvalues.EthLCOnCosmosTypeAttestorNative { + return nil + } + case testvalues.EthTestnetTypePoS: + if ethLcOnCosmos == testvalues.EthLCOnCosmosTypeFullWasm || ethLcOnCosmos == testvalues.EthLCOnCosmosTypeAttestorNative { + return nil + } + case testvalues.EthTestnetTypeBesuQBFT: + if ethLcOnCosmos == testvalues.EthLCOnCosmosTypeAttestorNative { + return nil + } + default: + return fmt.Errorf("invalid config: unsupported ETH_TESTNET_TYPE=%s", ethTestnetType) } - // Anvil cannot use full light client (no beacon chain to verify) - if c.ethereum.isAnvilBased() && ethLcOnCosmos == testvalues.EthLCOnCosmosTypeFullWasm { - return fmt.Errorf("invalid config: ETH_TESTNET_TYPE=%s cannot use ETH_LC_ON_COSMOS=%s (Anvil doesn't have beacon chain)", ethTestnetType, ethLcOnCosmos) - } - - // PoS testnets cannot use dummy light client (requires actual verification) - if !c.ethereum.isAnvilBased() && ethLcOnCosmos == testvalues.EthLCOnCosmosTypeDummyWasm { - return fmt.Errorf("invalid config: ETH_TESTNET_TYPE=%s cannot use ETH_LC_ON_COSMOS=%s (PoS requires actual verification)", ethTestnetType, ethLcOnCosmos) - } - - return nil + return fmt.Errorf("invalid config: ETH_TESTNET_TYPE=%s does not support ETH_LC_ON_COSMOS=%s", ethTestnetType, ethLcOnCosmos) } // Result types for parallel chain setup diff --git a/e2e/interchaintestv8/e2esuite/config_test.go b/e2e/interchaintestv8/e2esuite/config_test.go new file mode 100644 index 000000000..92b9e297f --- /dev/null +++ b/e2e/interchaintestv8/e2esuite/config_test.go @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: Apache-2.0 + +package e2esuite + +import ( + "testing" + + "github.com/srdtrk/solidity-ibc-eureka/e2e/v8/testvalues" +) + +func TestSetupConfigValidateEthereumCompatibility(t *testing.T) { + const unknown = "unknown" + + tests := []struct { + name string + testnetType string + clientType string + wantErr bool + }{ + {"anvil dummy", testvalues.EthTestnetTypeAnvil, testvalues.EthLCOnCosmosTypeDummyWasm, false}, + {"anvil attestor", testvalues.EthTestnetTypeAnvil, testvalues.EthLCOnCosmosTypeAttestorNative, false}, + {"pos full", testvalues.EthTestnetTypePoS, testvalues.EthLCOnCosmosTypeFullWasm, false}, + {"pos attestor", testvalues.EthTestnetTypePoS, testvalues.EthLCOnCosmosTypeAttestorNative, false}, + {"besu attestor", testvalues.EthTestnetTypeBesuQBFT, testvalues.EthLCOnCosmosTypeAttestorNative, false}, + {"anvil full", testvalues.EthTestnetTypeAnvil, testvalues.EthLCOnCosmosTypeFullWasm, true}, + {"pos dummy", testvalues.EthTestnetTypePoS, testvalues.EthLCOnCosmosTypeDummyWasm, true}, + {"besu dummy", testvalues.EthTestnetTypeBesuQBFT, testvalues.EthLCOnCosmosTypeDummyWasm, true}, + {"besu full", testvalues.EthTestnetTypeBesuQBFT, testvalues.EthLCOnCosmosTypeFullWasm, true}, + {"active empty client", testvalues.EthTestnetTypeAnvil, "", true}, + {"active unknown client", testvalues.EthTestnetTypePoS, unknown, true}, + {"unknown testnet", unknown, testvalues.EthLCOnCosmosTypeAttestorNative, true}, + {"disabled empty", "", unknown, false}, + {"disabled none", testvalues.EthTestnetType_None, unknown, false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cfg := setupConfig{ + ethereum: ethereumConfig{testnetType: tt.testnetType}, + cosmos: cosmosConfig{lightClientType: tt.clientType}, + } + if err := cfg.validate(); (err != nil) != tt.wantErr { + t.Fatalf("validate() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } + + for _, clientType := range []string{"", unknown} { + cfg := setupConfig{ + ethereum: ethereumConfig{testnetType: testvalues.EthTestnetTypeAnvil, anvilCount: 2}, + cosmos: cosmosConfig{lightClientType: clientType}, + } + if err := cfg.validate(); err != nil { + t.Errorf("multiple Anvil chains with ETH_LC_ON_COSMOS=%q: %v", clientType, err) + } + } +} diff --git a/e2e/interchaintestv8/e2esuite/setup_ethereum.go b/e2e/interchaintestv8/e2esuite/setup_ethereum.go index 50c002cfd..bd1eb8e7d 100644 --- a/e2e/interchaintestv8/e2esuite/setup_ethereum.go +++ b/e2e/interchaintestv8/e2esuite/setup_ethereum.go @@ -85,6 +85,37 @@ func (s *TestSuite) processEthereumPoSResult(ctx context.Context, chain *chainco s.Eth.Chains = append(s.Eth.Chains, ðChain) } +func (s *TestSuite) setupEthereumBesuQBFT(ctx context.Context, networkID string) (*chainconfig.BesuQBFTChain, error) { + params := chainconfig.DefaultBesuQBFTParams() + params.DockerRPCAlias = "besu-qbft-rpc" + params.InterchainNetworkID = networkID + + chain, err := chainconfig.SpinUpBesuQBFT(ctx, params) + if err != nil { + return nil, err + } + return &chain, nil +} + +func (s *TestSuite) processEthereumBesuQBFTResult(ctx context.Context, chain *chainconfig.BesuQBFTChain) { + if chain == nil { + return + } + + s.T().Cleanup(func() { + cleanupCtx := context.Background() + if s.T().Failed() { + _ = chain.DumpLogs(cleanupCtx) + } + chain.Destroy(cleanupCtx) + }) + + ethChain, err := ethereum.NewEthereum(ctx, chain.RPC, nil, chain.Faucet) + s.Require().NoError(err, "Failed to create Ethereum client") + ethChain.DockerRPC = chain.DockerRPC + s.Eth.Chains = append(s.Eth.Chains, ðChain) +} + // setupAnvilChains detects and sets up any Anvil chains in the slice. func (s *TestSuite) setupAnvilChains(ctx context.Context, chains []ibc.Chain) { faucet, err := crypto.HexToECDSA(testvalues.E2EDeployerPrivateKeyHex) diff --git a/e2e/interchaintestv8/e2esuite/suite.go b/e2e/interchaintestv8/e2esuite/suite.go index 51cd89564..d70bfaf97 100644 --- a/e2e/interchaintestv8/e2esuite/suite.go +++ b/e2e/interchaintestv8/e2esuite/suite.go @@ -16,6 +16,7 @@ import ( "github.com/cosmos/interchaintest/v11/ibc" "github.com/cosmos/interchaintest/v11/testreporter" + "github.com/srdtrk/solidity-ibc-eureka/e2e/v8/chainconfig" "github.com/srdtrk/solidity-ibc-eureka/e2e/v8/ethereum" "github.com/srdtrk/solidity-ibc-eureka/e2e/v8/solana" "github.com/srdtrk/solidity-ibc-eureka/e2e/v8/testvalues" @@ -128,17 +129,26 @@ func (s *TestSuite) setupChainsInParallel( ethPosCh <- ethPosSetupResult{} } + interchainRes := <-interchainCh + s.Require().NoError(interchainRes.err, "Interchain setup failed") + + var ethBesuQBFTChain *chainconfig.BesuQBFTChain + var ethBesuQBFTErr error + if cfg.ethereum.isBesuQBFT() { + ethBesuQBFTChain, ethBesuQBFTErr = s.setupEthereumBesuQBFT(ctx, interchainRes.network) + } + solanaRes := <-solanaCh s.Require().NoError(solanaRes.err, "Solana chain setup failed") s.processSolanaResult(solanaRes.chain) - interchainRes := <-interchainCh - s.Require().NoError(interchainRes.err, "Interchain setup failed") - ethPosRes := <-ethPosCh s.Require().NoError(ethPosRes.err, "Ethereum PoS chain setup failed") s.processEthereumPoSResult(ctx, ethPosRes.chain) + s.Require().NoError(ethBesuQBFTErr, "Ethereum Besu QBFT chain setup failed") + s.processEthereumBesuQBFTResult(ctx, ethBesuQBFTChain) + return interchainRes.chains, interchainRes.dockerClient, interchainRes.network, interchainRes.logger } diff --git a/e2e/interchaintestv8/ethereum/ethereum.go b/e2e/interchaintestv8/ethereum/ethereum.go index 54ff43b83..76e203fde 100644 --- a/e2e/interchaintestv8/ethereum/ethereum.go +++ b/e2e/interchaintestv8/ethereum/ethereum.go @@ -12,6 +12,7 @@ import ( "math/big" "os" "os/exec" + "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" ethcommon "github.com/ethereum/go-ethereum/common" @@ -24,6 +25,8 @@ import ( "github.com/srdtrk/solidity-ibc-eureka/e2e/v8/testvalues" ) +const forgeScriptTimeout = 5 * time.Minute + type Ethereum struct { ChainID *big.Int RPC string @@ -102,15 +105,20 @@ func (e *Ethereum) BroadcastTx(ctx context.Context, userKey *ecdsa.PrivateKey, g } func (e Ethereum) ForgeScript(deployer *ecdsa.PrivateKey, solidityContract string, args ...string) ([]byte, error) { + return e.forgeScript(forgeScriptTimeout, deployer, solidityContract, args...) +} + +func (e Ethereum) forgeScript(timeout time.Duration, deployer *ecdsa.PrivateKey, solidityContract string, args ...string) ([]byte, error) { cmdArgs := []string{ "script", "--rpc-url", e.RPC, "--private-key", hex.EncodeToString(crypto.FromECDSA(deployer)), "--broadcast", "--non-interactive", "-vvvv", solidityContract, } cmdArgs = append(cmdArgs, args...) - cmd := exec.Command( - "forge", cmdArgs..., - ) + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + cmd := exec.CommandContext(ctx, "forge", cmdArgs...) // Tests run from the repository root; forge must run from the Foundry project root // so that foundry.toml and script paths resolve. cmd.Dir = testvalues.SolidityProjectDir @@ -125,23 +133,20 @@ func (e Ethereum) ForgeScript(deployer *ecdsa.PrivateKey, solidityContract strin var stdoutBuf bytes.Buffer - // Create a MultiWriter to write to both os.Stdout and the buffer - multiWriter := io.MultiWriter(os.Stdout, &stdoutBuf) + // Preserve live output while retaining stdout for deploy-result parsing. + stdoutWriter := io.MultiWriter(os.Stdout, &stdoutBuf) - // Set the command's stdout to the MultiWriter - cmd.Stdout = multiWriter + cmd.Stdout = stdoutWriter cmd.Stderr = os.Stderr - // Run the command if err := cmd.Run(); err != nil { - fmt.Println("Error start command", cmd.Args, err) - return nil, err + if ctx.Err() == context.DeadlineExceeded { + return nil, fmt.Errorf("forge script %q timed out after %s: %w", solidityContract, timeout, ctx.Err()) + } + return nil, fmt.Errorf("forge script %q failed: %w", solidityContract, err) } - // Get the output as byte slices - stdoutBytes := stdoutBuf.Bytes() - - return stdoutBytes, nil + return stdoutBuf.Bytes(), nil } func (e Ethereum) CreateUser() (*ecdsa.PrivateKey, error) { diff --git a/e2e/interchaintestv8/ethereum/utils_test.go b/e2e/interchaintestv8/ethereum/utils_test.go index 7e8e1b046..a09d37bb8 100644 --- a/e2e/interchaintestv8/ethereum/utils_test.go +++ b/e2e/interchaintestv8/ethereum/utils_test.go @@ -11,126 +11,12 @@ import ( ) func TestGetEthAddressFromStdout(t *testing.T) { - exampleOutput := `Compiling 72 files with Solc 0.8.25 -Solc 0.8.25 finished in 2.43s -Compiler run successful! -Traces: - [13132696] E2ETestDeploy::run() - ├─ [0] VM::projectRoot() [staticcall] - │ └─ ← [Return] "/Users/gg/Code/solidity-ibc-eureka" - ├─ [0] VM::readFile("/Users/gg/Code/solidity-ibc-eureka/e2e/genesis.json") [staticcall] - │ └─ ← [Return] - ├─ [0] VM::parseJsonBytes("", ".trustedClientState") [staticcall] - │ └─ ← [Return] 0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000012754500000000000000000000000000000000000000000000000000000000001baf800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000673696d642d310000000000000000000000000000000000000000000000000000 - ├─ [0] VM::parseJsonBytes("", ".trustedConsensusState") [staticcall] - │ └─ ← [Return] 0x000000000000000000000000000000000000000000000000000000006708142974c0681a0dbf3e340cedb56abacacec3f01106cd13d1d240e6eb7fc60a34c31250d828ba2c80c290ee3edb5d12ec232dee758f20214af6fbd73a1f636f79d4d7 - ├─ [0] VM::parseJsonBytes32("", ".updateClientVkey") [staticcall] - │ └─ ← [Return] 0x00787fed71dce3ac5685c23cb727f0bbe41c9c40977506f33530f52eabab6c86 - ├─ [0] VM::parseJsonBytes32("", ".membershipVkey") [staticcall] - │ └─ ← [Return] 0x00a8f49c50bcef3ffaef3e8018be59281904d5951d6e20e0a824b9504da18c7f - ├─ [0] VM::parseJsonBytes32("", ".ucAndMembershipVkey") [staticcall] - │ └─ ← [Return] 0x0037bf750186b666717a245012144eb63d1c8675134c9a9c81133535c4f76656 - ├─ [0] VM::envUint("PRIVATE_KEY") [staticcall] - │ └─ ← [Return] - ├─ [0] VM::startBroadcast() - │ └─ ← [Return] - ├─ [2404781] → new SP1Verifier@0x867EBEE8fB04ef90a4161fe21b89420B0aeEF8f2 - │ └─ ← [Return] 12011 bytes of code - ├─ [2442427] → new SP1ICS07Tendermint@0x65cE09e5864dD1f45F4ae50396A307291AaD6631 - │ └─ ← [Return] 11624 bytes of code - ├─ [1171142] → new ICS02Client@0xEBC7C68E032d765e392CFf5B2a11E76C2C43BbbF - │ ├─ emit OwnershipTransferred(previousOwner: 0x0000000000000000000000000000000000000000, newOwner: 0x51A4283eBaeC10B9B764AE8B021BcAA30C0631Ff) - │ └─ ← [Return] 5730 bytes of code - ├─ [2953720] → new ICS26Router@0xfcf4c2FAc206cFABE9C2B68AefE5D0a9fA038501 - │ ├─ emit OwnershipTransferred(previousOwner: 0x0000000000000000000000000000000000000000, newOwner: 0x51A4283eBaeC10B9B764AE8B021BcAA30C0631Ff) - │ └─ ← [Return] 14411 bytes of code - ├─ [3299657] → new ICS20Transfer@0xD6D4C57D09bA13C9535Ee2d6BdB100231d793a22 - │ ├─ emit OwnershipTransferred(previousOwner: 0x0000000000000000000000000000000000000000, newOwner: ICS26Router: [0xfcf4c2FAc206cFABE9C2B68AefE5D0a9fA038501]) - │ └─ ← [Return] 16250 bytes of code - ├─ [531853] → new TestERC20@0x022b667cC0D57836CCb12669ce93Ae1e15d4f8BC - │ └─ ← [Return] 2431 bytes of code - ├─ [28083] ICS26Router::addIBCApp("transfer", ICS20Transfer: [0xD6D4C57D09bA13C9535Ee2d6BdB100231d793a22]) - │ ├─ emit IBCAppAdded(portId: "transfer", app: ICS20Transfer: [0xD6D4C57D09bA13C9535Ee2d6BdB100231d793a22]) - │ └─ ← [Stop] - ├─ [0] VM::stopBroadcast() - │ └─ ← [Return] - ├─ [0] VM::serializeString("", "ics07Tendermint", "0x65ce09e5864dd1f45f4ae50396a307291aad6631") - │ └─ ← [Return] "{\"ics07Tendermint\":\"0x65ce09e5864dd1f45f4ae50396a307291aad6631\"}" - ├─ [0] VM::serializeString("", "ics02Client", "0xebc7c68e032d765e392cff5b2a11e76c2c43bbbf") - │ └─ ← [Return] "{\"ics02Client\":\"0xebc7c68e032d765e392cff5b2a11e76c2c43bbbf\",\"ics07Tendermint\":\"0x65ce09e5864dd1f45f4ae50396a307291aad6631\"}" - ├─ [0] VM::serializeString("", "ics26Router", "0xfcf4c2fac206cfabe9c2b68aefe5d0a9fa038501") - │ └─ ← [Return] "{\"ics02Client\":\"0xebc7c68e032d765e392cff5b2a11e76c2c43bbbf\",\"ics07Tendermint\":\"0x65ce09e5864dd1f45f4ae50396a307291aad6631\",\"ics26Router\":\"0xfcf4c2fac206cfabe9c2b68aefe5d0a9fa038501\"}" - ├─ [0] VM::serializeString("", "ics20Transfer", "0xd6d4c57d09ba13c9535ee2d6bdb100231d793a22") - │ └─ ← [Return] "{\"ics02Client\":\"0xebc7c68e032d765e392cff5b2a11e76c2c43bbbf\",\"ics07Tendermint\":\"0x65ce09e5864dd1f45f4ae50396a307291aad6631\",\"ics20Transfer\":\"0xd6d4c57d09ba13c9535ee2d6bdb100231d793a22\",\"ics26Router\":\"0xfcf4c2fac206cfabe9c2b68aefe5d0a9fa038501\"}" - ├─ [0] VM::serializeString("", "erc20", "0x022b667cc0d57836ccb12669ce93ae1e15d4f8bc") - │ └─ ← [Return] "{\"erc20\":\"0x022b667cc0d57836ccb12669ce93ae1e15d4f8bc\",\"ics02Client\":\"0xebc7c68e032d765e392cff5b2a11e76c2c43bbbf\",\"ics07Tendermint\":\"0x65ce09e5864dd1f45f4ae50396a307291aad6631\",\"ics20Transfer\":\"0xd6d4c57d09ba13c9535ee2d6bdb100231d793a22\",\"ics26Router\":\"0xfcf4c2fac206cfabe9c2b68aefe5d0a9fa038501\"}" - └─ ← [Return] "{\"erc20\":\"0x022b667cc0d57836ccb12669ce93ae1e15d4f8bc\",\"ics02Client\":\"0xebc7c68e032d765e392cff5b2a11e76c2c43bbbf\",\"ics07Tendermint\":\"0x65ce09e5864dd1f45f4ae50396a307291aad6631\",\"ics20Transfer\":\"0xd6d4c57d09ba13c9535ee2d6bdb100231d793a22\",\"ics26Router\":\"0xfcf4c2fac206cfabe9c2b68aefe5d0a9fa038501\"}" + const output = `== Return == +0: string "{\"cosmosIftConstructor\":\"0x0000000000000000000000000000000000000000\",\"erc20\":\"0x851356ae760d987e095750cceb3bc6014560891c\",\"ics20Transfer\":\"0xb7f8bc63bbcad18155201308c8f3540b07f84f5e\",\"ics26Router\":\"0x2279b7a0a67db372996a5fab50d91eaa73d2ebe6\",\"ics27Gmp\":\"0x0dcd1bf9a1b36ce34237eeafef220932846bcd82\",\"ift\":\"0x0b306bf915c4d645ff596e518faf3f9669b97016\",\"solanaIftConstructor\":\"0x0000000000000000000000000000000000000000\",\"verifierGroth16\":\"0x9fe46736679d2d9a65f0992f2272de9f3c7fa6e0\",\"verifierMock\":\"0xcf7ed3acca5a467e9e704c703e8d87f634fb0fc9\",\"verifierPlonk\":\"0xe7f1725e7734ce288f8367e1bb143e90bb3f0512\"}"` - -Script ran successfully. - -== Return == -0: string "{\"erc20\":\"0x022b667cc0d57836ccb12669ce93ae1e15d4f8bc\",\"ics02Client\":\"0xebc7c68e032d765e392cff5b2a11e76c2c43bbbf\",\"ics07Tendermint\":\"0x65ce09e5864dd1f45f4ae50396a307291aad6631\",\"ics20Transfer\":\"0xd6d4c57d09ba13c9535ee2d6bdb100231d793a22\",\"ics26Router\":\"0xfcf4c2fac206cfabe9c2b68aefe5d0a9fa038501\"}" - -## Setting up 1 EVM. -========================== -Simulated On-chain Traces: - - [521379] → new ICS20Lib@0xDcC1FffeC88e1Fa830604047fad1Aa8D957A7DC7 - └─ ← [Return] 2604 bytes of code - - [2404781] → new SP1Verifier@0x867EBEE8fB04ef90a4161fe21b89420B0aeEF8f2 - └─ ← [Return] 12011 bytes of code - - [2442427] → new SP1ICS07Tendermint@0x65cE09e5864dD1f45F4ae50396A307291AaD6631 - └─ ← [Return] 11624 bytes of code - - [1171142] → new ICS02Client@0xEBC7C68E032d765e392CFf5B2a11E76C2C43BbbF - ├─ emit OwnershipTransferred(previousOwner: 0x0000000000000000000000000000000000000000, newOwner: 0x51A4283eBaeC10B9B764AE8B021BcAA30C0631Ff) - └─ ← [Return] 5730 bytes of code - - [2953720] → new ICS26Router@0xfcf4c2FAc206cFABE9C2B68AefE5D0a9fA038501 - ├─ emit OwnershipTransferred(previousOwner: 0x0000000000000000000000000000000000000000, newOwner: 0x51A4283eBaeC10B9B764AE8B021BcAA30C0631Ff) - └─ ← [Return] 14411 bytes of code - - [3299657] → new ICS20Transfer@0xD6D4C57D09bA13C9535Ee2d6BdB100231d793a22 - ├─ emit OwnershipTransferred(previousOwner: 0x0000000000000000000000000000000000000000, newOwner: ICS26Router: [0xfcf4c2FAc206cFABE9C2B68AefE5D0a9fA038501]) - └─ ← [Return] 16250 bytes of code - - [531853] → new TestERC20@0x022b667cC0D57836CCb12669ce93Ae1e15d4f8BC - └─ ← [Return] 2431 bytes of code - - [30083] ICS26Router::addIBCApp("transfer", ICS20Transfer: [0xD6D4C57D09bA13C9535Ee2d6BdB100231d793a22]) - ├─ emit IBCAppAdded(portId: "transfer", app: ICS20Transfer: [0xD6D4C57D09bA13C9535Ee2d6BdB100231d793a22]) - └─ ← [Stop] - - -========================== - -Chain 3151908 - -Estimated gas price: 0.460566435 gwei - -Estimated total gas used for script: 19196301 - -Estimated amount required: 0.008841171916756935 ETH - -========================== - - -========================== - -ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. - -Transactions saved to: /Users/gg/Code/solidity-ibc-eureka/broadcast/E2ETestDeploy.s.sol/3151908/run-latest.json - -Sensitive values saved to: /Users/gg/Code/solidity-ibc-eureka/cache/E2ETestDeploy.s.sol/3151908/run-latest.json -` - - deployedContracts, err := ethereum.GetEthContractsFromDeployOutput(exampleOutput) + deployedContracts, err := ethereum.GetEthContractsFromDeployOutput(output) require.NoError(t, err) - - require.Equal(t, "0xfcf4c2fac206cfabe9c2b68aefe5d0a9fa038501", deployedContracts.Ics26Router) - require.Equal(t, "0xd6d4c57d09ba13c9535ee2d6bdb100231d793a22", deployedContracts.Ics20Transfer) - require.Equal(t, "0x022b667cc0d57836ccb12669ce93ae1e15d4f8bc", deployedContracts.Erc20) + require.Equal(t, "0x2279b7a0a67db372996a5fab50d91eaa73d2ebe6", deployedContracts.Ics26Router) + require.Equal(t, "0xb7f8bc63bbcad18155201308c8f3540b07f84f5e", deployedContracts.Ics20Transfer) + require.Equal(t, "0x851356ae760d987e095750cceb3bc6014560891c", deployedContracts.Erc20) } diff --git a/e2e/interchaintestv8/go.mod b/e2e/interchaintestv8/go.mod index bc4fb87f8..d5a7d2de9 100644 --- a/e2e/interchaintestv8/go.mod +++ b/e2e/interchaintestv8/go.mod @@ -39,6 +39,11 @@ require ( google.golang.org/protobuf v1.36.12 ) +require ( + github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect + github.com/urfave/cli/v2 v2.27.6 // indirect +) + require ( cel.dev/expr v0.25.2 // indirect cloud.google.com/go v0.123.0 // indirect @@ -244,7 +249,7 @@ require ( github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.24 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mholt/archives v0.1.5 // indirect github.com/miekg/dns v1.1.72 // indirect github.com/mikelolasagasti/xz v1.0.1 // indirect @@ -288,6 +293,7 @@ require ( github.com/petermattis/goid v0.0.0-20260330135022-df67b199bc81 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pion/datachannel v1.5.10 // indirect + github.com/pion/dtls/v2 v2.2.12 // indirect github.com/pion/dtls/v3 v3.1.2 // indirect github.com/pion/ice/v4 v4.0.10 // indirect github.com/pion/interceptor v0.1.40 // indirect @@ -299,7 +305,9 @@ require ( github.com/pion/sctp v1.8.39 // indirect github.com/pion/sdp/v3 v3.0.18 // indirect github.com/pion/srtp/v3 v3.0.6 // indirect + github.com/pion/stun/v2 v2.0.0 // indirect github.com/pion/stun/v3 v3.1.2 // indirect + github.com/pion/transport/v2 v2.2.10 // indirect github.com/pion/transport/v3 v3.0.7 // indirect github.com/pion/transport/v4 v4.0.1 // indirect github.com/pion/turn/v4 v4.0.2 // indirect diff --git a/e2e/interchaintestv8/go.sum b/e2e/interchaintestv8/go.sum index 12e1d81af..d58569efa 100644 --- a/e2e/interchaintestv8/go.sum +++ b/e2e/interchaintestv8/go.sum @@ -337,8 +337,9 @@ github.com/cosmos/ledger-cosmos-go v1.0.0 h1:jNKW89nPf0vR0EkjHG8Zz16h6p3zqwYEOxl github.com/cosmos/ledger-cosmos-go v1.0.0/go.mod h1:mGaw2wDOf+Z6SfRJsMGxU9DIrBa4du0MAiPlpPhLAOE= 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.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= +github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/crate-crypto/go-eth-kzg v1.5.0 h1:FYRiJMJG2iv+2Dy3fi14SVGjcPteZ5HAAUe4YWlJygc= github.com/crate-crypto/go-eth-kzg v1.5.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg= @@ -873,8 +874,8 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI= github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mholt/archives v0.1.5 h1:Fh2hl1j7VEhc6DZs2DLMgiBNChUux154a1G+2esNvzQ= github.com/mholt/archives v0.1.5/go.mod h1:3TPMmBLPsgszL+1As5zECTuKwKvIfj6YcwWPpeTAXF4= @@ -1056,6 +1057,7 @@ github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4 github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o= github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= github.com/pion/dtls/v3 v3.1.2 h1:gqEdOUXLtCGW+afsBLO0LtDD8GnuBBjEy6HRtyofZTc= @@ -1064,6 +1066,7 @@ github.com/pion/ice/v4 v4.0.10 h1:P59w1iauC/wPk9PdY8Vjl4fOFL5B+USq1+xbDcN6gT4= github.com/pion/ice/v4 v4.0.10/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw= github.com/pion/interceptor v0.1.40 h1:e0BjnPcGpr2CFQgKhrQisBU7V3GXK6wrfYrGYaU6Jq4= github.com/pion/interceptor v0.1.40/go.mod h1:Z6kqH7M/FYirg3frjGJ21VLSRJGBXB/KqaTIrdqnOic= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= github.com/pion/logging v0.2.4 h1:tTew+7cmQ+Mc1pTBLKH2puKsOvhm32dROumOZ655zB8= github.com/pion/logging v0.2.4/go.mod h1:DffhXTKYdNZU+KtJ5pyQDjvOAh/GsNSyv1lbkFbe3so= github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM= @@ -1080,13 +1083,15 @@ github.com/pion/sdp/v3 v3.0.18 h1:l0bAXazKHpepazVdp+tPYnrsy9dfh7ZbT8DxesH5ZnI= github.com/pion/sdp/v3 v3.0.18/go.mod h1:ZREGo6A9ZygQ9XkqAj5xYCQtQpif0i6Pa81HOiAdqQ8= github.com/pion/srtp/v3 v3.0.6 h1:E2gyj1f5X10sB/qILUGIkL4C2CqK269Xq167PbGCc/4= github.com/pion/srtp/v3 v3.0.6/go.mod h1:BxvziG3v/armJHAaJ87euvkhHqWe9I7iiOy50K2QkhY= -github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0= github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ= github.com/pion/stun/v3 v3.1.2 h1:86IhD8wFn6IDW4b1/0QzoQS+f5PeA8OHHRn8UZW5ErY= github.com/pion/stun/v3 v3.1.2/go.mod h1:H7gDic7nNwlUL05pbs6T1dtaBehh/KjupxfWw3ZI7cA= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= +github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q= github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= +github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0= github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo= github.com/pion/transport/v4 v4.0.1 h1:sdROELU6BZ63Ab7FrOLn13M6YdJLY20wldXW2Cu2k8o= @@ -1267,6 +1272,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ 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/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE= @@ -1311,13 +1317,13 @@ github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oW github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY= github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= -github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= +github.com/urfave/cli/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g= +github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU= github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= @@ -1480,6 +1486,9 @@ golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw= golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1517,6 +1526,7 @@ 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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1559,7 +1569,12 @@ golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE= golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1580,6 +1595,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ 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.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1650,6 +1666,10 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= @@ -1660,6 +1680,10 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0= golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1671,6 +1695,9 @@ golang.org/x/text v0.3.5/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.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1724,6 +1751,7 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q= golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/e2e/interchaintestv8/ibc_eureka_test.go b/e2e/interchaintestv8/ibc_eureka_test.go index 83b8968ac..c4ce49eca 100644 --- a/e2e/interchaintestv8/ibc_eureka_test.go +++ b/e2e/interchaintestv8/ibc_eureka_test.go @@ -184,7 +184,11 @@ func (s *IbcEurekaTestSuite) SetupSuite(ctx context.Context, proofType types.Sup s.solidityFixtureGenerator = types.NewSolidityFixtureGenerator() s.Require().True(s.Run("Deploy IBC contracts", func() { - stdout, err := eth.ForgeScript(s.deployer, testvalues.E2EDeployScriptPath) + var forgeArgs []string + if os.Getenv(testvalues.EnvKeyEthTestnetType) == testvalues.EthTestnetTypeBesuQBFT { + forgeArgs = []string{"--slow"} + } + stdout, err := eth.ForgeScript(s.deployer, testvalues.E2EDeployScriptPath, forgeArgs...) s.Require().NoError(err) s.contractAddresses, err = ethereum.GetEthContractsFromDeployOutput(string(stdout)) diff --git a/e2e/interchaintestv8/proofapi/builder.go b/e2e/interchaintestv8/proofapi/builder.go index dedd4fc4d..5a4c2fbcb 100644 --- a/e2e/interchaintestv8/proofapi/builder.go +++ b/e2e/interchaintestv8/proofapi/builder.go @@ -104,11 +104,12 @@ func (b *ConfigBuilder) EthToCosmosAttested(p EthToCosmosAttestedParams) *Config SrcChain: p.EthChainID, DstChain: p.CosmosChainID, Config: EthToCosmosModuleConfig{ - Ics26Address: p.ICS26Address, - TmRpcUrl: p.TmRPC, - EthRpcUrl: p.EthRPC, - SignerAddress: p.SignerAddress, - Mode: AttestedMode{Config: aggConfig}, + Ics26Address: p.ICS26Address, + TmRpcUrl: p.TmRPC, + EthRpcUrl: p.EthRPC, + EthBeaconApiUrl: "", + SignerAddress: p.SignerAddress, + Mode: AttestedMode{Config: aggConfig}, }, } b.modules = append(b.modules, module) @@ -237,6 +238,39 @@ func (b *ConfigBuilder) EthToEthAttested(p EthToEthAttestedParams) *ConfigBuilde return b } +// ============================================================================= +// Besu → EVM +// ============================================================================= + +// BesuToEthParams contains parameters for besu_to_eth module. +type BesuToEthParams struct { + SrcChainID string + DstChainID string + SrcRPC string + DstRPC string + SrcICS26 string + DstICS26 string + ConsensusType string +} + +// BesuToEth adds a Besu→EVM module. +func (b *ConfigBuilder) BesuToEth(p BesuToEthParams) *ConfigBuilder { + module := ModuleConfig{ + Name: ModuleBesuToEth, + SrcChain: p.SrcChainID, + DstChain: p.DstChainID, + Config: BesuToEthModuleConfig{ + SrcRPCURL: p.SrcRPC, + SrcICS26Address: p.SrcICS26, + DstRPCURL: p.DstRPC, + DstICS26Address: p.DstICS26, + ConsensusType: p.ConsensusType, + }, + } + b.modules = append(b.modules, module) + return b +} + // ============================================================================= // Cosmos → Cosmos // ============================================================================= diff --git a/e2e/interchaintestv8/proofapi/builder_test.go b/e2e/interchaintestv8/proofapi/builder_test.go index bcc1dcfbe..a2ddaeda9 100644 --- a/e2e/interchaintestv8/proofapi/builder_test.go +++ b/e2e/interchaintestv8/proofapi/builder_test.go @@ -7,25 +7,26 @@ import ( "testing" ) -func TestEthToEthBuilderUsesRoutedSourceChain(t *testing.T) { - b := NewConfigBuilder().EthToEthAttested(EthToEthAttestedParams{ - SrcChainID: "eth-a", - DstChainID: "eth-b", - }) - module := b.modules[0] +func TestEVMToEVMBuildersEmitSourceChainOnlyAtRoutingLevel(t *testing.T) { + b := NewConfigBuilder(). + EthToEthAttested(EthToEthAttestedParams{SrcChainID: "eth-a", DstChainID: "eth-b"}). + BesuToEth(BesuToEthParams{SrcChainID: "besu-a", DstChainID: "besu-b"}) + wantSource := map[string]string{ModuleEthToEth: "eth-a", ModuleBesuToEth: "besu-a"} - config, err := json.Marshal(module.Config) - if err != nil { - t.Fatal(err) - } - var fields map[string]any - if err := json.Unmarshal(config, &fields); err != nil { - t.Fatal(err) - } - if _, ok := fields["src_chain_id"]; ok { - t.Error("module config contains obsolete src_chain_id") - } - if module.SrcChain != "eth-a" { - t.Errorf("routing src_chain = %q, want eth-a", module.SrcChain) + for _, module := range b.modules { + config, err := json.Marshal(module.Config) + if err != nil { + t.Fatal(err) + } + var fields map[string]any + if err := json.Unmarshal(config, &fields); err != nil { + t.Fatal(err) + } + if _, ok := fields["src_chain_id"]; ok { + t.Errorf("%s config contains obsolete src_chain_id", module.Name) + } + if module.SrcChain != wantSource[module.Name] { + t.Errorf("%s routing src_chain = %q, want %q", module.Name, module.SrcChain, wantSource[module.Name]) + } } } diff --git a/e2e/interchaintestv8/proofapi/config.go b/e2e/interchaintestv8/proofapi/config.go index fca6c89d0..28dceeca5 100644 --- a/e2e/interchaintestv8/proofapi/config.go +++ b/e2e/interchaintestv8/proofapi/config.go @@ -9,7 +9,6 @@ import ( "math/rand" "net" "os" - "text/template" "time" "github.com/srdtrk/solidity-ibc-eureka/e2e/v8/testvalues" @@ -21,6 +20,7 @@ const ( ModuleEthToCosmos = "eth_to_cosmos" ModuleEthToCosmosCompat = "eth_to_cosmos_compat" ModuleEthToEth = "eth_to_eth" + ModuleBesuToEth = "besu_to_eth" ModuleSolanaToCosmos = "solana_to_cosmos" ModuleCosmosToSolana = "cosmos_to_solana" ModuleEthToSolana = "eth_to_solana" @@ -148,43 +148,19 @@ func NewConfig(modules []ModuleConfig) Config { } } -// GenerateConfig creates a config from the template +// GenerateConfigFile writes the config as JSON. func (c *Config) GenerateConfigFile(filePath string) error { - tmpl, err := template.ParseFiles("e2e/interchaintestv8/proofapi/config.tmpl") - if err != nil { - return err + config := *c + if config.Modules == nil { + config.Modules = []ModuleConfig{} } - f, err := os.Create(filePath) + contents, err := json.MarshalIndent(config, "", " ") if err != nil { return err } - defer f.Close() - - return tmpl.Execute(f, c) -} -// ToJSON converts a ModuleConfig to JSON string - designed for use in templates -func (mc ModuleConfig) ToJSON() string { - jsonBytes, err := json.MarshalIndent(mc, "", " ") - if err != nil { - return fmt.Sprintf("\"Error generating JSON: %s\"", err) - } - return string(jsonBytes) -} - -// ModulesToJSON converts a slice of ModuleConfig to a JSON string -func ModulesToJSON(modules []ModuleConfig) (string, error) { - if len(modules) == 0 { - return "[]", nil - } - - jsonBytes, err := json.MarshalIndent(modules, "", " ") - if err != nil { - return "", fmt.Errorf("failed to marshal modules to JSON: %w", err) - } - - return string(jsonBytes), nil + return os.WriteFile(filePath, append(contents, '\n'), 0o600) } // EthToCosmosModuleConfig represents the configuration for eth_to_cosmos module @@ -254,6 +230,15 @@ type EthToEthModuleConfig struct { Mode TxBuilderMode `json:"mode"` } +// BesuToEthModuleConfig represents the configuration for besu_to_eth module. +type BesuToEthModuleConfig struct { + SrcRPCURL string `json:"src_rpc_url"` + SrcICS26Address string `json:"src_ics26_address"` + DstRPCURL string `json:"dst_rpc_url"` + DstICS26Address string `json:"dst_ics26_address"` + ConsensusType string `json:"consensus_type"` +} + // AttestorConfig represents the attestor configuration section type AttestorConfig struct { AttestorQueryTimeoutMs int `json:"attestor_query_timeout_ms"` diff --git a/e2e/interchaintestv8/proofapi/config.tmpl b/e2e/interchaintestv8/proofapi/config.tmpl deleted file mode 100644 index bf040c03b..000000000 --- a/e2e/interchaintestv8/proofapi/config.tmpl +++ /dev/null @@ -1,18 +0,0 @@ -{ - "modules": [ - {{- range $index, $module := .Modules }} - {{- if $index }},{{ end }} - {{ $module.ToJSON }} - {{- end }} - ], - "server": { - "address": "{{ .Server.Address }}", - "port": {{ .Server.Port }} - }, - "observability": { - "level": "{{ .Observability.Level }}", - "use_otel": {{ .Observability.UseOtel }}, - "service_name": "{{ .Observability.ServiceName }}"{{ if .Observability.OTelEndpoint }}, - "otel_endpoint": "{{ .Observability.OTelEndpoint }}"{{ end }} - } -} diff --git a/e2e/interchaintestv8/proofapi/config_test.go b/e2e/interchaintestv8/proofapi/config_test.go new file mode 100644 index 000000000..7c511a431 --- /dev/null +++ b/e2e/interchaintestv8/proofapi/config_test.go @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: Apache-2.0 + +package proofapi + +import ( + "bytes" + "os" + "path/filepath" + "testing" +) + +func TestGenerateConfigFileEscapesStringsAndWritesEmptyModules(t *testing.T) { + path := filepath.Join(t.TempDir(), "config.json") + config := Config{Server: ServerConfig{Address: "quoted \"address\""}} + + if err := config.GenerateConfigFile(path); err != nil { + t.Fatal(err) + } + contents, err := os.ReadFile(path) + if err != nil { + t.Fatal(err) + } + if !bytes.Contains(contents, []byte(`"modules": []`)) { + t.Errorf("config contains non-empty or null modules: %s", contents) + } + if !bytes.Contains(contents, []byte(`"address": "quoted \"address\""`)) { + t.Errorf("config does not escape address: %s", contents) + } +} diff --git a/e2e/interchaintestv8/testvalues/values.go b/e2e/interchaintestv8/testvalues/values.go index e579d6d12..253d060e9 100644 --- a/e2e/interchaintestv8/testvalues/values.go +++ b/e2e/interchaintestv8/testvalues/values.go @@ -58,6 +58,8 @@ const ( EnvKeyGenerateWasmFixtures = "GENERATE_WASM_FIXTURES" // EnvKeyGenerateTendermintLightClientFixtures Generate fixtures for the tendermint light client tests if set to true. EnvKeyGenerateTendermintLightClientFixtures = "GENERATE_TENDERMINT_LIGHT_CLIENT_FIXTURES" + // EnvKeyGenerateBesuLightClientFixtures Generate fixtures for the Besu light client tests if set to true. + EnvKeyGenerateBesuLightClientFixtures = "GENERATE_BESU_LIGHT_CLIENT_FIXTURES" // The log level for the Rust logger. EnvKeyRustLog = "RUST_LOG" @@ -94,6 +96,9 @@ const ( // EthTestnetTypePoS uses Kurtosis for full PoS infrastructure with beacon chain EthTestnetTypePoS = "pos" + // EthTestnetTypeBesuQBFT uses a real 4-validator Besu QBFT network + EthTestnetTypeBesuQBFT = "besu-qbft" + // EthTestnetType_None disables Ethereum chain setup EthTestnetType_None = "none" @@ -109,7 +114,7 @@ const ( // Attestor light client (for Cosmos verification on Ethereum) CosmosLcTypeAttestor = "attestor" - // EnvKeyEthTestnetType The Ethereum testnet type (anvil|pos). + // EnvKeyEthTestnetType The Ethereum testnet type (anvil|pos|besu-qbft|none). EnvKeyEthTestnetType = "ETH_TESTNET_TYPE" // EnvKeyEthAnvilCount Number of Anvil chains to create (only when ETH_TESTNET_TYPE=anvil). Defaults to 1. EnvKeyEthAnvilCount = "ETH_ANVIL_COUNT" @@ -197,6 +202,10 @@ const ( SolanaLedgerDir = "test-ledger" // TendermintLightClientFixturesDir is the directory where the Tendermint light client fixtures are stored. TendermintLightClientFixturesDir = "packages/tendermint-light-client/fixtures/" + // BesuBFTFixturesDir is the directory where the Besu BFT light client fixtures are stored. + // Relative to the repo root (e2e suites chdir there), and shared with the Foundry suite in + // ibc-solidity/test/besu-bft (which resolves it via vm.projectRoot()). + BesuBFTFixturesDir = "ibc-solidity/test/besu-bft/fixtures" // IbcCommitmentSlotHex is the storage slot in the IBC solidity contract for the IBC commitments. IbcCommitmentSlotHex = ics26router.IbcStoreStorageSlot @@ -229,8 +238,12 @@ const ( ParameterKey_Sp1Verifier = "sp1_verifier" // Zk algorithm parameter key for the proof API's sp1 light client creation. ParameterKey_ZkAlgorithm = "zk_algorithm" - // The role manager address parameter key for the proof API's sp1 light client creation. + // The role manager address parameter key for proof API light client creation. ParameterKey_RoleManager = "role_manager" + // Trusting period parameter key for proof API light client creation. + ParameterKey_TrustingPeriod = "trusting_period" + // Max clock drift parameter key for proof API light client creation. + ParameterKey_MaxClockDrift = "max_clock_drift" // Checksum hex parameter key for the proof API's ethereum light client creation. ParameterKey_ChecksumHex = "checksum_hex" diff --git a/e2e/interchaintestv8/types/besu_fixtures.go b/e2e/interchaintestv8/types/besu_fixtures.go new file mode 100644 index 000000000..2303e7e85 --- /dev/null +++ b/e2e/interchaintestv8/types/besu_fixtures.go @@ -0,0 +1,709 @@ +// SPDX-License-Identifier: Apache-2.0 + +package types + +import ( + "context" + "crypto/ecdsa" + "encoding/hex" + "encoding/json" + "fmt" + "math/big" + "os" + "path/filepath" + "strings" + + ethcommon "github.com/ethereum/go-ethereum/common" + gethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient/gethclient" + "github.com/ethereum/go-ethereum/rlp" + + channeltypesv2 "github.com/cosmos/ibc-go/v11/modules/core/04-channel/v2/types" + ibchostv2 "github.com/cosmos/ibc-go/v11/modules/core/24-host/v2" + + "github.com/cosmos/solidity-ibc-eureka/packages/go-abigen/ics26router" + + "github.com/srdtrk/solidity-ibc-eureka/e2e/v8/ethereum" + "github.com/srdtrk/solidity-ibc-eureka/e2e/v8/testvalues" +) + +type BesuFixtureGenerator struct { + Enabled bool +} + +type GenerateQBFTFixtureParams struct { + SourceChain *ethereum.Ethereum + RouterAddress ethcommon.Address + Packet ics26router.IICS26RouterMsgsPacket + InitialTrustedHeight uint64 + AdjacentUpdateHeight uint64 + NonAdjacentUpdateHeight uint64 + SyntheticSourceHeight uint64 + TrustingPeriod uint64 + MaxClockDrift uint64 +} + +type besuFixture struct { + RouterAddress string `json:"routerAddress"` + InitialTrustedHeight uint64 `json:"initialTrustedHeight"` + InitialTrustedTimestamp uint64 `json:"initialTrustedTimestamp"` + InitialTrustedStorageRoot string `json:"initialTrustedStorageRoot"` + InitialTrustedValidators []string `json:"initialTrustedValidators"` + TrustingPeriod uint64 `json:"trustingPeriod"` + MaxClockDrift uint64 `json:"maxClockDrift"` + AdjacentUpdate besuUpdateFixture `json:"adjacentUpdate"` + NonAdjacentUpdate besuUpdateFixture `json:"nonAdjacentUpdate"` + LowQuorumUpdate besuRejectionUpdateFixture `json:"lowQuorumUpdate"` + ConflictingUpdate besuRejectionUpdateFixture `json:"conflictingUpdate"` + LowOverlapUpdate besuRejectionUpdateFixture `json:"lowOverlapUpdate"` + Membership besuProofFixture `json:"membership"` + NonMembership besuProofFixture `json:"nonMembership"` +} + +type besuUpdateFixture struct { + Height uint64 `json:"height"` + HeaderRlp string `json:"headerRlp"` + TrustedHeight uint64 `json:"trustedHeight"` + AccountProof string `json:"accountProof"` + ExpectedTimestamp uint64 `json:"expectedTimestamp"` + ExpectedStorageRoot string `json:"expectedStorageRoot"` + ExpectedValidators []string `json:"expectedValidators"` +} + +type besuRejectionUpdateFixture struct { + Height uint64 `json:"height"` + HeaderRlp string `json:"headerRlp"` + TrustedHeight uint64 `json:"trustedHeight"` + AccountProof string `json:"accountProof"` +} + +type besuProofFixture struct { + Proof string `json:"proof"` + ProofHeight uint64 `json:"proofHeight"` + Path string `json:"path"` + Value string `json:"value,omitempty"` + ExpectedTimestamp uint64 `json:"expectedTimestamp"` +} + +type liveHeader struct { + Header *gethtypes.Header + HeaderRLP []byte + Validators []ethcommon.Address +} + +type mutableQBFTHeader struct { + items []rlp.RawValue + extraItems []rlp.RawValue +} + +var syntheticLowOverlapValidatorKeys = []string{ + "59c6995e998f97a5a0044966f094538f8e0f1c7f6d0bdf5f4b4a0d5c8fba8f5a", + "5de4111a39c2d6f5f2f1df6b0ad72037d399a8ce28b5c82853453ea50ccaa43d", + "7c852118294c1ec93b7d4c7d4b3f3b2d8f5f1e6d5c4b3a291817161514131211", +} + +func NewBesuFixtureGenerator() *BesuFixtureGenerator { + return &BesuFixtureGenerator{ + Enabled: os.Getenv(testvalues.EnvKeyGenerateBesuLightClientFixtures) == testvalues.EnvValueGenerateFixtures_True, + } +} + +func (g *BesuFixtureGenerator) GenerateAndSaveQBFTFixture(ctx context.Context, params GenerateQBFTFixtureParams) error { + if !g.Enabled { + return nil + } + + fixture, err := generateQBFTFixture(ctx, params) + if err != nil { + return err + } + + fixtureBz, err := json.MarshalIndent(fixture, "", " ") + if err != nil { + return err + } + + fixturePath := filepath.Join(testvalues.BesuBFTFixturesDir, "qbft.json") + // The checked-in fixture is intentionally readable by all test processes. + return os.WriteFile(fixturePath, fixtureBz, 0o644) //nolint:gosec +} + +func generateQBFTFixture(ctx context.Context, params GenerateQBFTFixtureParams) (besuFixture, error) { + if params.SourceChain == nil { + return besuFixture{}, fmt.Errorf("missing source chain") + } + if params.InitialTrustedHeight == 0 { + return besuFixture{}, fmt.Errorf("initial trusted height must be greater than zero") + } + if params.AdjacentUpdateHeight <= params.InitialTrustedHeight || params.AdjacentUpdateHeight-params.InitialTrustedHeight != 1 { + return besuFixture{}, fmt.Errorf("adjacent update height must equal initial trusted height plus one") + } + if params.NonAdjacentUpdateHeight <= params.AdjacentUpdateHeight { + return besuFixture{}, fmt.Errorf("non-adjacent update height must be greater than adjacent update height") + } + if params.SyntheticSourceHeight <= params.NonAdjacentUpdateHeight { + return besuFixture{}, fmt.Errorf("synthetic source height must be greater than non-adjacent update height") + } + + trustedHeader, err := fetchLiveHeader(ctx, params.SourceChain, params.InitialTrustedHeight) + if err != nil { + return besuFixture{}, err + } + nonAdjacentHeader, err := fetchLiveHeader(ctx, params.SourceChain, params.NonAdjacentUpdateHeight) + if err != nil { + return besuFixture{}, err + } + syntheticSourceHeader, err := fetchLiveHeader(ctx, params.SourceChain, params.SyntheticSourceHeight) + if err != nil { + return besuFixture{}, err + } + + validatorKeys, err := loadQBFTValidatorKeys() + if err != nil { + return besuFixture{}, err + } + + trustedProof, _, err := fetchAccountProof(ctx, params.SourceChain, params.RouterAddress, params.InitialTrustedHeight) + if err != nil { + return besuFixture{}, err + } + adjacentUpdate, err := buildLiveUpdateFixture(ctx, params.SourceChain, params.RouterAddress, params.InitialTrustedHeight, params.AdjacentUpdateHeight) + if err != nil { + return besuFixture{}, err + } + nonAdjacentUpdate, err := buildLiveUpdateFixture(ctx, params.SourceChain, params.RouterAddress, params.InitialTrustedHeight, params.NonAdjacentUpdateHeight) + if err != nil { + return besuFixture{}, err + } + lowQuorumUpdate, err := buildLowQuorumFixture(nonAdjacentUpdate, nonAdjacentHeader) + if err != nil { + return besuFixture{}, err + } + conflictingUpdate, err := buildConflictingFixture( + ctx, + params.InitialTrustedHeight, + nonAdjacentUpdate.Height, + syntheticSourceHeader, + validatorKeys, + params.SourceChain, + params.RouterAddress, + ) + if err != nil { + return besuFixture{}, err + } + lowOverlapUpdate, err := buildLowOverlapFixture( + params.InitialTrustedHeight, + nonAdjacentUpdate.Height+1, + syntheticSourceHeader, + validatorKeys, + ) + if err != nil { + return besuFixture{}, err + } + membership, err := buildMembershipFixture(ctx, params.SourceChain, params.RouterAddress, params.Packet, params.NonAdjacentUpdateHeight, nonAdjacentHeader.Header.Time) + if err != nil { + return besuFixture{}, err + } + nonMembership, err := buildNonMembershipFixture(ctx, params.SourceChain, params.RouterAddress, params.Packet, params.NonAdjacentUpdateHeight, nonAdjacentHeader.Header.Time) + if err != nil { + return besuFixture{}, err + } + + return besuFixture{ + RouterAddress: params.RouterAddress.Hex(), + InitialTrustedHeight: params.InitialTrustedHeight, + InitialTrustedTimestamp: trustedHeader.Header.Time, + InitialTrustedStorageRoot: trustedProof.StorageHash.Hex(), + InitialTrustedValidators: addressesToHex(trustedHeader.Validators), + TrustingPeriod: params.TrustingPeriod, + MaxClockDrift: params.MaxClockDrift, + AdjacentUpdate: adjacentUpdate, + NonAdjacentUpdate: nonAdjacentUpdate, + LowQuorumUpdate: lowQuorumUpdate, + ConflictingUpdate: conflictingUpdate, + LowOverlapUpdate: lowOverlapUpdate, + Membership: membership, + NonMembership: nonMembership, + }, nil +} + +func buildLiveUpdateFixture( + ctx context.Context, + chain *ethereum.Ethereum, + routerAddress ethcommon.Address, + trustedHeight uint64, + targetHeight uint64, +) (besuUpdateFixture, error) { + header, err := fetchLiveHeader(ctx, chain, targetHeight) + if err != nil { + return besuUpdateFixture{}, err + } + proof, accountProofRLP, err := fetchAccountProof(ctx, chain, routerAddress, targetHeight) + if err != nil { + return besuUpdateFixture{}, err + } + + return besuUpdateFixture{ + Height: targetHeight, + HeaderRlp: encodeHex(header.HeaderRLP), + TrustedHeight: trustedHeight, + AccountProof: encodeHex(accountProofRLP), + ExpectedTimestamp: header.Header.Time, + ExpectedStorageRoot: proof.StorageHash.Hex(), + ExpectedValidators: addressesToHex(header.Validators), + }, nil +} + +func buildLowQuorumFixture(update besuUpdateFixture, header liveHeader) (besuRejectionUpdateFixture, error) { + mutable, err := decodeMutableQBFTHeader(header.HeaderRLP) + if err != nil { + return besuRejectionUpdateFixture{}, err + } + commitSeals, err := mutable.commitSeals() + if err != nil { + return besuRejectionUpdateFixture{}, err + } + if len(commitSeals) < 2 { + return besuRejectionUpdateFixture{}, fmt.Errorf("expected at least two commit seals, got %d", len(commitSeals)) + } + mutable.setCommitSeals(commitSeals[:2]) + mutatedHeader, err := mutable.encode() + if err != nil { + return besuRejectionUpdateFixture{}, err + } + + return besuRejectionUpdateFixture{ + Height: update.Height, + HeaderRlp: encodeHex(mutatedHeader), + TrustedHeight: update.TrustedHeight, + AccountProof: "0x", + }, nil +} + +func buildConflictingFixture( + ctx context.Context, + trustedHeight uint64, + targetHeight uint64, + baseHeader liveHeader, + validatorKeys map[ethcommon.Address]*ecdsa.PrivateKey, + chain *ethereum.Ethereum, + routerAddress ethcommon.Address, +) (besuRejectionUpdateFixture, error) { + mutable, err := decodeMutableQBFTHeader(baseHeader.HeaderRLP) + if err != nil { + return besuRejectionUpdateFixture{}, err + } + mutable.setHeight(targetHeight) + validators, err := mutable.validators() + if err != nil { + return besuRejectionUpdateFixture{}, err + } + signerKeys, err := signerKeysFor(validators[:3], validatorKeys) + if err != nil { + return besuRejectionUpdateFixture{}, err + } + mutable.setCommitSeals(signQBFTCommitSeals(mutable, signerKeys)) + mutatedHeader, err := mutable.encode() + if err != nil { + return besuRejectionUpdateFixture{}, err + } + + _, accountProofRLP, err := fetchAccountProof(ctx, chain, routerAddress, baseHeader.Header.Number.Uint64()) + if err != nil { + return besuRejectionUpdateFixture{}, err + } + + return besuRejectionUpdateFixture{ + Height: targetHeight, + HeaderRlp: encodeHex(mutatedHeader), + TrustedHeight: trustedHeight, + AccountProof: encodeHex(accountProofRLP), + }, nil +} + +func buildLowOverlapFixture( + trustedHeight uint64, + targetHeight uint64, + baseHeader liveHeader, + validatorKeys map[ethcommon.Address]*ecdsa.PrivateKey, +) (besuRejectionUpdateFixture, error) { + mutable, err := decodeMutableQBFTHeader(baseHeader.HeaderRLP) + if err != nil { + return besuRejectionUpdateFixture{}, err + } + mutable.setHeight(targetHeight) + + baseValidators, err := mutable.validators() + if err != nil { + return besuRejectionUpdateFixture{}, err + } + if len(baseValidators) == 0 { + return besuRejectionUpdateFixture{}, fmt.Errorf("missing base validators") + } + + syntheticKeys, err := loadSyntheticLowOverlapValidatorKeys() + if err != nil { + return besuRejectionUpdateFixture{}, err + } + lowOverlapValidators := []ethcommon.Address{ + baseValidators[0], + crypto.PubkeyToAddress(syntheticKeys[0].PublicKey), + crypto.PubkeyToAddress(syntheticKeys[1].PublicKey), + crypto.PubkeyToAddress(syntheticKeys[2].PublicKey), + } + mutable.setValidators(lowOverlapValidators) + + signerKeys, err := signerKeysFor([]ethcommon.Address{ + lowOverlapValidators[0], + lowOverlapValidators[1], + lowOverlapValidators[2], + }, mergeValidatorKeyMaps(validatorKeys, toKeyMap(syntheticKeys))) + if err != nil { + return besuRejectionUpdateFixture{}, err + } + mutable.setCommitSeals(signQBFTCommitSeals(mutable, signerKeys)) + mutatedHeader, err := mutable.encode() + if err != nil { + return besuRejectionUpdateFixture{}, err + } + + return besuRejectionUpdateFixture{ + Height: targetHeight, + HeaderRlp: encodeHex(mutatedHeader), + TrustedHeight: trustedHeight, + AccountProof: "0x", + }, nil +} + +func buildMembershipFixture( + ctx context.Context, + chain *ethereum.Ethereum, + routerAddress ethcommon.Address, + packet ics26router.IICS26RouterMsgsPacket, + proofHeight uint64, + expectedTimestamp uint64, +) (besuProofFixture, error) { + path := ibchostv2.PacketCommitmentKey(packet.SourceClient, packet.Sequence) + proofRLP, err := fetchStorageProof(ctx, chain, routerAddress, path, proofHeight) + if err != nil { + return besuProofFixture{}, err + } + + return besuProofFixture{ + Proof: encodeHex(proofRLP), + ProofHeight: proofHeight, + Path: encodeHex(path), + Value: encodeHex(packetCommitment(packet)), + ExpectedTimestamp: expectedTimestamp, + }, nil +} + +func buildNonMembershipFixture( + ctx context.Context, + chain *ethereum.Ethereum, + routerAddress ethcommon.Address, + packet ics26router.IICS26RouterMsgsPacket, + proofHeight uint64, + expectedTimestamp uint64, +) (besuProofFixture, error) { + path := ibchostv2.PacketReceiptKey(packet.DestClient, packet.Sequence) + proofRLP, err := fetchStorageProof(ctx, chain, routerAddress, path, proofHeight) + if err != nil { + return besuProofFixture{}, err + } + + return besuProofFixture{ + Proof: encodeHex(proofRLP), + ProofHeight: proofHeight, + Path: encodeHex(path), + ExpectedTimestamp: expectedTimestamp, + }, nil +} + +func fetchLiveHeader(ctx context.Context, chain *ethereum.Ethereum, height uint64) (liveHeader, error) { + header, err := chain.RPCClient.HeaderByNumber(ctx, newUint64(height)) + if err != nil { + return liveHeader{}, fmt.Errorf("fetch header at height %d: %w", height, err) + } + headerRLP, err := rlp.EncodeToBytes(header) + if err != nil { + return liveHeader{}, fmt.Errorf("encode header rlp at height %d: %w", height, err) + } + mutable, err := decodeMutableQBFTHeader(headerRLP) + if err != nil { + return liveHeader{}, fmt.Errorf("decode header at height %d: %w", height, err) + } + validators, err := mutable.validators() + if err != nil { + return liveHeader{}, fmt.Errorf("extract validators at height %d: %w", height, err) + } + + return liveHeader{ + Header: header, + HeaderRLP: headerRLP, + Validators: validators, + }, nil +} + +func fetchAccountProof( + ctx context.Context, + chain *ethereum.Ethereum, + routerAddress ethcommon.Address, + height uint64, +) (*gethclient.AccountResult, []byte, error) { + proof, err := gethclient.New(chain.RPCClient.Client()).GetProof(ctx, routerAddress, nil, newUint64(height)) + if err != nil { + return nil, nil, fmt.Errorf("fetch account proof at height %d: %w", height, err) + } + proofRLP, err := encodeProofNodes(proof.AccountProof) + if err != nil { + return nil, nil, fmt.Errorf("encode account proof at height %d: %w", height, err) + } + return proof, proofRLP, nil +} + +func fetchStorageProof( + ctx context.Context, + chain *ethereum.Ethereum, + routerAddress ethcommon.Address, + path []byte, + height uint64, +) ([]byte, error) { + storageKey := ethereum.GetCommitmentsStorageKey(path) + proof, err := gethclient.New(chain.RPCClient.Client()).GetProof(ctx, routerAddress, []string{storageKey.Hex()}, newUint64(height)) + if err != nil { + return nil, fmt.Errorf("fetch storage proof at height %d: %w", height, err) + } + if len(proof.StorageProof) != 1 { + return nil, fmt.Errorf("expected one storage proof at height %d, got %d", height, len(proof.StorageProof)) + } + proofRLP, err := encodeProofNodes(proof.StorageProof[0].Proof) + if err != nil { + return nil, fmt.Errorf("encode storage proof at height %d: %w", height, err) + } + return proofRLP, nil +} + +func encodeProofNodes(nodes []string) ([]byte, error) { + rawNodes := make([]rlp.RawValue, len(nodes)) + for i, node := range nodes { + rawNodes[i] = ethcommon.FromHex(node) + } + return rlp.EncodeToBytes(rawNodes) +} + +func packetCommitment(packet ics26router.IICS26RouterMsgsPacket) []byte { + payloads := make([]channeltypesv2.Payload, len(packet.Payloads)) + for i, payload := range packet.Payloads { + payloads[i] = channeltypesv2.Payload{ + SourcePort: payload.SourcePort, + DestinationPort: payload.DestPort, + Version: payload.Version, + Encoding: payload.Encoding, + Value: payload.Value, + } + } + return channeltypesv2.CommitPacket(channeltypesv2.Packet{ + Sequence: packet.Sequence, + SourceClient: packet.SourceClient, + DestinationClient: packet.DestClient, + TimeoutTimestamp: packet.TimeoutTimestamp, + Payloads: payloads, + }) +} + +func decodeMutableQBFTHeader(headerRLP []byte) (*mutableQBFTHeader, error) { + var items []rlp.RawValue + if err := rlp.DecodeBytes(headerRLP, &items); err != nil { + return nil, err + } + if len(items) < 15 { + return nil, fmt.Errorf("expected at least 15 header items, got %d", len(items)) + } + var extraData []byte + if err := rlp.DecodeBytes(items[12], &extraData); err != nil { + return nil, err + } + var extraItems []rlp.RawValue + if err := rlp.DecodeBytes(extraData, &extraItems); err != nil { + return nil, err + } + if len(extraItems) != 5 { + return nil, fmt.Errorf("expected 5 extraData items, got %d", len(extraItems)) + } + return &mutableQBFTHeader{items: items, extraItems: extraItems}, nil +} + +func (h *mutableQBFTHeader) encode() ([]byte, error) { + extraData, err := rlp.EncodeToBytes(h.extraItems) + if err != nil { + return nil, err + } + items := cloneRawValues(h.items) + items[12], err = rlp.EncodeToBytes(extraData) + if err != nil { + return nil, err + } + return rlp.EncodeToBytes(items) +} + +func (h *mutableQBFTHeader) validators() ([]ethcommon.Address, error) { + var validators []ethcommon.Address + if err := rlp.DecodeBytes(h.extraItems[1], &validators); err != nil { + return nil, err + } + return validators, nil +} + +func (h *mutableQBFTHeader) commitSeals() ([][]byte, error) { + var seals [][]byte + if err := rlp.DecodeBytes(h.extraItems[4], &seals); err != nil { + return nil, err + } + return seals, nil +} + +func (h *mutableQBFTHeader) setHeight(height uint64) { + h.items[8] = mustRLP(height) +} + +func (h *mutableQBFTHeader) setValidators(validators []ethcommon.Address) { + h.extraItems[1] = mustRLP(validators) +} + +func (h *mutableQBFTHeader) setCommitSeals(seals [][]byte) { + h.extraItems[4] = mustRLP(seals) +} + +func signQBFTCommitSeals(header *mutableQBFTHeader, keys []*ecdsa.PrivateKey) [][]byte { + digest := header.commitSealDigest() + seals := make([][]byte, len(keys)) + for i, key := range keys { + seal, err := crypto.Sign(digest.Bytes(), key) + if err != nil { + panic(err) + } + seals[i] = seal + } + return seals +} + +func (h *mutableQBFTHeader) commitSealDigest() ethcommon.Hash { + signingExtraItems := cloneRawValues(h.extraItems) + signingExtraItems[4] = rlp.RawValue{0xc0} + signingExtraData, err := rlp.EncodeToBytes(signingExtraItems) + if err != nil { + panic(err) + } + + items := cloneRawValues(h.items) + items[12], err = rlp.EncodeToBytes(signingExtraData) + if err != nil { + panic(err) + } + payload, err := rlp.EncodeToBytes(items) + if err != nil { + panic(err) + } + return crypto.Keccak256Hash(payload) +} + +func loadQBFTValidatorKeys() (map[ethcommon.Address]*ecdsa.PrivateKey, error) { + validatorKeyPaths := []string{ + "e2e/interchaintestv8/chainconfig/testdata/besu/qbft/keys/validator1/key", + "e2e/interchaintestv8/chainconfig/testdata/besu/qbft/keys/validator2/key", + "e2e/interchaintestv8/chainconfig/testdata/besu/qbft/keys/validator3/key", + "e2e/interchaintestv8/chainconfig/testdata/besu/qbft/keys/validator4/key", + } + + keys := make(map[ethcommon.Address]*ecdsa.PrivateKey, len(validatorKeyPaths)) + for _, keyPath := range validatorKeyPaths { + keyHex, err := os.ReadFile(keyPath) + if err != nil { + return nil, err + } + key, err := crypto.HexToECDSA(strings.TrimPrefix(strings.TrimSpace(string(keyHex)), "0x")) + if err != nil { + return nil, err + } + keys[crypto.PubkeyToAddress(key.PublicKey)] = key + } + return keys, nil +} + +func loadSyntheticLowOverlapValidatorKeys() ([]*ecdsa.PrivateKey, error) { + keys := make([]*ecdsa.PrivateKey, len(syntheticLowOverlapValidatorKeys)) + for i, keyHex := range syntheticLowOverlapValidatorKeys { + key, err := crypto.HexToECDSA(strings.TrimPrefix(keyHex, "0x")) + if err != nil { + return nil, err + } + keys[i] = key + } + return keys, nil +} + +func signerKeysFor(validators []ethcommon.Address, keyMap map[ethcommon.Address]*ecdsa.PrivateKey) ([]*ecdsa.PrivateKey, error) { + keys := make([]*ecdsa.PrivateKey, len(validators)) + for i, validator := range validators { + key, ok := keyMap[validator] + if !ok { + return nil, fmt.Errorf("missing validator key for %s", validator.Hex()) + } + keys[i] = key + } + return keys, nil +} + +func toKeyMap(keys []*ecdsa.PrivateKey) map[ethcommon.Address]*ecdsa.PrivateKey { + out := make(map[ethcommon.Address]*ecdsa.PrivateKey, len(keys)) + for _, key := range keys { + out[crypto.PubkeyToAddress(key.PublicKey)] = key + } + return out +} + +func mergeValidatorKeyMaps( + primary map[ethcommon.Address]*ecdsa.PrivateKey, + secondary map[ethcommon.Address]*ecdsa.PrivateKey, +) map[ethcommon.Address]*ecdsa.PrivateKey { + out := make(map[ethcommon.Address]*ecdsa.PrivateKey, len(primary)+len(secondary)) + for address, key := range primary { + out[address] = key + } + for address, key := range secondary { + out[address] = key + } + return out +} + +func cloneRawValues(values []rlp.RawValue) []rlp.RawValue { + cloned := make([]rlp.RawValue, len(values)) + copy(cloned, values) + return cloned +} + +func mustRLP(value interface{}) rlp.RawValue { + encoded, err := rlp.EncodeToBytes(value) + if err != nil { + panic(err) + } + return encoded +} + +func addressesToHex(addresses []ethcommon.Address) []string { + encoded := make([]string, len(addresses)) + for i, address := range addresses { + encoded[i] = address.Hex() + } + return encoded +} + +func encodeHex(value []byte) string { + return "0x" + hex.EncodeToString(value) +} + +func newUint64(value uint64) *big.Int { + return new(big.Int).SetUint64(value) +} diff --git a/ibc-solana/AGENTS.md b/ibc-solana/AGENTS.md new file mode 100644 index 000000000..e9e809f7e --- /dev/null +++ b/ibc-solana/AGENTS.md @@ -0,0 +1,20 @@ +# AGENTS.md + +This subtree contains the Anchor-based Solana IBC programs and their ProgramTest integration harness. + +Look here first: +- `ibc-solana/README.md` +- `ibc-solana/Anchor.toml` +- `ibc-solana/Cargo.toml` +- `ibc-solana/integration-tests/README.md` + +Use the smallest relevant validation from the repo root: +- Build and refresh IDLs: `just solana::build-solana-programs` +- Solana unit tests: `just solana::test-solana` +- Anchor tests: `just solana::test-anchor-solana` +- Lint: `just solana::lint-solana` + +Local constraints: +- Prefer the repo `just` recipes over raw `anchor` commands; they auto-detect `anchor-nix` when available. +- If program interfaces or IDLs change, run `just solana::generate-solana-types`; do not hand-edit `packages/go-anchor/` except `packages/go-anchor/ics07_tendermint_patches/`, and do not hand-edit `e2e/interchaintestv8/solana/go-anchor/`. +- Cluster-specific program IDs live in `ibc-solana/Anchor.toml`, and keypairs live under `solana-keypairs//`; keep non-`localnet` keypairs out of git. diff --git a/ibc-solidity/abi/BesuIBFT2LightClient.json b/ibc-solidity/abi/BesuIBFT2LightClient.json new file mode 100644 index 000000000..76318a273 --- /dev/null +++ b/ibc-solidity/abi/BesuIBFT2LightClient.json @@ -0,0 +1,807 @@ +[ + { + "type": "constructor", + "inputs": [ + { + "name": "ibcRouter", + "type": "address", + "internalType": "address" + }, + { + "name": "initialTrustedHeight", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "initialTrustedTimestamp", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "initialTrustedStorageRoot", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "initialTrustedValidators", + "type": "address[]", + "internalType": "address[]" + }, + { + "name": "trustingPeriod", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "maxClockDrift", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "roleManager", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "DEFAULT_ADMIN_ROLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "PROOF_SUBMITTER_ROLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getClientState", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getConsensusState", + "inputs": [ + { + "name": "revisionHeight", + "type": "uint64", + "internalType": "uint64" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getRoleAdmin", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "grantRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "hasRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "misbehaviour", + "inputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "view" + }, + { + "type": "function", + "name": "renounceRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "callerConfirmation", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "interfaceId", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "updateClient", + "inputs": [ + { + "name": "updateMsg", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "uint8", + "internalType": "enum ILightClientMsgs.UpdateResult" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "verifyMembership", + "inputs": [ + { + "name": "msg_", + "type": "tuple", + "internalType": "struct ILightClientMsgs.MsgVerifyMembership", + "components": [ + { + "name": "proof", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "proofHeight", + "type": "tuple", + "internalType": "struct IICS02ClientMsgs.Height", + "components": [ + { + "name": "revisionNumber", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "revisionHeight", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "name": "path", + "type": "bytes[]", + "internalType": "bytes[]" + }, + { + "name": "value", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "verifyNonMembership", + "inputs": [ + { + "name": "msg_", + "type": "tuple", + "internalType": "struct ILightClientMsgs.MsgVerifyNonMembership", + "components": [ + { + "name": "proof", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "proofHeight", + "type": "tuple", + "internalType": "struct IICS02ClientMsgs.Height", + "components": [ + { + "name": "revisionNumber", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "revisionHeight", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "name": "path", + "type": "bytes[]", + "internalType": "bytes[]" + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "RoleAdminChanged", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "previousAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "newAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleGranted", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleRevoked", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AccessControlBadConfirmation", + "inputs": [] + }, + { + "type": "error", + "name": "AccessControlUnauthorizedAccount", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "neededRole", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "AccountNotFound", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ConflictingConsensusState", + "inputs": [ + { + "name": "revisionHeight", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "ConsensusStateExpired", + "inputs": [ + { + "name": "trustedTimestamp", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "currentTimestamp", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "trustingPeriod", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "ConsensusStateNotFound", + "inputs": [ + { + "name": "revisionHeight", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "DuplicateCommitSealSigner", + "inputs": [ + { + "name": "signer", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "DuplicateValidator", + "inputs": [ + { + "name": "validator", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "EmptyValidatorSet", + "inputs": [] + }, + { + "type": "error", + "name": "HeaderFromFuture", + "inputs": [ + { + "name": "currentTimestamp", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "headerTimestamp", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxClockDrift", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InsufficientTrustedValidatorOverlap", + "inputs": [ + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "required", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InsufficientValidatorQuorum", + "inputs": [ + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "required", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidCommitSeal", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidCommitmentValue", + "inputs": [ + { + "name": "expectedValue", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "actualValue", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InvalidDifficulty", + "inputs": [ + { + "name": "actualDifficulty", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidECDSASignatureLength", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidExtraDataFormat", + "inputs": [ + { + "name": "itemsLength", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidHeaderFormat", + "inputs": [ + { + "name": "itemsLength", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidHeaderHeight", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidHeaderTimestamp", + "inputs": [ + { + "name": "actualTimestamp", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidMixHash", + "inputs": [ + { + "name": "actualMixHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InvalidNonce", + "inputs": [ + { + "name": "actualNonce", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "type": "error", + "name": "InvalidOmmersHash", + "inputs": [ + { + "name": "actualOmmersHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InvalidPathLength", + "inputs": [ + { + "name": "expectedLength", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actualLength", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidRevisionNumber", + "inputs": [ + { + "name": "providedRevisionNumber", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "InvalidValidatorAddress", + "inputs": [ + { + "name": "validator", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidValidatorAddressLength", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidValueLength", + "inputs": [ + { + "name": "expectedLength", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actualLength", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidVanityDataLength", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "RLPInvalidEncoding", + "inputs": [] + }, + { + "type": "error", + "name": "TrieProofTraversalError", + "inputs": [ + { + "name": "err", + "type": "uint8", + "internalType": "enum MPTProof.ProofError" + } + ] + }, + { + "type": "error", + "name": "UnsupportedMisbehaviour", + "inputs": [] + }, + { + "type": "error", + "name": "ValueExists", + "inputs": [ + { + "name": "actualValue", + "type": "bytes32", + "internalType": "bytes32" + } + ] + } +] diff --git a/ibc-solidity/abi/BesuQBFTLightClient.json b/ibc-solidity/abi/BesuQBFTLightClient.json new file mode 100644 index 000000000..76318a273 --- /dev/null +++ b/ibc-solidity/abi/BesuQBFTLightClient.json @@ -0,0 +1,807 @@ +[ + { + "type": "constructor", + "inputs": [ + { + "name": "ibcRouter", + "type": "address", + "internalType": "address" + }, + { + "name": "initialTrustedHeight", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "initialTrustedTimestamp", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "initialTrustedStorageRoot", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "initialTrustedValidators", + "type": "address[]", + "internalType": "address[]" + }, + { + "name": "trustingPeriod", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "maxClockDrift", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "roleManager", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "DEFAULT_ADMIN_ROLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "PROOF_SUBMITTER_ROLE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getClientState", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getConsensusState", + "inputs": [ + { + "name": "revisionHeight", + "type": "uint64", + "internalType": "uint64" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getRoleAdmin", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "grantRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "hasRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "misbehaviour", + "inputs": [ + { + "name": "", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "view" + }, + { + "type": "function", + "name": "renounceRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "callerConfirmation", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeRole", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "interfaceId", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "updateClient", + "inputs": [ + { + "name": "updateMsg", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "", + "type": "uint8", + "internalType": "enum ILightClientMsgs.UpdateResult" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "verifyMembership", + "inputs": [ + { + "name": "msg_", + "type": "tuple", + "internalType": "struct ILightClientMsgs.MsgVerifyMembership", + "components": [ + { + "name": "proof", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "proofHeight", + "type": "tuple", + "internalType": "struct IICS02ClientMsgs.Height", + "components": [ + { + "name": "revisionNumber", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "revisionHeight", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "name": "path", + "type": "bytes[]", + "internalType": "bytes[]" + }, + { + "name": "value", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "verifyNonMembership", + "inputs": [ + { + "name": "msg_", + "type": "tuple", + "internalType": "struct ILightClientMsgs.MsgVerifyNonMembership", + "components": [ + { + "name": "proof", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "proofHeight", + "type": "tuple", + "internalType": "struct IICS02ClientMsgs.Height", + "components": [ + { + "name": "revisionNumber", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "revisionHeight", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "name": "path", + "type": "bytes[]", + "internalType": "bytes[]" + } + ] + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "RoleAdminChanged", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "previousAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "newAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleGranted", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleRevoked", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AccessControlBadConfirmation", + "inputs": [] + }, + { + "type": "error", + "name": "AccessControlUnauthorizedAccount", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + }, + { + "name": "neededRole", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "AccountNotFound", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ConflictingConsensusState", + "inputs": [ + { + "name": "revisionHeight", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "ConsensusStateExpired", + "inputs": [ + { + "name": "trustedTimestamp", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "currentTimestamp", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "trustingPeriod", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "ConsensusStateNotFound", + "inputs": [ + { + "name": "revisionHeight", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "DuplicateCommitSealSigner", + "inputs": [ + { + "name": "signer", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "DuplicateValidator", + "inputs": [ + { + "name": "validator", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "EmptyValidatorSet", + "inputs": [] + }, + { + "type": "error", + "name": "HeaderFromFuture", + "inputs": [ + { + "name": "currentTimestamp", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "headerTimestamp", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxClockDrift", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InsufficientTrustedValidatorOverlap", + "inputs": [ + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "required", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InsufficientValidatorQuorum", + "inputs": [ + { + "name": "actual", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "required", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidCommitSeal", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidCommitmentValue", + "inputs": [ + { + "name": "expectedValue", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "actualValue", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InvalidDifficulty", + "inputs": [ + { + "name": "actualDifficulty", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidECDSASignatureLength", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidExtraDataFormat", + "inputs": [ + { + "name": "itemsLength", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidHeaderFormat", + "inputs": [ + { + "name": "itemsLength", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidHeaderHeight", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidHeaderTimestamp", + "inputs": [ + { + "name": "actualTimestamp", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidMixHash", + "inputs": [ + { + "name": "actualMixHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InvalidNonce", + "inputs": [ + { + "name": "actualNonce", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "type": "error", + "name": "InvalidOmmersHash", + "inputs": [ + { + "name": "actualOmmersHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "InvalidPathLength", + "inputs": [ + { + "name": "expectedLength", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actualLength", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidRevisionNumber", + "inputs": [ + { + "name": "providedRevisionNumber", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "InvalidValidatorAddress", + "inputs": [ + { + "name": "validator", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "InvalidValidatorAddressLength", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidValueLength", + "inputs": [ + { + "name": "expectedLength", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "actualLength", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "InvalidVanityDataLength", + "inputs": [ + { + "name": "length", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "RLPInvalidEncoding", + "inputs": [] + }, + { + "type": "error", + "name": "TrieProofTraversalError", + "inputs": [ + { + "name": "err", + "type": "uint8", + "internalType": "enum MPTProof.ProofError" + } + ] + }, + { + "type": "error", + "name": "UnsupportedMisbehaviour", + "inputs": [] + }, + { + "type": "error", + "name": "ValueExists", + "inputs": [ + { + "name": "actualValue", + "type": "bytes32", + "internalType": "bytes32" + } + ] + } +] diff --git a/ibc-solidity/abi/bytecode/AttestationLightClient.json b/ibc-solidity/abi/bytecode/AttestationLightClient.json index 8039a88fc..25ced5389 100644 --- a/ibc-solidity/abi/bytecode/AttestationLightClient.json +++ b/ibc-solidity/abi/bytecode/AttestationLightClient.json @@ -1 +1 @@ -{"abi":[{"type":"constructor","inputs":[{"name":"attestorAddresses","type":"address[]","internalType":"address[]"},{"name":"minRequiredSigs","type":"uint8","internalType":"uint8"},{"name":"initialHeight","type":"uint64","internalType":"uint64"},{"name":"initialTimestampSeconds","type":"uint64","internalType":"uint64"},{"name":"roleManager","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"type":"function","name":"DEFAULT_ADMIN_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"PROOF_SUBMITTER_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"getAttestationSet","inputs":[],"outputs":[{"name":"attestorAddresses","type":"address[]","internalType":"address[]"},{"name":"minRequiredSigs","type":"uint8","internalType":"uint8"}],"stateMutability":"view"},{"type":"function","name":"getClientState","inputs":[],"outputs":[{"name":"","type":"bytes","internalType":"bytes"}],"stateMutability":"view"},{"type":"function","name":"getConsensusTimestamp","inputs":[{"name":"revisionHeight","type":"uint64","internalType":"uint64"}],"outputs":[{"name":"","type":"uint64","internalType":"uint64"}],"stateMutability":"view"},{"type":"function","name":"getRoleAdmin","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"grantRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"hasRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"misbehaviour","inputs":[{"name":"","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"view"},{"type":"function","name":"renounceRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"callerConfirmation","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"revokeRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"supportsInterface","inputs":[{"name":"interfaceId","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"updateClient","inputs":[{"name":"updateMsg","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"","type":"uint8","internalType":"enum ILightClientMsgs.UpdateResult"}],"stateMutability":"nonpayable"},{"type":"function","name":"verifyMembership","inputs":[{"name":"msg_","type":"tuple","internalType":"struct ILightClientMsgs.MsgVerifyMembership","components":[{"name":"proof","type":"bytes","internalType":"bytes"},{"name":"proofHeight","type":"tuple","internalType":"struct IICS02ClientMsgs.Height","components":[{"name":"revisionNumber","type":"uint64","internalType":"uint64"},{"name":"revisionHeight","type":"uint64","internalType":"uint64"}]},{"name":"path","type":"bytes[]","internalType":"bytes[]"},{"name":"value","type":"bytes","internalType":"bytes"}]}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"verifyNonMembership","inputs":[{"name":"msg_","type":"tuple","internalType":"struct ILightClientMsgs.MsgVerifyNonMembership","components":[{"name":"proof","type":"bytes","internalType":"bytes"},{"name":"proofHeight","type":"tuple","internalType":"struct IICS02ClientMsgs.Height","components":[{"name":"revisionNumber","type":"uint64","internalType":"uint64"},{"name":"revisionHeight","type":"uint64","internalType":"uint64"}]},{"name":"path","type":"bytes[]","internalType":"bytes[]"}]}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"event","name":"RoleAdminChanged","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"previousAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"newAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"error","name":"AccessControlBadConfirmation","inputs":[]},{"type":"error","name":"AccessControlUnauthorizedAccount","inputs":[{"name":"account","type":"address","internalType":"address"},{"name":"neededRole","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"BadQuorum","inputs":[{"name":"minRequired","type":"uint8","internalType":"uint8"},{"name":"attestationCount","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"ConsensusTimestampNotFound","inputs":[{"name":"height","type":"uint64","internalType":"uint64"}]},{"type":"error","name":"DuplicateSigner","inputs":[{"name":"signer","type":"address","internalType":"address"}]},{"type":"error","name":"ECDSAInvalidSignature","inputs":[]},{"type":"error","name":"ECDSAInvalidSignatureLength","inputs":[{"name":"length","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"ECDSAInvalidSignatureS","inputs":[{"name":"s","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"EmptyPackets","inputs":[]},{"type":"error","name":"EmptySignatures","inputs":[]},{"type":"error","name":"EmptyValue","inputs":[]},{"type":"error","name":"FeatureNotSupported","inputs":[]},{"type":"error","name":"FrozenClientState","inputs":[]},{"type":"error","name":"HeightMismatch","inputs":[{"name":"expected","type":"uint64","internalType":"uint64"},{"name":"provided","type":"uint64","internalType":"uint64"}]},{"type":"error","name":"InvalidPathLength","inputs":[{"name":"expectedLength","type":"uint256","internalType":"uint256"},{"name":"providedLength","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InvalidSignatureLength","inputs":[{"name":"signature","type":"bytes","internalType":"bytes"}]},{"type":"error","name":"InvalidState","inputs":[{"name":"height","type":"uint64","internalType":"uint64"},{"name":"timestamp","type":"uint64","internalType":"uint64"}]},{"type":"error","name":"NoAttestors","inputs":[]},{"type":"error","name":"NotMember","inputs":[]},{"type":"error","name":"NotNonMember","inputs":[]},{"type":"error","name":"SignatureInvalid","inputs":[{"name":"signature","type":"bytes","internalType":"bytes"}]},{"type":"error","name":"ThresholdNotMet","inputs":[{"name":"validSigners","type":"uint256","internalType":"uint256"},{"name":"minRequired","type":"uint8","internalType":"uint8"}]},{"type":"error","name":"UnknownSigner","inputs":[{"name":"signer","type":"address","internalType":"address"}]}],"bytecode":{"object":"0x60806040523461032d57611f568038038061001981610349565b928339810160a08282031261032d5781516001600160401b03811161032d57820181601f8201121561032d578051916001600160401b0383116102c8578260051b916020610068818501610349565b8095815201906020829482010192831161032d57602001905b8282106103315750505060208301519260ff841680940361032d576100a860408201610382565b6100c060806100b960608501610382565b930161036e565b9284511561031e57851515806102f2575b855190156102dc575060405195608087016001600160401b038111888210176102c857604052858752602087019081526060604088019360018060401b03169788855201915f835286519060018060401b0382116102c8576801000000000000000082116102c85760015482600155808310610284575b5060015f5260205f205f5b838110610267575050505060ff90511669ff00000000000000000060025493610100600160481b03905160081b169251151560481b169260018060501b0319161717176002555f5b83518110156101fb5760018060a01b0360208260051b8601015116805f52600360205260ff60405f2054166101e957906001915f52600360205260405f208260ff198254161790550161019b565b637010e27960e11b5f5260045260245ffd5b505f84815260046020526040902080546001600160401b0319166001600160401b039092169190911790556001600160a01b03811661024e575061023d61048c565b505b6040516119a7908161050f8239f35b8061025b61026192610396565b5061040c565b5061023f565b82516001600160a01b031681830155602090920191600101610153565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf69081019083015b8181106102bd5750610148565b5f81556001016102b0565b634e487b7160e01b5f52604160045260245ffd5b866365846b7f60e01b5f5260045260245260445ffd5b5084515f19870160ff811161030a5760ff16106100d1565b634e487b7160e01b5f52601160045260245ffd5b6343d0a89360e11b5f5260045ffd5b5f80fd5b6020809161033e8461036e565b815201910190610081565b6040519190601f01601f191682016001600160401b038111838210176102c857604052565b51906001600160a01b038216820361032d57565b51906001600160401b038216820361032d57565b6001600160a01b0381165f9081525f516020611f365f395f51905f52602052604090205460ff16610407576001600160a01b03165f8181525f516020611f365f395f51905f5260205260408120805460ff191660011790553391905f516020611eb65f395f51905f528180a4600190565b505f90565b6001600160a01b0381165f9081525f516020611ed65f395f51905f52602052604090205460ff16610407576001600160a01b03165f8181525f516020611ed65f395f51905f5260205260408120805460ff191660011790553391905f516020611f165f395f51905f52905f516020611eb65f395f51905f529080a4600190565b5f80525f516020611ed65f395f51905f526020525f516020611ef65f395f51905f525460ff1661050a575f8080525f516020611ed65f395f51905f526020525f516020611ef65f395f51905f52805460ff1916600117905533905f516020611f165f395f51905f525f516020611eb65f395f51905f528280a4600190565b5f9056fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146106ab575080630bece356146105e8578063248a9ca3146105be5780632f2ff15d1461058f57806336568abe146105335780634d6d9ffb146104865780635832611b146104405780635972185a14610406578063682ed5f01461035157806391d1485414610308578063a217fddf146102ee578063a845a7f314610261578063d547741f1461022b578063ddba65371461015f5763ef913a4b146100c1575f80fd5b3461015b575f60031936011261015b576101576040516020808201526080604082015261014b816100f460c08201611228565b60ff600254818116606085015267ffffffffffffffff8160081c16608085015260481c16151560a0830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0810183528261085e565b604051918291826107cd565b0390f35b5f80fd5b3461015b5761016d36610749565b505060ff60025460481c16610203575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06020527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475460ff16156101f6575b7fda81d7c2000000000000000000000000000000000000000000000000000000005f5260045ffd5b6101fe611277565b6101ce565b7f928b1233000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461015b5761025f61023c3661079a565b9061025a610255825f525f602052600160405f20015490565b6112ff565b61175e565b005b3461015b575f60031936011261015b5760ff6002541660405161028e8161028781611228565b038261085e565b60405190604082019260408352815180945260206060840192015f945b8086106102c057505082935060208301520390f35b909260208060019273ffffffffffffffffffffffffffffffffffffffff8751168152019401950194906102ab565b3461015b575f60031936011261015b5760206040515f8152f35b3461015b576103163661079a565b905f525f60205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060ff60405f2054166040519015158152f35b3461015b57602060031936011261015b5760043567ffffffffffffffff811161015b5760a0600319823603011261015b5760ff60025460481c16610203575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e060209081527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475490916103f19160ff16156103f9575b6004016110cb565b604051908152f35b610401611277565b6103e9565b3461015b575f60031936011261015b5760206040517fbd893629a699470e4ec82a5715bb4981fdaacc5d0a728bf5f55b801d8f4ef10b8152f35b3461015b57602060031936011261015b5760043567ffffffffffffffff811680910361015b575f526004602052602067ffffffffffffffff60405f205416604051908152f35b3461015b57602060031936011261015b5760043567ffffffffffffffff811161015b576080600319823603011261015b5760ff60025460481c16610203575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e060209081527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475490916103f19160ff1615610526575b600401610ef5565b61052e611277565b61051e565b3461015b576105413661079a565b3373ffffffffffffffffffffffffffffffffffffffff8216036105675761025f9161175e565b7f6697b232000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461015b5761025f6105a03661079a565b906105b9610255825f525f602052600160405f20015490565b61168c565b3461015b57602060031936011261015b5760206103f16004355f525f602052600160405f20015490565b3461015b576105f636610749565b60ff60025460481c16610203575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06020527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475461065e929060ff161561069e57610a3c565b6040516003821015610671576020918152f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b6106a6611277565b610a3c565b3461015b57602060031936011261015b57600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361015b57817f7965db0b000000000000000000000000000000000000000000000000000000006020931490811561071f575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483610718565b90602060031983011261015b5760043567ffffffffffffffff811161015b578260238201121561015b5780600401359267ffffffffffffffff841161015b576024848301011161015b576024019190565b600319604091011261015b576004359060243573ffffffffffffffffffffffffffffffffffffffff8116810361015b5790565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602060409481855280519182918282880152018686015e5f8582860101520116010190565b6040810190811067ffffffffffffffff82111761083157604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761083157604052565b92919267ffffffffffffffff821161083157604051916108e760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116018461085e565b82948184528183011161015b578281602093845f960137010152565b9080601f8301121561015b5781602061091e9335910161089f565b90565b67ffffffffffffffff81116108315760051b60200190565b60208183031261015b5780359067ffffffffffffffff821161015b57019060408282031261015b576040519161096e83610815565b803567ffffffffffffffff811161015b578261098b918301610903565b835260208101359067ffffffffffffffff821161015b57019080601f8301121561015b5781356109ba81610921565b926109c8604051948561085e565b81845260208085019260051b8201019183831161015b5760208201905b8382106109f9575050505050602082015290565b813567ffffffffffffffff811161015b57602091610a1c87848094880101610903565b8152019101906109e5565b519067ffffffffffffffff8216820361015b57565b610a4891810190610939565b60205f818351604051918183925191829101835e8101838152039060025afa15610c915760205f8051604051838101917f01000000000000000000000000000000000000000000000000000000000000008352602182015260218152610aaf60418261085e565b604051918291518091835e8101838152039060025afa15610c9157610ada5f516020830151906113eb565b5160408180518101031261015b57604051610af481610815565b610b0f6040610b0560208501610a27565b9384845201610a27565b67ffffffffffffffff60208301938285521680151580610c7e575b15610c4457505067ffffffffffffffff8151165f52600460205267ffffffffffffffff60405f20541680610bf3575067ffffffffffffffff9051918183169260025490838260081c168511610bb6575b50505116905f52600460205260405f20907fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000008254161790555f90565b68ffffffffffffffff007fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ff9160081b169116176002555f80610b7a565b9167ffffffffffffffff9150511603610c0b57600290565b69010000000000000000007fffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff6002541617600255600190565b67ffffffffffffffff92507fdcbc5460000000000000000000000000000000000000000000000000000000005f526004521660245260445ffd5b5067ffffffffffffffff82161515610b2a565b6040513d5f823e3d90fd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561015b570180359067ffffffffffffffff821161015b57602001918160051b3603831361015b57565b3567ffffffffffffffff8116810361015b5790565b15610d0d5750565b67ffffffffffffffff907ff7caaa5c000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561015b570180359067ffffffffffffffff821161015b5760200191813603831361015b57565b60208183031261015b5780519067ffffffffffffffff821161015b57019060408282031261015b5760405191610dc983610815565b610dd281610a27565b835260208101519067ffffffffffffffff821161015b570181601f8201121561015b57805190610e0182610921565b92610e0f604051948561085e565b82845260208085019360061b8301019181831161015b57602001925b828410610e3e5750505050602082015290565b60408483031261015b5760206040918251610e5881610815565b865181528287015183820152815201930192610e2b565b15610e78575050565b9067ffffffffffffffff80927fc7441689000000000000000000000000000000000000000000000000000000005f52166004521660245260445ffd5b8051821015610ec85760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b6060810190610f048282610c9c565b90506001610f128484610c9c565b9290500361109b5750610fb8610f2a60408301610cf0565b9267ffffffffffffffff841692835f526004602052610fb367ffffffffffffffff60405f20541694610f5e87871515610d05565b610f9e610f76610f6e8580610d43565b810190610939565b610f8e610f838251611365565b6020830151906113eb565b5160208082518301019101610d94565b9667ffffffffffffffff885116918214610e6f565b610c9c565b15610ec857610fd3610fcc82602093610d43565b369161089f565b818151910120920180515115611073575f5b8151805182101561104b57610ffb828692610eb4565b51511461100a57600101610fe5565b60209293506110199151610eb4565b5101516110235790565b7f9a960b4f000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f291fc442000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f1e6c84da000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f88b3170e000000000000000000000000000000000000000000000000000000005f52600160045260245260445ffd5b608081016110d98183610d43565b9050156112005760608201906110ef8284610c9c565b905060016110fd8486610c9c565b9290500361109b575061111260408401610cf0565b9061117467ffffffffffffffff831693845f52600460205261116e67ffffffffffffffff60405f2054169561114986881515610d05565b611159610f76610f6e8a80610d43565b9567ffffffffffffffff875116918214610e6f565b85610c9c565b15610ec85760209161118c610fcc8361119894610d43565b83815191012095610d43565b908092918101031261015b576020903591019081515115611073575f5b8251805182101561104b576111cb828792610eb4565b515114806111e8575b6111e0576001016111b5565b505050905090565b508160206111f7838651610eb4565b510151146111d4565b7f1208b21b000000000000000000000000000000000000000000000000000000005f5260045ffd5b602060015491828152019060015f5260205f20905f5b81811061124b5750505090565b825473ffffffffffffffffffffffffffffffffffffffff1684526020909301926001928301920161123e565b335f9081527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e0602052604090205460ff16156112af57565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f52336004527fbd893629a699470e4ec82a5715bb4981fdaacc5d0a728bf5f55b801d8f4ef10b60245260445ffd5b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260ff60405f205416156113365750565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b5f60208092604051918183925191829101835e8101838152039060025afa15610c915760205f8051604051838101917f020000000000000000000000000000000000000000000000000000000000000083526021820152602181526113cb60418261085e565b604051918291518091835e8101838152039060025afa15610c91575f5190565b91909182511561166457825160ff60025416907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82019060ff82116116375760ff8651921610156116095750508251927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061147e61146886610921565b95611476604051978861085e565b808752610921565b013660208601375f5b81518110156116025761149a8183610eb4565b5160418151036115cc5773ffffffffffffffffffffffffffffffffffffffff6114cf6114c68387611826565b90929192611860565b169081156115925750805f52600360205260ff60405f20541615611567575f5b82811061150c5750906001916115058288610eb4565b5201611487565b8173ffffffffffffffffffffffffffffffffffffffff61152c838a610eb4565b51161461153b576001016114ef565b507fe021c4f2000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fd7e8a2c2000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6115c8906040519182917f9e3c1b3d000000000000000000000000000000000000000000000000000000008352600483016107cd565b0390fd5b6115c8906040519182917f2ee17a3d000000000000000000000000000000000000000000000000000000008352600483016107cd565b5050509050565b7f378b0805000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f301b38b6000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f205416155f1461175857805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905573ffffffffffffffffffffffffffffffffffffffff339216907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d5f80a4600190565b50505f90565b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f2054165f1461175857805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815416905573ffffffffffffffffffffffffffffffffffffffff339216907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b5f80a4600190565b81519190604183036118565761184f9250602082015190606060408401519301515f1a9061190b565b9192909190565b50505f9160029190565b60048110156106715780611872575050565b600181036118a2577ff645eedf000000000000000000000000000000000000000000000000000000005f5260045ffd5b600281036118d657507ffce698f7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6003146118e05750565b7fd78bce0c000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841161198f579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15610c91575f5173ffffffffffffffffffffffffffffffffffffffff81161561198557905f905f90565b505f906001905f90565b5050505f916003919056fea164736f6c634300081c000a2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac47bd893629a699470e4ec82a5715bb4981fdaacc5d0a728bf5f55b801d8f4ef10bad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5","sourceMap":"815:11749:29:-:0;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;-1:-1:-1;;;;;815:11749:29;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;815:11749:29;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;:::i;:::-;;;;2648:28;815:11749;;2723:19;;;:69;;;815:11749;;;;;;;-1:-1:-1;815:11749:29;;;;;;-1:-1:-1;;;;;815:11749:29;;;;;;;;;;;;;;2893:217;;815:11749;;;;;2893:217;;815:11749;;;;;;;;;;;2893:217;815:11749;-1:-1:-1;815:11749:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;815:11749:29;;-1:-1:-1;815:11749:29;-1:-1:-1;815:11749:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;3171:3:29;815:11749;;3141:28;;;;;815:11749;;;;;;;;;;;;;;;-1:-1:-1;815:11749:29;3251:11;815:11749;;;;-1:-1:-1;815:11749:29;;;;;;;;-1:-1:-1;815:11749:29;3251:11;815:11749;;;-1:-1:-1;815:11749:29;;;;;;;;;;;3126:13;;815:11749;;;;-1:-1:-1;815:11749:29;;;;-1:-1:-1;815:11749:29;3141:28;-1:-1:-1;;815:11749:29;;;3372:27;815:11749;;;;;;;-1:-1:-1;;;;;;815:11749:29;-1:-1:-1;;;;;815:11749:29;;;;;;;;;-1:-1:-1;;;;;815:11749:29;;;;3496:44;;;:::i;:::-;;3451:249;815:11749;;;;;;;;;3451:249;3587:43;;3644:45;3587:43;;:::i;:::-;;3644:45;:::i;:::-;;3451:249;;815:11749;;;-1:-1:-1;;;;;815:11749:29;;;;;;;;;;;;;;;;-1:-1:-1;815:11749:29;;;;;;;;;;;;;;;;;;-1:-1:-1;815:11749:29;;;;;;;;;;-1:-1:-1;815:11749:29;;;;;-1:-1:-1;815:11749:29;;;;;;-1:-1:-1;815:11749:29;;;;;;-1:-1:-1;815:11749:29;2723:69;-1:-1:-1;815:11749:29;;-1:-1:-1;;815:11749:29;;;;;;;;;-1:-1:-1;2723:69:29;;815:11749;;;;-1:-1:-1;815:11749:29;;;;;-1:-1:-1;815:11749:29;;;;;-1:-1:-1;815:11749:29;;-1:-1:-1;815:11749:29;;-1:-1:-1;815:11749:29;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;;815:11749:29;;;-1:-1:-1;;;;;815:11749:29;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;;;815:11749:29;;;;;;:::o;:::-;;;-1:-1:-1;;;;;815:11749:29;;;;;;:::o;6155:316:84:-;-1:-1:-1;;;;;815:11749:29;;2675:1;815:11749;;;-1:-1:-1;;;;;;;;;;;815:11749:29;;;;;;;;;;-1:-1:-1;;;;;815:11749:29;2675:1;815:11749;;;-1:-1:-1;;;;;;;;;;;815:11749:29;;;;;;;-1:-1:-1;;815:11749:29;;;;;735:10:112;;815:11749:29;-1:-1:-1;;;;;;;;;;;2675:1:29;;6346:40:84;6323:4;6400:11;:::o;6248:217::-;6442:12;2675:1:29;6442:12:84;:::o;6155:316::-;-1:-1:-1;;;;;815:11749:29;;;;;;-1:-1:-1;;;;;;;;;;;815:11749:29;;;;;;;;;;-1:-1:-1;;;;;815:11749:29;;;;;-1:-1:-1;;;;;;;;;;;815:11749:29;;;;;;;-1:-1:-1;;815:11749:29;;;;;735:10:112;;815:11749:29;-1:-1:-1;;;;;;;;;;;1507:33:29;-1:-1:-1;;;;;;;;;;;6346:40:84;815:11749:29;6346:40:84;6323:4;6400:11;:::o;6155:316::-;815:11749:29;;;-1:-1:-1;;;;;;;;;;;815:11749:29;;-1:-1:-1;;;;;;;;;;;815:11749:29;;;;;;;;;-1:-1:-1;;;;;;;;;;;815:11749:29;;-1:-1:-1;;;;;;;;;;;815:11749:29;;-1:-1:-1;;815:11749:29;6323:4:84;815:11749:29;;;735:10:112;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;815:11749:29;;6346:40:84;6323:4;6400:11;:::o;6248:217::-;815:11749:29;6442:12:84;:::o","linkReferences":{}},"deployedBytecode":{"object":"0x6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146106ab575080630bece356146105e8578063248a9ca3146105be5780632f2ff15d1461058f57806336568abe146105335780634d6d9ffb146104865780635832611b146104405780635972185a14610406578063682ed5f01461035157806391d1485414610308578063a217fddf146102ee578063a845a7f314610261578063d547741f1461022b578063ddba65371461015f5763ef913a4b146100c1575f80fd5b3461015b575f60031936011261015b576101576040516020808201526080604082015261014b816100f460c08201611228565b60ff600254818116606085015267ffffffffffffffff8160081c16608085015260481c16151560a0830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0810183528261085e565b604051918291826107cd565b0390f35b5f80fd5b3461015b5761016d36610749565b505060ff60025460481c16610203575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06020527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475460ff16156101f6575b7fda81d7c2000000000000000000000000000000000000000000000000000000005f5260045ffd5b6101fe611277565b6101ce565b7f928b1233000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461015b5761025f61023c3661079a565b9061025a610255825f525f602052600160405f20015490565b6112ff565b61175e565b005b3461015b575f60031936011261015b5760ff6002541660405161028e8161028781611228565b038261085e565b60405190604082019260408352815180945260206060840192015f945b8086106102c057505082935060208301520390f35b909260208060019273ffffffffffffffffffffffffffffffffffffffff8751168152019401950194906102ab565b3461015b575f60031936011261015b5760206040515f8152f35b3461015b576103163661079a565b905f525f60205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060ff60405f2054166040519015158152f35b3461015b57602060031936011261015b5760043567ffffffffffffffff811161015b5760a0600319823603011261015b5760ff60025460481c16610203575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e060209081527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475490916103f19160ff16156103f9575b6004016110cb565b604051908152f35b610401611277565b6103e9565b3461015b575f60031936011261015b5760206040517fbd893629a699470e4ec82a5715bb4981fdaacc5d0a728bf5f55b801d8f4ef10b8152f35b3461015b57602060031936011261015b5760043567ffffffffffffffff811680910361015b575f526004602052602067ffffffffffffffff60405f205416604051908152f35b3461015b57602060031936011261015b5760043567ffffffffffffffff811161015b576080600319823603011261015b5760ff60025460481c16610203575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e060209081527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475490916103f19160ff1615610526575b600401610ef5565b61052e611277565b61051e565b3461015b576105413661079a565b3373ffffffffffffffffffffffffffffffffffffffff8216036105675761025f9161175e565b7f6697b232000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461015b5761025f6105a03661079a565b906105b9610255825f525f602052600160405f20015490565b61168c565b3461015b57602060031936011261015b5760206103f16004355f525f602052600160405f20015490565b3461015b576105f636610749565b60ff60025460481c16610203575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06020527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475461065e929060ff161561069e57610a3c565b6040516003821015610671576020918152f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b6106a6611277565b610a3c565b3461015b57602060031936011261015b57600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361015b57817f7965db0b000000000000000000000000000000000000000000000000000000006020931490811561071f575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483610718565b90602060031983011261015b5760043567ffffffffffffffff811161015b578260238201121561015b5780600401359267ffffffffffffffff841161015b576024848301011161015b576024019190565b600319604091011261015b576004359060243573ffffffffffffffffffffffffffffffffffffffff8116810361015b5790565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602060409481855280519182918282880152018686015e5f8582860101520116010190565b6040810190811067ffffffffffffffff82111761083157604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761083157604052565b92919267ffffffffffffffff821161083157604051916108e760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116018461085e565b82948184528183011161015b578281602093845f960137010152565b9080601f8301121561015b5781602061091e9335910161089f565b90565b67ffffffffffffffff81116108315760051b60200190565b60208183031261015b5780359067ffffffffffffffff821161015b57019060408282031261015b576040519161096e83610815565b803567ffffffffffffffff811161015b578261098b918301610903565b835260208101359067ffffffffffffffff821161015b57019080601f8301121561015b5781356109ba81610921565b926109c8604051948561085e565b81845260208085019260051b8201019183831161015b5760208201905b8382106109f9575050505050602082015290565b813567ffffffffffffffff811161015b57602091610a1c87848094880101610903565b8152019101906109e5565b519067ffffffffffffffff8216820361015b57565b610a4891810190610939565b60205f818351604051918183925191829101835e8101838152039060025afa15610c915760205f8051604051838101917f01000000000000000000000000000000000000000000000000000000000000008352602182015260218152610aaf60418261085e565b604051918291518091835e8101838152039060025afa15610c9157610ada5f516020830151906113eb565b5160408180518101031261015b57604051610af481610815565b610b0f6040610b0560208501610a27565b9384845201610a27565b67ffffffffffffffff60208301938285521680151580610c7e575b15610c4457505067ffffffffffffffff8151165f52600460205267ffffffffffffffff60405f20541680610bf3575067ffffffffffffffff9051918183169260025490838260081c168511610bb6575b50505116905f52600460205260405f20907fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000008254161790555f90565b68ffffffffffffffff007fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ff9160081b169116176002555f80610b7a565b9167ffffffffffffffff9150511603610c0b57600290565b69010000000000000000007fffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff6002541617600255600190565b67ffffffffffffffff92507fdcbc5460000000000000000000000000000000000000000000000000000000005f526004521660245260445ffd5b5067ffffffffffffffff82161515610b2a565b6040513d5f823e3d90fd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561015b570180359067ffffffffffffffff821161015b57602001918160051b3603831361015b57565b3567ffffffffffffffff8116810361015b5790565b15610d0d5750565b67ffffffffffffffff907ff7caaa5c000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561015b570180359067ffffffffffffffff821161015b5760200191813603831361015b57565b60208183031261015b5780519067ffffffffffffffff821161015b57019060408282031261015b5760405191610dc983610815565b610dd281610a27565b835260208101519067ffffffffffffffff821161015b570181601f8201121561015b57805190610e0182610921565b92610e0f604051948561085e565b82845260208085019360061b8301019181831161015b57602001925b828410610e3e5750505050602082015290565b60408483031261015b5760206040918251610e5881610815565b865181528287015183820152815201930192610e2b565b15610e78575050565b9067ffffffffffffffff80927fc7441689000000000000000000000000000000000000000000000000000000005f52166004521660245260445ffd5b8051821015610ec85760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b6060810190610f048282610c9c565b90506001610f128484610c9c565b9290500361109b5750610fb8610f2a60408301610cf0565b9267ffffffffffffffff841692835f526004602052610fb367ffffffffffffffff60405f20541694610f5e87871515610d05565b610f9e610f76610f6e8580610d43565b810190610939565b610f8e610f838251611365565b6020830151906113eb565b5160208082518301019101610d94565b9667ffffffffffffffff885116918214610e6f565b610c9c565b15610ec857610fd3610fcc82602093610d43565b369161089f565b818151910120920180515115611073575f5b8151805182101561104b57610ffb828692610eb4565b51511461100a57600101610fe5565b60209293506110199151610eb4565b5101516110235790565b7f9a960b4f000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f291fc442000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f1e6c84da000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f88b3170e000000000000000000000000000000000000000000000000000000005f52600160045260245260445ffd5b608081016110d98183610d43565b9050156112005760608201906110ef8284610c9c565b905060016110fd8486610c9c565b9290500361109b575061111260408401610cf0565b9061117467ffffffffffffffff831693845f52600460205261116e67ffffffffffffffff60405f2054169561114986881515610d05565b611159610f76610f6e8a80610d43565b9567ffffffffffffffff875116918214610e6f565b85610c9c565b15610ec85760209161118c610fcc8361119894610d43565b83815191012095610d43565b908092918101031261015b576020903591019081515115611073575f5b8251805182101561104b576111cb828792610eb4565b515114806111e8575b6111e0576001016111b5565b505050905090565b508160206111f7838651610eb4565b510151146111d4565b7f1208b21b000000000000000000000000000000000000000000000000000000005f5260045ffd5b602060015491828152019060015f5260205f20905f5b81811061124b5750505090565b825473ffffffffffffffffffffffffffffffffffffffff1684526020909301926001928301920161123e565b335f9081527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e0602052604090205460ff16156112af57565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f52336004527fbd893629a699470e4ec82a5715bb4981fdaacc5d0a728bf5f55b801d8f4ef10b60245260445ffd5b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260ff60405f205416156113365750565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b5f60208092604051918183925191829101835e8101838152039060025afa15610c915760205f8051604051838101917f020000000000000000000000000000000000000000000000000000000000000083526021820152602181526113cb60418261085e565b604051918291518091835e8101838152039060025afa15610c91575f5190565b91909182511561166457825160ff60025416907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82019060ff82116116375760ff8651921610156116095750508251927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061147e61146886610921565b95611476604051978861085e565b808752610921565b013660208601375f5b81518110156116025761149a8183610eb4565b5160418151036115cc5773ffffffffffffffffffffffffffffffffffffffff6114cf6114c68387611826565b90929192611860565b169081156115925750805f52600360205260ff60405f20541615611567575f5b82811061150c5750906001916115058288610eb4565b5201611487565b8173ffffffffffffffffffffffffffffffffffffffff61152c838a610eb4565b51161461153b576001016114ef565b507fe021c4f2000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fd7e8a2c2000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6115c8906040519182917f9e3c1b3d000000000000000000000000000000000000000000000000000000008352600483016107cd565b0390fd5b6115c8906040519182917f2ee17a3d000000000000000000000000000000000000000000000000000000008352600483016107cd565b5050509050565b7f378b0805000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f301b38b6000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f205416155f1461175857805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905573ffffffffffffffffffffffffffffffffffffffff339216907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d5f80a4600190565b50505f90565b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f2054165f1461175857805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815416905573ffffffffffffffffffffffffffffffffffffffff339216907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b5f80a4600190565b81519190604183036118565761184f9250602082015190606060408401519301515f1a9061190b565b9192909190565b50505f9160029190565b60048110156106715780611872575050565b600181036118a2577ff645eedf000000000000000000000000000000000000000000000000000000005f5260045ffd5b600281036118d657507ffce698f7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6003146118e05750565b7fd78bce0c000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841161198f579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15610c91575f5173ffffffffffffffffffffffffffffffffffffffff81161561198557905f905f90565b505f906001905f90565b5050505f916003919056fea164736f6c634300081c000a","sourceMap":"815:11749:29:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;815:11749:29;;;;;;;;3825:23;;;;815:11749;;;;;;3825:23;815:11749;;;;;;:::i;:::-;;;;;;;;;;;;1787:4;;;815:11749;;;;;;;;;;;;;;3825:23;;;;;;;;:::i;:::-;815:11749;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;12225:20;815:11749;;;;;;;;;;;;;;;;12444:42;12440:105;;815:11749;9710:21;815:11749;9710:21;815:11749;;9710:21;12440:105;12513:20;;:::i;:::-;12440:105;;815:11749;;;;;;;;;;;4723:26:84;815:11749:29;;;:::i;:::-;4693:18:84;2484:4;4693:18;;3877:6;815:11749:29;3877:6:84;815:11749:29;;3877:22:84;815:11749:29;3877:6:84;815:11749:29;3877:22:84;815:11749:29;3786:120:84;;4693:18;2484:4;:::i;:::-;4723:26;:::i;:::-;815:11749:29;;;;;;-1:-1:-1;;815:11749:29;;;;;;4065:27;815:11749;;;;;;;;;:::i;:::-;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4034:11;815:11749;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;815:11749:29;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;2930:29:84;815:11749:29;-1:-1:-1;815:11749:29;;;;;;-1:-1:-1;815:11749:29;;;;;;;;;;;;;;;;-1:-1:-1;;815:11749:29;;;;;;;;;;;;;-1:-1:-1;;815:11749:29;;;;;;;;12225:20;815:11749;;;;;;;;;;;;;;;;;;5841:1853;;815:11749;;12444:42;12440:105;;815:11749;;;5841:1853;:::i;:::-;815:11749;;;;;;12440:105;12513:20;;:::i;:::-;12440:105;;815:11749;;;;;-1:-1:-1;;815:11749:29;;;;;;;;1507:33;815:11749;;;;;;;;-1:-1:-1;;815:11749:29;;;;;;;;;;;;;;;;1787:4;815:11749;;1787:4;815:11749;;;;1787:4;;815:11749;;;;;;;;;;;;-1:-1:-1;;815:11749:29;;;;;;;;;;;;;-1:-1:-1;;815:11749:29;;;;;;;;12225:20;815:11749;;;;;;;;;;;;;;;;;;7733:1799;;815:11749;;12444:42;12440:105;;815:11749;;;7733:1799;:::i;12440:105::-;12513:20;;:::i;:::-;12440:105;;815:11749;;;;;;;:::i;:::-;735:10:112;815:11749:29;;;5397:34:84;5393:102;;5505:37;;;:::i;5393:102::-;5454:30;815:11749:29;5454:30:84;815:11749:29;;5454:30:84;815:11749:29;;;;4306:25:84;815:11749:29;;;:::i;:::-;4276:18:84;2484:4;4276:18;;3877:6;815:11749:29;3877:6:84;815:11749:29;;3877:22:84;815:11749:29;3877:6:84;815:11749:29;3877:22:84;815:11749:29;3786:120:84;;2484:4;4306:25;:::i;815:11749:29:-;;;;;-1:-1:-1;;815:11749:29;;;;;;;;;3877:6:84;815:11749:29;3877:6:84;815:11749:29;;3877:22:84;815:11749:29;3877:6:84;815:11749:29;3877:22:84;815:11749:29;3786:120:84;;815:11749:29;;;;;;;:::i;:::-;;12225:20;815:11749;;;;;;;;;;;;;;4341:1461;;815:11749;;;12444:42;12440:105;;4341:1461;:::i;:::-;815:11749;;;;;;;;;;;;;;;;;;;;;;;12440:105;12513:20;;:::i;:::-;4341:1461;:::i;815:11749::-;;;;;-1:-1:-1;;815:11749:29;;;;;;;;;;;;;;;;2649:47:84;2664:32;815:11749:29;2649:47:84;;:87;;;;;815:11749:29;;;;;;;2649:87:84;844:25:124;829:40;;;2649:87:84;;;815:11749:29;;;-1:-1:-1;;815:11749:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;-1:-1:-1;;815:11749:29;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::o;:::-;;-1:-1:-1;815:11749:29;;;;;-1:-1:-1;815:11749:29;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;-1:-1:-1;815:11749:29;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;:::o;:::-;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;1787:4;;815:11749;;;;;;;;1787:4::o;4341:1461::-;4562:58;4341:1461;4562:58;;;;:::i;:::-;815:11749;-1:-1:-1;4668:21:29;;;815:11749;;;;;;;;;;;;;;;;;;10125:12;;;;;;;;815:11749;-1:-1:-1;10125:12:29;;815:11749;;10099:39;;;815:11749;;;;;;;;;10099:39;;;;;;:::i;:::-;815:11749;;;;;;;;;;;;;;;10092:47;;10125:12;10092:47;;;;;4759:16;-1:-1:-1;10092:47:29;815:11749;4759:16;;;;;:::i;:::-;4859:21;815:11749;;;;4848:70;;1787:4;;;;815:11749;;;;;:::i;:::-;1787:4;815:11749;1787:4;815:11749;4848:70;;1787:4;:::i;:::-;;;;;;;:::i;:::-;815:11749;;1787:4;;;;;;815:11749;4937:16;;;:39;;;4341:1461;1787:4;;;;;815:11749;1787:4;;815:11749;-1:-1:-1;1787:4:29;5227:27;815:11749;1787:4;815:11749;;-1:-1:-1;1787:4:29;;815:11749;5282:22;5278:276;;1787:4;815:11749;1787:4;;815:11749;;;;1787:4;10125:12;1787:4;;;;;;815:11749;5568:39;;5564:109;;4341:1461;1787:4;;;815:11749;1787:4;-1:-1:-1;1787:4:29;5227:27;815:11749;1787:4;815:11749;-1:-1:-1;1787:4:29;;;;;;;;;-1:-1:-1;4341:1461:29;:::o;5564:109::-;1787:4;;;;;;;;;10125:12;1787:4;5564:109;;;;5278:276;1787:4;815:11749;1787:4;;;815:11749;5324:36;5320:169;;10125:12;5502:41;:::o;5320:169::-;1787:4;;10125:12;1787:4;;;10125:12;1787:4;;5425:49;:::o;1787:4::-;815:11749;1787:4;;;-1:-1:-1;1787:4:29;;815:11749;;1787:4;815:11749;1787:4;-1:-1:-1;1787:4:29;4937:39;815:11749;;;;4957:19;;4937:39;;10092:47;815:11749;;;-1:-1:-1;815:11749:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;1910:4::-;;;;;;;;;;;;;;;;;;;;;;;;;;815:11749;;;;;:::i;:::-;1787:4;;;:::i;:::-;1910;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;815:11749;;1910:4;815:11749;;;;:::i;:::-;1910:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;815:11749;;;;;;:::i;:::-;1910:4;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;815:11749;1910:4;;;;;815:11749;1910:4;815:11749;;1787:4;815:11749;1787:4;1910;;;815:11749;;1910:4;;;;;;;;;;;;:::o;:::-;;;;;;;;;;7733:1799;7940:9;;;;;;;;:::i;:::-;7984;;7960:1;7984:9;;;;:::i;:::-;7940:21;;;;815:11749;;8104:31;9118:9;8104:31;;;;;:::i;:::-;815:11749;;;;1787:4;;-1:-1:-1;1787:4:29;8157:27;8104:16;1787:4;8893:103;815:11749;8104:31;-1:-1:-1;1787:4:29;;815:11749;8215:7;8207:57;8215:7;;;;8207:57;:::i;:::-;8739:71;8324:59;8335:10;;;;:::i;:::-;8324:59;;;;:::i;:::-;8522:16;8410:67;8430:21;;8410:67;:::i;:::-;8104:16;8522;;;;;:::i;:::-;8750:21;8104:16;815:11749;;;8739:71;;;;;;:::i;:::-;1787:4;815:11749;1787:4;;815:11749;8901:39;;;8893:103;:::i;:::-;9118:9;:::i;:::-;1910:4;;;;;;8104:16;1910:4;;:::i;:::-;;;;:::i;:::-;815:11749;;;;;9108:23;9149:25;;;;815:11749;9149:36;1910:4;;-1:-1:-1;9270:3:29;9236:25;;815:11749;;9232:36;;;;;9293:28;;;;;:::i;:::-;;1910:4;9293:45;9289:198;;7960:1;1910:4;9217:13;;9289:198;8104:16;9366:25;;;:28;:25;;:28;:::i;:::-;;:39;1910:4;;;9454:18;:::o;1910:4::-;;-1:-1:-1;1910:4:29;8157:27;-1:-1:-1;1910:4:29;9232:36;9514:11;-1:-1:-1;9514:11:29;8157:27;-1:-1:-1;9514:11:29;1910:4;;-1:-1:-1;1910:4:29;8157:27;-1:-1:-1;1910:4:29;815:11749;;;;7960:1;815:11749;;;;;;;5841:1853;6042:10;;;;;;;:::i;:::-;:22;;;815:11749;;6097:9;;;;;;;;:::i;:::-;6141;;6117:1;6141:9;;;;:::i;:::-;6097:21;;;;815:11749;;6261:31;;;;;;:::i;:::-;815:11749;7265:9;815:11749;;;1787:4;;6063:1;1787:4;6314:27;6261:16;1787:4;7050:103;815:11749;6261:31;6063:1;1787:4;;815:11749;6372:7;6364:57;6372:7;;;;6364:57;:::i;:::-;6896:71;6481:59;6492:10;;;;:::i;6896:71::-;1787:4;815:11749;1787:4;;815:11749;7058:39;;;7050:103;:::i;:::-;7265:9;;:::i;:::-;1910:4;;;6261:16;1910:4;;;;7315:10;1910:4;;:::i;:::-;815:11749;;;;;7255:23;7315:10;;:::i;:::-;7304:33;;;;;;815:11749;;;;6261:16;815:11749;;7355:25;;;;;815:11749;7355:36;1910:4;;6063:1;7476:3;7442:25;;815:11749;;7438:36;;;;;7499:28;;;;;:::i;:::-;;1910:4;7499:45;:97;;;7476:3;7495:154;;6117:1;1910:4;7423:13;;7495:154;7616:18;;;;;;:::o;7499:97::-;7548:25;;6261:16;7548:28;:25;;;:28;:::i;:::-;;:39;1910:4;7548:48;7499:97;;815:11749;;6063:1;815:11749;;6063:1;815:11749;;;4034:11;815:11749;;;;;;;4034:11;-1:-1:-1;815:11749:29;;-1:-1:-1;815:11749:29;;-1:-1:-1;815:11749:29;;;;;;;;;;:::o;:::-;;;;;;;;;;;;4034:11;815:11749;;;;;;;3175:103:84;735:10:112;2930:6:84;815:11749:29;;;;;;;;;;;;3495:23:84;3491:108;;3175:103::o;3491:108::-;3541:47;2930:6;3541:47;735:10:112;3541:47:84;815:11749:29;1507:33;815:11749;;;2930:6:84;3541:47;3175:103;815:11749:29;2930:6:84;815:11749:29;2930:6:84;815:11749:29;;;2930:6:84;815:11749:29;;735:10:112;815:11749:29;-1:-1:-1;815:11749:29;;;;;-1:-1:-1;815:11749:29;;;3495:23:84;3491:108;;3175:103;:::o;3491:108::-;3541:47;2930:6;3541:47;735:10:112;3541:47:84;815:11749:29;;;;2930:6:84;3541:47;9980:166:29;-1:-1:-1;815:11749:29;9980:166;;815:11749;;;;;;;;;;;;;;;;;;10125:12;;;;;;;;815:11749;-1:-1:-1;10125:12:29;;815:11749;;10099:39;;;815:11749;;;;;;;;;10099:39;;;;;;:::i;:::-;815:11749;;;;;;;;;;;;;;;10092:47;;10125:12;10092:47;;;;;-1:-1:-1;10092:47:29;9980:166;:::o;10562:773::-;;;;815:11749;;10672:21;815:11749;;;;;10765:27;815:11749;;;;;;;;;;;;;;;;;-1:-1:-1;815:11749:29;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;10692:1;11003:3;815:11749;;10980:21;;;;;11041:13;;;;:::i;:::-;;1660:2;815:11749;;11811:42;1660:2;;815:11749;5503:8:122;5447:27;;;;:::i;:::-;5503:8;;;;;:::i;:::-;815:11749:29;11970:23;;;1660:2;;815:11749;;10692:1;815:11749;12041:11;815:11749;;;;10692:1;815:11749;;;1660:2;;;10692:1;11184:5;;;;;;11299:19;;10765:11;11299:19;;;;;:::i;:::-;815:11749;1910:4;10965:13;;11191:3;11222:7;815:11749;11222:7;;;;:::i;:::-;815:11749;;11222:20;815:11749;;10765:11;1910:4;11169:13;;815:11749;;;10692:1;815:11749;;;;10692:1;815:11749;1660:2;;10692:1;1660:2;;815:11749;;10692:1;1660:2;;;815:11749;;;1660:2;;;;;;;;;;:::i;:::-;;;;;;815:11749;;;1660:2;;;;;;;;;;:::i;10980:21::-;;;;;;10562:773::o;815:11749::-;;10692:1;815:11749;;;;;;10692:1;815:11749;;;10692:1;815:11749;;;;;10692:1;815:11749;;;10692:1;815:11749;;10692:1;815:11749;6155:316:84;815:11749:29;;;;;;;;;;;;-1:-1:-1;815:11749:29;;;;;-1:-1:-1;815:11749:29;;;6252:23:84;6248:217;815:11749:29;;;;;;;;;;;;;;;-1:-1:-1;815:11749:29;;;;-1:-1:-1;815:11749:29;6323:4:84;815:11749:29;;;;;;;;735:10:112;815:11749:29;;6346:40:84;;815:11749:29;6346:40:84;;6323:4;6400:11;:::o;6248:217::-;6442:12;;815:11749:29;6442:12:84;:::o;6708:317::-;815:11749:29;;;;;;;;;;;;-1:-1:-1;815:11749:29;;;;;-1:-1:-1;815:11749:29;;;6802:217:84;815:11749:29;;;;;;;;;;;;;;;-1:-1:-1;815:11749:29;;;;-1:-1:-1;815:11749:29;;;;;;;;735:10:112;815:11749:29;;6900:40:84;;815:11749:29;6900:40:84;;815:11749:29;6954:11:84;:::o;2433:778:122:-;815:11749:29;;;2433:778:122;2623:2;2603:22;;2623:2;;3055:25;2839:196;;;;;;;;;;;;;;;-1:-1:-1;2839:196:122;3055:25;;:::i;:::-;3048:32;;;;;:::o;2599:606::-;3111:83;;3127:1;3111:83;3131:35;3111:83;;:::o;11630:532::-;815:11749:29;;;;;;11716:29:122;;;11761:7;;:::o;11712:444::-;815:11749:29;11812:38:122;;815:11749:29;;11873:23:122;11725:20;11873:23;815:11749:29;11725:20:122;11873:23;11808:348;11926:35;11917:44;;11926:35;;11984:46;;11725:20;11984:46;815:11749:29;;;11725:20:122;11984:46;11913:243;12060:30;12051:39;12047:109;;11913:243;11630:532::o;12047:109::-;12113:32;11725:20;12113:32;815:11749:29;;;11725:20:122;12113:32;7142:1551;;;8222:66;8209:79;;8205:164;;815:11749:29;;;;;;-1:-1:-1;815:11749:29;;;;;;;;;;;;;;;;;;;8480:24:122;;;;;;;;;-1:-1:-1;8480:24:122;815:11749:29;;;8518:20:122;8514:113;;8637:49;-1:-1:-1;8637:49:122;-1:-1:-1;7142:1551:122;:::o;8514:113::-;8554:62;-1:-1:-1;8554:62:122;8480:24;8554:62;-1:-1:-1;8554:62:122;:::o;8205:164::-;8304:54;;;8320:1;8304:54;8324:30;8304:54;;:::o","linkReferences":{}},"methodIdentifiers":{"DEFAULT_ADMIN_ROLE()":"a217fddf","PROOF_SUBMITTER_ROLE()":"5972185a","getAttestationSet()":"a845a7f3","getClientState()":"ef913a4b","getConsensusTimestamp(uint64)":"5832611b","getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","misbehaviour(bytes)":"ddba6537","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7","updateClient(bytes)":"0bece356","verifyMembership((bytes,(uint64,uint64),bytes[],bytes))":"682ed5f0","verifyNonMembership((bytes,(uint64,uint64),bytes[]))":"4d6d9ffb"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.28+commit.7893614a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"attestorAddresses\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"minRequiredSigs\",\"type\":\"uint8\"},{\"internalType\":\"uint64\",\"name\":\"initialHeight\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"initialTimestampSeconds\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"roleManager\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"minRequired\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"attestationCount\",\"type\":\"uint256\"}],\"name\":\"BadQuorum\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"height\",\"type\":\"uint64\"}],\"name\":\"ConsensusTimestampNotFound\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"signer\",\"type\":\"address\"}],\"name\":\"DuplicateSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ECDSAInvalidSignature\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"length\",\"type\":\"uint256\"}],\"name\":\"ECDSAInvalidSignatureLength\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"ECDSAInvalidSignatureS\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyPackets\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptySignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FeatureNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FrozenClientState\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"expected\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"provided\",\"type\":\"uint64\"}],\"name\":\"HeightMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expectedLength\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"providedLength\",\"type\":\"uint256\"}],\"name\":\"InvalidPathLength\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"InvalidSignatureLength\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"height\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"timestamp\",\"type\":\"uint64\"}],\"name\":\"InvalidState\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoAttestors\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotMember\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotNonMember\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"SignatureInvalid\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"validSigners\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"minRequired\",\"type\":\"uint8\"}],\"name\":\"ThresholdNotMet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"signer\",\"type\":\"address\"}],\"name\":\"UnknownSigner\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PROOF_SUBMITTER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAttestationSet\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"attestorAddresses\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"minRequiredSigs\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getClientState\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"revisionHeight\",\"type\":\"uint64\"}],\"name\":\"getConsensusTimestamp\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"misbehaviour\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"updateMsg\",\"type\":\"bytes\"}],\"name\":\"updateClient\",\"outputs\":[{\"internalType\":\"enum ILightClientMsgs.UpdateResult\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"proof\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"revisionNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"revisionHeight\",\"type\":\"uint64\"}],\"internalType\":\"struct IICS02ClientMsgs.Height\",\"name\":\"proofHeight\",\"type\":\"tuple\"},{\"internalType\":\"bytes[]\",\"name\":\"path\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"value\",\"type\":\"bytes\"}],\"internalType\":\"struct ILightClientMsgs.MsgVerifyMembership\",\"name\":\"msg_\",\"type\":\"tuple\"}],\"name\":\"verifyMembership\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"proof\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"revisionNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"revisionHeight\",\"type\":\"uint64\"}],\"internalType\":\"struct IICS02ClientMsgs.Height\",\"name\":\"proofHeight\",\"type\":\"tuple\"},{\"internalType\":\"bytes[]\",\"name\":\"path\",\"type\":\"bytes[]\"}],\"internalType\":\"struct ILightClientMsgs.MsgVerifyNonMembership\",\"name\":\"msg_\",\"type\":\"tuple\"}],\"name\":\"verifyNonMembership\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"BadQuorum(uint8,uint256)\":[{\"params\":{\"attestationCount\":\"The size of the configured attestation set.\",\"minRequired\":\"The provided minimum required signatures.\"}}],\"ConsensusTimestampNotFound(uint64)\":[{\"params\":{\"height\":\"The height that has no associated timestamp.\"}}],\"DuplicateSigner(address)\":[{\"params\":{\"signer\":\"Address of the duplicate signer.\"}}],\"ECDSAInvalidSignature()\":[{\"details\":\"The signature derives the `address(0)`.\"}],\"ECDSAInvalidSignatureLength(uint256)\":[{\"details\":\"The signature has an invalid length.\"}],\"ECDSAInvalidSignatureS(bytes32)\":[{\"details\":\"The signature has an S value that is in the upper half order.\"}],\"HeightMismatch(uint64,uint64)\":[{\"params\":{\"expected\":\"The expected height from the proofHeight field.\",\"provided\":\"The height that was present in the attested payload.\"}}],\"InvalidPathLength(uint256,uint256)\":[{\"params\":{\"expectedLength\":\"The expected length of the path.\",\"providedLength\":\"The length of the provided path.\"}}],\"InvalidSignatureLength(bytes)\":[{\"params\":{\"signature\":\"The invalid signature.\"}}],\"InvalidState(uint64,uint64)\":[{\"params\":{\"height\":\"The height of the attested state.\",\"timestamp\":\"The timestamp of the attested state.\"}}],\"SignatureInvalid(bytes)\":[{\"params\":{\"signature\":\"The invalid signature.\"}}],\"ThresholdNotMet(uint256,uint8)\":[{\"params\":{\"minRequired\":\"The minimum required signatures.\",\"validSigners\":\"Number of valid, unique attestation signatures.\"}}],\"UnknownSigner(address)\":[{\"params\":{\"signer\":\"Address of the unknown signer.\"}}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted to signal this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call. This account bears the admin role (for the granted role). Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"attestorAddresses\":\"The configured attestor addresses (EOAs)\",\"initialHeight\":\"The initial known height\",\"initialTimestampSeconds\":\"The initial timestamp in seconds for the initial height\",\"minRequiredSigs\":\"The quorum threshold\",\"roleManager\":\"Address that will administer roles and be allowed to submit proofs; if zero, anyone can submit\"}},\"getAttestationSet()\":{\"details\":\"The attestation set is fixed for the initial scope; rotation is out of scope.\",\"returns\":{\"attestorAddresses\":\"The configured attestor EOA addresses\",\"minRequiredSigs\":\"The minimum number of unique valid signatures required\"}},\"getClientState()\":{\"returns\":{\"_0\":\"The client state.\"}},\"getConsensusTimestamp(uint64)\":{\"params\":{\"revisionHeight\":\"The height for which to query the timestamp\"},\"returns\":{\"_0\":\"The trusted timestamp in unix seconds\"}},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"misbehaviour(bytes)\":{\"params\":{\"misbehaviourMsg\":\"The misbehaviour message\"}},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] to learn more about how these ids are created. This function call must use less than 30 000 gas.\"},\"updateClient(bytes)\":{\"params\":{\"updateMsg\":\"The encoded update message e.g., an SP1 proof.\"},\"returns\":{\"_0\":\"The result of the update operation\"}},\"verifyMembership((bytes,(uint64,uint64),bytes[],bytes))\":{\"details\":\"Notice that this message is not view, as it may update the client state for caching purposes.\",\"params\":{\"msg_\":\"The membership message\"},\"returns\":{\"_0\":\"The unix timestamp of the verification height in the counterparty chain in seconds.\"}},\"verifyNonMembership((bytes,(uint64,uint64),bytes[]))\":{\"details\":\"Notice that this message is not view, as it may update the client state for caching purposes.\",\"params\":{\"msg_\":\"The membership message\"},\"returns\":{\"_0\":\"The unix timestamp of the verification height in the counterparty chain in seconds.\"}}},\"stateVariables\":{\"PROOF_SUBMITTER_ROLE\":{\"details\":\"If `address(0)` has this role, then anyone can submit proofs. If this client is used with `ICS26Router`, the router must be granted this role.\",\"return\":\"The role identifier\",\"returns\":{\"_0\":\"The role identifier\"}}},\"title\":\"Attestation-based IBC Light Client\",\"version\":1},\"userdoc\":{\"errors\":{\"BadQuorum(uint8,uint256)\":[{\"notice\":\"Reverts when the quorum threshold is zero or exceeds the attestation count.\"}],\"ConsensusTimestampNotFound(uint64)\":[{\"notice\":\"Missing trusted timestamp for the given height.\"}],\"DuplicateSigner(address)\":[{\"notice\":\"The recovered signer appears more than once among the signatures.\"}],\"EmptyPackets()\":[{\"notice\":\"The provided packet attestations were empty.\"}],\"EmptySignatures()\":[{\"notice\":\"The provided signatures were empty.\"}],\"EmptyValue()\":[{\"notice\":\"The provided membership value was empty.\"}],\"FeatureNotSupported()\":[{\"notice\":\"Reverts for functions that are out of scope for this implementation.\"}],\"FrozenClientState()\":[{\"notice\":\"Reverts when an action is attempted on a frozen client state.\"}],\"HeightMismatch(uint64,uint64)\":[{\"notice\":\"The attested height did not match the provided proof height.\"}],\"InvalidPathLength(uint256,uint256)\":[{\"notice\":\"The provided proof path length is invalid.\"}],\"InvalidSignatureLength(bytes)\":[{\"notice\":\"ECDSA signature has an invalid length.\"}],\"InvalidState(uint64,uint64)\":[{\"notice\":\"The attested state is invalid.\"}],\"NoAttestors()\":[{\"notice\":\"Reverts when the attestation set is empty during initialization.\"}],\"NotMember()\":[{\"notice\":\"The provided value is not a member of the attested set.\"}],\"NotNonMember()\":[{\"notice\":\"The attested commitment is not zero (receipt exists, so packet was received).\"}],\"SignatureInvalid(bytes)\":[{\"notice\":\"ECDSA signature failed to recover a valid signer.\"}],\"ThresholdNotMet(uint256,uint8)\":[{\"notice\":\"The number of valid unique signatures is below the required threshold.\"}],\"UnknownSigner(address)\":[{\"notice\":\"The recovered signer is not part of the attestation set.\"}]},\"kind\":\"user\",\"methods\":{\"PROOF_SUBMITTER_ROLE()\":{\"notice\":\"The role identifier for the proof submitter role\"},\"constructor\":{\"notice\":\"Initializes the attestor light client with its fixed attestor set and initial height/timestamp.\"},\"getAttestationSet()\":{\"notice\":\"Returns the attestation set configuration.\"},\"getClientState()\":{\"notice\":\"Returns the client state.\"},\"getConsensusTimestamp(uint64)\":{\"notice\":\"Returns the trusted consensus timestamp (in seconds) at the given revision height.\"},\"misbehaviour(bytes)\":{\"notice\":\"Misbehaviour handling, moves the light client to the frozen state if misbehaviour is detected\"},\"updateClient(bytes)\":{\"notice\":\"Updating the client and consensus state\"},\"verifyMembership((bytes,(uint64,uint64),bytes[],bytes))\":{\"notice\":\"Querying the membership of a key-value pair\"},\"verifyNonMembership((bytes,(uint64,uint64),bytes[]))\":{\"notice\":\"Querying the non-membership of a key\"}},\"notice\":\"Implements an IBC light client that trusts an off-chain m-of-n attestor set.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/light-clients/attestation/AttestationLightClient.sol\":\"AttestationLightClient\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[\":@openzeppelin-contracts/=node_modules/@openzeppelin/contracts/\",\":@openzeppelin-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/\",\":@openzeppelin/=node_modules/@openzeppelin/\",\":@sp1-contracts/=node_modules/sp1-contracts/contracts/src/\",\":@uniswap/permit2/=node_modules/@uniswap/permit2/\",\":forge-std/=node_modules/forge-std/src/\",\":sp1-contracts/=node_modules/sp1-contracts/\"],\"viaIR\":true},\"sources\":{\"contracts/interfaces/ILightClient.sol\":{\"keccak256\":\"0x1caae9e4f741a86c0056d5f7713a35f3bd96db7a9fd52fc9f1cf79aad76a442f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://4a536db3b926560f69547c17e4f451a2631ddea0f42bd224c7fd8382d74429f6\",\"dweb:/ipfs/QmcQ33kxcmmowXgMbQGTBgiKBjF7v8UiP4y73bB9hhDizC\"]},\"contracts/light-clients/attestation/AttestationLightClient.sol\":{\"keccak256\":\"0xb287ccfd4e7b3baa99215a62484a99117b3be10d9765899c221f3fb0d54876fd\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://752979b4fe813e9cee697e2c29c7b119f8f0f84e2a9b6b1d0db97685a4435660\",\"dweb:/ipfs/QmTxfSdTKcrfaKKKtsX5Wy8RVMYcyYfkKCaDm2brNYTLFz\"]},\"contracts/light-clients/attestation/errors/IAttestationLightClientErrors.sol\":{\"keccak256\":\"0x0d3592b3c36cfcde83e2510bb9179b41befb486cbb65f529ff68c09fad751564\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://8d9bd1170d3954f7af6bd9fe79efbeff8f943073d27eb7bbecc8b9c66a0bdc62\",\"dweb:/ipfs/QmRuorHcJVhDJdYf7y43tyZuDowoBGkeRjH2z9C939XuDa\"]},\"contracts/light-clients/attestation/interfaces/IAttestationLightClient.sol\":{\"keccak256\":\"0x115ffce5474e6127fdb1f2b9284ea6d51ec978efd47f4425ba693c6c69d8b0af\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://bebb9e7d156b1a3ec682ff9cb8c9680b718bf0ae8e217ed153811dd399e456e8\",\"dweb:/ipfs/QmcjbxSBU4jvZMxn7PYYM6fxLCovWj1rKAtZazXY2RSA8U\"]},\"contracts/light-clients/attestation/msgs/IAttestationLightClientMsgs.sol\":{\"keccak256\":\"0x08148f1409f7e3c8968916950d920b8a4352796191875a4672ad2404e3541ef5\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://94c4b12d851c5e7b581d2794c88481df658eaf55ad4e54ddef14423c90986a67\",\"dweb:/ipfs/QmZysvpbY1Xe7kNVw1iHZsPaVMUMqLauJssyrceQybBgXw\"]},\"contracts/light-clients/attestation/msgs/IAttestationMsgs.sol\":{\"keccak256\":\"0xba7901ec5fb4a4845272501a1a0b183309cd0ae37d9ec5f9e3c6ce699bfd281f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://72d0768a801a3c70910c10a1fc48c29c62d902dc602e20d72a1388ba498e8a4b\",\"dweb:/ipfs/QmUKLdbX2NwSyHFrh2WUHLm4zdFivu3Ryw2XyjT3R9Szse\"]},\"contracts/msgs/IICS02ClientMsgs.sol\":{\"keccak256\":\"0xb5fdb25319d5c32b3f527982d45ec1e9bec5215515581aee034d853006ea01a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6b8939bf552c62c952a491008bcd9b59ab7dda20a9482bf93438e05793881542\",\"dweb:/ipfs/QmfWmzNCp8bd4pP26Lfw5HHp4dSZnCDqZDjVN7SD8P7eDh\"]},\"contracts/msgs/ILightClientMsgs.sol\":{\"keccak256\":\"0xa0565e7748b8b3284d72e1aa6ef4cc8264fcaa5f4e0761d22d64686953db6378\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://c4476010d7090bfaa74127526f2051c6bc82ff42a09b936e848880a1f15a6065\",\"dweb:/ipfs/QmY87JgRsFQXSZdGXNjNHEJCkdTHzFXH4vZEJ3q7MnHuP8\"]},\"node_modules/@openzeppelin/contracts/access/AccessControl.sol\":{\"keccak256\":\"0x1a6b4f6b7798ab80929d491b89d5427a9b3338c0fd1acd0ba325f69c6f1646af\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7bb7f346c12a14dc622bc105ce3c47202fbc89f4b153a28a63bb68193297330c\",\"dweb:/ipfs/QmagwF8P3bUBXwdo159ueEnY9dLSvEWwK24kk2op58egwG\"]},\"node_modules/@openzeppelin/contracts/access/IAccessControl.sol\":{\"keccak256\":\"0xbff9f59c84e5337689161ce7641c0ef8e872d6a7536fbc1f5133f128887aba3c\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b308f882e796f7b79c9502deacb0a62983035c6f6f4e962b319ba6a1f4a77d3d\",\"dweb:/ipfs/QmaWCW7ahEQqFjwhSUhV7Ae7WhfNvzSpE7DQ58hvEooqPL\"]},\"node_modules/@openzeppelin/contracts/utils/Context.sol\":{\"keccak256\":\"0x493033a8d1b176a037b2cc6a04dad01a5c157722049bbecf632ca876224dd4b2\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6a708e8a5bdb1011c2c381c9a5cfd8a9a956d7d0a9dc1bd8bcdaf52f76ef2f12\",\"dweb:/ipfs/Qmax9WHBnVsZP46ZxEMNRQpLQnrdE4dK8LehML1Py8FowF\"]},\"node_modules/@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"keccak256\":\"0x360cf86214a764694dae1522a38200b1737fe90e46dcf56a0f89de143071cc20\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://2e393290a46ca6d1fa1addb40709d26e1d250638ab6acdd103b5af21768ebc7b\",\"dweb:/ipfs/QmPwT3tXwQ9NbGtZ99XRq7sr8LCQP8XaCrzw49JdXGn7us\"]},\"node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"keccak256\":\"0x2d9dc2fe26180f74c11c13663647d38e259e45f95eb88f57b61d2160b0109d3e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://81233d1f98060113d9922180bb0f14f8335856fe9f339134b09335e9f678c377\",\"dweb:/ipfs/QmWh6R35SarhAn4z2wH8SU456jJSYL2FgucfTFgbHJJN4E\"]},\"node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"keccak256\":\"0x8891738ffe910f0cf2da09566928589bf5d63f4524dd734fd9cedbac3274dd5c\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://971f954442df5c2ef5b5ebf1eb245d7105d9fbacc7386ee5c796df1d45b21617\",\"dweb:/ipfs/QmadRjHbkicwqwwh61raUEapaVEtaLMcYbQZWs9gUkgj3u\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.28+commit.7893614a"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"address[]","name":"attestorAddresses","type":"address[]"},{"internalType":"uint8","name":"minRequiredSigs","type":"uint8"},{"internalType":"uint64","name":"initialHeight","type":"uint64"},{"internalType":"uint64","name":"initialTimestampSeconds","type":"uint64"},{"internalType":"address","name":"roleManager","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"type":"error","name":"AccessControlBadConfirmation"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"type":"error","name":"AccessControlUnauthorizedAccount"},{"inputs":[{"internalType":"uint8","name":"minRequired","type":"uint8"},{"internalType":"uint256","name":"attestationCount","type":"uint256"}],"type":"error","name":"BadQuorum"},{"inputs":[{"internalType":"uint64","name":"height","type":"uint64"}],"type":"error","name":"ConsensusTimestampNotFound"},{"inputs":[{"internalType":"address","name":"signer","type":"address"}],"type":"error","name":"DuplicateSigner"},{"inputs":[],"type":"error","name":"ECDSAInvalidSignature"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"type":"error","name":"ECDSAInvalidSignatureLength"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"type":"error","name":"ECDSAInvalidSignatureS"},{"inputs":[],"type":"error","name":"EmptyPackets"},{"inputs":[],"type":"error","name":"EmptySignatures"},{"inputs":[],"type":"error","name":"EmptyValue"},{"inputs":[],"type":"error","name":"FeatureNotSupported"},{"inputs":[],"type":"error","name":"FrozenClientState"},{"inputs":[{"internalType":"uint64","name":"expected","type":"uint64"},{"internalType":"uint64","name":"provided","type":"uint64"}],"type":"error","name":"HeightMismatch"},{"inputs":[{"internalType":"uint256","name":"expectedLength","type":"uint256"},{"internalType":"uint256","name":"providedLength","type":"uint256"}],"type":"error","name":"InvalidPathLength"},{"inputs":[{"internalType":"bytes","name":"signature","type":"bytes"}],"type":"error","name":"InvalidSignatureLength"},{"inputs":[{"internalType":"uint64","name":"height","type":"uint64"},{"internalType":"uint64","name":"timestamp","type":"uint64"}],"type":"error","name":"InvalidState"},{"inputs":[],"type":"error","name":"NoAttestors"},{"inputs":[],"type":"error","name":"NotMember"},{"inputs":[],"type":"error","name":"NotNonMember"},{"inputs":[{"internalType":"bytes","name":"signature","type":"bytes"}],"type":"error","name":"SignatureInvalid"},{"inputs":[{"internalType":"uint256","name":"validSigners","type":"uint256"},{"internalType":"uint8","name":"minRequired","type":"uint8"}],"type":"error","name":"ThresholdNotMet"},{"inputs":[{"internalType":"address","name":"signer","type":"address"}],"type":"error","name":"UnknownSigner"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32","indexed":true},{"internalType":"bytes32","name":"previousAdminRole","type":"bytes32","indexed":true},{"internalType":"bytes32","name":"newAdminRole","type":"bytes32","indexed":true}],"type":"event","name":"RoleAdminChanged","anonymous":false},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32","indexed":true},{"internalType":"address","name":"account","type":"address","indexed":true},{"internalType":"address","name":"sender","type":"address","indexed":true}],"type":"event","name":"RoleGranted","anonymous":false},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32","indexed":true},{"internalType":"address","name":"account","type":"address","indexed":true},{"internalType":"address","name":"sender","type":"address","indexed":true}],"type":"event","name":"RoleRevoked","anonymous":false},{"inputs":[],"stateMutability":"view","type":"function","name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"PROOF_SUBMITTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"getAttestationSet","outputs":[{"internalType":"address[]","name":"attestorAddresses","type":"address[]"},{"internalType":"uint8","name":"minRequiredSigs","type":"uint8"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"getClientState","outputs":[{"internalType":"bytes","name":"","type":"bytes"}]},{"inputs":[{"internalType":"uint64","name":"revisionHeight","type":"uint64"}],"stateMutability":"view","type":"function","name":"getConsensusTimestamp","outputs":[{"internalType":"uint64","name":"","type":"uint64"}]},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"stateMutability":"view","type":"function","name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"grantRole"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"stateMutability":"view","type":"function","name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}]},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function","name":"misbehaviour"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"renounceRole"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"revokeRole"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"stateMutability":"view","type":"function","name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}]},{"inputs":[{"internalType":"bytes","name":"updateMsg","type":"bytes"}],"stateMutability":"nonpayable","type":"function","name":"updateClient","outputs":[{"internalType":"enum ILightClientMsgs.UpdateResult","name":"","type":"uint8"}]},{"inputs":[{"internalType":"struct ILightClientMsgs.MsgVerifyMembership","name":"msg_","type":"tuple","components":[{"internalType":"bytes","name":"proof","type":"bytes"},{"internalType":"struct IICS02ClientMsgs.Height","name":"proofHeight","type":"tuple","components":[{"internalType":"uint64","name":"revisionNumber","type":"uint64"},{"internalType":"uint64","name":"revisionHeight","type":"uint64"}]},{"internalType":"bytes[]","name":"path","type":"bytes[]"},{"internalType":"bytes","name":"value","type":"bytes"}]}],"stateMutability":"view","type":"function","name":"verifyMembership","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]},{"inputs":[{"internalType":"struct ILightClientMsgs.MsgVerifyNonMembership","name":"msg_","type":"tuple","components":[{"internalType":"bytes","name":"proof","type":"bytes"},{"internalType":"struct IICS02ClientMsgs.Height","name":"proofHeight","type":"tuple","components":[{"internalType":"uint64","name":"revisionNumber","type":"uint64"},{"internalType":"uint64","name":"revisionHeight","type":"uint64"}]},{"internalType":"bytes[]","name":"path","type":"bytes[]"}]}],"stateMutability":"view","type":"function","name":"verifyNonMembership","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]}],"devdoc":{"kind":"dev","methods":{"constructor":{"params":{"attestorAddresses":"The configured attestor addresses (EOAs)","initialHeight":"The initial known height","initialTimestampSeconds":"The initial timestamp in seconds for the initial height","minRequiredSigs":"The quorum threshold","roleManager":"Address that will administer roles and be allowed to submit proofs; if zero, anyone can submit"}},"getAttestationSet()":{"details":"The attestation set is fixed for the initial scope; rotation is out of scope.","returns":{"attestorAddresses":"The configured attestor EOA addresses","minRequiredSigs":"The minimum number of unique valid signatures required"}},"getClientState()":{"returns":{"_0":"The client state."}},"getConsensusTimestamp(uint64)":{"params":{"revisionHeight":"The height for which to query the timestamp"},"returns":{"_0":"The trusted timestamp in unix seconds"}},"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"misbehaviour(bytes)":{"params":{"misbehaviourMsg":"The misbehaviour message"}},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] to learn more about how these ids are created. This function call must use less than 30 000 gas."},"updateClient(bytes)":{"params":{"updateMsg":"The encoded update message e.g., an SP1 proof."},"returns":{"_0":"The result of the update operation"}},"verifyMembership((bytes,(uint64,uint64),bytes[],bytes))":{"details":"Notice that this message is not view, as it may update the client state for caching purposes.","params":{"msg_":"The membership message"},"returns":{"_0":"The unix timestamp of the verification height in the counterparty chain in seconds."}},"verifyNonMembership((bytes,(uint64,uint64),bytes[]))":{"details":"Notice that this message is not view, as it may update the client state for caching purposes.","params":{"msg_":"The membership message"},"returns":{"_0":"The unix timestamp of the verification height in the counterparty chain in seconds."}}},"version":1},"userdoc":{"kind":"user","methods":{"PROOF_SUBMITTER_ROLE()":{"notice":"The role identifier for the proof submitter role"},"constructor":{"notice":"Initializes the attestor light client with its fixed attestor set and initial height/timestamp."},"getAttestationSet()":{"notice":"Returns the attestation set configuration."},"getClientState()":{"notice":"Returns the client state."},"getConsensusTimestamp(uint64)":{"notice":"Returns the trusted consensus timestamp (in seconds) at the given revision height."},"misbehaviour(bytes)":{"notice":"Misbehaviour handling, moves the light client to the frozen state if misbehaviour is detected"},"updateClient(bytes)":{"notice":"Updating the client and consensus state"},"verifyMembership((bytes,(uint64,uint64),bytes[],bytes))":{"notice":"Querying the membership of a key-value pair"},"verifyNonMembership((bytes,(uint64,uint64),bytes[]))":{"notice":"Querying the non-membership of a key"}},"version":1}},"settings":{"remappings":["@openzeppelin-contracts/=node_modules/@openzeppelin/contracts/","@openzeppelin-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/","@openzeppelin/=node_modules/@openzeppelin/","@sp1-contracts/=node_modules/sp1-contracts/contracts/src/","@uniswap/permit2/=node_modules/@uniswap/permit2/","forge-std/=node_modules/forge-std/src/","sp1-contracts/=node_modules/sp1-contracts/"],"optimizer":{"enabled":true,"runs":10000},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"contracts/light-clients/attestation/AttestationLightClient.sol":"AttestationLightClient"},"evmVersion":"cancun","libraries":{},"viaIR":true},"sources":{"contracts/interfaces/ILightClient.sol":{"keccak256":"0x1caae9e4f741a86c0056d5f7713a35f3bd96db7a9fd52fc9f1cf79aad76a442f","urls":["bzz-raw://4a536db3b926560f69547c17e4f451a2631ddea0f42bd224c7fd8382d74429f6","dweb:/ipfs/QmcQ33kxcmmowXgMbQGTBgiKBjF7v8UiP4y73bB9hhDizC"],"license":"MIT"},"contracts/light-clients/attestation/AttestationLightClient.sol":{"keccak256":"0xb287ccfd4e7b3baa99215a62484a99117b3be10d9765899c221f3fb0d54876fd","urls":["bzz-raw://752979b4fe813e9cee697e2c29c7b119f8f0f84e2a9b6b1d0db97685a4435660","dweb:/ipfs/QmTxfSdTKcrfaKKKtsX5Wy8RVMYcyYfkKCaDm2brNYTLFz"],"license":"MIT"},"contracts/light-clients/attestation/errors/IAttestationLightClientErrors.sol":{"keccak256":"0x0d3592b3c36cfcde83e2510bb9179b41befb486cbb65f529ff68c09fad751564","urls":["bzz-raw://8d9bd1170d3954f7af6bd9fe79efbeff8f943073d27eb7bbecc8b9c66a0bdc62","dweb:/ipfs/QmRuorHcJVhDJdYf7y43tyZuDowoBGkeRjH2z9C939XuDa"],"license":"MIT"},"contracts/light-clients/attestation/interfaces/IAttestationLightClient.sol":{"keccak256":"0x115ffce5474e6127fdb1f2b9284ea6d51ec978efd47f4425ba693c6c69d8b0af","urls":["bzz-raw://bebb9e7d156b1a3ec682ff9cb8c9680b718bf0ae8e217ed153811dd399e456e8","dweb:/ipfs/QmcjbxSBU4jvZMxn7PYYM6fxLCovWj1rKAtZazXY2RSA8U"],"license":"MIT"},"contracts/light-clients/attestation/msgs/IAttestationLightClientMsgs.sol":{"keccak256":"0x08148f1409f7e3c8968916950d920b8a4352796191875a4672ad2404e3541ef5","urls":["bzz-raw://94c4b12d851c5e7b581d2794c88481df658eaf55ad4e54ddef14423c90986a67","dweb:/ipfs/QmZysvpbY1Xe7kNVw1iHZsPaVMUMqLauJssyrceQybBgXw"],"license":"MIT"},"contracts/light-clients/attestation/msgs/IAttestationMsgs.sol":{"keccak256":"0xba7901ec5fb4a4845272501a1a0b183309cd0ae37d9ec5f9e3c6ce699bfd281f","urls":["bzz-raw://72d0768a801a3c70910c10a1fc48c29c62d902dc602e20d72a1388ba498e8a4b","dweb:/ipfs/QmUKLdbX2NwSyHFrh2WUHLm4zdFivu3Ryw2XyjT3R9Szse"],"license":"MIT"},"contracts/msgs/IICS02ClientMsgs.sol":{"keccak256":"0xb5fdb25319d5c32b3f527982d45ec1e9bec5215515581aee034d853006ea01a0","urls":["bzz-raw://6b8939bf552c62c952a491008bcd9b59ab7dda20a9482bf93438e05793881542","dweb:/ipfs/QmfWmzNCp8bd4pP26Lfw5HHp4dSZnCDqZDjVN7SD8P7eDh"],"license":"MIT"},"contracts/msgs/ILightClientMsgs.sol":{"keccak256":"0xa0565e7748b8b3284d72e1aa6ef4cc8264fcaa5f4e0761d22d64686953db6378","urls":["bzz-raw://c4476010d7090bfaa74127526f2051c6bc82ff42a09b936e848880a1f15a6065","dweb:/ipfs/QmY87JgRsFQXSZdGXNjNHEJCkdTHzFXH4vZEJ3q7MnHuP8"],"license":"MIT"},"node_modules/@openzeppelin/contracts/access/AccessControl.sol":{"keccak256":"0x1a6b4f6b7798ab80929d491b89d5427a9b3338c0fd1acd0ba325f69c6f1646af","urls":["bzz-raw://7bb7f346c12a14dc622bc105ce3c47202fbc89f4b153a28a63bb68193297330c","dweb:/ipfs/QmagwF8P3bUBXwdo159ueEnY9dLSvEWwK24kk2op58egwG"],"license":"MIT"},"node_modules/@openzeppelin/contracts/access/IAccessControl.sol":{"keccak256":"0xbff9f59c84e5337689161ce7641c0ef8e872d6a7536fbc1f5133f128887aba3c","urls":["bzz-raw://b308f882e796f7b79c9502deacb0a62983035c6f6f4e962b319ba6a1f4a77d3d","dweb:/ipfs/QmaWCW7ahEQqFjwhSUhV7Ae7WhfNvzSpE7DQ58hvEooqPL"],"license":"MIT"},"node_modules/@openzeppelin/contracts/utils/Context.sol":{"keccak256":"0x493033a8d1b176a037b2cc6a04dad01a5c157722049bbecf632ca876224dd4b2","urls":["bzz-raw://6a708e8a5bdb1011c2c381c9a5cfd8a9a956d7d0a9dc1bd8bcdaf52f76ef2f12","dweb:/ipfs/Qmax9WHBnVsZP46ZxEMNRQpLQnrdE4dK8LehML1Py8FowF"],"license":"MIT"},"node_modules/@openzeppelin/contracts/utils/cryptography/ECDSA.sol":{"keccak256":"0x360cf86214a764694dae1522a38200b1737fe90e46dcf56a0f89de143071cc20","urls":["bzz-raw://2e393290a46ca6d1fa1addb40709d26e1d250638ab6acdd103b5af21768ebc7b","dweb:/ipfs/QmPwT3tXwQ9NbGtZ99XRq7sr8LCQP8XaCrzw49JdXGn7us"],"license":"MIT"},"node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol":{"keccak256":"0x2d9dc2fe26180f74c11c13663647d38e259e45f95eb88f57b61d2160b0109d3e","urls":["bzz-raw://81233d1f98060113d9922180bb0f14f8335856fe9f339134b09335e9f678c377","dweb:/ipfs/QmWh6R35SarhAn4z2wH8SU456jJSYL2FgucfTFgbHJJN4E"],"license":"MIT"},"node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol":{"keccak256":"0x8891738ffe910f0cf2da09566928589bf5d63f4524dd734fd9cedbac3274dd5c","urls":["bzz-raw://971f954442df5c2ef5b5ebf1eb245d7105d9fbacc7386ee5c796df1d45b21617","dweb:/ipfs/QmadRjHbkicwqwwh61raUEapaVEtaLMcYbQZWs9gUkgj3u"],"license":"MIT"}},"version":1},"id":29} \ No newline at end of file +{"abi":[{"type":"constructor","inputs":[{"name":"attestorAddresses","type":"address[]","internalType":"address[]"},{"name":"minRequiredSigs","type":"uint8","internalType":"uint8"},{"name":"initialHeight","type":"uint64","internalType":"uint64"},{"name":"initialTimestampSeconds","type":"uint64","internalType":"uint64"},{"name":"roleManager","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"type":"function","name":"DEFAULT_ADMIN_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"PROOF_SUBMITTER_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"getAttestationSet","inputs":[],"outputs":[{"name":"attestorAddresses","type":"address[]","internalType":"address[]"},{"name":"minRequiredSigs","type":"uint8","internalType":"uint8"}],"stateMutability":"view"},{"type":"function","name":"getClientState","inputs":[],"outputs":[{"name":"","type":"bytes","internalType":"bytes"}],"stateMutability":"view"},{"type":"function","name":"getConsensusTimestamp","inputs":[{"name":"revisionHeight","type":"uint64","internalType":"uint64"}],"outputs":[{"name":"","type":"uint64","internalType":"uint64"}],"stateMutability":"view"},{"type":"function","name":"getRoleAdmin","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"grantRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"hasRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"misbehaviour","inputs":[{"name":"","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"view"},{"type":"function","name":"renounceRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"callerConfirmation","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"revokeRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"supportsInterface","inputs":[{"name":"interfaceId","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"updateClient","inputs":[{"name":"updateMsg","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"","type":"uint8","internalType":"enum ILightClientMsgs.UpdateResult"}],"stateMutability":"nonpayable"},{"type":"function","name":"verifyMembership","inputs":[{"name":"msg_","type":"tuple","internalType":"struct ILightClientMsgs.MsgVerifyMembership","components":[{"name":"proof","type":"bytes","internalType":"bytes"},{"name":"proofHeight","type":"tuple","internalType":"struct IICS02ClientMsgs.Height","components":[{"name":"revisionNumber","type":"uint64","internalType":"uint64"},{"name":"revisionHeight","type":"uint64","internalType":"uint64"}]},{"name":"path","type":"bytes[]","internalType":"bytes[]"},{"name":"value","type":"bytes","internalType":"bytes"}]}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"verifyNonMembership","inputs":[{"name":"msg_","type":"tuple","internalType":"struct ILightClientMsgs.MsgVerifyNonMembership","components":[{"name":"proof","type":"bytes","internalType":"bytes"},{"name":"proofHeight","type":"tuple","internalType":"struct IICS02ClientMsgs.Height","components":[{"name":"revisionNumber","type":"uint64","internalType":"uint64"},{"name":"revisionHeight","type":"uint64","internalType":"uint64"}]},{"name":"path","type":"bytes[]","internalType":"bytes[]"}]}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"event","name":"RoleAdminChanged","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"previousAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"newAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"error","name":"AccessControlBadConfirmation","inputs":[]},{"type":"error","name":"AccessControlUnauthorizedAccount","inputs":[{"name":"account","type":"address","internalType":"address"},{"name":"neededRole","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"BadQuorum","inputs":[{"name":"minRequired","type":"uint8","internalType":"uint8"},{"name":"attestationCount","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"ConsensusTimestampNotFound","inputs":[{"name":"height","type":"uint64","internalType":"uint64"}]},{"type":"error","name":"DuplicateSigner","inputs":[{"name":"signer","type":"address","internalType":"address"}]},{"type":"error","name":"ECDSAInvalidSignature","inputs":[]},{"type":"error","name":"ECDSAInvalidSignatureLength","inputs":[{"name":"length","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"ECDSAInvalidSignatureS","inputs":[{"name":"s","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"EmptyPackets","inputs":[]},{"type":"error","name":"EmptySignatures","inputs":[]},{"type":"error","name":"EmptyValue","inputs":[]},{"type":"error","name":"FeatureNotSupported","inputs":[]},{"type":"error","name":"FrozenClientState","inputs":[]},{"type":"error","name":"HeightMismatch","inputs":[{"name":"expected","type":"uint64","internalType":"uint64"},{"name":"provided","type":"uint64","internalType":"uint64"}]},{"type":"error","name":"InvalidPathLength","inputs":[{"name":"expectedLength","type":"uint256","internalType":"uint256"},{"name":"providedLength","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InvalidSignatureLength","inputs":[{"name":"signature","type":"bytes","internalType":"bytes"}]},{"type":"error","name":"InvalidState","inputs":[{"name":"height","type":"uint64","internalType":"uint64"},{"name":"timestamp","type":"uint64","internalType":"uint64"}]},{"type":"error","name":"NoAttestors","inputs":[]},{"type":"error","name":"NotMember","inputs":[]},{"type":"error","name":"NotNonMember","inputs":[]},{"type":"error","name":"SignatureInvalid","inputs":[{"name":"signature","type":"bytes","internalType":"bytes"}]},{"type":"error","name":"ThresholdNotMet","inputs":[{"name":"validSigners","type":"uint256","internalType":"uint256"},{"name":"minRequired","type":"uint8","internalType":"uint8"}]},{"type":"error","name":"UnknownSigner","inputs":[{"name":"signer","type":"address","internalType":"address"}]}],"bytecode":{"object":"0x60806040523461032d57611f568038038061001981610349565b928339810160a08282031261032d5781516001600160401b03811161032d57820181601f8201121561032d578051916001600160401b0383116102c8578260051b916020610068818501610349565b8095815201906020829482010192831161032d57602001905b8282106103315750505060208301519260ff841680940361032d576100a860408201610382565b6100c060806100b960608501610382565b930161036e565b9284511561031e57851515806102f2575b855190156102dc575060405195608087016001600160401b038111888210176102c857604052858752602087019081526060604088019360018060401b03169788855201915f835286519060018060401b0382116102c8576801000000000000000082116102c85760015482600155808310610284575b5060015f5260205f205f5b838110610267575050505060ff90511669ff00000000000000000060025493610100600160481b03905160081b169251151560481b169260018060501b0319161717176002555f5b83518110156101fb5760018060a01b0360208260051b8601015116805f52600360205260ff60405f2054166101e957906001915f52600360205260405f208260ff198254161790550161019b565b637010e27960e11b5f5260045260245ffd5b505f84815260046020526040902080546001600160401b0319166001600160401b039092169190911790556001600160a01b03811661024e575061023d61048c565b505b6040516119a7908161050f8239f35b8061025b61026192610396565b5061040c565b5061023f565b82516001600160a01b031681830155602090920191600101610153565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf69081019083015b8181106102bd5750610148565b5f81556001016102b0565b634e487b7160e01b5f52604160045260245ffd5b866365846b7f60e01b5f5260045260245260445ffd5b5084515f19870160ff811161030a5760ff16106100d1565b634e487b7160e01b5f52601160045260245ffd5b6343d0a89360e11b5f5260045ffd5b5f80fd5b6020809161033e8461036e565b815201910190610081565b6040519190601f01601f191682016001600160401b038111838210176102c857604052565b51906001600160a01b038216820361032d57565b51906001600160401b038216820361032d57565b6001600160a01b0381165f9081525f516020611f365f395f51905f52602052604090205460ff16610407576001600160a01b03165f8181525f516020611f365f395f51905f5260205260408120805460ff191660011790553391905f516020611eb65f395f51905f528180a4600190565b505f90565b6001600160a01b0381165f9081525f516020611ed65f395f51905f52602052604090205460ff16610407576001600160a01b03165f8181525f516020611ed65f395f51905f5260205260408120805460ff191660011790553391905f516020611f165f395f51905f52905f516020611eb65f395f51905f529080a4600190565b5f80525f516020611ed65f395f51905f526020525f516020611ef65f395f51905f525460ff1661050a575f8080525f516020611ed65f395f51905f526020525f516020611ef65f395f51905f52805460ff1916600117905533905f516020611f165f395f51905f525f516020611eb65f395f51905f528280a4600190565b5f9056fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146106ab575080630bece356146105e8578063248a9ca3146105be5780632f2ff15d1461058f57806336568abe146105335780634d6d9ffb146104865780635832611b146104405780635972185a14610406578063682ed5f01461035157806391d1485414610308578063a217fddf146102ee578063a845a7f314610261578063d547741f1461022b578063ddba65371461015f5763ef913a4b146100c1575f80fd5b3461015b575f60031936011261015b576101576040516020808201526080604082015261014b816100f460c08201611228565b60ff600254818116606085015267ffffffffffffffff8160081c16608085015260481c16151560a0830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0810183528261085e565b604051918291826107cd565b0390f35b5f80fd5b3461015b5761016d36610749565b505060ff60025460481c16610203575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06020527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475460ff16156101f6575b7fda81d7c2000000000000000000000000000000000000000000000000000000005f5260045ffd5b6101fe611277565b6101ce565b7f928b1233000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461015b5761025f61023c3661079a565b9061025a610255825f525f602052600160405f20015490565b6112ff565b61175e565b005b3461015b575f60031936011261015b5760ff6002541660405161028e8161028781611228565b038261085e565b60405190604082019260408352815180945260206060840192015f945b8086106102c057505082935060208301520390f35b909260208060019273ffffffffffffffffffffffffffffffffffffffff8751168152019401950194906102ab565b3461015b575f60031936011261015b5760206040515f8152f35b3461015b576103163661079a565b905f525f60205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060ff60405f2054166040519015158152f35b3461015b57602060031936011261015b5760043567ffffffffffffffff811161015b5760a0600319823603011261015b5760ff60025460481c16610203575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e060209081527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475490916103f19160ff16156103f9575b6004016110cb565b604051908152f35b610401611277565b6103e9565b3461015b575f60031936011261015b5760206040517fbd893629a699470e4ec82a5715bb4981fdaacc5d0a728bf5f55b801d8f4ef10b8152f35b3461015b57602060031936011261015b5760043567ffffffffffffffff811680910361015b575f526004602052602067ffffffffffffffff60405f205416604051908152f35b3461015b57602060031936011261015b5760043567ffffffffffffffff811161015b576080600319823603011261015b5760ff60025460481c16610203575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e060209081527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475490916103f19160ff1615610526575b600401610ef5565b61052e611277565b61051e565b3461015b576105413661079a565b3373ffffffffffffffffffffffffffffffffffffffff8216036105675761025f9161175e565b7f6697b232000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461015b5761025f6105a03661079a565b906105b9610255825f525f602052600160405f20015490565b61168c565b3461015b57602060031936011261015b5760206103f16004355f525f602052600160405f20015490565b3461015b576105f636610749565b60ff60025460481c16610203575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06020527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475461065e929060ff161561069e57610a3c565b6040516003821015610671576020918152f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b6106a6611277565b610a3c565b3461015b57602060031936011261015b57600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361015b57817f7965db0b000000000000000000000000000000000000000000000000000000006020931490811561071f575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483610718565b90602060031983011261015b5760043567ffffffffffffffff811161015b578260238201121561015b5780600401359267ffffffffffffffff841161015b576024848301011161015b576024019190565b600319604091011261015b576004359060243573ffffffffffffffffffffffffffffffffffffffff8116810361015b5790565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602060409481855280519182918282880152018686015e5f8582860101520116010190565b6040810190811067ffffffffffffffff82111761083157604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761083157604052565b92919267ffffffffffffffff821161083157604051916108e760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116018461085e565b82948184528183011161015b578281602093845f960137010152565b9080601f8301121561015b5781602061091e9335910161089f565b90565b67ffffffffffffffff81116108315760051b60200190565b60208183031261015b5780359067ffffffffffffffff821161015b57019060408282031261015b576040519161096e83610815565b803567ffffffffffffffff811161015b578261098b918301610903565b835260208101359067ffffffffffffffff821161015b57019080601f8301121561015b5781356109ba81610921565b926109c8604051948561085e565b81845260208085019260051b8201019183831161015b5760208201905b8382106109f9575050505050602082015290565b813567ffffffffffffffff811161015b57602091610a1c87848094880101610903565b8152019101906109e5565b519067ffffffffffffffff8216820361015b57565b610a4891810190610939565b60205f818351604051918183925191829101835e8101838152039060025afa15610c915760205f8051604051838101917f01000000000000000000000000000000000000000000000000000000000000008352602182015260218152610aaf60418261085e565b604051918291518091835e8101838152039060025afa15610c9157610ada5f516020830151906113eb565b5160408180518101031261015b57604051610af481610815565b610b0f6040610b0560208501610a27565b9384845201610a27565b67ffffffffffffffff60208301938285521680151580610c7e575b15610c4457505067ffffffffffffffff8151165f52600460205267ffffffffffffffff60405f20541680610bf3575067ffffffffffffffff9051918183169260025490838260081c168511610bb6575b50505116905f52600460205260405f20907fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000008254161790555f90565b68ffffffffffffffff007fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ff9160081b169116176002555f80610b7a565b9167ffffffffffffffff9150511603610c0b57600290565b69010000000000000000007fffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff6002541617600255600190565b67ffffffffffffffff92507fdcbc5460000000000000000000000000000000000000000000000000000000005f526004521660245260445ffd5b5067ffffffffffffffff82161515610b2a565b6040513d5f823e3d90fd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561015b570180359067ffffffffffffffff821161015b57602001918160051b3603831361015b57565b3567ffffffffffffffff8116810361015b5790565b15610d0d5750565b67ffffffffffffffff907ff7caaa5c000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561015b570180359067ffffffffffffffff821161015b5760200191813603831361015b57565b60208183031261015b5780519067ffffffffffffffff821161015b57019060408282031261015b5760405191610dc983610815565b610dd281610a27565b835260208101519067ffffffffffffffff821161015b570181601f8201121561015b57805190610e0182610921565b92610e0f604051948561085e565b82845260208085019360061b8301019181831161015b57602001925b828410610e3e5750505050602082015290565b60408483031261015b5760206040918251610e5881610815565b865181528287015183820152815201930192610e2b565b15610e78575050565b9067ffffffffffffffff80927fc7441689000000000000000000000000000000000000000000000000000000005f52166004521660245260445ffd5b8051821015610ec85760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b6060810190610f048282610c9c565b90506001610f128484610c9c565b9290500361109b5750610fb8610f2a60408301610cf0565b9267ffffffffffffffff841692835f526004602052610fb367ffffffffffffffff60405f20541694610f5e87871515610d05565b610f9e610f76610f6e8580610d43565b810190610939565b610f8e610f838251611365565b6020830151906113eb565b5160208082518301019101610d94565b9667ffffffffffffffff885116918214610e6f565b610c9c565b15610ec857610fd3610fcc82602093610d43565b369161089f565b818151910120920180515115611073575f5b8151805182101561104b57610ffb828692610eb4565b51511461100a57600101610fe5565b60209293506110199151610eb4565b5101516110235790565b7f9a960b4f000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f291fc442000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f1e6c84da000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f88b3170e000000000000000000000000000000000000000000000000000000005f52600160045260245260445ffd5b608081016110d98183610d43565b9050156112005760608201906110ef8284610c9c565b905060016110fd8486610c9c565b9290500361109b575061111260408401610cf0565b9061117467ffffffffffffffff831693845f52600460205261116e67ffffffffffffffff60405f2054169561114986881515610d05565b611159610f76610f6e8a80610d43565b9567ffffffffffffffff875116918214610e6f565b85610c9c565b15610ec85760209161118c610fcc8361119894610d43565b83815191012095610d43565b908092918101031261015b576020903591019081515115611073575f5b8251805182101561104b576111cb828792610eb4565b515114806111e8575b6111e0576001016111b5565b505050905090565b508160206111f7838651610eb4565b510151146111d4565b7f1208b21b000000000000000000000000000000000000000000000000000000005f5260045ffd5b602060015491828152019060015f5260205f20905f5b81811061124b5750505090565b825473ffffffffffffffffffffffffffffffffffffffff1684526020909301926001928301920161123e565b335f9081527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e0602052604090205460ff16156112af57565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f52336004527fbd893629a699470e4ec82a5715bb4981fdaacc5d0a728bf5f55b801d8f4ef10b60245260445ffd5b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260ff60405f205416156113365750565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b5f60208092604051918183925191829101835e8101838152039060025afa15610c915760205f8051604051838101917f020000000000000000000000000000000000000000000000000000000000000083526021820152602181526113cb60418261085e565b604051918291518091835e8101838152039060025afa15610c91575f5190565b91909182511561166457825160ff60025416907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82019060ff82116116375760ff8651921610156116095750508251927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061147e61146886610921565b95611476604051978861085e565b808752610921565b013660208601375f5b81518110156116025761149a8183610eb4565b5160418151036115cc5773ffffffffffffffffffffffffffffffffffffffff6114cf6114c68387611826565b90929192611860565b169081156115925750805f52600360205260ff60405f20541615611567575f5b82811061150c5750906001916115058288610eb4565b5201611487565b8173ffffffffffffffffffffffffffffffffffffffff61152c838a610eb4565b51161461153b576001016114ef565b507fe021c4f2000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fd7e8a2c2000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6115c8906040519182917f9e3c1b3d000000000000000000000000000000000000000000000000000000008352600483016107cd565b0390fd5b6115c8906040519182917f2ee17a3d000000000000000000000000000000000000000000000000000000008352600483016107cd565b5050509050565b7f378b0805000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f301b38b6000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f205416155f1461175857805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905573ffffffffffffffffffffffffffffffffffffffff339216907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d5f80a4600190565b50505f90565b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f2054165f1461175857805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815416905573ffffffffffffffffffffffffffffffffffffffff339216907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b5f80a4600190565b81519190604183036118565761184f9250602082015190606060408401519301515f1a9061190b565b9192909190565b50505f9160029190565b60048110156106715780611872575050565b600181036118a2577ff645eedf000000000000000000000000000000000000000000000000000000005f5260045ffd5b600281036118d657507ffce698f7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6003146118e05750565b7fd78bce0c000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841161198f579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15610c91575f5173ffffffffffffffffffffffffffffffffffffffff81161561198557905f905f90565b505f906001905f90565b5050505f916003919056fea164736f6c634300081c000a2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac47bd893629a699470e4ec82a5715bb4981fdaacc5d0a728bf5f55b801d8f4ef10bad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5"}} diff --git a/ibc-solidity/abi/bytecode/BesuIBFT2LightClient.json b/ibc-solidity/abi/bytecode/BesuIBFT2LightClient.json new file mode 100644 index 000000000..8af2af480 --- /dev/null +++ b/ibc-solidity/abi/bytecode/BesuIBFT2LightClient.json @@ -0,0 +1 @@ +{"abi":[{"type":"constructor","inputs":[{"name":"ibcRouter","type":"address","internalType":"address"},{"name":"initialTrustedHeight","type":"uint64","internalType":"uint64"},{"name":"initialTrustedTimestamp","type":"uint64","internalType":"uint64"},{"name":"initialTrustedStorageRoot","type":"bytes32","internalType":"bytes32"},{"name":"initialTrustedValidators","type":"address[]","internalType":"address[]"},{"name":"trustingPeriod","type":"uint64","internalType":"uint64"},{"name":"maxClockDrift","type":"uint64","internalType":"uint64"},{"name":"roleManager","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"type":"function","name":"DEFAULT_ADMIN_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"PROOF_SUBMITTER_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"getClientState","inputs":[],"outputs":[{"name":"","type":"bytes","internalType":"bytes"}],"stateMutability":"view"},{"type":"function","name":"getConsensusState","inputs":[{"name":"revisionHeight","type":"uint64","internalType":"uint64"}],"outputs":[{"name":"","type":"bytes","internalType":"bytes"}],"stateMutability":"view"},{"type":"function","name":"getRoleAdmin","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"grantRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"hasRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"misbehaviour","inputs":[{"name":"","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"view"},{"type":"function","name":"renounceRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"callerConfirmation","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"revokeRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"supportsInterface","inputs":[{"name":"interfaceId","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"updateClient","inputs":[{"name":"updateMsg","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"","type":"uint8","internalType":"enum ILightClientMsgs.UpdateResult"}],"stateMutability":"nonpayable"},{"type":"function","name":"verifyMembership","inputs":[{"name":"msg_","type":"tuple","internalType":"struct ILightClientMsgs.MsgVerifyMembership","components":[{"name":"proof","type":"bytes","internalType":"bytes"},{"name":"proofHeight","type":"tuple","internalType":"struct IICS02ClientMsgs.Height","components":[{"name":"revisionNumber","type":"uint64","internalType":"uint64"},{"name":"revisionHeight","type":"uint64","internalType":"uint64"}]},{"name":"path","type":"bytes[]","internalType":"bytes[]"},{"name":"value","type":"bytes","internalType":"bytes"}]}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"verifyNonMembership","inputs":[{"name":"msg_","type":"tuple","internalType":"struct ILightClientMsgs.MsgVerifyNonMembership","components":[{"name":"proof","type":"bytes","internalType":"bytes"},{"name":"proofHeight","type":"tuple","internalType":"struct IICS02ClientMsgs.Height","components":[{"name":"revisionNumber","type":"uint64","internalType":"uint64"},{"name":"revisionHeight","type":"uint64","internalType":"uint64"}]},{"name":"path","type":"bytes[]","internalType":"bytes[]"}]}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"event","name":"RoleAdminChanged","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"previousAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"newAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"error","name":"AccessControlBadConfirmation","inputs":[]},{"type":"error","name":"AccessControlUnauthorizedAccount","inputs":[{"name":"account","type":"address","internalType":"address"},{"name":"neededRole","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"AccountNotFound","inputs":[{"name":"account","type":"address","internalType":"address"}]},{"type":"error","name":"ConflictingConsensusState","inputs":[{"name":"revisionHeight","type":"uint64","internalType":"uint64"}]},{"type":"error","name":"ConsensusStateExpired","inputs":[{"name":"trustedTimestamp","type":"uint64","internalType":"uint64"},{"name":"currentTimestamp","type":"uint256","internalType":"uint256"},{"name":"trustingPeriod","type":"uint64","internalType":"uint64"}]},{"type":"error","name":"ConsensusStateNotFound","inputs":[{"name":"revisionHeight","type":"uint64","internalType":"uint64"}]},{"type":"error","name":"DuplicateCommitSealSigner","inputs":[{"name":"signer","type":"address","internalType":"address"}]},{"type":"error","name":"DuplicateValidator","inputs":[{"name":"validator","type":"address","internalType":"address"}]},{"type":"error","name":"EmptyValidatorSet","inputs":[]},{"type":"error","name":"HeaderFromFuture","inputs":[{"name":"currentTimestamp","type":"uint256","internalType":"uint256"},{"name":"headerTimestamp","type":"uint256","internalType":"uint256"},{"name":"maxClockDrift","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InsufficientTrustedValidatorOverlap","inputs":[{"name":"actual","type":"uint256","internalType":"uint256"},{"name":"required","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InsufficientValidatorQuorum","inputs":[{"name":"actual","type":"uint256","internalType":"uint256"},{"name":"required","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InvalidCommitSeal","inputs":[]},{"type":"error","name":"InvalidCommitmentValue","inputs":[{"name":"expectedValue","type":"bytes32","internalType":"bytes32"},{"name":"actualValue","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"InvalidDifficulty","inputs":[{"name":"actualDifficulty","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InvalidECDSASignatureLength","inputs":[{"name":"length","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InvalidExtraDataFormat","inputs":[{"name":"itemsLength","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InvalidHeaderFormat","inputs":[{"name":"itemsLength","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InvalidHeaderHeight","inputs":[]},{"type":"error","name":"InvalidHeaderTimestamp","inputs":[{"name":"actualTimestamp","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InvalidMixHash","inputs":[{"name":"actualMixHash","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"InvalidNonce","inputs":[{"name":"actualNonce","type":"bytes","internalType":"bytes"}]},{"type":"error","name":"InvalidOmmersHash","inputs":[{"name":"actualOmmersHash","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"InvalidPathLength","inputs":[{"name":"expectedLength","type":"uint256","internalType":"uint256"},{"name":"actualLength","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InvalidRevisionNumber","inputs":[{"name":"providedRevisionNumber","type":"uint64","internalType":"uint64"}]},{"type":"error","name":"InvalidValidatorAddress","inputs":[{"name":"validator","type":"address","internalType":"address"}]},{"type":"error","name":"InvalidValidatorAddressLength","inputs":[{"name":"length","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InvalidValueLength","inputs":[{"name":"expectedLength","type":"uint256","internalType":"uint256"},{"name":"actualLength","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InvalidVanityDataLength","inputs":[{"name":"length","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"RLPInvalidEncoding","inputs":[]},{"type":"error","name":"TrieProofTraversalError","inputs":[{"name":"err","type":"uint8","internalType":"enum MPTProof.ProofError"}]},{"type":"error","name":"UnsupportedMisbehaviour","inputs":[]},{"type":"error","name":"ValueExists","inputs":[{"name":"actualValue","type":"bytes32","internalType":"bytes32"}]}],"bytecode":{"object":"0x6080604052346103dc576139cc80380380610019816103e0565b928339810190610100818303126103dc5761003381610405565b9061004060208201610419565b9061004d60408201610419565b92606082015191608081015160018060401b0381116103dc5781019286601f850112156103dc578351966001600160401b03881161037f578760051b9460206100978188016103e0565b809a81520190602082978201019283116103dc57602001905b8282106103c4575050506100c660a08301610419565b956100df60e06100d860c08601610419565b9401610405565b956001600160401b03169081156103b5576001600160401b03169283156103a257885115610393575f5b89518110156101bf576001600160a01b03610124828c61042d565b511615610198575f5b81811061013d5750600101610109565b6001600160a01b0361014f828d61042d565b51166001600160a01b03610163848e61042d565b5116146101725760010161012d565b6001600160a01b03610184838d61042d565b511663107f863360e21b5f5260045260245ffd5b6001600160a01b03906101ab908b61042d565b51166359bff38760e01b5f5260045260245ffd5b5060408051979896978a979181016001600160401b0381118282101761037f576040525f81526020810190848252604051926080840198848a1060018060401b038b111761037f576040998a526001600160a01b031680855260208086018490526001600160401b03928316868c01819052878416606090970196909652600180546001600160a01b031916909217825592516002805495516fffffffffffffffff0000000000000000908d1b81169285166001600160801b03199788161792909217815560038054988d1b90921697909516909517959095179093555f948552600490529590922080546001600160401b031916949094178455830191909155925193910191831161037f5768010000000000000000831161037f578154838355808410610359575b50905f5260205f205f5b83811061033c57846001600160a01b038116610323575061031261054b565b505b60405161335e90816105ce8239f35b8061033061033692610455565b506104cb565b50610314565b82516001600160a01b0316818301556020909201916001016102f3565b825f528360205f2091820191015b81811061037457506102e9565b5f8155600101610367565b634e487b7160e01b5f52604160045260245ffd5b63339e1ffb60e01b5f5260045ffd5b83638c0b052760e01b5f5260045260245ffd5b6359d119e360e01b5f5260045ffd5b602080916103d184610405565b8152019101906100b0565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761037f57604052565b51906001600160a01b03821682036103dc57565b51906001600160401b03821682036103dc57565b80518210156104415760209160051b010190565b634e487b7160e01b5f52603260045260245ffd5b6001600160a01b0381165f9081525f5160206139ac5f395f51905f52602052604090205460ff166104c6576001600160a01b03165f8181525f5160206139ac5f395f51905f5260205260408120805460ff191660011790553391905f51602061392c5f395f51905f528180a4600190565b505f90565b6001600160a01b0381165f9081525f51602061394c5f395f51905f52602052604090205460ff166104c6576001600160a01b03165f8181525f51602061394c5f395f51905f5260205260408120805460ff191660011790553391905f51602061398c5f395f51905f52905f51602061392c5f395f51905f529080a4600190565b5f80525f51602061394c5f395f51905f526020525f51602061396c5f395f51905f525460ff166105c9575f8080525f51602061394c5f395f51905f526020525f51602061396c5f395f51905f52805460ff1916600117905533905f51602061398c5f395f51905f525f51602061392c5f395f51905f528280a4600190565b5f9056fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146108ea575080630bece35614610833578063248a9ca3146108015780632f2ff15d146107d257806336568abe146107765780634d6d9ffb146106015780635972185a146105c7578063682ed5f0146102f157806391d14854146102a8578063a217fddf1461028e578063d547741f14610258578063ddba6537146101c1578063edce8bdc146101475763ef913a4b146100b6575f80fd5b34610143575f6003193601126101435761013f60405173ffffffffffffffffffffffffffffffffffffffff60015416602082015267ffffffffffffffff600254818116604084015260401c16606082015267ffffffffffffffff600354818116608084015260401c1660a082015260a0815261013360c082610a4b565b60405191829182610a21565b0390f35b5f80fd5b346101435760206003193601126101435760043567ffffffffffffffff811681036101435761017861013f91611ee4565b61013367ffffffffffffffff8254166101b3600184015493604051948593602085015260408401526060808401526002608084019101611c68565b03601f198101835282610a4b565b34610143576101cf36610988565b50505f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06020527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475460ff161561024b575b7f2c1ed462000000000000000000000000000000000000000000000000000000005f5260045ffd5b610253611cb5565b610223565b346101435761028c610269366109d9565b90610287610282825f525f602052600160405f20015490565b611d3d565b6120e9565b005b34610143575f6003193601126101435760206040515f8152f35b34610143576102b6366109d9565b905f525f60205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060ff60405f2054166040519015158152f35b346101435760206003193601126101435760043567ffffffffffffffff8111610143578060040160a06003198336030112610143575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06020527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475460ff16156105ba575b61038c61038760248401611bae565b611da3565b6064820191600161039d8484611bc3565b90500361057e57608481019060206103b58385611c17565b905003610542576103d36103ce60446103da9301611bae565b611ee4565b9383611bc3565b91909115610515576104396104326103fe6103f785602096611c17565b3691610ab7565b602081519101205f527f1260944489272988d9df285149b5aa1b0f48f2136d6f416159f840a3e074760060205260405f2090565b9184611c17565b9080939181010312610143576104576103f761048093359480611c17565b906001850154906040516020810191825260208152610477604082610a4b565b519020916121b1565b90156104e5578060206104999201905160801b1761229e565b908082036104b757602067ffffffffffffffff845416604051908152f35b7f56ed1b63000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b507f56ed1b63000000000000000000000000000000000000000000000000000000005f526004525f60245260445ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5061054c91611c17565b90507f24fadac8000000000000000000000000000000000000000000000000000000005f52602060045260245260445ffd5b6105888383611bc3565b90507f88b3170e000000000000000000000000000000000000000000000000000000005f52600160045260245260445ffd5b6105c2611cb5565b610378565b34610143575f6003193601126101435760206040517fbd893629a699470e4ec82a5715bb4981fdaacc5d0a728bf5f55b801d8f4ef10b8152f35b346101435760206003193601126101435760043567ffffffffffffffff8111610143578060040160806003198336030112610143575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06020527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475460ff1615610769575b61069761038760248401611bae565b606482019160016106a88484611bc3565b90500361057e576106c16103ce60446106c89301611bae565b9282611bc3565b91909115610515576106f06103f76106e96103fe6103f78661071097611c17565b9280611c17565b906001840154906040516020810191825260208152610477604082610a4b565b9061072b57602067ffffffffffffffff835416604051908152f35b80602061073e9201905160801b1761229e565b7fd039601e000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b610771611cb5565b610688565b3461014357610784366109d9565b3373ffffffffffffffffffffffffffffffffffffffff8216036107aa5761028c916120e9565b7f6697b232000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101435761028c6107e3366109d9565b906107fc610282825f525f602052600160405f20015490565b61201d565b3461014357602060031936011261014357602061082b6004355f525f602052600160405f20015490565b604051908152f35b346101435761089d61084436610988565b5f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06020527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475490919060ff16156108dd57610b45565b60405160038210156108b0576020918152f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b6108e5611cb5565b610b45565b3461014357602060031936011261014357600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361014357817f7965db0b000000000000000000000000000000000000000000000000000000006020931490811561095e575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483610957565b9060206003198301126101435760043567ffffffffffffffff811161014357826023820112156101435780600401359267ffffffffffffffff84116101435760248483010111610143576024019190565b6003196040910112610143576004359060243573ffffffffffffffffffffffffffffffffffffffff811681036101435790565b359067ffffffffffffffff8216820361014357565b601f19601f602060409481855280519182918282880152018686015e5f8582860101520116010190565b90601f601f19910116810190811067ffffffffffffffff821117610a6e57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b67ffffffffffffffff8111610a6e57601f01601f191660200190565b929192610ac382610a9b565b91610ad16040519384610a4b565b829481845281830111610143578281602093845f960137010152565b9080601f8301121561014357816020610b0893359101610ab7565b90565b91908201809211610b1857565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b908101906020818303126101435780359067ffffffffffffffff8211610143570190818103916080831261014357604051926060840184811067ffffffffffffffff821117610a6e57604052813567ffffffffffffffff811161014357604091610bb485601f19938601610aed565b8652011261014357604051916040830183811067ffffffffffffffff821117610a6e57604052610be660208301610a0c565b8352610bf460408301610a0c565b602084015260208401928352606082013567ffffffffffffffff811161014357610c1e9201610aed565b9160408101928352610c3b67ffffffffffffffff83515116611da3565b51926040519360e0850185811067ffffffffffffffff821117610a6e5760405260608552602085019060608252604086015f815260608701965f885260808101915f835260a082019860608a52610ca360c08401956060875260208101905160801b17612388565b80845251600f8110611b8357507f1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347610ce4610cde8551611de0565b51612262565b03611b4b576001610cfe610cf88551611df0565b5161229e565b03611b13577f63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365610d31610cde8551611e01565b03611adb5782518051600e1015610515576101e0610d5091015161235d565b80516008811490811591611aab575b50611a715750825180516008101561051557610120610d7f91015161229e565b80158015611a60575b61194c5767ffffffffffffffff168252610da5610cde8451611e12565b815282518051600b101561051557610180610dc191015161229e565b80158015611a4f575b611a245767ffffffffffffffff16845282518051600c101561051557610df76101a0610e0692015161235d565b60208101905160801b17612388565b80875251600581036119f95750610e26610e208751611e22565b5161235d565b51602081036119ce5750610e43610e3d8751611de0565b51612388565b978851156119a657610e558951611e6b565b8b525f5b8951811015610fc757610e6f610e20828c611e3f565b805160148103610f9c5750602081519101517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000081169160148110610f67575b505060601c8015610f3c57908c915f5b828110610eda5750610ed38260019451611e3f565b5201610e59565b9073ffffffffffffffffffffffffffffffffffffffff610efd8383959651611e3f565b511614610f10578d929190600101610ebe565b507f41fe18cc000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f59bff387000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009250829060140360031b1b16165f80610eae565b7f83e46ad2000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b509194975092959891949788518051600410156105155760a0610feb910151612388565b99610ff68b51611e9c565b89525f5b8b51811015611032578061102b816110188f600195610e2091611e3f565b8d51906110258383611e3f565b52611e3f565b5001610ffa565b509194979396995091949760035467ffffffffffffffff8160401c166110588142610b0b565b67ffffffffffffffff8d511680911061197457505061108567ffffffffffffffff60208851015116611ee4565b9567ffffffffffffffff6020818c51169251015116101561194c5767ffffffffffffffff168015158061192e575b6118f057506040519060a06110c88184610a4b565b60048352601f19015f5b8181106118df575050906111556110f3836110f96110f361116e9651611e22565b51612fcc565b61110285611e22565b5261110c84611e22565b5061111a6110f38251611de0565b61112385611de0565b5261112d84611de0565b5061113b6110f38251611e2f565b61114485611e2f565b5261114e84611e2f565b5051611e12565b61115e82611e12565b5261116881611e12565b50612442565b9861117a895151611e9c565b975f5b8a5180518210156112f057600c82036112db57508b80516001811490816112c1575b50156111f1579060206111d5816001946040519381859251918291018484015e81015f838201520301601f198101835282610a4b565b6111df828d611e3f565b526111ea818c611e3f565b500161117d565b508b51908c603783116112275760218360019460206040519487830186526080830182870153018385015e8201016040526111d5565b506fffffffffffffffffffffffffffffffff821160071b67ffffffffffffffff83821c1160061b1763ffffffff83821c1160051b1761ffff83821c1160041b1760ff83821c119060031c17916001830190818411610b185760018f92602192829660226020604051978484810196600288018b5260b88601848c015360031b610100031b888a015201918701015e830101016040526111d5565b91505015610515578b6080602082015160f81c105f61119f565b906112eb6110f382600194611e3f565b6111d5565b505093979094985061130791959950959195612442565b6020815191012095519461131b8651611e6b565b985f5b87518110156114ed576113318189611e3f565b518051604181036114c25750805160401015610515576060810190601b825160f81c1061146b575b61136491508a61302b565b9060048110156108b0571590811591611461575b508015611443575b61141b578b919073ffffffffffffffffffffffffffffffffffffffff165f5b8281106113ba57506113b382600194611e3f565b520161131e565b9073ffffffffffffffffffffffffffffffffffffffff6113dc83839596611e3f565b5116146113ef578c92919060010161139f565b507f33af0d5f000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f09cb44e6000000000000000000000000000000000000000000000000000000005f5260045ffd5b5073ffffffffffffffffffffffffffffffffffffffff811615611380565b905015155f611378565b80516040101561051557601b825160f81c019160ff8311610b1857815160401015610515577fff000000000000000000000000000000000000000000000000000000000000006113649360f81b165f1a9053611359565b7ff2db9ce1000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5092965092966002919498955001965f955f5b86518110156115545761153373ffffffffffffffffffffffffffffffffffffffff61152b838a611e3f565b51168b612595565b611540575b600101611500565b9661154c600191611f3b565b979050611538565b509296919590939760039054049060018201809211610b18578181106118b15750508451945f975f5b86518110156115d1576115b073ffffffffffffffffffffffffffffffffffffffff6115a8838a611e3f565b5116896125f4565b6115bd575b60010161157d565b986115c9600191611f3b565b9990506115b5565b50939791956115ea919550969296516003810490611f49565b9081811061188357505061163f90600154925190519060405160208101907fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008660601b16825260148152610477603482610a4b565b9190156118415750610cde6116608260206116659401905160801b17612388565b611e2f565b67ffffffffffffffff8451165f52600460205260405f2067ffffffffffffffff8154166117e857509060029167ffffffffffffffff8551165f52600460205267ffffffffffffffff60405f209451167fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000855416178455600184015551910181519167ffffffffffffffff8311610a6e57680100000000000000008311610a6e5781548383558084106117c2575b50602001905f5260205f205f5b8381106117985750505050516002549067ffffffffffffffff8260401c1667ffffffffffffffff821611611754575b50505f90565b6fffffffffffffffff00000000000000007fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff9160401b169116176002555f8061174e565b600190602073ffffffffffffffffffffffffffffffffffffffff855116940193818401550161171f565b825f528360205f2091820191015b8181106117dd5750611712565b5f81556001016117d0565b9167ffffffffffffffff611800945116905192611f56565b61183b5767ffffffffffffffff9051167fc1aea5f7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50600290565b73ffffffffffffffffffffffffffffffffffffffff907fa700fc32000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b7f7818f4e4000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fe2dcb1b9000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b8060606020809387010152016110d2565b67ffffffffffffffff8654167feae35725000000000000000000000000000000000000000000000000000000005f526004524260245260445260645ffd5b50426119458267ffffffffffffffff895416610b0b565b11156110b3565b7f59d119e3000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f9b772277000000000000000000000000000000000000000000000000000000005f524260045260245260445260645ffd5b7f339e1ffb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fe7719a54000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f30c6792a000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f8c0b0527000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5067ffffffffffffffff8111610dca565b5067ffffffffffffffff8111610d88565b611aa7906040519182917fd5edd2a500000000000000000000000000000000000000000000000000000000835260048301610a21565b0390fd5b7f011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce9150602083012014155f610d5f565b611ae8610cde8451611e01565b7fa19e609c000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b611b20610cf88451611df0565b7ff71b722f000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b611b58610cde8451611de0565b7fb8120dca000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fbc277732000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b3567ffffffffffffffff811681036101435790565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610143570180359067ffffffffffffffff821161014357602001918160051b3603831361014357565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610143570180359067ffffffffffffffff82116101435760200191813603831361014357565b90602082549182815201915f5260205f20905f5b818110611c895750505090565b825473ffffffffffffffffffffffffffffffffffffffff16845260209093019260019283019201611c7c565b335f9081527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e0602052604090205460ff1615611ced57565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f52336004527fbd893629a699470e4ec82a5715bb4981fdaacc5d0a728bf5f55b801d8f4ef10b60245260445ffd5b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260ff60405f20541615611d745750565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b67ffffffffffffffff1680611db55750565b7f3ce598a9000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b8051600110156105155760400190565b805160071015610515576101000190565b8051600d1015610515576101c00190565b8051600310156105155760800190565b8051156105155760200190565b8051600210156105155760600190565b80518210156105155760209160051b010190565b67ffffffffffffffff8111610a6e5760051b60200190565b90611e7582611e53565b611e826040519182610a4b565b828152601f19611e928294611e53565b0190602036910137565b90611ea682611e53565b611eb36040519182610a4b565b828152601f19611ec38294611e53565b01905f5b828110611ed357505050565b806060602080938501015201611ec7565b67ffffffffffffffff1690815f52600460205260405f209167ffffffffffffffff83541615611f105750565b7ff761631b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f198114610b185760010190565b91908203918211610b1857565b919067ffffffffffffffff808454169116149081159161200e575b5061174e57604051611f96816101b36020820194602086526002604084019101611c68565b5190209060405160208101918160408101916020855280518093526020606083019101925f5b818110611fdf575050611fd8925003601f198101835282610a4b565b5190201490565b845173ffffffffffffffffffffffffffffffffffffffff16835260209485019486945090920191600101611fbc565b9050600182015414155f611f71565b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f205416155f1461174e57805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905573ffffffffffffffffffffffffffffffffffffffff339216907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d5f80a4600190565b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f2054165f1461174e57805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815416905573ffffffffffffffffffffffffffffffffffffffff339216907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b5f80a4600190565b6121d09092919260405192602084015260208352610df7604084610a4b565b926121db8451611e9c565b915f5b855181101561221357806121f76110f360019389611e3f565b6122018287611e3f565b5261220c8186611e3f565b50016121de565b50909350612220926126d8565b8190600e8110156108b05780612237575051151591565b7f1121c9d0000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b60218160801c0361227657610b089061229e565b7ff3dd7004000000000000000000000000000000000000000000000000000000005f5260045ffd5b8060801c9060218211612276576122b481612cda565b60028195929510156108b05761227657836122d157505050505f90565b816020019081602011610b185782036020019081111502601f811161234b575f196fffffffffffffffffffffffffffffffff9160031b1b9216015116907f1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103610b185760031b610100036101008111610b18571c90565b634e487b715f5260326020526024601cfd5b61236681612cda565b60028194939410156108b05761227657610b089261238392612f95565b612fcc565b908160801c9161239781612cda565b60028194939410156108b057600114908161242f575b501561227657926040519360208501925b8281106123d957505050601f198382030160051c8352604052565b92612419846123f56123f085969761241396612ff9565b612cda565b5061240d6124068383989498610b0b565b8489612f95565b95610b0b565b90610b0b565b91815260208101809111610b18579291906123be565b61243a915083610b0b565b84145f6123ad565b905f805b835182101561246f5761246760019161245f8487611e3f565b515190610b0b565b910190612446565b91905061249461247e83610a9b565b9261248c6040519485610a4b565b808452610a9b565b91601f196020820193013684375f9160205b85518410156124d1576001906124bc8588611e3f565b518051602082018387015e51019301926124a6565b50905190935090506037811161250557806021916040519360018201855260c0820160208601538385015e82010160405290565b6fffffffffffffffffffffffffffffffff811160071b67ffffffffffffffff82821c1160061b1763ffffffff82821c1160051b1761ffff82821c1160041b1760ff82821c119060031c179160018301808411610b18576021926001926022604051968381810195600287018a5260f8830160208b015360031b610100031b878901528701015e8301010160405290565b905f5b82548110156125ed57825f5273ffffffffffffffffffffffffffffffffffffffff8160205f2001541673ffffffffffffffffffffffffffffffffffffffff8316146125e557600101612598565b505050600190565b5050505f90565b905f5b82518110156125ed5773ffffffffffffffffffffffffffffffffffffffff61261f8285611e3f565b511673ffffffffffffffffffffffffffffffffffffffff8316146125e5576001016125f7565b60ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff409116019060ff8211610b1857565b60ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc99116019060ff8211610b1857565b60ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff809116019060ff8211610b1857565b9092916060935f94815115612ccf5750815115612c93576126fb90949294613065565b6040515f9391908480805b8651881015612c81576127198888611e3f565b519183612bda575050888151602083012003612bc95761274790989392919860208101905160801b17612388565b975b885160110361291157825181036127ac575050505084516010101561277f575061022061277b939401519051906131e8565b9091565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526032600452fd5b9091929783518210156128e4576127cd906020838601015160f81c90611e3f565b5160018160801c1480612891575b612880576127e88161321f565b928391906001810180911161285357936020148015612837575b61281b57505061281190612388565b975b929190612749565b929394999150966001905b856040520196989392919098612706565b5060018901808a116128535761284e90898561324d565b612802565b6024887f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b505050505061277b9293505161318a565b507f80000000000000000000000000000000000000000000000000000000000000007fff000000000000000000000000000000000000000000000000000000000000006128dd83612f25565b16146127db565b6024857f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b9091929760028151145f14612bb85761293461292f610e2083611e22565b613065565b90815115612ba65760208201805160f81c9060038211612b92576129618560208901895160801b17612ff9565b935160801b176001821660020360ff8111612b65579060ff612984921690612ff9565b908160801c938060801c92838611918215612ab1575b5050612a9d57600110612a2f57508115612a1d57906129bc6129d49392611de0565b519160206129c98461321f565b959093869493610b0b565b94148015612a01575b6129f25750506129ec90612388565b97612813565b92939499915096600190612826565b5060018901808a1161285357612a1890898561324d565b6129dd565b50505050505050509050606090600790565b94509850915050145f14612a545750612a4b61277b9394611de0565b519051906131aa565b935090612a61915161318a565b92600e841015612a7057509190565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526021600452fd5b505050505050505061277b9293505161318a565b91909980612b38575061234b576fffffffffffffffffffffffffffffffff612b309116985f997fffffffffffffffffffffffffffffffff000000000000000000000000000000008216176fffffffffffffffffffffffffffffffff8160801c911620906fffffffffffffffffffffffffffffffff8160801c9116201490565b155f8061299a565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526011600452fd5b6024897f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b505050505050505050509050606090600b90565b50505050505050509050606090600590565b505050505050509050606090600c90565b505050505050509050606090600290565b82519160208310908382612c2c57506020148015939150612c1c575b5050612c0b57612747905b9893929198610df7565b505050505050509050606090600390565b6020840120141590505f80612bf6565b1492831593612c57575b505050612c465761274790612c01565b505050505050509050606090600490565b602085015192935090612c70575b5014155f8080612c36565b5f199060200360031b1b165f612c65565b50505050505050509050606090600d90565b50507f56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421919250145f14612cc7576060905f90565b606090600d90565b945060019392505050565b908160801c91821561227657612cef81612f25565b60f81c60c0811015612e54576080811015612d1057505f9250600191839150565b60b78111612da657612d2360ff916126a7565b168093119081612d3c575b501561227657600191905f90565b6001841480159250612d50575b505f612d2e565b7f80000000000000000000000000000000000000000000000000000000000000009150612d9d7fff0000000000000000000000000000000000000000000000000000000000000091612f5b565b1610155f612d49565b612db2612db7916126a7565b612676565b612dc460ff821692612f5b565b9082851180612e29575b156122765760ff81168303610b18576107f89060031b16610100036101008111610b18571c92603784119081612e16575b50156122765760018101809111610b185791905f90565b9050612e228483610b0b565b105f612dff565b507fff0000000000000000000000000000000000000000000000000000000000000082161515612dce565b9060f78211612e7a5750612e6960ff91612645565b168092111561227657600191908290565b90612db2612e8791612645565b612e9460ff821692612f5b565b9082851180612efa575b156122765760ff81168303610b18576107f89060031b16610100036101008111610b18571c92603784119081612ee7575b50156122765760018101809111610b18579190600190565b9050612ef38483610b0b565b105f612ecf565b507fff0000000000000000000000000000000000000000000000000000000000000082161515612e9e565b60208160801c5f0301602081111502601f811161234b575f196fffffffffffffffffffffffffffffffff9160031b1b9116511690565b60208160801c60010301602181111502601f811161234b576fffffffffffffffffffffffffffffffff5f1960019260031b1b921601511690565b90612fa08382610b0b565b8260801c1061234b576fffffffffffffffffffffffffffffffff612fc49216610b0b565b9060801b1790565b9060208260801c806fffffffffffffffffffffffffffffffff60405195828752168386015e830101604052565b908160801c9081811161234b576fffffffffffffffffffffffffffffffff61302482612fc494611f49565b9316610b0b565b815191906041830361305b576130549250602082015190606060408401519301515f1a906132b7565b9192909190565b50505f9160029190565b908151604051928160011b60208186010160405284525f5b82811061308957505050565b806020601092840101518060801c9060401c73ffffffff0000000000000000000000000000000073ffffffff000000000000000000000000ffffffff7bffffffff000000000000000000000000ffffffff00000000000000008477ffffffffffffffffffffffffffffffff000000000000000085161760201b1693169116171780831b177cff000000ff000000ff000000ff000000ff000000ff000000ff000000ff7eff000000ff000000ff000000ff000000ff000000ff000000ff000000ff00008260081b169116178060041b177f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f1660208260011b880101520161307d565b905f198201918211610b1857036131a2576060905f90565b606090600890565b909291925f935f198201918211610b1857036131de576131c99061235d565b8051156131d4579190565b5060609150600990565b5060609150600890565b915f198201918211610b185703613216576132029061235d565b80511561320e57905f90565b506060905f90565b50606090600890565b908160801c91602183105f1461323c5761323890612f25565b9190565b61324791925061229e565b90602090565b9091825181109283613260575b50505090565b6132af93509061326f91611e3f565b5160208101905160801b176fffffffffffffffffffffffffffffffff8160801c911620906fffffffffffffffffffffffffffffffff8160801c9116201490565b5f808061325a565b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411613346579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa1561333b575f5173ffffffffffffffffffffffffffffffffffffffff81161561333157905f905f90565b505f906001905f90565b6040513d5f823e3d90fd5b5050505f916003919056fea164736f6c634300081c000a2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac47bd893629a699470e4ec82a5715bb4981fdaacc5d0a728bf5f55b801d8f4ef10bad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5"}} diff --git a/ibc-solidity/abi/bytecode/BesuQBFTLightClient.json b/ibc-solidity/abi/bytecode/BesuQBFTLightClient.json new file mode 100644 index 000000000..b180fd124 --- /dev/null +++ b/ibc-solidity/abi/bytecode/BesuQBFTLightClient.json @@ -0,0 +1 @@ +{"abi":[{"type":"constructor","inputs":[{"name":"ibcRouter","type":"address","internalType":"address"},{"name":"initialTrustedHeight","type":"uint64","internalType":"uint64"},{"name":"initialTrustedTimestamp","type":"uint64","internalType":"uint64"},{"name":"initialTrustedStorageRoot","type":"bytes32","internalType":"bytes32"},{"name":"initialTrustedValidators","type":"address[]","internalType":"address[]"},{"name":"trustingPeriod","type":"uint64","internalType":"uint64"},{"name":"maxClockDrift","type":"uint64","internalType":"uint64"},{"name":"roleManager","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"type":"function","name":"DEFAULT_ADMIN_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"PROOF_SUBMITTER_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"getClientState","inputs":[],"outputs":[{"name":"","type":"bytes","internalType":"bytes"}],"stateMutability":"view"},{"type":"function","name":"getConsensusState","inputs":[{"name":"revisionHeight","type":"uint64","internalType":"uint64"}],"outputs":[{"name":"","type":"bytes","internalType":"bytes"}],"stateMutability":"view"},{"type":"function","name":"getRoleAdmin","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"grantRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"hasRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"misbehaviour","inputs":[{"name":"","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"view"},{"type":"function","name":"renounceRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"callerConfirmation","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"revokeRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"supportsInterface","inputs":[{"name":"interfaceId","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"updateClient","inputs":[{"name":"updateMsg","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"","type":"uint8","internalType":"enum ILightClientMsgs.UpdateResult"}],"stateMutability":"nonpayable"},{"type":"function","name":"verifyMembership","inputs":[{"name":"msg_","type":"tuple","internalType":"struct ILightClientMsgs.MsgVerifyMembership","components":[{"name":"proof","type":"bytes","internalType":"bytes"},{"name":"proofHeight","type":"tuple","internalType":"struct IICS02ClientMsgs.Height","components":[{"name":"revisionNumber","type":"uint64","internalType":"uint64"},{"name":"revisionHeight","type":"uint64","internalType":"uint64"}]},{"name":"path","type":"bytes[]","internalType":"bytes[]"},{"name":"value","type":"bytes","internalType":"bytes"}]}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"verifyNonMembership","inputs":[{"name":"msg_","type":"tuple","internalType":"struct ILightClientMsgs.MsgVerifyNonMembership","components":[{"name":"proof","type":"bytes","internalType":"bytes"},{"name":"proofHeight","type":"tuple","internalType":"struct IICS02ClientMsgs.Height","components":[{"name":"revisionNumber","type":"uint64","internalType":"uint64"},{"name":"revisionHeight","type":"uint64","internalType":"uint64"}]},{"name":"path","type":"bytes[]","internalType":"bytes[]"}]}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"event","name":"RoleAdminChanged","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"previousAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"newAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"error","name":"AccessControlBadConfirmation","inputs":[]},{"type":"error","name":"AccessControlUnauthorizedAccount","inputs":[{"name":"account","type":"address","internalType":"address"},{"name":"neededRole","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"AccountNotFound","inputs":[{"name":"account","type":"address","internalType":"address"}]},{"type":"error","name":"ConflictingConsensusState","inputs":[{"name":"revisionHeight","type":"uint64","internalType":"uint64"}]},{"type":"error","name":"ConsensusStateExpired","inputs":[{"name":"trustedTimestamp","type":"uint64","internalType":"uint64"},{"name":"currentTimestamp","type":"uint256","internalType":"uint256"},{"name":"trustingPeriod","type":"uint64","internalType":"uint64"}]},{"type":"error","name":"ConsensusStateNotFound","inputs":[{"name":"revisionHeight","type":"uint64","internalType":"uint64"}]},{"type":"error","name":"DuplicateCommitSealSigner","inputs":[{"name":"signer","type":"address","internalType":"address"}]},{"type":"error","name":"DuplicateValidator","inputs":[{"name":"validator","type":"address","internalType":"address"}]},{"type":"error","name":"EmptyValidatorSet","inputs":[]},{"type":"error","name":"HeaderFromFuture","inputs":[{"name":"currentTimestamp","type":"uint256","internalType":"uint256"},{"name":"headerTimestamp","type":"uint256","internalType":"uint256"},{"name":"maxClockDrift","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InsufficientTrustedValidatorOverlap","inputs":[{"name":"actual","type":"uint256","internalType":"uint256"},{"name":"required","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InsufficientValidatorQuorum","inputs":[{"name":"actual","type":"uint256","internalType":"uint256"},{"name":"required","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InvalidCommitSeal","inputs":[]},{"type":"error","name":"InvalidCommitmentValue","inputs":[{"name":"expectedValue","type":"bytes32","internalType":"bytes32"},{"name":"actualValue","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"InvalidDifficulty","inputs":[{"name":"actualDifficulty","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InvalidECDSASignatureLength","inputs":[{"name":"length","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InvalidExtraDataFormat","inputs":[{"name":"itemsLength","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InvalidHeaderFormat","inputs":[{"name":"itemsLength","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InvalidHeaderHeight","inputs":[]},{"type":"error","name":"InvalidHeaderTimestamp","inputs":[{"name":"actualTimestamp","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InvalidMixHash","inputs":[{"name":"actualMixHash","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"InvalidNonce","inputs":[{"name":"actualNonce","type":"bytes","internalType":"bytes"}]},{"type":"error","name":"InvalidOmmersHash","inputs":[{"name":"actualOmmersHash","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"InvalidPathLength","inputs":[{"name":"expectedLength","type":"uint256","internalType":"uint256"},{"name":"actualLength","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InvalidRevisionNumber","inputs":[{"name":"providedRevisionNumber","type":"uint64","internalType":"uint64"}]},{"type":"error","name":"InvalidValidatorAddress","inputs":[{"name":"validator","type":"address","internalType":"address"}]},{"type":"error","name":"InvalidValidatorAddressLength","inputs":[{"name":"length","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InvalidValueLength","inputs":[{"name":"expectedLength","type":"uint256","internalType":"uint256"},{"name":"actualLength","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"InvalidVanityDataLength","inputs":[{"name":"length","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"RLPInvalidEncoding","inputs":[]},{"type":"error","name":"TrieProofTraversalError","inputs":[{"name":"err","type":"uint8","internalType":"enum MPTProof.ProofError"}]},{"type":"error","name":"UnsupportedMisbehaviour","inputs":[]},{"type":"error","name":"ValueExists","inputs":[{"name":"actualValue","type":"bytes32","internalType":"bytes32"}]}],"bytecode":{"object":"0x6080604052346103dc57613a3180380380610019816103e0565b928339810190610100818303126103dc5761003381610405565b9061004060208201610419565b9061004d60408201610419565b92606082015191608081015160018060401b0381116103dc5781019286601f850112156103dc578351966001600160401b03881161037f578760051b9460206100978188016103e0565b809a81520190602082978201019283116103dc57602001905b8282106103c4575050506100c660a08301610419565b956100df60e06100d860c08601610419565b9401610405565b956001600160401b03169081156103b5576001600160401b03169283156103a257885115610393575f5b89518110156101bf576001600160a01b03610124828c61042d565b511615610198575f5b81811061013d5750600101610109565b6001600160a01b0361014f828d61042d565b51166001600160a01b03610163848e61042d565b5116146101725760010161012d565b6001600160a01b03610184838d61042d565b511663107f863360e21b5f5260045260245ffd5b6001600160a01b03906101ab908b61042d565b51166359bff38760e01b5f5260045260245ffd5b5060408051979896978a979181016001600160401b0381118282101761037f576040525f81526020810190848252604051926080840198848a1060018060401b038b111761037f576040998a526001600160a01b031680855260208086018490526001600160401b03928316868c01819052878416606090970196909652600180546001600160a01b031916909217825592516002805495516fffffffffffffffff0000000000000000908d1b81169285166001600160801b03199788161792909217815560038054988d1b90921697909516909517959095179093555f948552600490529590922080546001600160401b031916949094178455830191909155925193910191831161037f5768010000000000000000831161037f578154838355808410610359575b50905f5260205f205f5b83811061033c57846001600160a01b038116610323575061031261054b565b505b6040516133c390816105ce8239f35b8061033061033692610455565b506104cb565b50610314565b82516001600160a01b0316818301556020909201916001016102f3565b825f528360205f2091820191015b81811061037457506102e9565b5f8155600101610367565b634e487b7160e01b5f52604160045260245ffd5b63339e1ffb60e01b5f5260045ffd5b83638c0b052760e01b5f5260045260245ffd5b6359d119e360e01b5f5260045ffd5b602080916103d184610405565b8152019101906100b0565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761037f57604052565b51906001600160a01b03821682036103dc57565b51906001600160401b03821682036103dc57565b80518210156104415760209160051b010190565b634e487b7160e01b5f52603260045260245ffd5b6001600160a01b0381165f9081525f516020613a115f395f51905f52602052604090205460ff166104c6576001600160a01b03165f8181525f516020613a115f395f51905f5260205260408120805460ff191660011790553391905f5160206139915f395f51905f528180a4600190565b505f90565b6001600160a01b0381165f9081525f5160206139b15f395f51905f52602052604090205460ff166104c6576001600160a01b03165f8181525f5160206139b15f395f51905f5260205260408120805460ff191660011790553391905f5160206139f15f395f51905f52905f5160206139915f395f51905f529080a4600190565b5f80525f5160206139b15f395f51905f526020525f5160206139d15f395f51905f525460ff166105c9575f8080525f5160206139b15f395f51905f526020525f5160206139d15f395f51905f52805460ff1916600117905533905f5160206139f15f395f51905f525f5160206139915f395f51905f528280a4600190565b5f9056fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146108ea575080630bece35614610833578063248a9ca3146108015780632f2ff15d146107d257806336568abe146107765780634d6d9ffb146106015780635972185a146105c7578063682ed5f0146102f157806391d14854146102a8578063a217fddf1461028e578063d547741f14610258578063ddba6537146101c1578063edce8bdc146101475763ef913a4b146100b6575f80fd5b34610143575f6003193601126101435761013f60405173ffffffffffffffffffffffffffffffffffffffff60015416602082015267ffffffffffffffff600254818116604084015260401c16606082015267ffffffffffffffff600354818116608084015260401c1660a082015260a0815261013360c082610a4b565b60405191829182610a21565b0390f35b5f80fd5b346101435760206003193601126101435760043567ffffffffffffffff811681036101435761017861013f91611f4a565b61013367ffffffffffffffff8254166101b3600184015493604051948593602085015260408401526060808401526002608084019101611cbe565b03601f198101835282610a4b565b34610143576101cf36610988565b50505f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06020527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475460ff161561024b575b7f2c1ed462000000000000000000000000000000000000000000000000000000005f5260045ffd5b610253611d0b565b610223565b346101435761028c610269366109d9565b90610287610282825f525f602052600160405f20015490565b611d93565b612155565b005b34610143575f6003193601126101435760206040515f8152f35b34610143576102b6366109d9565b905f525f60205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060ff60405f2054166040519015158152f35b346101435760206003193601126101435760043567ffffffffffffffff8111610143578060040160a06003198336030112610143575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06020527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475460ff16156105ba575b61038c61038760248401611c04565b611df9565b6064820191600161039d8484611c19565b90500361057e57608481019060206103b58385611c6d565b905003610542576103d36103ce60446103da9301611c04565b611f4a565b9383611c19565b91909115610515576104396104326103fe6103f785602096611c6d565b3691610ab7565b602081519101205f527f1260944489272988d9df285149b5aa1b0f48f2136d6f416159f840a3e074760060205260405f2090565b9184611c6d565b9080939181010312610143576104576103f761048093359480611c6d565b906001850154906040516020810191825260208152610477604082610a4b565b5190209161221d565b90156104e5578060206104999201905160801b1761230a565b908082036104b757602067ffffffffffffffff845416604051908152f35b7f56ed1b63000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b507f56ed1b63000000000000000000000000000000000000000000000000000000005f526004525f60245260445ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5061054c91611c6d565b90507f24fadac8000000000000000000000000000000000000000000000000000000005f52602060045260245260445ffd5b6105888383611c19565b90507f88b3170e000000000000000000000000000000000000000000000000000000005f52600160045260245260445ffd5b6105c2611d0b565b610378565b34610143575f6003193601126101435760206040517fbd893629a699470e4ec82a5715bb4981fdaacc5d0a728bf5f55b801d8f4ef10b8152f35b346101435760206003193601126101435760043567ffffffffffffffff8111610143578060040160806003198336030112610143575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06020527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475460ff1615610769575b61069761038760248401611c04565b606482019160016106a88484611c19565b90500361057e576106c16103ce60446106c89301611c04565b9282611c19565b91909115610515576106f06103f76106e96103fe6103f78661071097611c6d565b9280611c6d565b906001840154906040516020810191825260208152610477604082610a4b565b9061072b57602067ffffffffffffffff835416604051908152f35b80602061073e9201905160801b1761230a565b7fd039601e000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b610771611d0b565b610688565b3461014357610784366109d9565b3373ffffffffffffffffffffffffffffffffffffffff8216036107aa5761028c91612155565b7f6697b232000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101435761028c6107e3366109d9565b906107fc610282825f525f602052600160405f20015490565b612089565b3461014357602060031936011261014357602061082b6004355f525f602052600160405f20015490565b604051908152f35b346101435761089d61084436610988565b5f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06020527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475490919060ff16156108dd57610b45565b60405160038210156108b0576020918152f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b6108e5611d0b565b610b45565b3461014357602060031936011261014357600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361014357817f7965db0b000000000000000000000000000000000000000000000000000000006020931490811561095e575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483610957565b9060206003198301126101435760043567ffffffffffffffff811161014357826023820112156101435780600401359267ffffffffffffffff84116101435760248483010111610143576024019190565b6003196040910112610143576004359060243573ffffffffffffffffffffffffffffffffffffffff811681036101435790565b359067ffffffffffffffff8216820361014357565b601f19601f602060409481855280519182918282880152018686015e5f8582860101520116010190565b90601f601f19910116810190811067ffffffffffffffff821117610a6e57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b67ffffffffffffffff8111610a6e57601f01601f191660200190565b929192610ac382610a9b565b91610ad16040519384610a4b565b829481845281830111610143578281602093845f960137010152565b9080601f8301121561014357816020610b0893359101610ab7565b90565b91908201809211610b1857565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b908101906020818303126101435780359067ffffffffffffffff8211610143570191828203926080841261014357604051936060850185811067ffffffffffffffff821117610a6e57604052813567ffffffffffffffff811161014357604091610bb486601f19938601610aed565b8752011261014357604051926040840184811067ffffffffffffffff821117610a6e57604052610be660208301610a0c565b8452610bf460408301610a0c565b602085015260208501938452606082013567ffffffffffffffff811161014357610c1e9201610aed565b9260408101938452610c3b67ffffffffffffffff84515116611df9565b5160405160e0810181811067ffffffffffffffff821117610a6e576040526060815260208101906060825260408101905f825260608101915f835260808201935f855260a083019860608a52610ca260c08501976060895260208101905160801b176123f4565b80855251600f8110611bd957507f1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347610ce3610cdd8651611e36565b516122ce565b03611ba1576001610cfd610cf78651611e46565b5161230a565b03611b69577f63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365610d30610cdd8651611e57565b03611b315783518051600e1015610515576101e0610d4f9101516123c9565b80516008811490811591611b01575b50611ac75750835180516008101561051557610120610d7e91015161230a565b80158015611ab6575b6119a25767ffffffffffffffff168352610da4610cdd8551611e68565b855283518051600b101561051557610180610dc091015161230a565b80158015611aa5575b611a7a5767ffffffffffffffff16865283518051600c101561051557610df66101a0610e059201516123c9565b60208101905160801b176123f4565b8083525160058103611a4f5750610e25610e1f8351611e78565b516123c9565b5160208103611a245750610e42610e3c8351611e36565b516123f4565b978851156119fc57610e548951611ed1565b8b525f5b8951811015610fc657610e6e610e1f828c611ea5565b805160148103610f9b5750602081519101517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000081169160148110610f66575b505060601c8015610f3b57908c915f5b828110610ed95750610ed28260019451611ea5565b5201610e58565b9073ffffffffffffffffffffffffffffffffffffffff610efc8383959651611ea5565b511614610f0f578d929190600101610ebd565b507f41fe18cc000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f59bff387000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009250829060140360031b1b16165f80610ead565b7f83e46ad2000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50919395989092949750989598610fe0610e3c8551611e85565b97610feb8951611f02565b8b525f5b89518110156110285780611021818e61100e610e1f8f96600197611ea5565b90519061101b8383611ea5565b52611ea5565b5001610fef565b509194975092959891949760035467ffffffffffffffff8160401c1661104e8142610b0b565b67ffffffffffffffff8451168091106119ca57505061107b67ffffffffffffffff60208751015116611f4a565b9467ffffffffffffffff6020818c5116925101511610156119a25767ffffffffffffffff1680151580611984575b61194657506040519660c06110be818a610a4b565b60058952601f19015f5b8181106119355750506110e5816110eb6110e56111479451611e78565b51613031565b6110f48b611e78565b526110fe8a611e78565b5061110c6110e58251611e36565b6111158b611e36565b5261111f8a611e36565b5061112d6110e58251611e95565b6111368b611e95565b526111408a611e95565b5051611e68565b61115088611e68565b5261115a87611e68565b506111b0604097885161116d8a82610a4b565b600181527fc00000000000000000000000000000000000000000000000000000000000000060208201526111a082611e85565b526111aa81611e85565b506124ae565b976111bc8a5151611f02565b9a5f5b8b518051821015611345578d90600c830361132b57508b8b815160018114908161130d575b501561122f57928092602061121e8161122895600198519381859251918291018484015e81015f838201520301601f198101835282610a4b565b61101b8383611ea5565b50016111bf565b50508b519190508d8c8c6037851161126f579183918360218760019860206112289851958b830187526080830182880153018386015e830101905261121e565b5050506fffffffffffffffffffffffffffffffff821160071b67ffffffffffffffff83821c1160061b1763ffffffff83821c1160051b1761ffff83821c1160041b1760ff83821c119060031c1760018101808211610b18578f8e8e602160018795819961122898602260208751988484810196600288018c5260b88601848d015360031b610100031b888b015201918801015e84010101905261121e565b935050505015610515578c8b8b6080602083015160f81c105f6111e4565b8280926113406110e560019661122895611ea5565b61121e565b505093979850939850939861135c909591956124ae565b602081519101209551946113708651611ed1565b995f5b875181101561153f576113868189611ea5565b51805160418103611514575080518b1015610515576060810190601b825160f81c106114bf575b6113b891508a613090565b9060048110156108b05715908115916114b5575b508015611497575b61146f578c919073ffffffffffffffffffffffffffffffffffffffff165f5b82811061140e575061140782600194611ea5565b5201611373565b9073ffffffffffffffffffffffffffffffffffffffff61143083839596611ea5565b511614611443578d9291906001016113f3565b507f33af0d5f000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f09cb44e6000000000000000000000000000000000000000000000000000000005f5260045ffd5b5073ffffffffffffffffffffffffffffffffffffffff8116156113d4565b905015155f6113cc565b80518c101561051557601b825160f81c019160ff8311610b185781518d1015610515577fff000000000000000000000000000000000000000000000000000000000000006113b89360f81b165f1a90536113ad565b7ff2db9ce1000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5092955092969895509296600201975f965f5b87518110156115a65761158573ffffffffffffffffffffffffffffffffffffffff61157d838b611ea5565b51168c612601565b611592575b600101611552565b9761159e600191611fa1565b98905061158a565b50929690939791949860039054049060018201809211610b18578181106119075750508751975f965f5b87518110156116245761160373ffffffffffffffffffffffffffffffffffffffff6115fb838b611ea5565b51168c612659565b611610575b6001016115d0565b9761161c600191611fa1565b989050611608565b5093979296919550939761163d90516003810490611faf565b908181106118d9575050611691906001549251905190875160208101907fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008660601b16825260148152610477603482610a4b565b9190156118975750610cdd6116b28260206116b79401905160801b176123f4565b611e95565b67ffffffffffffffff8451165f526004602052845f2067ffffffffffffffff81541661183857509060029167ffffffffffffffff8551165f52600460205267ffffffffffffffff865f209451167fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000855416178455600184015551910181519167ffffffffffffffff8311610a6e57680100000000000000008311610a6e578154838355808410611812575b50602001905f5260205f205f5b8381106117e85750505050516002549167ffffffffffffffff83821c1667ffffffffffffffff8316116117a4575b5050505f90565b7fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff916fffffffffffffffff0000000000000000911b169116176002555f808061179d565b600190602073ffffffffffffffffffffffffffffffffffffffff855116940193818401550161176f565b825f528360205f2091820191015b81811061182d5750611762565b5f8155600101611820565b9261185694955067ffffffffffffffff909291925116905192611fbc565b6118915767ffffffffffffffff9051167fc1aea5f7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50600290565b73ffffffffffffffffffffffffffffffffffffffff907fa700fc32000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b7f7818f4e4000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fe2dcb1b9000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b806060602080938d010152016110c8565b67ffffffffffffffff8554167feae35725000000000000000000000000000000000000000000000000000000005f526004524260245260445260645ffd5b504261199b8267ffffffffffffffff885416610b0b565b11156110a9565b7f59d119e3000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f9b772277000000000000000000000000000000000000000000000000000000005f524260045260245260445260645ffd5b7f339e1ffb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fe7719a54000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f30c6792a000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f8c0b0527000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5067ffffffffffffffff8111610dc9565b5067ffffffffffffffff8111610d87565b611afd906040519182917fd5edd2a500000000000000000000000000000000000000000000000000000000835260048301610a21565b0390fd5b7f011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce9150602083012014155f610d5e565b611b3e610cdd8551611e57565b7fa19e609c000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b611b76610cf78551611e46565b7ff71b722f000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b611bae610cdd8551611e36565b7fb8120dca000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fbc277732000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b3567ffffffffffffffff811681036101435790565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610143570180359067ffffffffffffffff821161014357602001918160051b3603831361014357565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610143570180359067ffffffffffffffff82116101435760200191813603831361014357565b90602082549182815201915f5260205f20905f5b818110611cdf5750505090565b825473ffffffffffffffffffffffffffffffffffffffff16845260209093019260019283019201611cd2565b335f9081527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e0602052604090205460ff1615611d4357565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f52336004527fbd893629a699470e4ec82a5715bb4981fdaacc5d0a728bf5f55b801d8f4ef10b60245260445ffd5b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260ff60405f20541615611dca5750565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b67ffffffffffffffff1680611e0b5750565b7f3ce598a9000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b8051600110156105155760400190565b805160071015610515576101000190565b8051600d1015610515576101c00190565b8051600310156105155760800190565b8051156105155760200190565b8051600410156105155760a00190565b8051600210156105155760600190565b80518210156105155760209160051b010190565b67ffffffffffffffff8111610a6e5760051b60200190565b90611edb82611eb9565b611ee86040519182610a4b565b828152601f19611ef88294611eb9565b0190602036910137565b90611f0c82611eb9565b611f196040519182610a4b565b828152601f19611f298294611eb9565b01905f5b828110611f3957505050565b806060602080938501015201611f2d565b67ffffffffffffffff1690815f52600460205260405f209167ffffffffffffffff83541615611f765750565b7ff761631b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f198114610b185760010190565b91908203918211610b1857565b919067ffffffffffffffff808454169116149081159161207a575b5061207457604051611ffc816101b36020820194602086526002604084019101611cbe565b5190209060405160208101918160408101916020855280518093526020606083019101925f5b81811061204557505061203e925003601f198101835282610a4b565b5190201490565b845173ffffffffffffffffffffffffffffffffffffffff16835260209485019486945090920191600101612022565b50505f90565b9050600182015414155f611fd7565b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f205416155f1461207457805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905573ffffffffffffffffffffffffffffffffffffffff339216907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d5f80a4600190565b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f2054165f1461207457805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815416905573ffffffffffffffffffffffffffffffffffffffff339216907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b5f80a4600190565b61223c9092919260405192602084015260208352610df6604084610a4b565b926122478451611f02565b915f5b855181101561227f57806122636110e560019389611ea5565b61226d8287611ea5565b526122788186611ea5565b500161224a565b5090935061228c9261273d565b8190600e8110156108b057806122a3575051151591565b7f1121c9d0000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b60218160801c036122e257610b089061230a565b7ff3dd7004000000000000000000000000000000000000000000000000000000005f5260045ffd5b8060801c90602182116122e25761232081612d3f565b60028195929510156108b0576122e2578361233d57505050505f90565b816020019081602011610b185782036020019081111502601f81116123b7575f196fffffffffffffffffffffffffffffffff9160031b1b9216015116907f1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103610b185760031b610100036101008111610b18571c90565b634e487b715f5260326020526024601cfd5b6123d281612d3f565b60028194939410156108b0576122e257610b08926123ef92612ffa565b613031565b908160801c9161240381612d3f565b60028194939410156108b057600114908161249b575b50156122e257926040519360208501925b82811061244557505050601f198382030160051c8352604052565b926124858461246161245c85969761247f9661305e565b612d3f565b506124796124728383989498610b0b565b8489612ffa565b95610b0b565b90610b0b565b91815260208101809111610b185792919061242a565b6124a6915083610b0b565b84145f612419565b905f805b83518210156124db576124d36001916124cb8487611ea5565b515190610b0b565b9101906124b2565b9190506125006124ea83610a9b565b926124f86040519485610a4b565b808452610a9b565b91601f196020820193013684375f9160205b855184101561253d576001906125288588611ea5565b518051602082018387015e5101930192612512565b50905190935090506037811161257157806021916040519360018201855260c0820160208601538385015e82010160405290565b6fffffffffffffffffffffffffffffffff811160071b67ffffffffffffffff82821c1160061b1763ffffffff82821c1160051b1761ffff82821c1160041b1760ff82821c119060031c179160018301808411610b18576021926001926022604051968381810195600287018a5260f8830160208b015360031b610100031b878901528701015e8301010160405290565b905f5b825481101561179d57825f5273ffffffffffffffffffffffffffffffffffffffff8160205f2001541673ffffffffffffffffffffffffffffffffffffffff83161461265157600101612604565b505050600190565b905f5b825181101561179d5773ffffffffffffffffffffffffffffffffffffffff6126848285611ea5565b511673ffffffffffffffffffffffffffffffffffffffff8316146126515760010161265c565b60ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff409116019060ff8211610b1857565b60ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc99116019060ff8211610b1857565b60ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff809116019060ff8211610b1857565b9092916060935f94815115612d345750815115612cf857612760909492946130ca565b6040515f9391908480805b8651881015612ce65761277e8888611ea5565b519183612c3f575050888151602083012003612c2e576127ac90989392919860208101905160801b176123f4565b975b8851601103612976578251810361281157505050508451601010156127e457506102206127e09394015190519061324d565b9091565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526032600452fd5b90919297835182101561294957612832906020838601015160f81c90611ea5565b5160018160801c14806128f6575b6128e55761284d81613284565b92839190600181018091116128b85793602014801561289c575b612880575050612876906123f4565b975b9291906127ae565b929394999150966001905b85604052019698939291909861276b565b5060018901808a116128b8576128b39089856132b2565b612867565b6024887f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b50505050506127e0929350516131ef565b507f80000000000000000000000000000000000000000000000000000000000000007fff0000000000000000000000000000000000000000000000000000000000000061294283612f8a565b1614612840565b6024857f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b9091929760028151145f14612c1d57612999612994610e1f83611e78565b6130ca565b90815115612c0b5760208201805160f81c9060038211612bf7576129c68560208901895160801b1761305e565b935160801b176001821660020360ff8111612bca579060ff6129e992169061305e565b908160801c938060801c92838611918215612b16575b5050612b0257600110612a9457508115612a825790612a21612a399392611e36565b51916020612a2e84613284565b959093869493610b0b565b94148015612a66575b612a57575050612a51906123f4565b97612878565b9293949991509660019061288b565b5060018901808a116128b857612a7d9089856132b2565b612a42565b50505050505050509050606090600790565b94509850915050145f14612ab95750612ab06127e09394611e36565b5190519061320f565b935090612ac691516131ef565b92600e841015612ad557509190565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526021600452fd5b50505050505050506127e0929350516131ef565b91909980612b9d57506123b7576fffffffffffffffffffffffffffffffff612b959116985f997fffffffffffffffffffffffffffffffff000000000000000000000000000000008216176fffffffffffffffffffffffffffffffff8160801c911620906fffffffffffffffffffffffffffffffff8160801c9116201490565b155f806129ff565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526011600452fd5b6024897f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b505050505050505050509050606090600b90565b50505050505050509050606090600590565b505050505050509050606090600c90565b505050505050509050606090600290565b82519160208310908382612c9157506020148015939150612c81575b5050612c70576127ac905b9893929198610df6565b505050505050509050606090600390565b6020840120141590505f80612c5b565b1492831593612cbc575b505050612cab576127ac90612c66565b505050505050509050606090600490565b602085015192935090612cd5575b5014155f8080612c9b565b5f199060200360031b1b165f612cca565b50505050505050509050606090600d90565b50507f56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421919250145f14612d2c576060905f90565b606090600d90565b945060019392505050565b908160801c9182156122e257612d5481612f8a565b60f81c60c0811015612eb9576080811015612d7557505f9250600191839150565b60b78111612e0b57612d8860ff9161270c565b168093119081612da1575b50156122e257600191905f90565b6001841480159250612db5575b505f612d93565b7f80000000000000000000000000000000000000000000000000000000000000009150612e027fff0000000000000000000000000000000000000000000000000000000000000091612fc0565b1610155f612dae565b612e17612e1c9161270c565b6126db565b612e2960ff821692612fc0565b9082851180612e8e575b156122e25760ff81168303610b18576107f89060031b16610100036101008111610b18571c92603784119081612e7b575b50156122e25760018101809111610b185791905f90565b9050612e878483610b0b565b105f612e64565b507fff0000000000000000000000000000000000000000000000000000000000000082161515612e33565b9060f78211612edf5750612ece60ff916126aa565b16809211156122e257600191908290565b90612e17612eec916126aa565b612ef960ff821692612fc0565b9082851180612f5f575b156122e25760ff81168303610b18576107f89060031b16610100036101008111610b18571c92603784119081612f4c575b50156122e25760018101809111610b18579190600190565b9050612f588483610b0b565b105f612f34565b507fff0000000000000000000000000000000000000000000000000000000000000082161515612f03565b60208160801c5f0301602081111502601f81116123b7575f196fffffffffffffffffffffffffffffffff9160031b1b9116511690565b60208160801c60010301602181111502601f81116123b7576fffffffffffffffffffffffffffffffff5f1960019260031b1b921601511690565b906130058382610b0b565b8260801c106123b7576fffffffffffffffffffffffffffffffff6130299216610b0b565b9060801b1790565b9060208260801c806fffffffffffffffffffffffffffffffff60405195828752168386015e830101604052565b908160801c908181116123b7576fffffffffffffffffffffffffffffffff6130898261302994611faf565b9316610b0b565b81519190604183036130c0576130b99250602082015190606060408401519301515f1a9061331c565b9192909190565b50505f9160029190565b908151604051928160011b60208186010160405284525f5b8281106130ee57505050565b806020601092840101518060801c9060401c73ffffffff0000000000000000000000000000000073ffffffff000000000000000000000000ffffffff7bffffffff000000000000000000000000ffffffff00000000000000008477ffffffffffffffffffffffffffffffff000000000000000085161760201b1693169116171780831b177cff000000ff000000ff000000ff000000ff000000ff000000ff000000ff7eff000000ff000000ff000000ff000000ff000000ff000000ff000000ff00008260081b169116178060041b177f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f1660208260011b88010152016130e2565b905f198201918211610b185703613207576060905f90565b606090600890565b909291925f935f198201918211610b1857036132435761322e906123c9565b805115613239579190565b5060609150600990565b5060609150600890565b915f198201918211610b18570361327b57613267906123c9565b80511561327357905f90565b506060905f90565b50606090600890565b908160801c91602183105f146132a15761329d90612f8a565b9190565b6132ac91925061230a565b90602090565b90918251811092836132c5575b50505090565b6133149350906132d491611ea5565b5160208101905160801b176fffffffffffffffffffffffffffffffff8160801c911620906fffffffffffffffffffffffffffffffff8160801c9116201490565b5f80806132bf565b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084116133ab579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa156133a0575f5173ffffffffffffffffffffffffffffffffffffffff81161561339657905f905f90565b505f906001905f90565b6040513d5f823e3d90fd5b5050505f916003919056fea164736f6c634300081c000a2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac47bd893629a699470e4ec82a5715bb4981fdaacc5d0a728bf5f55b801d8f4ef10bad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5"}} diff --git a/ibc-solidity/abi/bytecode/CosmosIFTSendCallConstructor.json b/ibc-solidity/abi/bytecode/CosmosIFTSendCallConstructor.json deleted file mode 100644 index a4369292e..000000000 --- a/ibc-solidity/abi/bytecode/CosmosIFTSendCallConstructor.json +++ /dev/null @@ -1 +0,0 @@ -{"abi":[{"type":"constructor","inputs":[{"name":"bridgeReceiveTypeUrl_","type":"string","internalType":"string"},{"name":"denom_","type":"string","internalType":"string"},{"name":"icaAddress_","type":"string","internalType":"string"}],"stateMutability":"nonpayable"},{"type":"function","name":"bridgeReceiveTypeUrl","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"type":"function","name":"constructMintCall","inputs":[{"name":"receiver","type":"string","internalType":"string"},{"name":"amount","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bytes","internalType":"bytes"}],"stateMutability":"view"},{"type":"function","name":"denom","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"type":"function","name":"icaAddress","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"}],"bytecode":{"object":"0x60806040523461046857610ecb803803806100198161046c565b92833981016060828203126104685781516001600160401b0381116104685781610044918401610491565b60208301519092906001600160401b0381116104685782610066918301610491565b60408201519092906001600160401b038111610468576100869201610491565b82516001600160401b0381116102a3575f54600181811c9116801561045e575b602082101461028557601f81116103fc575b506020601f821160011461039b57819293945f92610390575b50508160011b915f199060031b1c1916175f555b81516001600160401b0381116102a357600154600181811c91168015610386575b602082101461028557601f8111610323575b50602092601f82116001146102c257928192935f926102b7575b50508160011b915f199060031b1c1916176001555b80516001600160401b0381116102a357600254600181811c91168015610299575b602082101461028557601f8111610222575b50602091601f82116001146101c2579181925f926101b7575b50508160011b915f199060031b1c1916176002555b6040516109e890816104e38239f35b015190505f80610193565b601f1982169260025f52805f20915f5b85811061020a575083600195106101f2575b505050811b016002556101a8565b01515f1960f88460031b161c191690555f80806101e4565b919260206001819286850151815501940192016101d2565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c8101916020841061027b575b601f0160051c01905b818110610270575061017a565b5f8155600101610263565b909150819061025a565b634e487b7160e01b5f52602260045260245ffd5b90607f1690610168565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610132565b601f1982169360015f52805f20915f5b86811061030b57508360019596106102f3575b505050811b01600155610147565b01515f1960f88460031b161c191690555f80806102e5565b919260206001819286850151815501940192016102d2565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c8101916020841061037c575b601f0160051c01905b8181106103715750610118565b5f8155600101610364565b909150819061035b565b90607f1690610106565b015190505f806100d1565b601f198216905f8052805f20915f5b8181106103e4575095836001959697106103cc575b505050811b015f556100e5565b01515f1960f88460031b161c191690555f80806103bf565b9192602060018192868b0151815501940192016103aa565b5f80527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563601f830160051c81019160208410610454575b601f0160051c01905b81811061044957506100b8565b5f815560010161043c565b9091508190610433565b90607f16906100a6565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102a357604052565b81601f82011215610468578051906001600160401b0382116102a3576104c0601f8301601f191660200161046c565b928284526020838301011161046857815f9260208093018386015e830101529056fe60806040526004361015610011575f80fd5b5f3560e01c80632ff02e27146107dc57806356d981a7146102275780638f2edc84146101675763c370b04214610045575f80fd5b34610163575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610163576040515f6001546100838161089f565b808452906001811690811561012157506001146100c3575b6100bf836100ab818503826108f0565b60405191829160208352602083019061095e565b0390f35b60015f9081527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6939250905b808210610107575090915081016020016100ab61009b565b9192600181602092548385880101520191019092916100ef565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b840190910191506100ab905061009b565b5f80fd5b34610163575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610163576040515f5f546101a48161089f565b808452906001811690811561012157506001146101cb576100bf836100ab818503826108f0565b5f8080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563939250905b80821061020d575090915081016020016100ab61009b565b9192600181602092548385880101520191019092916101f5565b346101635760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101635760043567ffffffffffffffff8111610163573660238201121561016357806004013567ffffffffffffffff8111610163573660248284010111610163575f602435807a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008110156107b4575b806d04ee2d6d415b85acef8100000000600a921015610799575b662386f26fc10000811015610785575b6305f5e100811015610774575b612710811015610765575b6064811015610757575b101561074d575b6001820190600a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602161035b610345866109a1565b9561035360405197886108f0565b8087526109a1565b957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06020870197013688378501015b01917f30313233343536373839616263646566000000000000000000000000000000008282061a83530480156103e4577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600a919261038a565b5050604051927f7b226d65737361676573223a5b7b224074797065223a2200000000000000000060208501525f945f5461041d8161089f565b906001811690811561071257506001146106bc575b507f222c227369676e6572223a22000000000000000000000000000000000000000086526002545f966104648261089f565b916001811690811561067e5750600114610625575b50507f222c2264656e6f6d223a2200000000000000000000000000000000000000000086525f956001546104ac8161089f565b90600181169081156105e25750600114610584575b5050600e6100ab946004948489600c9660248b977f222c227265636569766572223a220000000000000000000000000000000000006100bf9e52018683013701907f222c22616d6f756e74223a22000000000000000000000000000000000000000084830152518092601a83015e01017f227d5d7d000000000000000000000000000000000000000000000000000000008382015203017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe48101845201826108f0565b60015f908152919750907fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b8282106105cb57505095909501600b0194600e6100ab6104c1565b60018160209254600b858d010152019101906105b0565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600b84810191909152821515909202909201019650600e90506100ab6104c1565b60025f90815292975090917f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b83821061066757505001600c01948680610479565b60018160209254600c858701015201910190610652565b600c9499507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091509291921683830152801515020101948680610479565b5f808052919650907f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b8282106106fb57505084016037019486610432565b600181602092546037858b010152019101906106e6565b60379398507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682870152801515028501019486610432565b906001019061030f565b606460029104930192610308565b612710600491049301926102fe565b6305f5e100600891049301926102f3565b662386f26fc10000601091049301926102e6565b6d04ee2d6d415b85acef8100000000602091049301926102d6565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000081046102bc565b34610163575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610163576040515f60025461081a8161089f565b80845290600181169081156101215750600114610841576100bf836100ab818503826108f0565b60025f9081527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace939250905b808210610885575090915081016020016100ab61009b565b91926001816020925483858801015201910190929161086d565b90600182811c921680156108e6575b60208310146108b957565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f16916108ae565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761093157604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b67ffffffffffffffff811161093157601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0166020019056fea164736f6c634300081c000a","sourceMap":"462:1821:57:-:0;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;-1:-1:-1;;;;;462:1821:57;;;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1;;;;;462:1821:57;;;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1;;;;;462:1821:57;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;462:1821:57;;;;-1:-1:-1;462:1821:57;;;;;;;;;;;-1:-1:-1;462:1821:57;;;;;;;;;;;-1:-1:-1;462:1821:57;;;;;;;;;;;;;-1:-1:-1;462:1821:57;;;;;;;;;;;;;;;;;;;-1:-1:-1;462:1821:57;;;;-1:-1:-1;;;;;462:1821:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;462:1821:57;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;462:1821:57;;;;1624:24;462:1821;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;462:1821:57;;;;;;;;;;;;;;;;;;;1624:24;462:1821;;;;;;;;;;;;;;;-1:-1:-1;462:1821:57;;;;;;;;;;1624:24;-1:-1:-1;462:1821:57;;-1:-1:-1;462:1821:57;;-1:-1:-1;462:1821:57;;;;;;;;;;;;;;;;;;;;1624:24;462:1821;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1624:24;-1:-1:-1;462:1821:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;462:1821:57;;;;;;;;;-1:-1:-1;462:1821:57;;;;;;;;-1:-1:-1;462:1821:57;;;;;-1:-1:-1;462:1821:57;;;;;;;;;;;;-1:-1:-1;462:1821:57;;;;;-1:-1:-1;462:1821:57;;;;;-1:-1:-1;462:1821:57;;;;;;;;;;;-1:-1:-1;462:1821:57;;-1:-1:-1;462:1821:57;;-1:-1:-1;462:1821:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;462:1821:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;462:1821:57;;;;;;;;;-1:-1:-1;462:1821:57;;;;;;;;;;;;;;;-1:-1:-1;462:1821:57;;;;;;;;;;-1:-1:-1;462:1821:57;;;-1:-1:-1;462:1821:57;;-1:-1:-1;462:1821:57;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;462:1821:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;462:1821:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;462:1821:57;;;;;;;;;-1:-1:-1;462:1821:57;;;;;;;;;;;;-1:-1:-1;462:1821:57;;;;;;;;;-1:-1:-1;;462:1821:57;;;-1:-1:-1;;;;;462:1821:57;;;;;;;;;;:::o;:::-;;;;;;;;;;;;-1:-1:-1;;;;;462:1821:57;;;;;;;;-1:-1:-1;;462:1821:57;;;;:::i;:::-;;;;;;;;;;;;;;-1:-1:-1;462:1821:57;;;;;;;;;;;;;;:::o","linkReferences":{}},"deployedBytecode":{"object":"0x60806040526004361015610011575f80fd5b5f3560e01c80632ff02e27146107dc57806356d981a7146102275780638f2edc84146101675763c370b04214610045575f80fd5b34610163575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610163576040515f6001546100838161089f565b808452906001811690811561012157506001146100c3575b6100bf836100ab818503826108f0565b60405191829160208352602083019061095e565b0390f35b60015f9081527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6939250905b808210610107575090915081016020016100ab61009b565b9192600181602092548385880101520191019092916100ef565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b840190910191506100ab905061009b565b5f80fd5b34610163575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610163576040515f5f546101a48161089f565b808452906001811690811561012157506001146101cb576100bf836100ab818503826108f0565b5f8080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563939250905b80821061020d575090915081016020016100ab61009b565b9192600181602092548385880101520191019092916101f5565b346101635760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101635760043567ffffffffffffffff8111610163573660238201121561016357806004013567ffffffffffffffff8111610163573660248284010111610163575f602435807a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008110156107b4575b806d04ee2d6d415b85acef8100000000600a921015610799575b662386f26fc10000811015610785575b6305f5e100811015610774575b612710811015610765575b6064811015610757575b101561074d575b6001820190600a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602161035b610345866109a1565b9561035360405197886108f0565b8087526109a1565b957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06020870197013688378501015b01917f30313233343536373839616263646566000000000000000000000000000000008282061a83530480156103e4577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600a919261038a565b5050604051927f7b226d65737361676573223a5b7b224074797065223a2200000000000000000060208501525f945f5461041d8161089f565b906001811690811561071257506001146106bc575b507f222c227369676e6572223a22000000000000000000000000000000000000000086526002545f966104648261089f565b916001811690811561067e5750600114610625575b50507f222c2264656e6f6d223a2200000000000000000000000000000000000000000086525f956001546104ac8161089f565b90600181169081156105e25750600114610584575b5050600e6100ab946004948489600c9660248b977f222c227265636569766572223a220000000000000000000000000000000000006100bf9e52018683013701907f222c22616d6f756e74223a22000000000000000000000000000000000000000084830152518092601a83015e01017f227d5d7d000000000000000000000000000000000000000000000000000000008382015203017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe48101845201826108f0565b60015f908152919750907fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b8282106105cb57505095909501600b0194600e6100ab6104c1565b60018160209254600b858d010152019101906105b0565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600b84810191909152821515909202909201019650600e90506100ab6104c1565b60025f90815292975090917f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b83821061066757505001600c01948680610479565b60018160209254600c858701015201910190610652565b600c9499507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091509291921683830152801515020101948680610479565b5f808052919650907f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b8282106106fb57505084016037019486610432565b600181602092546037858b010152019101906106e6565b60379398507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682870152801515028501019486610432565b906001019061030f565b606460029104930192610308565b612710600491049301926102fe565b6305f5e100600891049301926102f3565b662386f26fc10000601091049301926102e6565b6d04ee2d6d415b85acef8100000000602091049301926102d6565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000081046102bc565b34610163575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610163576040515f60025461081a8161089f565b80845290600181169081156101215750600114610841576100bf836100ab818503826108f0565b60025f9081527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace939250905b808210610885575090915081016020016100ab61009b565b91926001816020925483858801015201910190929161086d565b90600182811c921680156108e6575b60208310146108b957565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f16916108ae565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761093157604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b67ffffffffffffffff811161093157601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0166020019056fea164736f6c634300081c000a","sourceMap":"462:1821:57:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;842:19;462:1821;;;;:::i;:::-;;;;;842:19;462:1821;;;842:19;;;;462:1821;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;842:19;462:1821;;;;;;;-1:-1:-1;462:1821:57;;;;;;;-1:-1:-1;462:1821:57;;-1:-1:-1;462:1821:57;;;;;;;;;;842:19;462:1821;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;462:1821:57;;-1:-1:-1;462:1821:57;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1;462:1821:57;;;;;;;-1:-1:-1;462:1821:57;;-1:-1:-1;462:1821:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;29291:8:123;29282:17;;;29278:103;;462:1821:57;29398:17:123;29407:8;29978:7;29398:17;;;29394:103;;462:1821:57;29523:8:123;29514:17;;;29510:103;;462:1821:57;29639:7:123;29630:16;;;29626:100;;462:1821:57;29752:7:123;29743:16;;;29739:100;;462:1821:57;29865:7:123;29856:16;;;29852:100;;462:1821:57;29969:16:123;;29965:66;;462:1821:57;;;;;29978:7:123;462:1821:57;1545:94:117;462:1821:57;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;;;1545:94:117;;;1652:247;462:1821:57;1706:111:117;;;;;;;;462:1821:57;1867:10:117;;1863:21;;462:1821:57;29978:7:123;1652:247:117;;;;1863:21;1879:5;;462:1821:57;;1917:357;462:1821;;1917:357;;462:1821;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;462:1821:57;;;2057:10;462:1821;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;1917:357;462:1821;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1917:357;;;;;;;;;;:::i;462:1821::-;;;;;;;;-1:-1:-1;462:1821:57;;;;;;;;-1:-1:-1;;462:1821:57;;;;;;;;1917:357;462:1821;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;462:1821:57;;-1:-1:-1;1917:357:57;462:1821;;;2057:10;462:1821;;;;;;-1:-1:-1;462:1821:57;;;;;;;;;-1:-1:-1;;462:1821:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;462:1821:57;;;;;;;;-1:-1:-1;;462:1821:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;29965:66:123;462:1821:57;;;29965:66:123;;;29852:100;29865:7;29936:1;462:1821:57;;;;29852:100:123;;;29739;29752:7;462:1821:57;;;;;29739:100:123;;;29626;29639:7;29710:1;462:1821:57;;;;29626:100:123;;;29510:103;29523:8;29596:2;462:1821:57;;;;29510:103:123;;;29394;29407:8;462:1821:57;;;;;29394:103:123;;;29278;-1:-1:-1;462:1821:57;;-1:-1:-1;29291:8:123;462:1821:57;;29278:103:123;;462:1821:57;;;;;;;;;;;;;;1105:24;462:1821;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1105:24;462:1821;;;;;;;-1:-1:-1;462:1821:57;;;;;;;-1:-1:-1;462:1821:57;;-1:-1:-1;462:1821:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;-1:-1:-1;462:1821:57;;;;;-1:-1:-1;462:1821:57;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;462:1821:57;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;:::o","linkReferences":{}},"methodIdentifiers":{"bridgeReceiveTypeUrl()":"8f2edc84","constructMintCall(string,uint256)":"56d981a7","denom()":"c370b042","icaAddress()":"2ff02e27"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.28+commit.7893614a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"bridgeReceiveTypeUrl_\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"denom_\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"icaAddress_\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"bridgeReceiveTypeUrl\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"receiver\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"constructMintCall\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"denom\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"icaAddress\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This implementation encodes mint calls in protojson format for Cosmos SDK IFT module\",\"kind\":\"dev\",\"methods\":{\"constructMintCall(string,uint256)\":{\"details\":\"Encodes the mint call as protojson CosmosTx for Cosmos SDK ICS27-GMP module\",\"params\":{\"amount\":\"The amount of tokens to mint\",\"receiver\":\"The address of the receiver on the counterparty chain\"},\"returns\":{\"_0\":\"The constructed call data for the ICS27-GMP message\"}},\"constructor\":{\"params\":{\"bridgeReceiveTypeUrl_\":\"The type URL for MsgIFTMint\",\"denom_\":\"The denom of the token on the Cosmos SDK chain (e.g., \\\"uatom\\\", \\\"ibc/...\\\")\",\"icaAddress_\":\"The interchain account address on the Cosmos SDK chain\"}}},\"stateVariables\":{\"icaAddress\":{\"details\":\"Required to set the signer of the MsgIFTMint message (Cosmos SDK limitation)\"}},\"title\":\"Cosmos SDK IFT Send Call Constructor\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridgeReceiveTypeUrl()\":{\"notice\":\"The type URL for the MsgIFTMint message in the TokenFactory module\"},\"constructMintCall(string,uint256)\":{\"notice\":\"Constructs the ICS27-GMP call data for minting IFT tokens on the counterparty chain\"},\"constructor\":{\"notice\":\"Creates a new CosmosIFTSendCallConstructor\"},\"denom()\":{\"notice\":\"The denomination of the counterparty token on the Cosmos SDK chain\"},\"icaAddress()\":{\"notice\":\"The interchain account address of the submitter account on the Cosmos SDK chain\"}},\"notice\":\"Constructs ICS27-GMP call data for minting IFT tokens on Cosmos SDK-based counterparty chains\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/utils/CosmosIFTSendCallConstructor.sol\":\"CosmosIFTSendCallConstructor\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[\":@openzeppelin-contracts/=node_modules/@openzeppelin/contracts/\",\":@openzeppelin-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/\",\":@openzeppelin/=node_modules/@openzeppelin/\",\":@sp1-contracts/=node_modules/sp1-contracts/contracts/src/\",\":@uniswap/permit2/=node_modules/@uniswap/permit2/\",\":forge-std/=node_modules/forge-std/src/\",\":sp1-contracts/=node_modules/sp1-contracts/\"],\"viaIR\":true},\"sources\":{\"contracts/interfaces/IIFTSendCallConstructor.sol\":{\"keccak256\":\"0xaa49a7ac2dbdc445c5d6c2d49484f39c343da930f9d6dd62ad20b5b0c7a99e55\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://014c493ca7b15906323cc74464dbfacce33d5c1025670971074f5d54572c6970\",\"dweb:/ipfs/QmdbaM8S4jyT3PBDoHuWJnsrXx24K566qZgDjhD1EFzhrS\"]},\"contracts/utils/CosmosIFTSendCallConstructor.sol\":{\"keccak256\":\"0xc231e15347e5d16bca9d699025402b3ed0631ce4b9b389bb1e161d9a4f5a9646\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://73977e15c36a317001a3482bad415526461708d4f85028d0276f47eccaabb759\",\"dweb:/ipfs/QmeM1NatEEZ3a5bcL5uGZs7GxeniXo4sWX3jeXs6aGuQFH\"]},\"node_modules/@openzeppelin/contracts/utils/Panic.sol\":{\"keccak256\":\"0xf7fe324703a64fc51702311dc51562d5cb1497734f074e4f483bfb6717572d7a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://c6a5ff4f9fd8649b7ee20800b7fa387d3465bd77cf20c2d1068cd5c98e1ed57a\",\"dweb:/ipfs/QmVSaVJf9FXFhdYEYeCEfjMVHrxDh5qL4CGkxdMWpQCrqG\"]},\"node_modules/@openzeppelin/contracts/utils/Strings.sol\":{\"keccak256\":\"0xad148d59f05165f9217d0a9e1ac8f772abb02ea6aaad8a756315c532bf79f9f4\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://15e3599867c2182f5831e9268b274b2ef2047825837df6b4d81c9e89254b093e\",\"dweb:/ipfs/QmZbL7XAYr5RmaNaooPgZRmcDXaudfsYQfYD9y5iAECvpS\"]},\"node_modules/@openzeppelin/contracts/utils/math/Math.sol\":{\"keccak256\":\"0x1225214420c83ebcca88f2ae2b50f053aaa7df7bd684c3e878d334627f2edfc6\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6c5fab4970634f9ab9a620983dc1c8a30153981a0b1a521666e269d0a11399d3\",\"dweb:/ipfs/QmVRnBC575MESGkEHndjujtR7qub2FzU9RWy9eKLp4hPZB\"]},\"node_modules/@openzeppelin/contracts/utils/math/SafeCast.sol\":{\"keccak256\":\"0x195533c86d0ef72bcc06456a4f66a9b941f38eb403739b00f21fd7c1abd1ae54\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b1d578337048cad08c1c03041cca5978eff5428aa130c781b271ad9e5566e1f8\",\"dweb:/ipfs/QmPFKL2r9CBsMwmUqqdcFPfHZB2qcs9g1HDrPxzWSxomvy\"]},\"node_modules/@openzeppelin/contracts/utils/math/SignedMath.sol\":{\"keccak256\":\"0xb1970fac7b64e6c09611e6691791e848d5e3fe410fa5899e7df2e0afd77a99e3\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://db5fbb3dddd8b7047465b62575d96231ba8a2774d37fb4737fbf23340fabbb03\",\"dweb:/ipfs/QmVUSvooZKEdEdap619tcJjTLcAuH6QBdZqAzWwnAXZAWJ\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.28+commit.7893614a"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"string","name":"bridgeReceiveTypeUrl_","type":"string"},{"internalType":"string","name":"denom_","type":"string"},{"internalType":"string","name":"icaAddress_","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"stateMutability":"view","type":"function","name":"bridgeReceiveTypeUrl","outputs":[{"internalType":"string","name":"","type":"string"}]},{"inputs":[{"internalType":"string","name":"receiver","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function","name":"constructMintCall","outputs":[{"internalType":"bytes","name":"","type":"bytes"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"denom","outputs":[{"internalType":"string","name":"","type":"string"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"icaAddress","outputs":[{"internalType":"string","name":"","type":"string"}]}],"devdoc":{"kind":"dev","methods":{"constructMintCall(string,uint256)":{"details":"Encodes the mint call as protojson CosmosTx for Cosmos SDK ICS27-GMP module","params":{"amount":"The amount of tokens to mint","receiver":"The address of the receiver on the counterparty chain"},"returns":{"_0":"The constructed call data for the ICS27-GMP message"}},"constructor":{"params":{"bridgeReceiveTypeUrl_":"The type URL for MsgIFTMint","denom_":"The denom of the token on the Cosmos SDK chain (e.g., \"uatom\", \"ibc/...\")","icaAddress_":"The interchain account address on the Cosmos SDK chain"}}},"version":1},"userdoc":{"kind":"user","methods":{"bridgeReceiveTypeUrl()":{"notice":"The type URL for the MsgIFTMint message in the TokenFactory module"},"constructMintCall(string,uint256)":{"notice":"Constructs the ICS27-GMP call data for minting IFT tokens on the counterparty chain"},"constructor":{"notice":"Creates a new CosmosIFTSendCallConstructor"},"denom()":{"notice":"The denomination of the counterparty token on the Cosmos SDK chain"},"icaAddress()":{"notice":"The interchain account address of the submitter account on the Cosmos SDK chain"}},"version":1}},"settings":{"remappings":["@openzeppelin-contracts/=node_modules/@openzeppelin/contracts/","@openzeppelin-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/","@openzeppelin/=node_modules/@openzeppelin/","@sp1-contracts/=node_modules/sp1-contracts/contracts/src/","@uniswap/permit2/=node_modules/@uniswap/permit2/","forge-std/=node_modules/forge-std/src/","sp1-contracts/=node_modules/sp1-contracts/"],"optimizer":{"enabled":true,"runs":10000},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"contracts/utils/CosmosIFTSendCallConstructor.sol":"CosmosIFTSendCallConstructor"},"evmVersion":"cancun","libraries":{},"viaIR":true},"sources":{"contracts/interfaces/IIFTSendCallConstructor.sol":{"keccak256":"0xaa49a7ac2dbdc445c5d6c2d49484f39c343da930f9d6dd62ad20b5b0c7a99e55","urls":["bzz-raw://014c493ca7b15906323cc74464dbfacce33d5c1025670971074f5d54572c6970","dweb:/ipfs/QmdbaM8S4jyT3PBDoHuWJnsrXx24K566qZgDjhD1EFzhrS"],"license":"MIT"},"contracts/utils/CosmosIFTSendCallConstructor.sol":{"keccak256":"0xc231e15347e5d16bca9d699025402b3ed0631ce4b9b389bb1e161d9a4f5a9646","urls":["bzz-raw://73977e15c36a317001a3482bad415526461708d4f85028d0276f47eccaabb759","dweb:/ipfs/QmeM1NatEEZ3a5bcL5uGZs7GxeniXo4sWX3jeXs6aGuQFH"],"license":"MIT"},"node_modules/@openzeppelin/contracts/utils/Panic.sol":{"keccak256":"0xf7fe324703a64fc51702311dc51562d5cb1497734f074e4f483bfb6717572d7a","urls":["bzz-raw://c6a5ff4f9fd8649b7ee20800b7fa387d3465bd77cf20c2d1068cd5c98e1ed57a","dweb:/ipfs/QmVSaVJf9FXFhdYEYeCEfjMVHrxDh5qL4CGkxdMWpQCrqG"],"license":"MIT"},"node_modules/@openzeppelin/contracts/utils/Strings.sol":{"keccak256":"0xad148d59f05165f9217d0a9e1ac8f772abb02ea6aaad8a756315c532bf79f9f4","urls":["bzz-raw://15e3599867c2182f5831e9268b274b2ef2047825837df6b4d81c9e89254b093e","dweb:/ipfs/QmZbL7XAYr5RmaNaooPgZRmcDXaudfsYQfYD9y5iAECvpS"],"license":"MIT"},"node_modules/@openzeppelin/contracts/utils/math/Math.sol":{"keccak256":"0x1225214420c83ebcca88f2ae2b50f053aaa7df7bd684c3e878d334627f2edfc6","urls":["bzz-raw://6c5fab4970634f9ab9a620983dc1c8a30153981a0b1a521666e269d0a11399d3","dweb:/ipfs/QmVRnBC575MESGkEHndjujtR7qub2FzU9RWy9eKLp4hPZB"],"license":"MIT"},"node_modules/@openzeppelin/contracts/utils/math/SafeCast.sol":{"keccak256":"0x195533c86d0ef72bcc06456a4f66a9b941f38eb403739b00f21fd7c1abd1ae54","urls":["bzz-raw://b1d578337048cad08c1c03041cca5978eff5428aa130c781b271ad9e5566e1f8","dweb:/ipfs/QmPFKL2r9CBsMwmUqqdcFPfHZB2qcs9g1HDrPxzWSxomvy"],"license":"MIT"},"node_modules/@openzeppelin/contracts/utils/math/SignedMath.sol":{"keccak256":"0xb1970fac7b64e6c09611e6691791e848d5e3fe410fa5899e7df2e0afd77a99e3","urls":["bzz-raw://db5fbb3dddd8b7047465b62575d96231ba8a2774d37fb4737fbf23340fabbb03","dweb:/ipfs/QmVUSvooZKEdEdap619tcJjTLcAuH6QBdZqAzWwnAXZAWJ"],"license":"MIT"}},"version":1},"id":57} \ No newline at end of file diff --git a/ibc-solidity/abi/bytecode/SP1ICS07Tendermint.json b/ibc-solidity/abi/bytecode/SP1ICS07Tendermint.json index d023e9a37..3c553641c 100644 --- a/ibc-solidity/abi/bytecode/SP1ICS07Tendermint.json +++ b/ibc-solidity/abi/bytecode/SP1ICS07Tendermint.json @@ -1 +1 @@ -{"abi":[{"type":"constructor","inputs":[{"name":"updateClientProgramVkey","type":"bytes32","internalType":"bytes32"},{"name":"membershipProgramVkey","type":"bytes32","internalType":"bytes32"},{"name":"updateClientAndMembershipProgramVkey","type":"bytes32","internalType":"bytes32"},{"name":"misbehaviourProgramVkey","type":"bytes32","internalType":"bytes32"},{"name":"sp1Verifier","type":"address","internalType":"address"},{"name":"_clientState","type":"bytes","internalType":"bytes"},{"name":"_consensusState","type":"bytes32","internalType":"bytes32"},{"name":"roleManager","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"type":"function","name":"ALLOWED_SP1_CLOCK_DRIFT","inputs":[],"outputs":[{"name":"","type":"uint16","internalType":"uint16"}],"stateMutability":"view"},{"type":"function","name":"DEFAULT_ADMIN_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"MEMBERSHIP_PROGRAM_VKEY","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"MISBEHAVIOUR_PROGRAM_VKEY","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"PROOF_SUBMITTER_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"UPDATE_CLIENT_AND_MEMBERSHIP_PROGRAM_VKEY","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"UPDATE_CLIENT_PROGRAM_VKEY","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"VERIFIER","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract ISP1Verifier"}],"stateMutability":"view"},{"type":"function","name":"clientState","inputs":[],"outputs":[{"name":"chainId","type":"string","internalType":"string"},{"name":"trustLevel","type":"tuple","internalType":"struct IICS07TendermintMsgs.TrustThreshold","components":[{"name":"numerator","type":"uint8","internalType":"uint8"},{"name":"denominator","type":"uint8","internalType":"uint8"}]},{"name":"latestHeight","type":"tuple","internalType":"struct IICS02ClientMsgs.Height","components":[{"name":"revisionNumber","type":"uint64","internalType":"uint64"},{"name":"revisionHeight","type":"uint64","internalType":"uint64"}]},{"name":"trustingPeriod","type":"uint32","internalType":"uint32"},{"name":"unbondingPeriod","type":"uint32","internalType":"uint32"},{"name":"isFrozen","type":"bool","internalType":"bool"},{"name":"zkAlgorithm","type":"uint8","internalType":"enum IICS07TendermintMsgs.SupportedZkAlgorithm"}],"stateMutability":"view"},{"type":"function","name":"getClientState","inputs":[],"outputs":[{"name":"","type":"bytes","internalType":"bytes"}],"stateMutability":"view"},{"type":"function","name":"getConsensusStateHash","inputs":[{"name":"revisionHeight","type":"uint64","internalType":"uint64"}],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"getRoleAdmin","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"grantRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"hasRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"misbehaviour","inputs":[{"name":"misbehaviourMsg","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"multicall","inputs":[{"name":"data","type":"bytes[]","internalType":"bytes[]"}],"outputs":[{"name":"results","type":"bytes[]","internalType":"bytes[]"}],"stateMutability":"nonpayable"},{"type":"function","name":"renounceRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"callerConfirmation","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"revokeRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"supportsInterface","inputs":[{"name":"interfaceId","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"updateClient","inputs":[{"name":"updateMsg","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"","type":"uint8","internalType":"enum ILightClientMsgs.UpdateResult"}],"stateMutability":"nonpayable"},{"type":"function","name":"verifyMembership","inputs":[{"name":"msg_","type":"tuple","internalType":"struct ILightClientMsgs.MsgVerifyMembership","components":[{"name":"proof","type":"bytes","internalType":"bytes"},{"name":"proofHeight","type":"tuple","internalType":"struct IICS02ClientMsgs.Height","components":[{"name":"revisionNumber","type":"uint64","internalType":"uint64"},{"name":"revisionHeight","type":"uint64","internalType":"uint64"}]},{"name":"path","type":"bytes[]","internalType":"bytes[]"},{"name":"value","type":"bytes","internalType":"bytes"}]}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"nonpayable"},{"type":"function","name":"verifyNonMembership","inputs":[{"name":"msg_","type":"tuple","internalType":"struct ILightClientMsgs.MsgVerifyNonMembership","components":[{"name":"proof","type":"bytes","internalType":"bytes"},{"name":"proofHeight","type":"tuple","internalType":"struct IICS02ClientMsgs.Height","components":[{"name":"revisionNumber","type":"uint64","internalType":"uint64"},{"name":"revisionHeight","type":"uint64","internalType":"uint64"}]},{"name":"path","type":"bytes[]","internalType":"bytes[]"}]}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"nonpayable"},{"type":"event","name":"RoleAdminChanged","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"previousAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"newAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"error","name":"AccessControlBadConfirmation","inputs":[]},{"type":"error","name":"AccessControlUnauthorizedAccount","inputs":[{"name":"account","type":"address","internalType":"address"},{"name":"neededRole","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"AddressEmptyCode","inputs":[{"name":"target","type":"address","internalType":"address"}]},{"type":"error","name":"CannotHandleMisbehavior","inputs":[]},{"type":"error","name":"ChainIdMismatch","inputs":[{"name":"expected","type":"string","internalType":"string"},{"name":"actual","type":"string","internalType":"string"}]},{"type":"error","name":"ClientStateMismatch","inputs":[{"name":"expected","type":"bytes","internalType":"bytes"},{"name":"actual","type":"bytes","internalType":"bytes"}]},{"type":"error","name":"ConsensusStateHashMismatch","inputs":[{"name":"expected","type":"bytes32","internalType":"bytes32"},{"name":"actual","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"ConsensusStateNotFound","inputs":[]},{"type":"error","name":"ConsensusStateRootMismatch","inputs":[{"name":"expected","type":"bytes32","internalType":"bytes32"},{"name":"actual","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"EmptyValue","inputs":[]},{"type":"error","name":"FailedCall","inputs":[]},{"type":"error","name":"FeatureNotSupported","inputs":[]},{"type":"error","name":"FrozenClientState","inputs":[]},{"type":"error","name":"InvalidMembershipProof","inputs":[]},{"type":"error","name":"KeyValuePairNotInCache","inputs":[{"name":"path","type":"bytes[]","internalType":"bytes[]"},{"name":"value","type":"bytes","internalType":"bytes"}]},{"type":"error","name":"LengthIsOutOfRange","inputs":[{"name":"length","type":"uint256","internalType":"uint256"},{"name":"min","type":"uint256","internalType":"uint256"},{"name":"max","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"MembershipProofKeyNotFound","inputs":[{"name":"path","type":"bytes[]","internalType":"bytes[]"}]},{"type":"error","name":"MembershipProofValueMismatch","inputs":[{"name":"expected","type":"bytes","internalType":"bytes"},{"name":"actual","type":"bytes","internalType":"bytes"}]},{"type":"error","name":"ProofHeightMismatch","inputs":[{"name":"expectedRevisionNumber","type":"uint64","internalType":"uint64"},{"name":"expectedRevisionHeight","type":"uint64","internalType":"uint64"},{"name":"actualRevisionNumber","type":"uint64","internalType":"uint64"},{"name":"actualRevisionHeight","type":"uint64","internalType":"uint64"}]},{"type":"error","name":"ProofIsInTheFuture","inputs":[{"name":"now","type":"uint256","internalType":"uint256"},{"name":"proofTimestamp","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"ProofIsTooOld","inputs":[{"name":"now","type":"uint256","internalType":"uint256"},{"name":"proofTimestamp","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"TrustThresholdMismatch","inputs":[{"name":"expectedNumerator","type":"uint256","internalType":"uint256"},{"name":"expectedDenominator","type":"uint256","internalType":"uint256"},{"name":"actualNumerator","type":"uint256","internalType":"uint256"},{"name":"actualDenominator","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"TrustingPeriodMismatch","inputs":[{"name":"expected","type":"uint256","internalType":"uint256"},{"name":"actual","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"TrustingPeriodTooLong","inputs":[{"name":"trustingPeriod","type":"uint256","internalType":"uint256"},{"name":"unbondingPeriod","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"UnbondingPeriodMismatch","inputs":[{"name":"expected","type":"uint256","internalType":"uint256"},{"name":"actual","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"UnknownMembershipProofType","inputs":[{"name":"proofType","type":"uint8","internalType":"uint8"}]},{"type":"error","name":"UnknownZkAlgorithm","inputs":[{"name":"algorithm","type":"uint8","internalType":"uint8"}]},{"type":"error","name":"VerificationKeyMismatch","inputs":[{"name":"expected","type":"bytes32","internalType":"bytes32"},{"name":"actual","type":"bytes32","internalType":"bytes32"}]}],"bytecode":{"object":"0x61012060405234610541576137268038038061001a81610564565b928339810161010082820312610541578151916020810151604082015160608301519061004960808501610589565b60a08501519095906001600160401b0381116105415785019080601f8301121561054157815161007b9260200161059d565b9261008d60e060c08701519601610589565b9660805260a05260c05260e05280518101906020820190602081840312610541576020810151906001600160401b038211610541570191829003601f1981019061012013610541576040519160e083016001600160401b0381118482101761052d5760405260208401516001600160401b038111610541576020908501019080601f830112156105415781516101259260200161059d565b825260408112610541576040610139610545565b916101458286016105dd565b8352610153606086016105dd565b602084015260208401928352603f19011261054157610170610545565b61017c608085016105eb565b815261018a60a085016105eb565b6020820152604083019081526101a260c085016105ff565b90606084019182526101b660e086016105ff565b92608085019384526101008601519586151587036105415760a0860196875261012001519460028610156105415760c08101958652518051906001600160401b03821161052d57600154600181811c91168015610523575b602082101461050f57601f81116104ac575b50602090601f831160011461043f5763ffffffff95949392915f9183610434575b50508160011b915f199060031b1c1916176001555b5160ff81511661ff00602060025493015160081b169161ffff191617176002555160018060401b0381511660035491602068010000000000000000600160801b0391015160401b169160018060801b031916171760035551169267ffffffff00000000600454925160201b169051151560401b92519160028310156104205769ff00000000000000000068ff00000000000000009360481b169469ff000000000000000000199160018060481b0319161716179116171760045560018060401b0360035460401c165f52600560205260405f205560018060a01b03166101005260045463ffffffff8116610708810163ffffffff811161040c5763ffffffff809360201c1692839116116103f757826001600160a01b0381166103de575061037c610706565b505b604051612efd908161078982396080518181816105570152611445015260a0518181816101f90152611e01015260c051818181610cb30152612185015260e0518181816102a00152610ac1015261010051818181610c780152611a1a0152f35b806103eb6103f192610610565b50610686565b5061037e565b6333fae18560e21b5f5260045260245260445ffd5b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52602160045260245ffd5b015190505f80610241565b90601f1983169160015f52815f20925f5b818110610494575091600193918563ffffffff99989796941061047c575b505050811b01600155610256565b01515f1960f88460031b161c191690555f808061046e565b92936020600181928786015181550195019301610450565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c81019160208510610505575b601f0160051c01905b8181106104fa5750610220565b5f81556001016104ed565b90915081906104e4565b634e487b7160e01b5f52602260045260245ffd5b90607f169061020e565b634e487b7160e01b5f52604160045260245ffd5b5f80fd5b60408051919082016001600160401b0381118382101761052d57604052565b6040519190601f01601f191682016001600160401b0381118382101761052d57604052565b51906001600160a01b038216820361054157565b9192916001600160401b03821161052d576105c1601f8301601f1916602001610564565b938285528282011161054157815f926020928387015e84010152565b519060ff8216820361054157565b51906001600160401b038216820361054157565b519063ffffffff8216820361054157565b6001600160a01b0381165f9081525f5160206137065f395f51905f52602052604090205460ff16610681576001600160a01b03165f8181525f5160206137065f395f51905f5260205260408120805460ff191660011790553391905f5160206136865f395f51905f528180a4600190565b505f90565b6001600160a01b0381165f9081525f5160206136a65f395f51905f52602052604090205460ff16610681576001600160a01b03165f8181525f5160206136a65f395f51905f5260205260408120805460ff191660011790553391905f5160206136e65f395f51905f52905f5160206136865f395f51905f529080a4600190565b5f80525f5160206136a65f395f51905f526020525f5160206136c65f395f51905f525460ff16610784575f8080525f5160206136a65f395f51905f526020525f5160206136c65f395f51905f52805460ff1916600117905533905f5160206136e65f395f51905f525f5160206136865f395f51905f528280a4600190565b5f9056fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a714610cd6575080630225293e14610c9c57806308c84e7014610c4c5780630bece35614610b8957806323842fb814610b59578063248a9ca314610b2f5780632c3ee47414610b135780632f2ff15d14610ae4578063314d4dff14610aaa57806336568abe14610a4e5780634d6d9ffb1461096c5780635972185a14610932578063682ed5f01461080e57806391d14854146107c5578063a217fddf146107ab578063ac9650d81461066a578063bd3ce6b01461057a578063ca7242f914610540578063d547741f1461050a578063ddba65371461021c578063e45a6d0d146101e25763ef913a4b1461010e575f80fd5b346101de575f6003193601126101de576101da60405160208082015261012060408201526101c6816101436101608201610ec6565b60ff600254818116606085015260081c16608083015267ffffffffffffffff60035481811660a085015260401c1660c083015260ff60045463ffffffff811660e085015263ffffffff8160201c16610100850152818160401c16151561012085015260481c166101b28161105f565b61014083015203601f19810183528261103c565b604051918291602083526020830190610df8565b0390f35b5f80fd5b346101de575f6003193601126101de5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346101de5761022a36610d74565b6004549160ff8360401c166104e2575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06020527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac4754610298929060ff16156104d5575b8101906110d9565b6102c78151517f0000000000000000000000000000000000000000000000000000000000000000808214611189565b6020815101518051810160208101916020818303126101de57602081015167ffffffffffffffff81116101de57019061018090829003126101de576040519061030f82610fcc565b602081015167ffffffffffffffff81116101de57839082016020019061033491611260565b825261034260408201611348565b60208301908152906103578460608301611219565b604084019081529161036c8560a08401611219565b60608501908152946103818160e08501611365565b9260808601938452610140019061039791611365565b9360a081019485525190516fffffffffffffffffffffffffffffffff166103bd916126e8565b516040805182516fffffffffffffffffffffffffffffffff16602080830191825284015182840152919092015160608084019190915282529061040160808261103c565b51902090516020015167ffffffffffffffff1661041d90611649565b61042a919081811461187c565b516040805182516fffffffffffffffffffffffffffffffff16602080830191825284015182840152919092015160608084019190915282529061046e60808261103c565b51902090516020015167ffffffffffffffff1661048a90611649565b610497919081811461187c565b516104a190611a03565b7fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff1668010000000000000000176004555f80f35b6104dd61178e565b610290565b7f928b1233000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101de5761053e61051b36610dc5565b90610539610534825f525f602052600160405f20015490565b611816565b611ba5565b005b346101de575f6003193601126101de5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346101de575f6003193601126101de576040516105a18161059a81610ec6565b038261103c565b6101206040516105b081610f83565b60025460ff8116825260ff602083019160081c16815260ff6040516105d481610f83565b67ffffffffffffffff600354818116835281602084019160401c168152816004549385808660481c1697816106146040519d8d8f9e8f9081520190610df8565b9a511660208c0152511660408a0152511660608801525116608086015263ffffffff811660a086015263ffffffff8160201c1660c086015260401c16151560e08401526106608161105f565b6101008301520390f35b346101de5760206003193601126101de5760043567ffffffffffffffff81116101de57366023820112156101de57806004013567ffffffffffffffff81116101de57602482013660248360051b850101116101de5760405160206106ce818361103c565b5f825280820192601f1982013685376106e685611735565b956106f4604051978861103c565b858752601f1961070387611735565b01835f5b82811061079b575050505f5b868110156107885760019061076c61076661073660248460051b87010187611690565b9190888b846040519586948486013783018281015f81528d519283915e01015f815203601f19810183528261103c565b30612621565b610776828b61174d565b52610781818a61174d565b5001610713565b604051848152806101da8187018b610e1d565b606082828c010152018490610707565b346101de575f6003193601126101de5760206040515f8152f35b346101de576107d336610dc5565b905f525f60205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060ff60405f2054166040519015158152f35b346101de5760206003193601126101de5760043567ffffffffffffffff81116101de578060040160a060031983360301126101de5760ff60045460401c166104e2575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06020527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475460ff1615610925575b60848201916108b18383611690565b9050156108fd57602092826108c9816108f595611690565b60246108ed6108e66108de60648901876116e1565b979096611690565b3691611085565b950191611cee565b604051908152f35b7f1208b21b000000000000000000000000000000000000000000000000000000005f5260045ffd5b61092d61178e565b6108a2565b346101de575f6003193601126101de5760206040517fbd893629a699470e4ec82a5715bb4981fdaacc5d0a728bf5f55b801d8f4ef10b8152f35b346101de5760206003193601126101de5760043567ffffffffffffffff81116101de5780600401608060031983360301126101de5760ff60045460401c166104e2575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e060209081527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475490926108f592909160ff1615610a41575b610a24610a178280611690565b91909260648501906116e1565b929091602460405195610a37898861103c565b5f87520191611cee565b610a4961178e565b610a0a565b346101de57610a5c36610dc5565b3373ffffffffffffffffffffffffffffffffffffffff821603610a825761053e91611ba5565b7f6697b232000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101de575f6003193601126101de5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346101de5761053e610af536610dc5565b90610b0e610534825f525f602052600160405f20015490565b611ad3565b346101de575f6003193601126101de5760206040516107088152f35b346101de5760206003193601126101de5760206108f56004355f525f602052600160405f20015490565b346101de5760206003193601126101de5760043567ffffffffffffffff811681036101de576108f5602091611649565b346101de57610b9736610d74565b60ff60045460401c166104e2575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06020527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac4754610bff929060ff1615610c3f57611431565b6040516003821015610c12576020918152f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b610c4761178e565b611431565b346101de575f6003193601126101de57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346101de575f6003193601126101de5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346101de5760206003193601126101de57600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101de57817f7965db0b0000000000000000000000000000000000000000000000000000000060209314908115610d4a575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483610d43565b9060206003198301126101de5760043567ffffffffffffffff81116101de57826023820112156101de5780600401359267ffffffffffffffff84116101de57602484830101116101de576024019190565b60031960409101126101de576004359060243573ffffffffffffffffffffffffffffffffffffffff811681036101de5790565b90601f19601f602080948051918291828752018686015e5f8582860101520116010190565b9080602083519182815201916020808360051b8301019401925f915b838310610e4857505050505090565b9091929394602080610e6683601f1986600196030187528951610df8565b97019301930191939290610e39565b90600182811c92168015610ebc575b6020831014610e8f57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691610e84565b6001545f9291610ed582610e75565b8082529160018116908115610f495750600114610ef0575050565b60015f9081529293509091907fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b838310610f2f575060209250010190565b600181602092949394548385870101520191019190610f1e565b60209495507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091509291921683830152151560051b010190565b6040810190811067ffffffffffffffff821117610f9f57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60c0810190811067ffffffffffffffff821117610f9f57604052565b6020810190811067ffffffffffffffff821117610f9f57604052565b6060810190811067ffffffffffffffff821117610f9f57604052565b60e0810190811067ffffffffffffffff821117610f9f57604052565b90601f601f19910116810190811067ffffffffffffffff821117610f9f57604052565b60021115610c1257565b67ffffffffffffffff8111610f9f57601f01601f191660200190565b92919261109182611069565b9161109f604051938461103c565b8294818452818301116101de578281602093845f960137010152565b9080601f830112156101de578160206110d693359101611085565b90565b6020818303126101de5780359067ffffffffffffffff82116101de5701906020828203126101de576040519161110e83610fe8565b80359067ffffffffffffffff82116101de57016060818303126101de576040519161113883611004565b81358352602082013567ffffffffffffffff81116101de578161115c9184016110bb565b6020840152604082013567ffffffffffffffff81116101de5761117f92016110bb565b6040820152815290565b15611192575050565b7fd56bdc26000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9291926111cc82611069565b916111da604051938461103c565b8294818452818301116101de578281602093845f96015e010152565b519060ff821682036101de57565b519067ffffffffffffffff821682036101de57565b91908260409103126101de5760405161123181610f83565b602061124a81839561124281611204565b855201611204565b910152565b519063ffffffff821682036101de57565b91908281039261012084126101de576040519161127c83611020565b8294825167ffffffffffffffff81116101de57830182601f820112156101de576040916112b284836020601f19955191016111c0565b865201126101de576112f7906040516112ca81610f83565b6112d6602085016111f6565b81526112e4604085016111f6565b6020820152602085015260608301611219565b604083015261130860a0820161124f565b606083015261131960c0820161124f565b608083015260e08101519081151582036101de576101009160a084015201519060028210156101de5760c00152565b51906fffffffffffffffffffffffffffffffff821682036101de57565b91908260609103126101de5760405161137d81611004565b604080829461138b81611348565b8452602081015160208501520151910152565b9190610180838203126101de57604051906113b882610fcc565b819380519167ffffffffffffffff83116101de57610140826113e18360a09661124a9601611260565b86526113f08360208301611365565b60208701526114028360808301611365565b604087015261141360e08201611348565b6060870152611426836101008301611219565b608087015201611219565b61143d918101906110d9565b61146c8151517f0000000000000000000000000000000000000000000000000000000000000000808214611189565b60208151015180518101906020818303126101de5760208101519167ffffffffffffffff83116101de576114a792602080920192010161139e565b906114b1826118b3565b6114ba82611946565b916003831015610c1257826115ec57908167ffffffffffffffff6020604060a06110d6960193845184848201511685600354851c168111611564575b505001516040516115498161153b858201948591909160408060608301946fffffffffffffffffffffffffffffffff8151168452602081015160208501520151910152565b03601f19810183528261103c565b51902092510151165f52600560205260405f20555b51611a03565b6115a3866115e593511667ffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000006003541617600355565b7fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff6fffffffffffffffff00000000000000006003549260401b16911617600355565b5f806114f6565b5060018203611631576110d690680100000000000000007fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff600454161760045561155e565b60028214611642576110d69061155e565b5050600290565b67ffffffffffffffff165f52600560205260405f205480156116685790565b7f5b48b457000000000000000000000000000000000000000000000000000000005f5260045ffd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156101de570180359067ffffffffffffffff82116101de576020019181360383136101de57565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156101de570180359067ffffffffffffffff82116101de57602001918160051b360383136101de57565b67ffffffffffffffff8111610f9f5760051b60200190565b80518210156117615760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b335f9081527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e0602052604090205460ff16156117c657565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f52336004527fbd893629a699470e4ec82a5715bb4981fdaacc5d0a728bf5f55b801d8f4ef10b60245260445ffd5b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260ff60405f2054161561184d5750565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b15611885575050565b7f6d23e8a3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b611944906118d981516fffffffffffffffffffffffffffffffff606084015116906126e8565b61193c67ffffffffffffffff602060808185015160405161192e8161153b868201948591909160408060608301946fffffffffffffffffffffffffffffffff8151168452602081015160208501520151910152565b519020940151015116611649565b80821461187c565b565b67ffffffffffffffff602060a08301510151165f52600560205260405f205480155f146119735750505f90565b604082019081516040516119bc8161153b60208201948591909160408060608301946fffffffffffffffffffffffffffffffff8151168452602081015160208501520151910152565b51902014918215926119da575b5050156119d557600190565b600290565b6fffffffffffffffffffffffffffffffff91925060208291015151169151511611155f806119c9565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169080516040602083015192015192803b156101de575f92611a9b92611aad604051968795869485947f41493c600000000000000000000000000000000000000000000000000000000086526004860152606060248601526064850190610df8565b90600319848303016044850152610df8565b03915afa8015611ac857611abe5750565b5f6119449161103c565b6040513d5f823e3d90fd5b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f205416155f14611b9f57805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905573ffffffffffffffffffffffffffffffffffffffff339216907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d5f80a4600190565b50505f90565b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f2054165f14611b9f57805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815416905573ffffffffffffffffffffffffffffffffffffffff339216907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b5f80a4600190565b3567ffffffffffffffff811681036101de5790565b929190611c8e81611735565b93611c9c604051958661103c565b602085838152019160051b8101918383116101de5781905b838210611cc2575050505050565b813567ffffffffffffffff81116101de57602091611ce387849387016110bb565b815201910190611cb4565b9094929193948015612568578101906020818303126101de5780359067ffffffffffffffff82116101de57016040818303126101de5760405191611d3183610f83565b813560028110156101de578352602082013567ffffffffffffffff81116101de57611d5c92016110bb565b90602081019182528051611d6f8161105f565b611d788161105f565b611fe5575051908151820160208101926020818303126101de57602081015167ffffffffffffffff81116101de570190608090829003126101de5760405192611dc084610f83565b602082015167ffffffffffffffff81116101de5782611de9836020604094611df1970101612a5a565b865201611365565b9460208301958652611e288351517f0000000000000000000000000000000000000000000000000000000000000000808214611189565b6020835101519182518301926020818503126101de5760208101519067ffffffffffffffff82116101de5701926040848203126101de5760405193611e6c85610f83565b6020810151855260408101519167ffffffffffffffff83116101de57611e99926020809201920101612ac0565b94611eb360208501968088525180151580611fd957612c0d565b5f805b87518051831015611fa657611ece83611ee19261174d565b5151611edb368888611c82565b90612da9565b15611f9c57508694611f40611f55956fffffffffffffffffffffffffffffffff9a9895611f3961155e966020633b9aca009f9d8198611f20915161174d565b51015190815181518082149182611f88575b5050612c4b565b6001612c99565b51950194611f4d86611c6d565b875191612e1b565b516001815111611f69575b50505151160490565b611f75611f8192611c6d565b90848451511691612eab565b5f80611f60565b909150898401209089830120145f80611f32565b9060010190611eb6565b5061155e92506020915094611f40611f55956fffffffffffffffffffffffffffffffff9a9895633b9aca009c9a98612c99565b5061ffff811115612c0d565b94906001869593949551611ff88161105f565b6120018161105f565b146120485760ff86516120138161105f565b61201c8161105f565b7fd3a2e6c9000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b90919293945051926060602060405161206081610f83565b60405161206c81610fcc565b60405161207881611020565b84815260405161208781610f83565b5f81525f858201528482015260405161209f81610f83565b5f81525f8582015260408201525f858201525f60808201525f60a08201525f60c082015281526120cd612a22565b838201526120d9612a22565b60408201525f848201526040516120ef81610f83565b5f81525f84820152608082015260405161210881610f83565b5f81525f8482015260a08201528152015283518401936020818603126101de5760208101519067ffffffffffffffff82116101de5701936020858203126101de576040519461215686610fe8565b60208101519067ffffffffffffffff82116101de57602061217f92816121ac9501920101612a5a565b808652517f0000000000000000000000000000000000000000000000000000000000000000808214611189565b602084510151948551860160208101966020818303126101de57602081015167ffffffffffffffff81116101de570190604090829003126101de57604051966121f488610f83565b602082015167ffffffffffffffff81116101de578160206122179285010161139e565b885260408201519167ffffffffffffffff83116101de5761223b9201602001612ac0565b9361225560208801958087525180151580611fd957612c0d565b602081019561226387611c6d565b67ffffffffffffffff60a08a5101519181602084015116918291161480612549575b61228e85611c6d565b9267ffffffffffffffff6122a18c611c6d565b91511691156124fb57505050506122bc9061155e89516118b3565b6122c68751611946565b6003811015610c1257806124ca57506122de86611c6d565b67ffffffffffffffff8060035460401c16911611612477575b506040865101516040516123408161153b60208201948591909160408060608301946fffffffffffffffffffffffffffffffff8151168452602081015160208501520151910152565b51902067ffffffffffffffff61235587611c6d565b165f52600560205260405f20555b5f805b8551805183101561244c57611ece8361237e9261174d565b156124425750633b9aca0096936fffffffffffffffffffffffffffffffff9693611f39879460206123b56123cd9660409b5161174d565b5101519081518151808214918261242c575050612c4b565b6123f48351858101519067ffffffffffffffff602060a08185015193015101511690612e1b565b51600181511161240a575b505051015151160490565b61241661242592611c6d565b90858585510151511691612eab565b5f806123ff565b9091506020840120906020830120145f80611f32565b9060010190612366565b5060409592506123cd9150936fffffffffffffffffffffffffffffffff9693633b9aca009895612c99565b6124836124b891611c6d565b67ffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000006003541617600355565b6124c46115a386611c6d565b5f6122f7565b6001915003612363577f59bc8fd3000000000000000000000000000000000000000000000000000000005f5260045ffd5b6084945067ffffffffffffffff9081604051957fb8d8167e00000000000000000000000000000000000000000000000000000000875216600486015216602484015260448301526064820152fd5b5061255384611c6d565b67ffffffffffffffff80845116911614612285565b5050909161257b60206125909201611c6d565b916040519461258986610f83565b3691611c82565b8352602083019182526040516125af8161153b86602083019586612954565b5190205c9151905182156125c9575050633b9aca00900490565b9061261d61260b926040519384937ff06fc33b000000000000000000000000000000000000000000000000000000008552604060048601526044850190610e1d565b90600319848303016024850152610df8565b0390fd5b905f8091602081519101845af480806126d5575b156126555750506040513d81523d5f602083013e60203d82010160405290565b1561269c5773ffffffffffffffffffffffffffffffffffffffff907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b3d156126ad576040513d5f823e3d90fd5b7fd6bda275000000000000000000000000000000000000000000000000000000005f5260045ffd5b503d1515806126355750813b1515612635565b906fffffffffffffffffffffffffffffffff633b9aca00911604428111612925578042034281116128f857610708106128c9575080515161272a600154610e75565b14806128a2575b815190156128625750602081015160ff815116906002549160ff8316928382149283612849575b6020015160ff169215612801575050505063ffffffff606082015116906004549163ffffffff83168082036127d357505063ffffffff608081920151169160201c168082036127a5575050565b7f1eb5c1eb000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f73b1bde3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b6084945060ff90604051947fd382033a000000000000000000000000000000000000000000000000000000008652600486015260081c16602484015260448301526064820152fd5b6020810151600883901c60ff9081169116149350612758565b61261d906040519182917ff6b6676b0000000000000000000000000000000000000000000000000000000083526040600484015261260b60448401610ec6565b508051602081519101206040516128bc8161059a81610ec6565b6020815191012014612731565b7f12e74add000000000000000000000000000000000000000000000000000000005f524260045260245260445ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f20daedb6000000000000000000000000000000000000000000000000000000005f524260045260245260445ffd5b9067ffffffffffffffff90939293168152604060208201526080810190835191604080830152825180915260a0820190602060a08260051b8501019401915f905b8282106129d9575050505060206110d6939401519060607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc082850301910152610df8565b90919294602080612a14837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6089600196030186528951610df8565b970192019201909291612995565b60405190612a2f82611004565b5f6040838281528260208201520152565b9080601f830112156101de5781516110d6926020016111c0565b91906060838203126101de5760405190612a7382611004565b819380518352602081015167ffffffffffffffff81116101de5782612a99918301612a40565b602084015260408101519167ffffffffffffffff83116101de5760409261124a9201612a40565b9080601f830112156101de57815191612ad883611735565b92612ae6604051948561103c565b80845260208085019160051b830101918383116101de5760208101915b838310612b1257505050505090565b825167ffffffffffffffff81116101de578201906040601f1983880301126101de5760405190612b4182610f83565b602083015167ffffffffffffffff81116101de5760209084010187601f820112156101de578051612b7181611735565b91612b7f604051938461103c565b81835260208084019260051b820101918a83116101de5760208201905b838210612bdf5750505050825260408301519167ffffffffffffffff83116101de57612bd088602080969581960101612a40565b83820152815201920191612b03565b815167ffffffffffffffff81116101de57602091612c028e848094880101612a40565b815201910190612b9c565b15612c155750565b7fb0369c31000000000000000000000000000000000000000000000000000000005f52600452600160245261ffff60445260645ffd5b91909115612c57575050565b9061261d61260b926040519384937f5f1ca381000000000000000000000000000000000000000000000000000000008552604060048601526044850190610df8565b91909115612ca5575050565b604051907ffef760c700000000000000000000000000000000000000000000000000000000825280602483016020600485015252604482019260448260051b84010191815f907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603015b838310612d1e5786860387fd5b90919293947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc8782030188528535828112156101de578301906020823592019167ffffffffffffffff81116101de5780360383136101de57602082601f19601f8480600198869897879852868601375f85828601015201160101970198019301919096939296612d11565b908151815103611b9f575f5b8251811015612e1357612dc8818461174d565b5151612dd4828461174d565b515103612e0c57612de5818461174d565b5160208151910120612df7828461174d565b516020815191012003612e0c57600101612db5565b5050505f90565b505050600190565b91612e7060209261193c60405185810190612e678161153b888591909160408060608301946fffffffffffffffffffffffffffffffff8151168452602081015160208501520151910152565b51902091611649565b0151808203612e7d575050565b7f4b2dfe98000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b929190925f5b8451811015612ee9578083612ec86001938861174d565b51604051612edf8161153b60208201948986612954565b5190205d01612eb1565b505050905056fea164736f6c634300081c000a2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac47bd893629a699470e4ec82a5715bb4981fdaacc5d0a728bf5f55b801d8f4ef10bad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5","sourceMap":"1355:25496:38:-:0;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1;;;;;1355:25496:38;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;3774:52;1355:25496;3774:52;1355:25496;3836:47;1355:25496;3893:80;1355:25496;3983:51;1355:25496;;4059:60;;;1355:25496;4059:60;;1355:25496;;;;;;;;;4059:60;;1355:25496;;-1:-1:-1;;;;;1355:25496:38;;;;;;;;;-1:-1:-1;;1355:25496:38;;;;-1:-1:-1;1355:25496:38;;;;;;;;-1:-1:-1;;;;;1355:25496:38;;;;;;;;;;;;;;-1:-1:-1;;;;;1355:25496:38;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1355:25496:38;;;;;;;;;;;;;;;;-1:-1:-1;1355:25496:38;;;;;;;;;;;-1:-1:-1;1355:25496:38;;;;;;;;;;;;;;;;-1:-1:-1;;1355:25496:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1355:25496:38;4129:21;1355:25496;;;-1:-1:-1;1355:25496:38;;;;;;;;;4220:36;1355:25496;;;;;2472:10;;;1355:25496;2472:10;;;;1355:25496;2472:10;;1355:25496;2472:10;1355:25496;;;;;4288:83;2472:10;;1355:25496;-1:-1:-1;;;;;1355:25496:38;;;;4529:44;;;:::i;:::-;;4484:351;1355:25496;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4484:351;4637:43;;4736:45;4637:43;;:::i;:::-;;4736:45;:::i;:::-;;4484:351;;2472:10;;;;-1:-1:-1;2472:10:38;1355:25496;2472:10;;;;-1:-1:-1;2472:10:38;;1355:25496;;;-1:-1:-1;2472:10:38;;1355:25496;2472:10;;-1:-1:-1;2472:10:38;1355:25496;;;;-1:-1:-1;1355:25496:38;;;;;-1:-1:-1;1355:25496:38;;;;;-1:-1:-1;1355:25496:38;;;;;;;;;;;;-1:-1:-1;1355:25496:38;;-1:-1:-1;1355:25496:38;;-1:-1:-1;1355:25496:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1355:25496:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1355:25496:38;;;;;;;;;-1:-1:-1;1355:25496:38;;;;;;;;-1:-1:-1;1355:25496:38;;;;;-1:-1:-1;1355:25496:38;;;;;;;;;;;;-1:-1:-1;1355:25496:38;;;;;-1:-1:-1;1355:25496:38;;-1:-1:-1;1355:25496:38;;;;;;;;;;-1:-1:-1;;;;;1355:25496:38;;;;;;;;;;:::o;:::-;;;;;;;-1:-1:-1;;1355:25496:38;;;-1:-1:-1;;;;;1355:25496:38;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;;;1355:25496:38;;;;;;:::o;:::-;;;;-1:-1:-1;;;;;1355:25496:38;;;;;;;;-1:-1:-1;;1355:25496:38;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;;;;1355:25496:38;;;;;;:::o;:::-;;;;;;;;;;:::o;6155:316:84:-;-1:-1:-1;;;;;1355:25496:38;;;;;;-1:-1:-1;;;;;;;;;;;1355:25496:38;;;;;;;;;;-1:-1:-1;;;;;1355:25496:38;;;;;-1:-1:-1;;;;;;;;;;;1355:25496:38;;;;;;;-1:-1:-1;;1355:25496:38;;;;;735:10:112;;1355:25496:38;-1:-1:-1;;;;;;;;;;;1355:25496:38;;6346:40:84;6323:4;6400:11;:::o;6248:217::-;6442:12;1355:25496:38;6442:12:84;:::o;6155:316::-;-1:-1:-1;;;;;1355:25496:38;;;;;;-1:-1:-1;;;;;;;;;;;1355:25496:38;;;;;;;;;;-1:-1:-1;;;;;1355:25496:38;;;;;-1:-1:-1;;;;;;;;;;;1355:25496:38;;;;;;;-1:-1:-1;;1355:25496:38;;;;;735:10:112;;1355:25496:38;-1:-1:-1;;;;;;;;;;;2576:33:38;-1:-1:-1;;;;;;;;;;;6346:40:84;1355:25496:38;6346:40:84;6323:4;6400:11;:::o;6155:316::-;1355:25496:38;;;-1:-1:-1;;;;;;;;;;;1355:25496:38;;-1:-1:-1;;;;;;;;;;;1355:25496:38;;;;;;;;;-1:-1:-1;;;;;;;;;;;1355:25496:38;;-1:-1:-1;;;;;;;;;;;1355:25496:38;;-1:-1:-1;;1355:25496:38;6323:4:84;1355:25496:38;;;735:10:112;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;1355:25496:38;;6346:40:84;6323:4;6400:11;:::o;6248:217::-;1355:25496:38;6442:12:84;:::o","linkReferences":{}},"deployedBytecode":{"object":"0x6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a714610cd6575080630225293e14610c9c57806308c84e7014610c4c5780630bece35614610b8957806323842fb814610b59578063248a9ca314610b2f5780632c3ee47414610b135780632f2ff15d14610ae4578063314d4dff14610aaa57806336568abe14610a4e5780634d6d9ffb1461096c5780635972185a14610932578063682ed5f01461080e57806391d14854146107c5578063a217fddf146107ab578063ac9650d81461066a578063bd3ce6b01461057a578063ca7242f914610540578063d547741f1461050a578063ddba65371461021c578063e45a6d0d146101e25763ef913a4b1461010e575f80fd5b346101de575f6003193601126101de576101da60405160208082015261012060408201526101c6816101436101608201610ec6565b60ff600254818116606085015260081c16608083015267ffffffffffffffff60035481811660a085015260401c1660c083015260ff60045463ffffffff811660e085015263ffffffff8160201c16610100850152818160401c16151561012085015260481c166101b28161105f565b61014083015203601f19810183528261103c565b604051918291602083526020830190610df8565b0390f35b5f80fd5b346101de575f6003193601126101de5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346101de5761022a36610d74565b6004549160ff8360401c166104e2575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06020527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac4754610298929060ff16156104d5575b8101906110d9565b6102c78151517f0000000000000000000000000000000000000000000000000000000000000000808214611189565b6020815101518051810160208101916020818303126101de57602081015167ffffffffffffffff81116101de57019061018090829003126101de576040519061030f82610fcc565b602081015167ffffffffffffffff81116101de57839082016020019061033491611260565b825261034260408201611348565b60208301908152906103578460608301611219565b604084019081529161036c8560a08401611219565b60608501908152946103818160e08501611365565b9260808601938452610140019061039791611365565b9360a081019485525190516fffffffffffffffffffffffffffffffff166103bd916126e8565b516040805182516fffffffffffffffffffffffffffffffff16602080830191825284015182840152919092015160608084019190915282529061040160808261103c565b51902090516020015167ffffffffffffffff1661041d90611649565b61042a919081811461187c565b516040805182516fffffffffffffffffffffffffffffffff16602080830191825284015182840152919092015160608084019190915282529061046e60808261103c565b51902090516020015167ffffffffffffffff1661048a90611649565b610497919081811461187c565b516104a190611a03565b7fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff1668010000000000000000176004555f80f35b6104dd61178e565b610290565b7f928b1233000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101de5761053e61051b36610dc5565b90610539610534825f525f602052600160405f20015490565b611816565b611ba5565b005b346101de575f6003193601126101de5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346101de575f6003193601126101de576040516105a18161059a81610ec6565b038261103c565b6101206040516105b081610f83565b60025460ff8116825260ff602083019160081c16815260ff6040516105d481610f83565b67ffffffffffffffff600354818116835281602084019160401c168152816004549385808660481c1697816106146040519d8d8f9e8f9081520190610df8565b9a511660208c0152511660408a0152511660608801525116608086015263ffffffff811660a086015263ffffffff8160201c1660c086015260401c16151560e08401526106608161105f565b6101008301520390f35b346101de5760206003193601126101de5760043567ffffffffffffffff81116101de57366023820112156101de57806004013567ffffffffffffffff81116101de57602482013660248360051b850101116101de5760405160206106ce818361103c565b5f825280820192601f1982013685376106e685611735565b956106f4604051978861103c565b858752601f1961070387611735565b01835f5b82811061079b575050505f5b868110156107885760019061076c61076661073660248460051b87010187611690565b9190888b846040519586948486013783018281015f81528d519283915e01015f815203601f19810183528261103c565b30612621565b610776828b61174d565b52610781818a61174d565b5001610713565b604051848152806101da8187018b610e1d565b606082828c010152018490610707565b346101de575f6003193601126101de5760206040515f8152f35b346101de576107d336610dc5565b905f525f60205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060ff60405f2054166040519015158152f35b346101de5760206003193601126101de5760043567ffffffffffffffff81116101de578060040160a060031983360301126101de5760ff60045460401c166104e2575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06020527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475460ff1615610925575b60848201916108b18383611690565b9050156108fd57602092826108c9816108f595611690565b60246108ed6108e66108de60648901876116e1565b979096611690565b3691611085565b950191611cee565b604051908152f35b7f1208b21b000000000000000000000000000000000000000000000000000000005f5260045ffd5b61092d61178e565b6108a2565b346101de575f6003193601126101de5760206040517fbd893629a699470e4ec82a5715bb4981fdaacc5d0a728bf5f55b801d8f4ef10b8152f35b346101de5760206003193601126101de5760043567ffffffffffffffff81116101de5780600401608060031983360301126101de5760ff60045460401c166104e2575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e060209081527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475490926108f592909160ff1615610a41575b610a24610a178280611690565b91909260648501906116e1565b929091602460405195610a37898861103c565b5f87520191611cee565b610a4961178e565b610a0a565b346101de57610a5c36610dc5565b3373ffffffffffffffffffffffffffffffffffffffff821603610a825761053e91611ba5565b7f6697b232000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101de575f6003193601126101de5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346101de5761053e610af536610dc5565b90610b0e610534825f525f602052600160405f20015490565b611ad3565b346101de575f6003193601126101de5760206040516107088152f35b346101de5760206003193601126101de5760206108f56004355f525f602052600160405f20015490565b346101de5760206003193601126101de5760043567ffffffffffffffff811681036101de576108f5602091611649565b346101de57610b9736610d74565b60ff60045460401c166104e2575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06020527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac4754610bff929060ff1615610c3f57611431565b6040516003821015610c12576020918152f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b610c4761178e565b611431565b346101de575f6003193601126101de57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346101de575f6003193601126101de5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346101de5760206003193601126101de57600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101de57817f7965db0b0000000000000000000000000000000000000000000000000000000060209314908115610d4a575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483610d43565b9060206003198301126101de5760043567ffffffffffffffff81116101de57826023820112156101de5780600401359267ffffffffffffffff84116101de57602484830101116101de576024019190565b60031960409101126101de576004359060243573ffffffffffffffffffffffffffffffffffffffff811681036101de5790565b90601f19601f602080948051918291828752018686015e5f8582860101520116010190565b9080602083519182815201916020808360051b8301019401925f915b838310610e4857505050505090565b9091929394602080610e6683601f1986600196030187528951610df8565b97019301930191939290610e39565b90600182811c92168015610ebc575b6020831014610e8f57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691610e84565b6001545f9291610ed582610e75565b8082529160018116908115610f495750600114610ef0575050565b60015f9081529293509091907fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b838310610f2f575060209250010190565b600181602092949394548385870101520191019190610f1e565b60209495507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091509291921683830152151560051b010190565b6040810190811067ffffffffffffffff821117610f9f57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60c0810190811067ffffffffffffffff821117610f9f57604052565b6020810190811067ffffffffffffffff821117610f9f57604052565b6060810190811067ffffffffffffffff821117610f9f57604052565b60e0810190811067ffffffffffffffff821117610f9f57604052565b90601f601f19910116810190811067ffffffffffffffff821117610f9f57604052565b60021115610c1257565b67ffffffffffffffff8111610f9f57601f01601f191660200190565b92919261109182611069565b9161109f604051938461103c565b8294818452818301116101de578281602093845f960137010152565b9080601f830112156101de578160206110d693359101611085565b90565b6020818303126101de5780359067ffffffffffffffff82116101de5701906020828203126101de576040519161110e83610fe8565b80359067ffffffffffffffff82116101de57016060818303126101de576040519161113883611004565b81358352602082013567ffffffffffffffff81116101de578161115c9184016110bb565b6020840152604082013567ffffffffffffffff81116101de5761117f92016110bb565b6040820152815290565b15611192575050565b7fd56bdc26000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9291926111cc82611069565b916111da604051938461103c565b8294818452818301116101de578281602093845f96015e010152565b519060ff821682036101de57565b519067ffffffffffffffff821682036101de57565b91908260409103126101de5760405161123181610f83565b602061124a81839561124281611204565b855201611204565b910152565b519063ffffffff821682036101de57565b91908281039261012084126101de576040519161127c83611020565b8294825167ffffffffffffffff81116101de57830182601f820112156101de576040916112b284836020601f19955191016111c0565b865201126101de576112f7906040516112ca81610f83565b6112d6602085016111f6565b81526112e4604085016111f6565b6020820152602085015260608301611219565b604083015261130860a0820161124f565b606083015261131960c0820161124f565b608083015260e08101519081151582036101de576101009160a084015201519060028210156101de5760c00152565b51906fffffffffffffffffffffffffffffffff821682036101de57565b91908260609103126101de5760405161137d81611004565b604080829461138b81611348565b8452602081015160208501520151910152565b9190610180838203126101de57604051906113b882610fcc565b819380519167ffffffffffffffff83116101de57610140826113e18360a09661124a9601611260565b86526113f08360208301611365565b60208701526114028360808301611365565b604087015261141360e08201611348565b6060870152611426836101008301611219565b608087015201611219565b61143d918101906110d9565b61146c8151517f0000000000000000000000000000000000000000000000000000000000000000808214611189565b60208151015180518101906020818303126101de5760208101519167ffffffffffffffff83116101de576114a792602080920192010161139e565b906114b1826118b3565b6114ba82611946565b916003831015610c1257826115ec57908167ffffffffffffffff6020604060a06110d6960193845184848201511685600354851c168111611564575b505001516040516115498161153b858201948591909160408060608301946fffffffffffffffffffffffffffffffff8151168452602081015160208501520151910152565b03601f19810183528261103c565b51902092510151165f52600560205260405f20555b51611a03565b6115a3866115e593511667ffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000006003541617600355565b7fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff6fffffffffffffffff00000000000000006003549260401b16911617600355565b5f806114f6565b5060018203611631576110d690680100000000000000007fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff600454161760045561155e565b60028214611642576110d69061155e565b5050600290565b67ffffffffffffffff165f52600560205260405f205480156116685790565b7f5b48b457000000000000000000000000000000000000000000000000000000005f5260045ffd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156101de570180359067ffffffffffffffff82116101de576020019181360383136101de57565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156101de570180359067ffffffffffffffff82116101de57602001918160051b360383136101de57565b67ffffffffffffffff8111610f9f5760051b60200190565b80518210156117615760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b335f9081527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e0602052604090205460ff16156117c657565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f52336004527fbd893629a699470e4ec82a5715bb4981fdaacc5d0a728bf5f55b801d8f4ef10b60245260445ffd5b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260ff60405f2054161561184d5750565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b15611885575050565b7f6d23e8a3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b611944906118d981516fffffffffffffffffffffffffffffffff606084015116906126e8565b61193c67ffffffffffffffff602060808185015160405161192e8161153b868201948591909160408060608301946fffffffffffffffffffffffffffffffff8151168452602081015160208501520151910152565b519020940151015116611649565b80821461187c565b565b67ffffffffffffffff602060a08301510151165f52600560205260405f205480155f146119735750505f90565b604082019081516040516119bc8161153b60208201948591909160408060608301946fffffffffffffffffffffffffffffffff8151168452602081015160208501520151910152565b51902014918215926119da575b5050156119d557600190565b600290565b6fffffffffffffffffffffffffffffffff91925060208291015151169151511611155f806119c9565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169080516040602083015192015192803b156101de575f92611a9b92611aad604051968795869485947f41493c600000000000000000000000000000000000000000000000000000000086526004860152606060248601526064850190610df8565b90600319848303016044850152610df8565b03915afa8015611ac857611abe5750565b5f6119449161103c565b6040513d5f823e3d90fd5b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f205416155f14611b9f57805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905573ffffffffffffffffffffffffffffffffffffffff339216907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d5f80a4600190565b50505f90565b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f2054165f14611b9f57805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815416905573ffffffffffffffffffffffffffffffffffffffff339216907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b5f80a4600190565b3567ffffffffffffffff811681036101de5790565b929190611c8e81611735565b93611c9c604051958661103c565b602085838152019160051b8101918383116101de5781905b838210611cc2575050505050565b813567ffffffffffffffff81116101de57602091611ce387849387016110bb565b815201910190611cb4565b9094929193948015612568578101906020818303126101de5780359067ffffffffffffffff82116101de57016040818303126101de5760405191611d3183610f83565b813560028110156101de578352602082013567ffffffffffffffff81116101de57611d5c92016110bb565b90602081019182528051611d6f8161105f565b611d788161105f565b611fe5575051908151820160208101926020818303126101de57602081015167ffffffffffffffff81116101de570190608090829003126101de5760405192611dc084610f83565b602082015167ffffffffffffffff81116101de5782611de9836020604094611df1970101612a5a565b865201611365565b9460208301958652611e288351517f0000000000000000000000000000000000000000000000000000000000000000808214611189565b6020835101519182518301926020818503126101de5760208101519067ffffffffffffffff82116101de5701926040848203126101de5760405193611e6c85610f83565b6020810151855260408101519167ffffffffffffffff83116101de57611e99926020809201920101612ac0565b94611eb360208501968088525180151580611fd957612c0d565b5f805b87518051831015611fa657611ece83611ee19261174d565b5151611edb368888611c82565b90612da9565b15611f9c57508694611f40611f55956fffffffffffffffffffffffffffffffff9a9895611f3961155e966020633b9aca009f9d8198611f20915161174d565b51015190815181518082149182611f88575b5050612c4b565b6001612c99565b51950194611f4d86611c6d565b875191612e1b565b516001815111611f69575b50505151160490565b611f75611f8192611c6d565b90848451511691612eab565b5f80611f60565b909150898401209089830120145f80611f32565b9060010190611eb6565b5061155e92506020915094611f40611f55956fffffffffffffffffffffffffffffffff9a9895633b9aca009c9a98612c99565b5061ffff811115612c0d565b94906001869593949551611ff88161105f565b6120018161105f565b146120485760ff86516120138161105f565b61201c8161105f565b7fd3a2e6c9000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b90919293945051926060602060405161206081610f83565b60405161206c81610fcc565b60405161207881611020565b84815260405161208781610f83565b5f81525f858201528482015260405161209f81610f83565b5f81525f8582015260408201525f858201525f60808201525f60a08201525f60c082015281526120cd612a22565b838201526120d9612a22565b60408201525f848201526040516120ef81610f83565b5f81525f84820152608082015260405161210881610f83565b5f81525f8482015260a08201528152015283518401936020818603126101de5760208101519067ffffffffffffffff82116101de5701936020858203126101de576040519461215686610fe8565b60208101519067ffffffffffffffff82116101de57602061217f92816121ac9501920101612a5a565b808652517f0000000000000000000000000000000000000000000000000000000000000000808214611189565b602084510151948551860160208101966020818303126101de57602081015167ffffffffffffffff81116101de570190604090829003126101de57604051966121f488610f83565b602082015167ffffffffffffffff81116101de578160206122179285010161139e565b885260408201519167ffffffffffffffff83116101de5761223b9201602001612ac0565b9361225560208801958087525180151580611fd957612c0d565b602081019561226387611c6d565b67ffffffffffffffff60a08a5101519181602084015116918291161480612549575b61228e85611c6d565b9267ffffffffffffffff6122a18c611c6d565b91511691156124fb57505050506122bc9061155e89516118b3565b6122c68751611946565b6003811015610c1257806124ca57506122de86611c6d565b67ffffffffffffffff8060035460401c16911611612477575b506040865101516040516123408161153b60208201948591909160408060608301946fffffffffffffffffffffffffffffffff8151168452602081015160208501520151910152565b51902067ffffffffffffffff61235587611c6d565b165f52600560205260405f20555b5f805b8551805183101561244c57611ece8361237e9261174d565b156124425750633b9aca0096936fffffffffffffffffffffffffffffffff9693611f39879460206123b56123cd9660409b5161174d565b5101519081518151808214918261242c575050612c4b565b6123f48351858101519067ffffffffffffffff602060a08185015193015101511690612e1b565b51600181511161240a575b505051015151160490565b61241661242592611c6d565b90858585510151511691612eab565b5f806123ff565b9091506020840120906020830120145f80611f32565b9060010190612366565b5060409592506123cd9150936fffffffffffffffffffffffffffffffff9693633b9aca009895612c99565b6124836124b891611c6d565b67ffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000006003541617600355565b6124c46115a386611c6d565b5f6122f7565b6001915003612363577f59bc8fd3000000000000000000000000000000000000000000000000000000005f5260045ffd5b6084945067ffffffffffffffff9081604051957fb8d8167e00000000000000000000000000000000000000000000000000000000875216600486015216602484015260448301526064820152fd5b5061255384611c6d565b67ffffffffffffffff80845116911614612285565b5050909161257b60206125909201611c6d565b916040519461258986610f83565b3691611c82565b8352602083019182526040516125af8161153b86602083019586612954565b5190205c9151905182156125c9575050633b9aca00900490565b9061261d61260b926040519384937ff06fc33b000000000000000000000000000000000000000000000000000000008552604060048601526044850190610e1d565b90600319848303016024850152610df8565b0390fd5b905f8091602081519101845af480806126d5575b156126555750506040513d81523d5f602083013e60203d82010160405290565b1561269c5773ffffffffffffffffffffffffffffffffffffffff907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b3d156126ad576040513d5f823e3d90fd5b7fd6bda275000000000000000000000000000000000000000000000000000000005f5260045ffd5b503d1515806126355750813b1515612635565b906fffffffffffffffffffffffffffffffff633b9aca00911604428111612925578042034281116128f857610708106128c9575080515161272a600154610e75565b14806128a2575b815190156128625750602081015160ff815116906002549160ff8316928382149283612849575b6020015160ff169215612801575050505063ffffffff606082015116906004549163ffffffff83168082036127d357505063ffffffff608081920151169160201c168082036127a5575050565b7f1eb5c1eb000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f73b1bde3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b6084945060ff90604051947fd382033a000000000000000000000000000000000000000000000000000000008652600486015260081c16602484015260448301526064820152fd5b6020810151600883901c60ff9081169116149350612758565b61261d906040519182917ff6b6676b0000000000000000000000000000000000000000000000000000000083526040600484015261260b60448401610ec6565b508051602081519101206040516128bc8161059a81610ec6565b6020815191012014612731565b7f12e74add000000000000000000000000000000000000000000000000000000005f524260045260245260445ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f20daedb6000000000000000000000000000000000000000000000000000000005f524260045260245260445ffd5b9067ffffffffffffffff90939293168152604060208201526080810190835191604080830152825180915260a0820190602060a08260051b8501019401915f905b8282106129d9575050505060206110d6939401519060607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc082850301910152610df8565b90919294602080612a14837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6089600196030186528951610df8565b970192019201909291612995565b60405190612a2f82611004565b5f6040838281528260208201520152565b9080601f830112156101de5781516110d6926020016111c0565b91906060838203126101de5760405190612a7382611004565b819380518352602081015167ffffffffffffffff81116101de5782612a99918301612a40565b602084015260408101519167ffffffffffffffff83116101de5760409261124a9201612a40565b9080601f830112156101de57815191612ad883611735565b92612ae6604051948561103c565b80845260208085019160051b830101918383116101de5760208101915b838310612b1257505050505090565b825167ffffffffffffffff81116101de578201906040601f1983880301126101de5760405190612b4182610f83565b602083015167ffffffffffffffff81116101de5760209084010187601f820112156101de578051612b7181611735565b91612b7f604051938461103c565b81835260208084019260051b820101918a83116101de5760208201905b838210612bdf5750505050825260408301519167ffffffffffffffff83116101de57612bd088602080969581960101612a40565b83820152815201920191612b03565b815167ffffffffffffffff81116101de57602091612c028e848094880101612a40565b815201910190612b9c565b15612c155750565b7fb0369c31000000000000000000000000000000000000000000000000000000005f52600452600160245261ffff60445260645ffd5b91909115612c57575050565b9061261d61260b926040519384937f5f1ca381000000000000000000000000000000000000000000000000000000008552604060048601526044850190610df8565b91909115612ca5575050565b604051907ffef760c700000000000000000000000000000000000000000000000000000000825280602483016020600485015252604482019260448260051b84010191815f907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603015b838310612d1e5786860387fd5b90919293947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc8782030188528535828112156101de578301906020823592019167ffffffffffffffff81116101de5780360383136101de57602082601f19601f8480600198869897879852868601375f85828601015201160101970198019301919096939296612d11565b908151815103611b9f575f5b8251811015612e1357612dc8818461174d565b5151612dd4828461174d565b515103612e0c57612de5818461174d565b5160208151910120612df7828461174d565b516020815191012003612e0c57600101612db5565b5050505f90565b505050600190565b91612e7060209261193c60405185810190612e678161153b888591909160408060608301946fffffffffffffffffffffffffffffffff8151168452602081015160208501520151910152565b51902091611649565b0151808203612e7d575050565b7f4b2dfe98000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b929190925f5b8451811015612ee9578083612ec86001938861174d565b51604051612edf8161153b60208201948986612954565b5190205d01612eb1565b505050905056fea164736f6c634300081c000a","sourceMap":"1355:25496:38:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1355:25496:38;;;;;;;;4960:23;;;;1355:25496;;;;;;4960:23;1355:25496;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4960:23;1355:25496;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;4960:23;-1:-1:-1;;4960:23:38;;;;;;:::i;:::-;1355:25496;;;;;4960:23;1355:25496;;4960:23;1355:25496;;;;:::i;:::-;;;;;;;;;;;;;-1:-1:-1;;1355:25496:38;;;;;;;;1648:48;1355:25496;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;9619:70;;1355:25496;;;26731:42;26727:105;;1355:25496;9619:70;;;;:::i;:::-;9699:196;9720:30;;1355:25496;9759:25;9720:64;;;9699:196;:::i;:::-;1355:25496;9982:30;;:43;;1355:25496;;9971:95;;1355:25496;9971:95;;1355:25496;;;;;;;;;9971:95;;1355:25496;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;19046:18;1355:25496;;;;19066:11;;;:::i;:::-;19282:29;1355:25496;;;;;;;;19271:41;;;1355:25496;;;;;;;;;;;;;;;;;;;;;;;19271:41;;;;1355:25496;;19271:41;:::i;:::-;1355:25496;19261:52;;19381:21;;1355:25496;19381:36;1355:25496;;;19359:59;;;:::i;:::-;19428:179;;19449:54;;;;19428:179;:::i;:::-;19811:29;1355:25496;;;;;;;;19800:41;;;1355:25496;;;;;;;;;;;;;;;;;;;;;;;19800:41;;;;1355:25496;;19800:41;:::i;:::-;1355:25496;19790:52;;19910:21;;1355:25496;19910:36;1355:25496;;;19888:59;;;:::i;:::-;19957:179;;19978:54;;;;19957:179;:::i;:::-;10139:30;;;;:::i;:::-;1355:25496;;;;;;;;;26727:105;26800:20;;:::i;:::-;26727:105;;1355:25496;;;;;;;;;;;4723:26:84;1355:25496:38;;;:::i;:::-;4693:18:84;2484:4;4693:18;;3877:6;1355:25496:38;3877:6:84;1355:25496:38;;3877:22:84;1355:25496:38;3877:6:84;1355:25496:38;3877:22:84;1355:25496:38;3786:120:84;;4693:18;2484:4;:::i;:::-;4723:26;:::i;:::-;1355:25496:38;;;;;;-1:-1:-1;;1355:25496:38;;;;;;;;1551:51;1355:25496;;;;;;;;-1:-1:-1;;1355:25496:38;;;;;;;;;;;;:::i;:::-;;;;:::i;:::-;;;;;;;:::i;:::-;2095:51;1355:25496;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;2095:51;1355:25496;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;-1:-1:-1;;1355:25496:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1;;1355:25496:38;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;-1:-1:-1;;1355:25496:38;;;:::i;:::-;;;;;;;;;;1526:13:116;;;1355:25496:38;1558:3:116;1541:15;;;;;;1347:26;1355:25496:38;1590:75:116;1355:25496:38;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1355:25496:38;;;;;;:::i;:::-;1627:4:116;1590:75;:::i;:::-;1577:88;;;;:::i;:::-;;;;;;:::i;:::-;;1355:25496:38;1526:13:116;;1541:15;1355:25496:38;;;;;;;;;;1541:15:116;1355:25496:38;:::i;:::-;;;;;;;;;;;;;;;;;;-1:-1:-1;;1355:25496:38;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;2930:29:84;1355:25496:38;-1:-1:-1;1355:25496:38;;;;;;-1:-1:-1;1355:25496:38;;;;;;;;;;;;;;;;-1:-1:-1;;1355:25496:38;;;;;;;;;;;;;;;;-1:-1:-1;;1355:25496:38;;;;;;;;;;;;;;;;;;;;;;;;;26731:42;26727:105;;1355:25496;7188:10;;;;;;;;:::i;:::-;:21;;;1355:25496;;;7253:10;;;;7241:64;7253:10;;:::i;:::-;7265:16;1355:25496;7294:10;7283:9;;;;;;:::i;:::-;7294:10;;;;:::i;:::-;1355:25496;;;:::i;:::-;7265:16;;7241:64;;:::i;:::-;1355:25496;;;;;;;;;;;;;26727:105;26800:20;;:::i;:::-;26727:105;;1355:25496;;;;;-1:-1:-1;;1355:25496:38;;;;;;;;2576:33;1355:25496;;;;;;;;-1:-1:-1;;1355:25496:38;;;;;;;;;;;;;;;;-1:-1:-1;;1355:25496:38;;;;;;;;;;;;;;;;;;;;;;;;;;;7544:63;;1355:25496;;;;26731:42;26727:105;;1355:25496;7586:9;7556:10;;;;:::i;:::-;7586:9;;;;;;;;:::i;:::-;1355:25496;;;7568:16;1355:25496;;;;;;;:::i;:::-;;;;7568:16;7544:63;;:::i;26727:105::-;26800:20;;:::i;:::-;26727:105;;1355:25496;;;;;;;:::i;:::-;735:10:112;1355:25496:38;;;5397:34:84;5393:102;;5505:37;;;:::i;5393:102::-;5454:30;1355:25496:38;5454:30:84;1355:25496:38;;5454:30:84;1355:25496:38;;;;;-1:-1:-1;;1355:25496:38;;;;;;;;1854:50;1355:25496;;;;;;;4306:25:84;1355:25496:38;;;:::i;:::-;4276:18:84;2484:4;4276:18;;3877:6;1355:25496:38;3877:6:84;1355:25496:38;;3877:22:84;1355:25496:38;3877:6:84;1355:25496:38;3877:22:84;1355:25496:38;3786:120:84;;2484:4;4306:25;:::i;1355:25496:38:-;;;;;-1:-1:-1;;1355:25496:38;;;;;;;;2472:10;1355:25496;;;;;;;;-1:-1:-1;;1355:25496:38;;;;;;;;;3877:6:84;1355:25496:38;3877:6:84;1355:25496:38;;3877:22:84;1355:25496:38;3877:6:84;1355:25496:38;3877:22:84;1355:25496:38;3786:120:84;;1355:25496:38;;;;;-1:-1:-1;;1355:25496:38;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;5401:1560;;1355:25496;;;26731:42;26727:105;;5401:1560;:::i;:::-;1355:25496;;;;;;;;;;;;;;;;;;;;;;;26727:105;26800:20;;:::i;:::-;5401:1560;:::i;1355:25496::-;;;;;-1:-1:-1;;1355:25496:38;;;;;;;;;1950:38;1355:25496;;;;;;;;;-1:-1:-1;;1355:25496:38;;;;;;;;1742:66;1355:25496;;;;;;;;-1:-1:-1;;1355:25496:38;;;;;;;;;;;;;;;;2649:47:84;2664:32;1355:25496:38;2649:47:84;;:87;;;;;1355:25496:38;;;;;;;2649:87:84;844:25:124;829:40;;;2649:87:84;;;1355:25496:38;;;-1:-1:-1;;1355:25496:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;-1:-1:-1;;1355:25496:38;;;;;;;;;;;;;;;;;;;:::o;:::-;;-1:-1:-1;;1355:25496:38;;;;;;;;;;;;;;;;;-1:-1:-1;1355:25496:38;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1355:25496:38;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;-1:-1:-1;;1355:25496:38;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;2095:51;1355:25496;;;;;;;:::i;:::-;;;;;2095:51;1355:25496;;;2095:51;;;;1355:25496;;;;;;;:::o;:::-;2095:51;-1:-1:-1;1355:25496:38;;;;;-1:-1:-1;1355:25496:38;;-1:-1:-1;1355:25496:38;;;;;;;;;;;;;;:::o;:::-;2095:51;1355:25496;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::o;:::-;;-1:-1:-1;1355:25496:38;;;;;-1:-1:-1;1355:25496:38;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;1355:25496:38;;;;;;;;;;;;;;;;:::o;:::-;;-1:-1:-1;1355:25496:38;;;:::o;:::-;;;;;;;;-1:-1:-1;;1355:25496:38;;;;:::o;:::-;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;-1:-1:-1;1355:25496:38;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::o;:::-;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;-1:-1:-1;1355:25496:38;;;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1355:25496:38;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;:::i;5401:1560::-;5644:58;5401:1560;5644:58;;;;:::i;:::-;5712:186;5733:24;;1355:25496;5766:26;5733:59;;;5712:186;:::i;:::-;5985:37;:24;;:37;;1355:25496;;5974:89;;1355:25496;5985:37;1355:25496;;;;;;5985:37;5974:89;;1355:25496;;;;;;;;5974:89;5985:37;5974:89;;;1355:25496;;;;:::i;:::-;6108:6;;;;:::i;:::-;6171:26;;;:::i;:::-;1355:25496;;;;;;;6211:52;;;6344:16;;1355:25496;5985:37;1355:25496;6344:16;6899:24;6344:16;;;;;:31;;;;1355:25496;;;;;;;;6344:73;;6340:155;;6207:666;6586:24;;;;1355:25496;;6575:36;;;;;;;;1355:25496;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6575:36;;-1:-1:-1;;6575:36:38;;;;;;:::i;:::-;1355:25496;6565:47;;6530:16;;:31;1355:25496;;-1:-1:-1;1355:25496:38;6508:21;5985:37;1355:25496;;-1:-1:-1;1355:25496:38;;6207:666;6899:24;;:::i;6340:155::-;1355:25496;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6340:155;;;;6207:666;-1:-1:-1;1355:25496:38;6633:58;;1355:25496;;6899:24;1355:25496;;;6707:20;1355:25496;;;6707:20;1355:25496;6207:666;;6629:244;6771:34;6755:50;;6751:122;;6899:24;6629:244;6207:666;;6751:122;6821:41;;6771:34;6821:41;:::o;5036:228::-;1355:25496;;-1:-1:-1;1355:25496:38;5145:21;1355:25496;;;-1:-1:-1;1355:25496:38;;5200:9;;1355:25496;;5036:228;:::o;1355:25496::-;;-1:-1:-1;1355:25496:38;;-1:-1:-1;1355:25496:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;3175:103:84;735:10:112;2930:6:84;1355:25496:38;;;;;;;;;;;;3495:23:84;3491:108;;3175:103::o;3491:108::-;3541:47;2930:6;3541:47;735:10:112;3541:47:84;1355:25496:38;2576:33;1355:25496;;;2930:6:84;3541:47;3175:103;1355:25496:38;2930:6:84;1355:25496:38;2930:6:84;1355:25496:38;;;2930:6:84;1355:25496:38;;735:10:112;1355:25496:38;-1:-1:-1;1355:25496:38;;;;;-1:-1:-1;1355:25496:38;;;3495:23:84;3491:108;;3175:103;:::o;3491:108::-;3541:47;2930:6;3541:47;735:10:112;3541:47:84;1355:25496:38;;;;2930:6:84;3541:47;1355:25496:38;;;;;;:::o;:::-;;;;;;;;;;;18217:570;18605:175;18217:570;18383:11;18363:18;;1355:25496;18383:11;;;1355:25496;;18383:11;;:::i;:::-;18537:58;1355:25496;18462:28;18559:20;18462:28;;;;1355:25496;;18451:40;;;;;;;;1355:25496;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18451:40;1355:25496;18441:51;;18559:20;;;:35;1355:25496;;18537:58;:::i;:::-;18626:52;;;18605:175;:::i;:::-;18217:570::o;22962:1028::-;1355:25496;23184:31;:16;;;;:31;1355:25496;;;;23162:21;23184:31;1355:25496;;;;;23230:32;;23226:758;23230:32;;;23350:43;;1355:25496;23350:43;:::o;23226:758::-;1355:25496;23470:24;;;;;1355:25496;;23459:36;;;23184:31;23459:36;;;;1355:25496;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23459:36;1355:25496;23449:47;;23427:69;;;;:165;;;23226:758;-1:-1:-1;;23410:574:38;;;23768:42;23761:49;:::o;23410:574::-;23939:34;23932:41;:::o;23427:165::-;1355:25496;23516:28;;;23184:31;23516:28;;;;1355:25496;;23558:24;;1355:25496;;-1:-1:-1;23516:76:38;23427:165;;;;24151:152;1355:25496;24231:8;1355:25496;;;;24284:11;24264:18;;;;24284:11;;;24231:65;;;;;;-1:-1:-1;1355:25496:38;;;;24284:11;1355:25496;24231:65;;;;;;;1355:25496;24231:65;;;;;1355:25496;;;;;;;;;;;:::i;:::-;;-1:-1:-1;;1355:25496:38;;;;;;;;;:::i;:::-;24231:65;;;;;;;;;;24151:152;:::o;24231:65::-;-1:-1:-1;24231:65:38;;;:::i;:::-;24284:11;1355:25496;;-1:-1:-1;1355:25496:38;;;;;6155:316:84;1355:25496:38;;;;;;;;;;;;-1:-1:-1;1355:25496:38;;;;;-1:-1:-1;1355:25496:38;;;6252:23:84;6248:217;1355:25496:38;;;;;;;;;;;;;;;-1:-1:-1;1355:25496:38;;;;-1:-1:-1;1355:25496:38;6323:4:84;1355:25496:38;;;;;;;;735:10:112;1355:25496:38;;6346:40:84;;1355:25496:38;6346:40:84;;6323:4;6400:11;:::o;6248:217::-;6442:12;;1355:25496:38;6442:12:84;:::o;6708:317::-;1355:25496:38;;;;;;;;;;;;-1:-1:-1;1355:25496:38;;;;;-1:-1:-1;1355:25496:38;;;6802:217:84;1355:25496:38;;;;;;;;;;;;;;;-1:-1:-1;1355:25496:38;;;;-1:-1:-1;1355:25496:38;;;;;;;;735:10:112;1355:25496:38;;6900:40:84;;1355:25496:38;6900:40:84;;1355:25496:38;6954:11:84;:::o;1355:25496:38:-;;;;;;;;;;:::o;:::-;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;8191:1064;;;;;;;8421:17;;8417:181;;8665:52;;1355:25496;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;:::i;:::-;;;;:::i;:::-;8731:83;;8876:21;;1355:25496;;;10929:60;;1355:25496;10929:60;;1355:25496;;;;;;;;;10929:60;;1355:25496;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;10999:160;11020:14;;1355:25496;11043:23;11020:46;;;10999:160;:::i;:::-;1355:25496;11242:14;;:27;;1355:25496;;;11231:75;;1355:25496;;;;;;;;;11231:75;;1355:25496;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;11231:75;1355:25496;11231:75;;;1355:25496;;;;:::i;:::-;;11316:177;1355:25496;;;;;;;;11337:25;;;:70;;;11316:177;:::i;:::-;1355:25496;;11663:3;11640:14;;1355:25496;;11636:25;;;;;11703:17;;11691:43;11703:17;;:::i;:::-;;:22;1355:25496;;;;;:::i;:::-;11691:43;;:::i;:::-;11690:44;11686:99;;11824:14;;;12132:50;12335:14;11824;1355:25496;11824:14;;;11865:185;12280:27;11824:14;1355:25496;26385:3;11824:14;;;;:17;:14;;:17;:::i;:::-;;:23;;1355:25496;;;;;11894:30;;;:72;;;;11663:3;11865:185;;;:::i;:::-;1355:25496;12132:50;:::i;:::-;1355:25496;12252:26;;;;;;:::i;:::-;12280:27;;;;:::i;12335:14::-;12464;1355:25496;;;12464:25;12460:152;;11616:503;12651:27;;;1355:25496;;;8830:81;:::o;12460:152::-;12519:26;12505:96;12519:26;;:::i;:::-;12563:27;;;;1355:25496;;12505:96;;:::i;:::-;12460:152;;;;11894:72;1355:25496;;;;;;11928:16;1355:25496;;;;11948:18;11928:38;11894:72;;;;11686:99;11758:8;1355:25496;;11621:13;;;11636:25;;12280:27;11636:25;;1355:25496;11636:25;;;12132:50;12335:14;11636:25;1355:25496;11636:25;;;26385:3;11636:25;;;12132:50;:::i;11337:70::-;11366:41;1355:25496;11366:41;;;11316:177;:::i;8727:421::-;1355:25496;;;;;;;;;;;;:::i;:::-;;;;:::i;:::-;8932:98;8928:220;;1355:25496;8727:421;1355:25496;;;;:::i;:::-;;;;:::i;:::-;9188:60;1355:25496;9188:60;1355:25496;9188:60;1355:25496;;;9188:60;8928:220;9102:21;;;;;;;1355:25496;;;;;;;;:::i;:::-;;;;;;:::i;:::-;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;-1:-1:-1;1355:25496:38;;-1:-1:-1;1355:25496:38;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;1355:25496:38;;-1:-1:-1;1355:25496:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;1355:25496:38;;-1:-1:-1;1355:25496:38;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;1355:25496:38;;-1:-1:-1;1355:25496:38;;;;;;;;;;;;;;13696:75;;1355:25496;;;;;;;;;13696:75;;1355:25496;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;13696:75;;13785:208;13696:75;;1355:25496;;;;:::i;:::-;;;;;13833:41;13810:64;;;13785:208;:::i;:::-;1355:25496;14028:14;;:27;;1355:25496;;;14017:95;;1355:25496;14017:95;;1355:25496;;;;;;;;;14017:95;;1355:25496;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;:::i;:::-;;14126:189;1355:25496;;;;;;;;14151:25;;;:70;;;14126:189;:::i;:::-;1355:25496;14355:26;;;;;;:::i;:::-;1355:25496;;14385:25;;:35;;:50;;1355:25496;14385:50;;1355:25496;;;;;;14355:80;:184;;;8928:220;14598:26;;;:::i;:::-;14646;1355:25496;14646:26;;;:::i;:::-;1355:25496;;;;;;;14897:25;;;;14954:14;14897:25;;;;;:::i;14954:14::-;15080:45;15099:25;;15080:45;:::i;:::-;1355:25496;;;;;;15143:52;;;15284:26;;;;:::i;:::-;1355:25496;;;;;;;;;15284:68;15280:153;;15139:599;15543:25;1355:25496;15543:25;;:43;;1355:25496;;15532:55;;;1355:25496;15532:55;;;;1355:25496;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15532:55;1355:25496;15522:66;;1355:25496;15472:26;;;:::i;:::-;1355:25496;;;15450:21;1355:25496;;;;;;15139:599;1355:25496;;15927:3;15904:14;;1355:25496;;15900:25;;;;;15967:17;;15955:43;15967:17;;:::i;15955:43::-;15954:44;15950:99;;16088:14;26385:3;16088:14;;1355:25496;16088:14;;16129:185;16088:14;;1355:25496;16088:17;16396:50;16088:14;1355:25496;16088:14;;:17;:::i;:::-;;:23;;1355:25496;;;;;16158:30;;;:72;;;;16129:185;;;:::i;16396:50::-;16632:43;16506:25;;:43;;;;:48;1355:25496;;;16506:48;;;1355:25496;16568:35;;;:50;1355:25496;;16632:43;;:::i;:::-;16799:14;1355:25496;;;16799:25;16795:198;;15880:503;17032:25;;;:43;;1355:25496;;;9046:91;:::o;16795:198::-;16871:26;16840:142;16871:26;;:::i;:::-;16915:25;;;;;:43;;1355:25496;;16840:142;;:::i;:::-;16795:198;;;;16158:72;1355:25496;;;;;;16192:16;1355:25496;;;;16212:18;16192:38;16158:72;;;;15950:99;16022:8;1355:25496;;15885:13;;;15900:25;;1355:25496;15900:25;;;16396:50;15900:25;;;1355:25496;15900:25;;26385:3;15900:25;;16396:50;:::i;15280:153::-;1355:25496;;;;:::i;:::-;;;;;;;;;;;;;;;;:::i;:::-;15280:153;;;15139:599;1355:25496;;;15613:58;15139:599;15609:129;15698:25;1355:25496;15698:25;;1355:25496;15698:25;1355:25496;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14355:184;14459:26;;;;:::i;:::-;1355:25496;;;;;;;14459:80;14355:184;;8417:181;8522:26;;;;;;1355:25496;8522:26;;;:::i;:::-;1355:25496;;;;;;;:::i;:::-;;;;:::i;:::-;;;8522:26;8550:35;;1355:25496;;;;;25522:31;;;;8522:26;25522:31;;;;;:::i;:::-;1355:25496;25512:42;;4288:69:121;25671:11:38;;25684:12;;25632:14;;1355:25496;;8489:98;;26385:3;8489:98;1355:25496;8482:105;:::o;1355:25496::-;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;-1:-1:-1;;1355:25496:38;;;;;;;;;:::i;:::-;;;;4691:549:110;;-1:-1:-1;4691:549:110;;3490:129:115;;;;;;;;;;4874:72:110;;4691:549;4870:364;;;4774:252:115;;;;;;;;-1:-1:-1;3490:129:115;4774:252;;;3490:129;4774:252;;;;;;4962:32:110;:::o;4870:364::-;5011:223;;;1355:25496:38;5045:24:110;;-1:-1:-1;5045:24:110;1355:25496:38;5045:24:110;1355:25496:38;;-1:-1:-1;5045:24:110;5011:223;4536:73:115;5090:33:110;4536:73:115;;1355:25496:38;;;-1:-1:-1;1355:25496:38;;;;;5086:148:110;5204:19;-1:-1:-1;5204:19:110;;-1:-1:-1;5204:19:110;4874:72;-1:-1:-1;4536:73:115;4886:33:110;;;4874:72;4886:59;4923:18;;;:22;;4874:72;;20400:2140:38;;1355:25496;26385:3;20400:2140;1355:25496;;20608:15;20583:40;;1355:25496;;20608:15;;1355:25496;20608:15;1355:25496;;;;2472:10;-1:-1:-1;1355:25496:38;;21386:25;;;1355:25496;;21429:11;1355:25496;;:::i;:::-;21380:76;:180;;;20400:2140;21611:25;;1355:25496;;;;21678:28;;;;;1355:25496;;;;;21720:22;1355:25496;;;;;21678:74;;;;:172;;;;20400:2140;21678:28;22062:40;1355:25496;;;;;;;22157:32;;;;1355:25496;22157:32;;;1355:25496;;;22193:26;1355:25496;;;;;22157:62;;;1355:25496;;22358:33;;1355:25496;22358:33;;;;1355:25496;;;21678:28;1355:25496;;22358:64;;;1355:25496;;20400:2140;;:::o;1355:25496::-;;-1:-1:-1;1355:25496:38;22193:26;1355:25496;;;;-1:-1:-1;1355:25496:38;;;-1:-1:-1;1355:25496:38;22193:26;1355:25496;;;;-1:-1:-1;1355:25496:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21678:172;:28;21772:40;;1355:25496;;;;;;;;;;;21772:78;;-1:-1:-1;21678:172:38;;1355:25496;;;;;;;;;;;;;;;;;;;;;:::i;21380:180::-;21492:25;;;1355:25496;;;;;21476:43;1355:25496;;;;;;;:::i;:::-;;;;;;21523:37;21476:84;21380:180;;1355:25496;;-1:-1:-1;1355:25496:38;20608:15;1355:25496;;;;;-1:-1:-1;1355:25496:38;;;-1:-1:-1;1355:25496:38;;;;;-1:-1:-1;1355:25496:38;;;-1:-1:-1;1355:25496:38;20608:15;1355:25496;;;;;-1:-1:-1;1355:25496:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;1355:25496:38;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;-1:-1:-1;;1355:25496:38;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::o;:::-;;;;;;8961:69;1355:25496;;14284:16;1355:25496;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1355:25496:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1355:25496:38;;;;;;;;;;;;;;;-1:-1:-1;1355:25496:38;;;;;;;;;;;;;;;;;;;;;;;;358:427:47;;1355:25496:38;;;;452:20:47;448:63;;1355:25496:38;554:3:47;1355:25496:38;;540:12:47;;;;;577:4;;;;:::i;:::-;;1355:25496:38;592:4:47;;;;:::i;:::-;;1355:25496:38;577:26:47;573:77;;677:4;;;;:::i;:::-;;1355:25496:38;;;;;667:15:47;696:4;;;;:::i;:::-;;1355:25496:38;;;;;686:15:47;667:34;663:85;;1355:25496:38;;525:13:47;;663:85;721:12;;;1355:25496:38;721:12:47;:::o;540:::-;;;;1355:25496:38;358:427:47;:::o;17339:759:38:-;;17732:177;17609:33;17339:759;17688:34;1355:25496;;17609:33;;;;;;;;;1355:25496;;;;;;;;;;;;;;;;;;;;;;;;;;;;;17609:33;1355:25496;17599:44;;17688:34;;:::i;17732:177::-;17965:26;1355:25496;17941:50;;;1355:25496;;17339:759;;:::o;1355:25496::-;;-1:-1:-1;1355:25496:38;;;;;;-1:-1:-1;1355:25496:38;24776:318;;;;;24914:1;24937:3;1355:25496;;24917:18;;;;;25011:10;;;1355:25496;25011:10;;;:::i;:::-;;1355:25496;;24987:35;;;;;;;;;;:::i;:::-;1355:25496;24977:46;;4520:68:121;1355:25496:38;24902:13;;24917:18;;;;;;24776:318::o","linkReferences":{},"immutableReferences":{"6424":[{"start":1367,"length":32},{"start":5189,"length":32}],"6427":[{"start":505,"length":32},{"start":7681,"length":32}],"6430":[{"start":3251,"length":32},{"start":8581,"length":32}],"6433":[{"start":672,"length":32},{"start":2753,"length":32}],"6437":[{"start":3192,"length":32},{"start":6682,"length":32}]}},"methodIdentifiers":{"ALLOWED_SP1_CLOCK_DRIFT()":"2c3ee474","DEFAULT_ADMIN_ROLE()":"a217fddf","MEMBERSHIP_PROGRAM_VKEY()":"e45a6d0d","MISBEHAVIOUR_PROGRAM_VKEY()":"314d4dff","PROOF_SUBMITTER_ROLE()":"5972185a","UPDATE_CLIENT_AND_MEMBERSHIP_PROGRAM_VKEY()":"0225293e","UPDATE_CLIENT_PROGRAM_VKEY()":"ca7242f9","VERIFIER()":"08c84e70","clientState()":"bd3ce6b0","getClientState()":"ef913a4b","getConsensusStateHash(uint64)":"23842fb8","getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","misbehaviour(bytes)":"ddba6537","multicall(bytes[])":"ac9650d8","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7","updateClient(bytes)":"0bece356","verifyMembership((bytes,(uint64,uint64),bytes[],bytes))":"682ed5f0","verifyNonMembership((bytes,(uint64,uint64),bytes[]))":"4d6d9ffb"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.28+commit.7893614a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"updateClientProgramVkey\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"membershipProgramVkey\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"updateClientAndMembershipProgramVkey\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"misbehaviourProgramVkey\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"sp1Verifier\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_clientState\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"_consensusState\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"roleManager\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotHandleMisbehavior\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"expected\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"actual\",\"type\":\"string\"}],\"name\":\"ChainIdMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"expected\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"actual\",\"type\":\"bytes\"}],\"name\":\"ClientStateMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"expected\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"actual\",\"type\":\"bytes32\"}],\"name\":\"ConsensusStateHashMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConsensusStateNotFound\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"expected\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"actual\",\"type\":\"bytes32\"}],\"name\":\"ConsensusStateRootMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FeatureNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FrozenClientState\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidMembershipProof\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"path\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"value\",\"type\":\"bytes\"}],\"name\":\"KeyValuePairNotInCache\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"length\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"min\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"max\",\"type\":\"uint256\"}],\"name\":\"LengthIsOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"path\",\"type\":\"bytes[]\"}],\"name\":\"MembershipProofKeyNotFound\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"expected\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"actual\",\"type\":\"bytes\"}],\"name\":\"MembershipProofValueMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"expectedRevisionNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"expectedRevisionHeight\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"actualRevisionNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"actualRevisionHeight\",\"type\":\"uint64\"}],\"name\":\"ProofHeightMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"now\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"proofTimestamp\",\"type\":\"uint256\"}],\"name\":\"ProofIsInTheFuture\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"now\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"proofTimestamp\",\"type\":\"uint256\"}],\"name\":\"ProofIsTooOld\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expectedNumerator\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expectedDenominator\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actualNumerator\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actualDenominator\",\"type\":\"uint256\"}],\"name\":\"TrustThresholdMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"TrustingPeriodMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"trustingPeriod\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unbondingPeriod\",\"type\":\"uint256\"}],\"name\":\"TrustingPeriodTooLong\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"UnbondingPeriodMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"proofType\",\"type\":\"uint8\"}],\"name\":\"UnknownMembershipProofType\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"algorithm\",\"type\":\"uint8\"}],\"name\":\"UnknownZkAlgorithm\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"expected\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"actual\",\"type\":\"bytes32\"}],\"name\":\"VerificationKeyMismatch\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"ALLOWED_SP1_CLOCK_DRIFT\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MEMBERSHIP_PROGRAM_VKEY\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MISBEHAVIOUR_PROGRAM_VKEY\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PROOF_SUBMITTER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"UPDATE_CLIENT_AND_MEMBERSHIP_PROGRAM_VKEY\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"UPDATE_CLIENT_PROGRAM_VKEY\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VERIFIER\",\"outputs\":[{\"internalType\":\"contract ISP1Verifier\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"clientState\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"chainId\",\"type\":\"string\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"numerator\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"denominator\",\"type\":\"uint8\"}],\"internalType\":\"struct IICS07TendermintMsgs.TrustThreshold\",\"name\":\"trustLevel\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"revisionNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"revisionHeight\",\"type\":\"uint64\"}],\"internalType\":\"struct IICS02ClientMsgs.Height\",\"name\":\"latestHeight\",\"type\":\"tuple\"},{\"internalType\":\"uint32\",\"name\":\"trustingPeriod\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"unbondingPeriod\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isFrozen\",\"type\":\"bool\"},{\"internalType\":\"enum IICS07TendermintMsgs.SupportedZkAlgorithm\",\"name\":\"zkAlgorithm\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getClientState\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"revisionHeight\",\"type\":\"uint64\"}],\"name\":\"getConsensusStateHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"misbehaviourMsg\",\"type\":\"bytes\"}],\"name\":\"misbehaviour\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"updateMsg\",\"type\":\"bytes\"}],\"name\":\"updateClient\",\"outputs\":[{\"internalType\":\"enum ILightClientMsgs.UpdateResult\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"proof\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"revisionNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"revisionHeight\",\"type\":\"uint64\"}],\"internalType\":\"struct IICS02ClientMsgs.Height\",\"name\":\"proofHeight\",\"type\":\"tuple\"},{\"internalType\":\"bytes[]\",\"name\":\"path\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"value\",\"type\":\"bytes\"}],\"internalType\":\"struct ILightClientMsgs.MsgVerifyMembership\",\"name\":\"msg_\",\"type\":\"tuple\"}],\"name\":\"verifyMembership\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"proof\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"revisionNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"revisionHeight\",\"type\":\"uint64\"}],\"internalType\":\"struct IICS02ClientMsgs.Height\",\"name\":\"proofHeight\",\"type\":\"tuple\"},{\"internalType\":\"bytes[]\",\"name\":\"path\",\"type\":\"bytes[]\"}],\"internalType\":\"struct ILightClientMsgs.MsgVerifyNonMembership\",\"name\":\"msg_\",\"type\":\"tuple\"}],\"name\":\"verifyNonMembership\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"srdtrk\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"CannotHandleMisbehavior()\":[{\"details\":\"Misbehavior cannot be handled in membership handler, so it is returned as an error.\"}],\"ChainIdMismatch(string,string)\":[{\"params\":{\"actual\":\"The actual chain ID.\",\"expected\":\"The expected chain ID.\"}}],\"ClientStateMismatch(bytes,bytes)\":[{\"params\":{\"actual\":\"The actual client state.\",\"expected\":\"The expected client state.\"}}],\"ConsensusStateHashMismatch(bytes32,bytes32)\":[{\"params\":{\"actual\":\"The actual consensus state hash.\",\"expected\":\"The expected consensus state hash.\"}}],\"ConsensusStateRootMismatch(bytes32,bytes32)\":[{\"params\":{\"actual\":\"The actual consensus state root.\",\"expected\":\"The expected consensus state root.\"}}],\"FailedCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"KeyValuePairNotInCache(bytes[],bytes)\":[{\"params\":{\"path\":\"The path of the key-value pair.\",\"value\":\"The value of the key-value pair.\"}}],\"LengthIsOutOfRange(uint256,uint256,uint256)\":[{\"params\":{\"length\":\"The length of the value.\",\"max\":\"The maximum length of the value.\",\"min\":\"The minimum length of the value.\"}}],\"MembershipProofKeyNotFound(bytes[])\":[{\"params\":{\"path\":\"The path of the key-value pair.\"}}],\"MembershipProofValueMismatch(bytes,bytes)\":[{\"params\":{\"actual\":\"The actual value.\",\"expected\":\"The expected value.\"}}],\"ProofHeightMismatch(uint64,uint64,uint64,uint64)\":[{\"params\":{\"actualRevisionHeight\":\"The actual revision height.\",\"actualRevisionNumber\":\"The actual revision number.\",\"expectedRevisionHeight\":\"The expected revision height.\",\"expectedRevisionNumber\":\"The expected revision number.\"}}],\"ProofIsInTheFuture(uint256,uint256)\":[{\"params\":{\"now\":\"The current timestamp in seconds.\",\"proofTimestamp\":\"The timestamp in the proof in seconds.\"}}],\"ProofIsTooOld(uint256,uint256)\":[{\"params\":{\"now\":\"The current timestamp in seconds.\",\"proofTimestamp\":\"The timestamp in the proof in seconds.\"}}],\"TrustThresholdMismatch(uint256,uint256,uint256,uint256)\":[{\"params\":{\"actualDenominator\":\"The actual denominator of the trust threshold.\",\"actualNumerator\":\"The actual numerator of the trust threshold.\",\"expectedDenominator\":\"The expected denominator of the trust threshold.\",\"expectedNumerator\":\"The expected numerator of the trust threshold.\"}}],\"TrustingPeriodMismatch(uint256,uint256)\":[{\"params\":{\"actual\":\"The actual trusting period in seconds.\",\"expected\":\"The expected trusting period in seconds.\"}}],\"TrustingPeriodTooLong(uint256,uint256)\":[{\"params\":{\"trustingPeriod\":\"The trusting period in seconds.\",\"unbondingPeriod\":\"The unbonding period in seconds.\"}}],\"UnbondingPeriodMismatch(uint256,uint256)\":[{\"params\":{\"actual\":\"The actual unbonding period in seconds.\",\"expected\":\"The expected unbonding period in seconds.\"}}],\"UnknownMembershipProofType(uint8)\":[{\"params\":{\"proofType\":\"The unknown membership proof type.\"}}],\"UnknownZkAlgorithm(uint8)\":[{\"params\":{\"algorithm\":\"The unknown zk algorithm.\"}}],\"VerificationKeyMismatch(bytes32,bytes32)\":[{\"params\":{\"actual\":\"The actual verification key.\",\"expected\":\"The expected verification key.\"}}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted to signal this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call. This account bears the admin role (for the granted role). Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_clientState\":\"The encoded initial client state.\",\"_consensusState\":\"The encoded initial consensus state.\",\"membershipProgramVkey\":\"The verification key for the verify (non)membership program.\",\"misbehaviourProgramVkey\":\"The verification key for the misbehaviour program.\",\"roleManager\":\"Manages the proof submitters and can submit proofs. Should be the ICS26Router if used in IBC.\",\"sp1Verifier\":\"The address of the SP1 verifier contract.\",\"updateClientAndMembershipProgramVkey\":\"The verification key for the update client and membership program.\",\"updateClientProgramVkey\":\"The verification key for the update client program.\"}},\"getClientState()\":{\"returns\":{\"_0\":\"The client state.\"}},\"getConsensusStateHash(uint64)\":{\"params\":{\"revisionHeight\":\"The revision height.\"},\"returns\":{\"_0\":\"The consensus state at the given revision height.\"}},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"misbehaviour(bytes)\":{\"details\":\"The misbehavior is verfied in the sp1 program. Here we only check the public values which contain the trusted headers.\",\"params\":{\"misbehaviourMsg\":\"The misbehaviour message\"}},\"multicall(bytes[])\":{\"custom:oz-upgrades-unsafe-allow-reachable\":\"delegatecall\",\"details\":\"Receives and executes a batch of function calls on this contract.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] to learn more about how these ids are created. This function call must use less than 30 000 gas.\"},\"updateClient(bytes)\":{\"details\":\"This function verifies the public values and forwards the proof to the SP1 verifier.\",\"params\":{\"updateMsg\":\"The encoded update message e.g., an SP1 proof.\"},\"returns\":{\"_0\":\"The result of the update operation\"}},\"verifyMembership((bytes,(uint64,uint64),bytes[],bytes))\":{\"details\":\"Notice that this message is not view, as it may update the client state for caching purposes.\",\"params\":{\"msg_\":\"The membership message\"},\"returns\":{\"_0\":\"The unix timestamp of the verification height in the counterparty chain in seconds.\"}},\"verifyNonMembership((bytes,(uint64,uint64),bytes[]))\":{\"details\":\"Notice that this message is not view, as it may update the client state for caching purposes.\",\"params\":{\"msg_\":\"The membership message\"},\"returns\":{\"_0\":\"The unix timestamp of the verification height in the counterparty chain in seconds.\"}}},\"stateVariables\":{\"ALLOWED_SP1_CLOCK_DRIFT\":{\"return\":\"The allowed prover clock drift in seconds.\",\"returns\":{\"_0\":\"The allowed prover clock drift in seconds.\"}},\"MEMBERSHIP_PROGRAM_VKEY\":{\"return\":\"The verification key for the membership program.\",\"returns\":{\"_0\":\"The verification key for the membership program.\"}},\"MISBEHAVIOUR_PROGRAM_VKEY\":{\"return\":\"The verification key for the misbehaviour program.\",\"returns\":{\"_0\":\"The verification key for the misbehaviour program.\"}},\"PROOF_SUBMITTER_ROLE\":{\"details\":\"The proof submitter role is used to whitelist addresses that can submit proofsIf `address(0)` has this role, then anyone can submit proofsIf this client is hooked up to ICS26Router, the router must be given this role\",\"return\":\"The role identifier\",\"returns\":{\"_0\":\"The role identifier\"}},\"UPDATE_CLIENT_AND_MEMBERSHIP_PROGRAM_VKEY\":{\"return\":\"The verification key for the update client and membership program.\",\"returns\":{\"_0\":\"The verification key for the update client and membership program.\"}},\"UPDATE_CLIENT_PROGRAM_VKEY\":{\"return\":\"The verification key for the update client program.\",\"returns\":{\"_0\":\"The verification key for the update client program.\"}},\"VERIFIER\":{\"return\":\"The SP1 verifier contract.\",\"returns\":{\"_0\":\"The SP1 verifier contract.\"}},\"_consensusStateHashes\":{\"details\":\"Revision number need not be keyed as it is not allowed to change.\"}},\"title\":\"SP1 ICS07 Tendermint Light Client\",\"version\":1},\"userdoc\":{\"errors\":{\"CannotHandleMisbehavior()\":[{\"notice\":\"The error that is returned when the update client and membership program contains misbehavior.\"}],\"ChainIdMismatch(string,string)\":[{\"notice\":\"The error that is returned when the chain ID does not match the expected value.\"}],\"ClientStateMismatch(bytes,bytes)\":[{\"notice\":\"The error that is returned when the client state does not match the expected value.\"}],\"ConsensusStateHashMismatch(bytes32,bytes32)\":[{\"notice\":\"The error that is returned when the consensus state hash does not match the expected value.\"}],\"ConsensusStateNotFound()\":[{\"notice\":\"The error that is returned when the consensus state is not found.\"}],\"ConsensusStateRootMismatch(bytes32,bytes32)\":[{\"notice\":\"The error that is returned when the consensus state root does not match the expected value.\"}],\"EmptyValue()\":[{\"notice\":\"Returned when the membership value is empty.\"}],\"FeatureNotSupported()\":[{\"notice\":\"Returned when the feature is not supported.\"}],\"FrozenClientState()\":[{\"notice\":\"The error that is returned when the client state is frozen.\"}],\"InvalidMembershipProof()\":[{\"notice\":\"Returned when the membership proof is invalid.\"}],\"KeyValuePairNotInCache(bytes[],bytes)\":[{\"notice\":\"Returned when a key-value pair is not in the cache.\"}],\"LengthIsOutOfRange(uint256,uint256,uint256)\":[{\"notice\":\"The error that is returned when the length of a value is out of range.\"}],\"MembershipProofKeyNotFound(bytes[])\":[{\"notice\":\"The error that is returned when the key-value pair's path is not contained in the proof.\"}],\"MembershipProofValueMismatch(bytes,bytes)\":[{\"notice\":\"The error that is returned when the key-value pair's value does not match the expected value.\"}],\"ProofHeightMismatch(uint64,uint64,uint64,uint64)\":[{\"notice\":\"The error that is returned when the proof height does not match the expected value.\"}],\"ProofIsInTheFuture(uint256,uint256)\":[{\"notice\":\"The error that is returned when a proof is in the future.\"}],\"ProofIsTooOld(uint256,uint256)\":[{\"notice\":\"The error that is returned when a proof is too old.\"}],\"TrustThresholdMismatch(uint256,uint256,uint256,uint256)\":[{\"notice\":\"The error that is returned when the trust threshold does not match the expected value.\"}],\"TrustingPeriodMismatch(uint256,uint256)\":[{\"notice\":\"The error that is returned when the trusting period does not match the expected value.\"}],\"TrustingPeriodTooLong(uint256,uint256)\":[{\"notice\":\"The error that is returned when the trusting period is longer than the unbonding period.\"}],\"UnbondingPeriodMismatch(uint256,uint256)\":[{\"notice\":\"The error that is returned when the unbonding period does not match the expected value.\"}],\"UnknownMembershipProofType(uint8)\":[{\"notice\":\"The error that is returned when the membership proof type is unknown.\"}],\"UnknownZkAlgorithm(uint8)\":[{\"notice\":\"The error that is returned when the zk algorithm is unknown.\"}],\"VerificationKeyMismatch(bytes32,bytes32)\":[{\"notice\":\"The error that is returned when the verification key does not match the expected value.\"}]},\"kind\":\"user\",\"methods\":{\"ALLOWED_SP1_CLOCK_DRIFT()\":{\"notice\":\"Constant allowed prover clock drift in seconds.\"},\"MEMBERSHIP_PROGRAM_VKEY()\":{\"notice\":\"Immutable membership program verification key.\"},\"MISBEHAVIOUR_PROGRAM_VKEY()\":{\"notice\":\"Immutable misbehaviour program verification key.\"},\"PROOF_SUBMITTER_ROLE()\":{\"notice\":\"The role identifier for the proof submitter role\"},\"UPDATE_CLIENT_AND_MEMBERSHIP_PROGRAM_VKEY()\":{\"notice\":\"Immutable update client and membership program verification key.\"},\"UPDATE_CLIENT_PROGRAM_VKEY()\":{\"notice\":\"Immutable update client program verification key.\"},\"VERIFIER()\":{\"notice\":\"Immutable SP1 verifier contract address.\"},\"clientState()\":{\"notice\":\"The ICS07Tendermint client state\"},\"constructor\":{\"notice\":\"The constructor sets the program verification key and the initial client and consensus states.\"},\"getClientState()\":{\"notice\":\"Returns the client state.\"},\"getConsensusStateHash(uint64)\":{\"notice\":\"Returns the consensus state keccak256 hash at the given revision height.\"},\"misbehaviour(bytes)\":{\"notice\":\"Misbehaviour handling, moves the light client to the frozen state if misbehaviour is detected\"},\"updateClient(bytes)\":{\"notice\":\"Updating the client and consensus state\"},\"verifyMembership((bytes,(uint64,uint64),bytes[],bytes))\":{\"notice\":\"Querying the membership of a key-value pair\"},\"verifyNonMembership((bytes,(uint64,uint64),bytes[]))\":{\"notice\":\"Querying the non-membership of a key\"}},\"notice\":\"This contract implements an ICS07 IBC tendermint light client using SP1.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/light-clients/sp1-ics07/SP1ICS07Tendermint.sol\":\"SP1ICS07Tendermint\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[\":@openzeppelin-contracts/=node_modules/@openzeppelin/contracts/\",\":@openzeppelin-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/\",\":@openzeppelin/=node_modules/@openzeppelin/\",\":@sp1-contracts/=node_modules/sp1-contracts/contracts/src/\",\":@uniswap/permit2/=node_modules/@uniswap/permit2/\",\":forge-std/=node_modules/forge-std/src/\",\":sp1-contracts/=node_modules/sp1-contracts/\"],\"viaIR\":true},\"sources\":{\"contracts/interfaces/ILightClient.sol\":{\"keccak256\":\"0x1caae9e4f741a86c0056d5f7713a35f3bd96db7a9fd52fc9f1cf79aad76a442f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://4a536db3b926560f69547c17e4f451a2631ddea0f42bd224c7fd8382d74429f6\",\"dweb:/ipfs/QmcQ33kxcmmowXgMbQGTBgiKBjF7v8UiP4y73bB9hhDizC\"]},\"contracts/light-clients/sp1-ics07/SP1ICS07Tendermint.sol\":{\"keccak256\":\"0x2e03f0f1e058e7184ea70dc2a423a3d32a609620b6a1e8b764ec9c287b0b6187\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://9e3c0b2f3b3af9cfc8a3ab085e0decffcd40230a27530142293f0b79a4aefe51\",\"dweb:/ipfs/Qmf3qEAMWdiGAMEXSae6mzZ7Sncsbr4QzDC4JzMeiNwgei\"]},\"contracts/light-clients/sp1-ics07/errors/ISP1ICS07TendermintErrors.sol\":{\"keccak256\":\"0xe1a0526f9913308f761af480ef7d87091d6038659b9058f89c50083d49768db1\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://a31d6d4a059182b3dfd3e99595d82a134963c448c9152ef35b42c62ccca87635\",\"dweb:/ipfs/QmfQ2Cfa4kxWem3f88o9UnFQgL8oRU6vKkDFWSGmLsVLqN\"]},\"contracts/light-clients/sp1-ics07/interfaces/ISP1ICS07Tendermint.sol\":{\"keccak256\":\"0x0f00aea96b194d1a9db14f708f0de1fe7723fedc7b72bb8ea182e768ffc0a731\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://3111a76ebabf4b57917e93669892df895a54a93a4963e384d8c13a1c47877b44\",\"dweb:/ipfs/QmPCZ7Z4dJpowkzMhizUAW1j8QdJLD3DDjMbYq8G5VeXc1\"]},\"contracts/light-clients/sp1-ics07/msgs/IICS07TendermintMsgs.sol\":{\"keccak256\":\"0xae0ae6ff2742192ebaaee297c7d7473a1e1b4dc73393d45a944b0b7a8a647703\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://43b2f6492a1f727416bbcf55876d9c08ac1f66f4724efc75b935c5022555be20\",\"dweb:/ipfs/QmfTaPFNSFuUEsEBgJjnF2Jr2knayS7YwatfjP7dgdcAyH\"]},\"contracts/light-clients/sp1-ics07/msgs/IMembershipMsgs.sol\":{\"keccak256\":\"0x9dff6833fddbc11caf27387c9f8cba5dca9d1e430c9643d4e4a2e8eb09924d96\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://efa6cfc654510dfcef6f4286e3e66446082bcd5671662ae6e1c6fd0f893a5a4a\",\"dweb:/ipfs/QmRWAg1kHvmRtXgDm4ajVC7tEWQnzTWmHeHMYQJfyFuDGq\"]},\"contracts/light-clients/sp1-ics07/msgs/IMisbehaviourMsgs.sol\":{\"keccak256\":\"0x165b37d890b06eccd47558bf1efd6495e18541627758736a1f5b9c33d0333832\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://15ab15cd5439147abed697bc9644b0175754845608bf3d57c81c2c864d31ce46\",\"dweb:/ipfs/QmYcV88YsM1sZCmhP8LKUFHq3hJ6bsvd66W5axBnsBBoUM\"]},\"contracts/light-clients/sp1-ics07/msgs/ISP1Msgs.sol\":{\"keccak256\":\"0x8ede29b02182df4be9c075b3b48083277e5dd93bb3e7ce1eecfea9728db49aed\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://48edb4bbcd440454fffceb4f85b83c08c3973a212239d7da07c079634fe413dd\",\"dweb:/ipfs/Qmf7ma1nXWghfZKrJJvLpPuY5aN2xZZjHY7kWP3KVFCoDJ\"]},\"contracts/light-clients/sp1-ics07/msgs/IUcAndMembershipMsgs.sol\":{\"keccak256\":\"0xef3619c79de37cabe95d9d8af9d145fc2ea2dd55137407fb4b0082b0491170d0\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://93646d813cdacf5e38e609e54baa67c60d749f0f111d00cd18b003c3cb328204\",\"dweb:/ipfs/QmVcuwPujbiZ644a4jRw2V1LZxhhGsm2HKMXweVqndwUnZ\"]},\"contracts/light-clients/sp1-ics07/msgs/IUpdateClientMsgs.sol\":{\"keccak256\":\"0x370cdfca1c65f1898c7da80507e66972a6fe51a5d5c4e7aeabdd7060ce875aed\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://ff34288a142b6f40d6843818b9ec0a542db016bc0d4a7be582eb2e255655c43e\",\"dweb:/ipfs/QmXwbJHDbqZdw3JTT48Le1ZWGqmKAG7omf2ePvDfBHomzj\"]},\"contracts/light-clients/sp1-ics07/utils/Paths.sol\":{\"keccak256\":\"0x0e4eec6cd6cd0ef684383946419a2bf53c8f800033acfc298db81688e5aa178b\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://824b58c13ff96b6ee38b5d25435fcc1305c45735f52df6347dba3dacdc144ffa\",\"dweb:/ipfs/QmT7qomKM46ChfVVwfBQHwjpoHW9vrG9nXkGXsPeZRLJ7w\"]},\"contracts/msgs/IICS02ClientMsgs.sol\":{\"keccak256\":\"0xb5fdb25319d5c32b3f527982d45ec1e9bec5215515581aee034d853006ea01a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6b8939bf552c62c952a491008bcd9b59ab7dda20a9482bf93438e05793881542\",\"dweb:/ipfs/QmfWmzNCp8bd4pP26Lfw5HHp4dSZnCDqZDjVN7SD8P7eDh\"]},\"contracts/msgs/ILightClientMsgs.sol\":{\"keccak256\":\"0xa0565e7748b8b3284d72e1aa6ef4cc8264fcaa5f4e0761d22d64686953db6378\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://c4476010d7090bfaa74127526f2051c6bc82ff42a09b936e848880a1f15a6065\",\"dweb:/ipfs/QmY87JgRsFQXSZdGXNjNHEJCkdTHzFXH4vZEJ3q7MnHuP8\"]},\"node_modules/@openzeppelin/contracts/access/AccessControl.sol\":{\"keccak256\":\"0x1a6b4f6b7798ab80929d491b89d5427a9b3338c0fd1acd0ba325f69c6f1646af\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7bb7f346c12a14dc622bc105ce3c47202fbc89f4b153a28a63bb68193297330c\",\"dweb:/ipfs/QmagwF8P3bUBXwdo159ueEnY9dLSvEWwK24kk2op58egwG\"]},\"node_modules/@openzeppelin/contracts/access/IAccessControl.sol\":{\"keccak256\":\"0xbff9f59c84e5337689161ce7641c0ef8e872d6a7536fbc1f5133f128887aba3c\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b308f882e796f7b79c9502deacb0a62983035c6f6f4e962b319ba6a1f4a77d3d\",\"dweb:/ipfs/QmaWCW7ahEQqFjwhSUhV7Ae7WhfNvzSpE7DQ58hvEooqPL\"]},\"node_modules/@openzeppelin/contracts/utils/Address.sol\":{\"keccak256\":\"0x0fa9e0d3a859900b5a46f70a03c73adf259603d5e05027a37fe0b45529d85346\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://c2add4da0240c9f2ce47649c8bb6b11b40e98cf6f88b8bdc76b2704e89391710\",\"dweb:/ipfs/QmNQTwF2uVzu4CRtNxr8bxyP9XuW6VsZuo2Nr4KR2bZr3d\"]},\"node_modules/@openzeppelin/contracts/utils/Context.sol\":{\"keccak256\":\"0x493033a8d1b176a037b2cc6a04dad01a5c157722049bbecf632ca876224dd4b2\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6a708e8a5bdb1011c2c381c9a5cfd8a9a956d7d0a9dc1bd8bcdaf52f76ef2f12\",\"dweb:/ipfs/Qmax9WHBnVsZP46ZxEMNRQpLQnrdE4dK8LehML1Py8FowF\"]},\"node_modules/@openzeppelin/contracts/utils/Errors.sol\":{\"keccak256\":\"0x6afa713bfd42cf0f7656efa91201007ac465e42049d7de1d50753a373648c123\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://ba1d02f4847670a1b83dec9f7d37f0b0418d6043447b69f3a29a5f9efc547fcf\",\"dweb:/ipfs/QmQ7iH2keLNUKgq2xSWcRmuBE5eZ3F5whYAkAGzCNNoEWB\"]},\"node_modules/@openzeppelin/contracts/utils/LowLevelCall.sol\":{\"keccak256\":\"0x5b4802a4352474792df3107e961d1cc593e47b820c14f69d3505cb28f5a6a583\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://a6f86fd01f829499fe0545ff5dda07d4521988e88bfe0bf801fc15650921ed56\",\"dweb:/ipfs/QmUUKu4ZDffHAmfkf3asuQfmLTyfpuy2Amdncc3SqfzKPG\"]},\"node_modules/@openzeppelin/contracts/utils/Multicall.sol\":{\"keccak256\":\"0x72a5499dfae7676e4298a7299bccd3b27438ba1a4c72df5cd69c1c343c7ea20d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://de0fb51ccae3a0ff377ed185d187440fc612a71bf8e42fdb0e032ce747fa3eef\",\"dweb:/ipfs/QmPNBaiVsAiUhz8qfXcSy27S7CqBbtSd8rPqmaykKBhw7Q\"]},\"node_modules/@openzeppelin/contracts/utils/TransientSlot.sol\":{\"keccak256\":\"0xac673fa1e374d9e6107504af363333e3e5f6344d2e83faf57d9bfd41d77cc946\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://5982478dbbb218e9dd5a6e83f5c0e8d1654ddf20178484b43ef21dd2246809de\",\"dweb:/ipfs/QmaB1hS68n2kG8vTbt7EPEzmrGhkUbfiFyykGGLsAr9X22\"]},\"node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"keccak256\":\"0x2d9dc2fe26180f74c11c13663647d38e259e45f95eb88f57b61d2160b0109d3e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://81233d1f98060113d9922180bb0f14f8335856fe9f339134b09335e9f678c377\",\"dweb:/ipfs/QmWh6R35SarhAn4z2wH8SU456jJSYL2FgucfTFgbHJJN4E\"]},\"node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"keccak256\":\"0x8891738ffe910f0cf2da09566928589bf5d63f4524dd734fd9cedbac3274dd5c\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://971f954442df5c2ef5b5ebf1eb245d7105d9fbacc7386ee5c796df1d45b21617\",\"dweb:/ipfs/QmadRjHbkicwqwwh61raUEapaVEtaLMcYbQZWs9gUkgj3u\"]},\"node_modules/sp1-contracts/contracts/src/ISP1Verifier.sol\":{\"keccak256\":\"0x9e3ba64860bea920772dcf16be7946de2a2900d80bd51e9c0771184138f4f4d3\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0ec7230ca1fdd74edc6ab597d80bb345282aed3f0db4788ed96b4cc373ff46a3\",\"dweb:/ipfs/QmXPuSS5gzxMhFKWr1gsxBVu6WHh53ZZEvWkGgzrkM6Y7Q\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.28+commit.7893614a"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"bytes32","name":"updateClientProgramVkey","type":"bytes32"},{"internalType":"bytes32","name":"membershipProgramVkey","type":"bytes32"},{"internalType":"bytes32","name":"updateClientAndMembershipProgramVkey","type":"bytes32"},{"internalType":"bytes32","name":"misbehaviourProgramVkey","type":"bytes32"},{"internalType":"address","name":"sp1Verifier","type":"address"},{"internalType":"bytes","name":"_clientState","type":"bytes"},{"internalType":"bytes32","name":"_consensusState","type":"bytes32"},{"internalType":"address","name":"roleManager","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"type":"error","name":"AccessControlBadConfirmation"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"type":"error","name":"AccessControlUnauthorizedAccount"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"type":"error","name":"AddressEmptyCode"},{"inputs":[],"type":"error","name":"CannotHandleMisbehavior"},{"inputs":[{"internalType":"string","name":"expected","type":"string"},{"internalType":"string","name":"actual","type":"string"}],"type":"error","name":"ChainIdMismatch"},{"inputs":[{"internalType":"bytes","name":"expected","type":"bytes"},{"internalType":"bytes","name":"actual","type":"bytes"}],"type":"error","name":"ClientStateMismatch"},{"inputs":[{"internalType":"bytes32","name":"expected","type":"bytes32"},{"internalType":"bytes32","name":"actual","type":"bytes32"}],"type":"error","name":"ConsensusStateHashMismatch"},{"inputs":[],"type":"error","name":"ConsensusStateNotFound"},{"inputs":[{"internalType":"bytes32","name":"expected","type":"bytes32"},{"internalType":"bytes32","name":"actual","type":"bytes32"}],"type":"error","name":"ConsensusStateRootMismatch"},{"inputs":[],"type":"error","name":"EmptyValue"},{"inputs":[],"type":"error","name":"FailedCall"},{"inputs":[],"type":"error","name":"FeatureNotSupported"},{"inputs":[],"type":"error","name":"FrozenClientState"},{"inputs":[],"type":"error","name":"InvalidMembershipProof"},{"inputs":[{"internalType":"bytes[]","name":"path","type":"bytes[]"},{"internalType":"bytes","name":"value","type":"bytes"}],"type":"error","name":"KeyValuePairNotInCache"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"type":"error","name":"LengthIsOutOfRange"},{"inputs":[{"internalType":"bytes[]","name":"path","type":"bytes[]"}],"type":"error","name":"MembershipProofKeyNotFound"},{"inputs":[{"internalType":"bytes","name":"expected","type":"bytes"},{"internalType":"bytes","name":"actual","type":"bytes"}],"type":"error","name":"MembershipProofValueMismatch"},{"inputs":[{"internalType":"uint64","name":"expectedRevisionNumber","type":"uint64"},{"internalType":"uint64","name":"expectedRevisionHeight","type":"uint64"},{"internalType":"uint64","name":"actualRevisionNumber","type":"uint64"},{"internalType":"uint64","name":"actualRevisionHeight","type":"uint64"}],"type":"error","name":"ProofHeightMismatch"},{"inputs":[{"internalType":"uint256","name":"now","type":"uint256"},{"internalType":"uint256","name":"proofTimestamp","type":"uint256"}],"type":"error","name":"ProofIsInTheFuture"},{"inputs":[{"internalType":"uint256","name":"now","type":"uint256"},{"internalType":"uint256","name":"proofTimestamp","type":"uint256"}],"type":"error","name":"ProofIsTooOld"},{"inputs":[{"internalType":"uint256","name":"expectedNumerator","type":"uint256"},{"internalType":"uint256","name":"expectedDenominator","type":"uint256"},{"internalType":"uint256","name":"actualNumerator","type":"uint256"},{"internalType":"uint256","name":"actualDenominator","type":"uint256"}],"type":"error","name":"TrustThresholdMismatch"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"type":"error","name":"TrustingPeriodMismatch"},{"inputs":[{"internalType":"uint256","name":"trustingPeriod","type":"uint256"},{"internalType":"uint256","name":"unbondingPeriod","type":"uint256"}],"type":"error","name":"TrustingPeriodTooLong"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"type":"error","name":"UnbondingPeriodMismatch"},{"inputs":[{"internalType":"uint8","name":"proofType","type":"uint8"}],"type":"error","name":"UnknownMembershipProofType"},{"inputs":[{"internalType":"uint8","name":"algorithm","type":"uint8"}],"type":"error","name":"UnknownZkAlgorithm"},{"inputs":[{"internalType":"bytes32","name":"expected","type":"bytes32"},{"internalType":"bytes32","name":"actual","type":"bytes32"}],"type":"error","name":"VerificationKeyMismatch"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32","indexed":true},{"internalType":"bytes32","name":"previousAdminRole","type":"bytes32","indexed":true},{"internalType":"bytes32","name":"newAdminRole","type":"bytes32","indexed":true}],"type":"event","name":"RoleAdminChanged","anonymous":false},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32","indexed":true},{"internalType":"address","name":"account","type":"address","indexed":true},{"internalType":"address","name":"sender","type":"address","indexed":true}],"type":"event","name":"RoleGranted","anonymous":false},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32","indexed":true},{"internalType":"address","name":"account","type":"address","indexed":true},{"internalType":"address","name":"sender","type":"address","indexed":true}],"type":"event","name":"RoleRevoked","anonymous":false},{"inputs":[],"stateMutability":"view","type":"function","name":"ALLOWED_SP1_CLOCK_DRIFT","outputs":[{"internalType":"uint16","name":"","type":"uint16"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"MEMBERSHIP_PROGRAM_VKEY","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"MISBEHAVIOUR_PROGRAM_VKEY","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"PROOF_SUBMITTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"UPDATE_CLIENT_AND_MEMBERSHIP_PROGRAM_VKEY","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"UPDATE_CLIENT_PROGRAM_VKEY","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"VERIFIER","outputs":[{"internalType":"contract ISP1Verifier","name":"","type":"address"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"clientState","outputs":[{"internalType":"string","name":"chainId","type":"string"},{"internalType":"struct IICS07TendermintMsgs.TrustThreshold","name":"trustLevel","type":"tuple","components":[{"internalType":"uint8","name":"numerator","type":"uint8"},{"internalType":"uint8","name":"denominator","type":"uint8"}]},{"internalType":"struct IICS02ClientMsgs.Height","name":"latestHeight","type":"tuple","components":[{"internalType":"uint64","name":"revisionNumber","type":"uint64"},{"internalType":"uint64","name":"revisionHeight","type":"uint64"}]},{"internalType":"uint32","name":"trustingPeriod","type":"uint32"},{"internalType":"uint32","name":"unbondingPeriod","type":"uint32"},{"internalType":"bool","name":"isFrozen","type":"bool"},{"internalType":"enum IICS07TendermintMsgs.SupportedZkAlgorithm","name":"zkAlgorithm","type":"uint8"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"getClientState","outputs":[{"internalType":"bytes","name":"","type":"bytes"}]},{"inputs":[{"internalType":"uint64","name":"revisionHeight","type":"uint64"}],"stateMutability":"view","type":"function","name":"getConsensusStateHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"stateMutability":"view","type":"function","name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"grantRole"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"stateMutability":"view","type":"function","name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}]},{"inputs":[{"internalType":"bytes","name":"misbehaviourMsg","type":"bytes"}],"stateMutability":"nonpayable","type":"function","name":"misbehaviour"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function","name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}]},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"renounceRole"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"revokeRole"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"stateMutability":"view","type":"function","name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}]},{"inputs":[{"internalType":"bytes","name":"updateMsg","type":"bytes"}],"stateMutability":"nonpayable","type":"function","name":"updateClient","outputs":[{"internalType":"enum ILightClientMsgs.UpdateResult","name":"","type":"uint8"}]},{"inputs":[{"internalType":"struct ILightClientMsgs.MsgVerifyMembership","name":"msg_","type":"tuple","components":[{"internalType":"bytes","name":"proof","type":"bytes"},{"internalType":"struct IICS02ClientMsgs.Height","name":"proofHeight","type":"tuple","components":[{"internalType":"uint64","name":"revisionNumber","type":"uint64"},{"internalType":"uint64","name":"revisionHeight","type":"uint64"}]},{"internalType":"bytes[]","name":"path","type":"bytes[]"},{"internalType":"bytes","name":"value","type":"bytes"}]}],"stateMutability":"nonpayable","type":"function","name":"verifyMembership","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]},{"inputs":[{"internalType":"struct ILightClientMsgs.MsgVerifyNonMembership","name":"msg_","type":"tuple","components":[{"internalType":"bytes","name":"proof","type":"bytes"},{"internalType":"struct IICS02ClientMsgs.Height","name":"proofHeight","type":"tuple","components":[{"internalType":"uint64","name":"revisionNumber","type":"uint64"},{"internalType":"uint64","name":"revisionHeight","type":"uint64"}]},{"internalType":"bytes[]","name":"path","type":"bytes[]"}]}],"stateMutability":"nonpayable","type":"function","name":"verifyNonMembership","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]}],"devdoc":{"kind":"dev","methods":{"constructor":{"params":{"_clientState":"The encoded initial client state.","_consensusState":"The encoded initial consensus state.","membershipProgramVkey":"The verification key for the verify (non)membership program.","misbehaviourProgramVkey":"The verification key for the misbehaviour program.","roleManager":"Manages the proof submitters and can submit proofs. Should be the ICS26Router if used in IBC.","sp1Verifier":"The address of the SP1 verifier contract.","updateClientAndMembershipProgramVkey":"The verification key for the update client and membership program.","updateClientProgramVkey":"The verification key for the update client program."}},"getClientState()":{"returns":{"_0":"The client state."}},"getConsensusStateHash(uint64)":{"params":{"revisionHeight":"The revision height."},"returns":{"_0":"The consensus state at the given revision height."}},"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"misbehaviour(bytes)":{"details":"The misbehavior is verfied in the sp1 program. Here we only check the public values which contain the trusted headers.","params":{"misbehaviourMsg":"The misbehaviour message"}},"multicall(bytes[])":{"custom:oz-upgrades-unsafe-allow-reachable":"delegatecall","details":"Receives and executes a batch of function calls on this contract."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] to learn more about how these ids are created. This function call must use less than 30 000 gas."},"updateClient(bytes)":{"details":"This function verifies the public values and forwards the proof to the SP1 verifier.","params":{"updateMsg":"The encoded update message e.g., an SP1 proof."},"returns":{"_0":"The result of the update operation"}},"verifyMembership((bytes,(uint64,uint64),bytes[],bytes))":{"details":"Notice that this message is not view, as it may update the client state for caching purposes.","params":{"msg_":"The membership message"},"returns":{"_0":"The unix timestamp of the verification height in the counterparty chain in seconds."}},"verifyNonMembership((bytes,(uint64,uint64),bytes[]))":{"details":"Notice that this message is not view, as it may update the client state for caching purposes.","params":{"msg_":"The membership message"},"returns":{"_0":"The unix timestamp of the verification height in the counterparty chain in seconds."}}},"version":1},"userdoc":{"kind":"user","methods":{"ALLOWED_SP1_CLOCK_DRIFT()":{"notice":"Constant allowed prover clock drift in seconds."},"MEMBERSHIP_PROGRAM_VKEY()":{"notice":"Immutable membership program verification key."},"MISBEHAVIOUR_PROGRAM_VKEY()":{"notice":"Immutable misbehaviour program verification key."},"PROOF_SUBMITTER_ROLE()":{"notice":"The role identifier for the proof submitter role"},"UPDATE_CLIENT_AND_MEMBERSHIP_PROGRAM_VKEY()":{"notice":"Immutable update client and membership program verification key."},"UPDATE_CLIENT_PROGRAM_VKEY()":{"notice":"Immutable update client program verification key."},"VERIFIER()":{"notice":"Immutable SP1 verifier contract address."},"clientState()":{"notice":"The ICS07Tendermint client state"},"constructor":{"notice":"The constructor sets the program verification key and the initial client and consensus states."},"getClientState()":{"notice":"Returns the client state."},"getConsensusStateHash(uint64)":{"notice":"Returns the consensus state keccak256 hash at the given revision height."},"misbehaviour(bytes)":{"notice":"Misbehaviour handling, moves the light client to the frozen state if misbehaviour is detected"},"updateClient(bytes)":{"notice":"Updating the client and consensus state"},"verifyMembership((bytes,(uint64,uint64),bytes[],bytes))":{"notice":"Querying the membership of a key-value pair"},"verifyNonMembership((bytes,(uint64,uint64),bytes[]))":{"notice":"Querying the non-membership of a key"}},"version":1}},"settings":{"remappings":["@openzeppelin-contracts/=node_modules/@openzeppelin/contracts/","@openzeppelin-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/","@openzeppelin/=node_modules/@openzeppelin/","@sp1-contracts/=node_modules/sp1-contracts/contracts/src/","@uniswap/permit2/=node_modules/@uniswap/permit2/","forge-std/=node_modules/forge-std/src/","sp1-contracts/=node_modules/sp1-contracts/"],"optimizer":{"enabled":true,"runs":10000},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"contracts/light-clients/sp1-ics07/SP1ICS07Tendermint.sol":"SP1ICS07Tendermint"},"evmVersion":"cancun","libraries":{},"viaIR":true},"sources":{"contracts/interfaces/ILightClient.sol":{"keccak256":"0x1caae9e4f741a86c0056d5f7713a35f3bd96db7a9fd52fc9f1cf79aad76a442f","urls":["bzz-raw://4a536db3b926560f69547c17e4f451a2631ddea0f42bd224c7fd8382d74429f6","dweb:/ipfs/QmcQ33kxcmmowXgMbQGTBgiKBjF7v8UiP4y73bB9hhDizC"],"license":"MIT"},"contracts/light-clients/sp1-ics07/SP1ICS07Tendermint.sol":{"keccak256":"0x2e03f0f1e058e7184ea70dc2a423a3d32a609620b6a1e8b764ec9c287b0b6187","urls":["bzz-raw://9e3c0b2f3b3af9cfc8a3ab085e0decffcd40230a27530142293f0b79a4aefe51","dweb:/ipfs/Qmf3qEAMWdiGAMEXSae6mzZ7Sncsbr4QzDC4JzMeiNwgei"],"license":"MIT"},"contracts/light-clients/sp1-ics07/errors/ISP1ICS07TendermintErrors.sol":{"keccak256":"0xe1a0526f9913308f761af480ef7d87091d6038659b9058f89c50083d49768db1","urls":["bzz-raw://a31d6d4a059182b3dfd3e99595d82a134963c448c9152ef35b42c62ccca87635","dweb:/ipfs/QmfQ2Cfa4kxWem3f88o9UnFQgL8oRU6vKkDFWSGmLsVLqN"],"license":"MIT"},"contracts/light-clients/sp1-ics07/interfaces/ISP1ICS07Tendermint.sol":{"keccak256":"0x0f00aea96b194d1a9db14f708f0de1fe7723fedc7b72bb8ea182e768ffc0a731","urls":["bzz-raw://3111a76ebabf4b57917e93669892df895a54a93a4963e384d8c13a1c47877b44","dweb:/ipfs/QmPCZ7Z4dJpowkzMhizUAW1j8QdJLD3DDjMbYq8G5VeXc1"],"license":"MIT"},"contracts/light-clients/sp1-ics07/msgs/IICS07TendermintMsgs.sol":{"keccak256":"0xae0ae6ff2742192ebaaee297c7d7473a1e1b4dc73393d45a944b0b7a8a647703","urls":["bzz-raw://43b2f6492a1f727416bbcf55876d9c08ac1f66f4724efc75b935c5022555be20","dweb:/ipfs/QmfTaPFNSFuUEsEBgJjnF2Jr2knayS7YwatfjP7dgdcAyH"],"license":"UNLICENSED"},"contracts/light-clients/sp1-ics07/msgs/IMembershipMsgs.sol":{"keccak256":"0x9dff6833fddbc11caf27387c9f8cba5dca9d1e430c9643d4e4a2e8eb09924d96","urls":["bzz-raw://efa6cfc654510dfcef6f4286e3e66446082bcd5671662ae6e1c6fd0f893a5a4a","dweb:/ipfs/QmRWAg1kHvmRtXgDm4ajVC7tEWQnzTWmHeHMYQJfyFuDGq"],"license":"UNLICENSED"},"contracts/light-clients/sp1-ics07/msgs/IMisbehaviourMsgs.sol":{"keccak256":"0x165b37d890b06eccd47558bf1efd6495e18541627758736a1f5b9c33d0333832","urls":["bzz-raw://15ab15cd5439147abed697bc9644b0175754845608bf3d57c81c2c864d31ce46","dweb:/ipfs/QmYcV88YsM1sZCmhP8LKUFHq3hJ6bsvd66W5axBnsBBoUM"],"license":"UNLICENSED"},"contracts/light-clients/sp1-ics07/msgs/ISP1Msgs.sol":{"keccak256":"0x8ede29b02182df4be9c075b3b48083277e5dd93bb3e7ce1eecfea9728db49aed","urls":["bzz-raw://48edb4bbcd440454fffceb4f85b83c08c3973a212239d7da07c079634fe413dd","dweb:/ipfs/Qmf7ma1nXWghfZKrJJvLpPuY5aN2xZZjHY7kWP3KVFCoDJ"],"license":"MIT"},"contracts/light-clients/sp1-ics07/msgs/IUcAndMembershipMsgs.sol":{"keccak256":"0xef3619c79de37cabe95d9d8af9d145fc2ea2dd55137407fb4b0082b0491170d0","urls":["bzz-raw://93646d813cdacf5e38e609e54baa67c60d749f0f111d00cd18b003c3cb328204","dweb:/ipfs/QmVcuwPujbiZ644a4jRw2V1LZxhhGsm2HKMXweVqndwUnZ"],"license":"UNLICENSED"},"contracts/light-clients/sp1-ics07/msgs/IUpdateClientMsgs.sol":{"keccak256":"0x370cdfca1c65f1898c7da80507e66972a6fe51a5d5c4e7aeabdd7060ce875aed","urls":["bzz-raw://ff34288a142b6f40d6843818b9ec0a542db016bc0d4a7be582eb2e255655c43e","dweb:/ipfs/QmXwbJHDbqZdw3JTT48Le1ZWGqmKAG7omf2ePvDfBHomzj"],"license":"UNLICENSED"},"contracts/light-clients/sp1-ics07/utils/Paths.sol":{"keccak256":"0x0e4eec6cd6cd0ef684383946419a2bf53c8f800033acfc298db81688e5aa178b","urls":["bzz-raw://824b58c13ff96b6ee38b5d25435fcc1305c45735f52df6347dba3dacdc144ffa","dweb:/ipfs/QmT7qomKM46ChfVVwfBQHwjpoHW9vrG9nXkGXsPeZRLJ7w"],"license":"MIT"},"contracts/msgs/IICS02ClientMsgs.sol":{"keccak256":"0xb5fdb25319d5c32b3f527982d45ec1e9bec5215515581aee034d853006ea01a0","urls":["bzz-raw://6b8939bf552c62c952a491008bcd9b59ab7dda20a9482bf93438e05793881542","dweb:/ipfs/QmfWmzNCp8bd4pP26Lfw5HHp4dSZnCDqZDjVN7SD8P7eDh"],"license":"MIT"},"contracts/msgs/ILightClientMsgs.sol":{"keccak256":"0xa0565e7748b8b3284d72e1aa6ef4cc8264fcaa5f4e0761d22d64686953db6378","urls":["bzz-raw://c4476010d7090bfaa74127526f2051c6bc82ff42a09b936e848880a1f15a6065","dweb:/ipfs/QmY87JgRsFQXSZdGXNjNHEJCkdTHzFXH4vZEJ3q7MnHuP8"],"license":"MIT"},"node_modules/@openzeppelin/contracts/access/AccessControl.sol":{"keccak256":"0x1a6b4f6b7798ab80929d491b89d5427a9b3338c0fd1acd0ba325f69c6f1646af","urls":["bzz-raw://7bb7f346c12a14dc622bc105ce3c47202fbc89f4b153a28a63bb68193297330c","dweb:/ipfs/QmagwF8P3bUBXwdo159ueEnY9dLSvEWwK24kk2op58egwG"],"license":"MIT"},"node_modules/@openzeppelin/contracts/access/IAccessControl.sol":{"keccak256":"0xbff9f59c84e5337689161ce7641c0ef8e872d6a7536fbc1f5133f128887aba3c","urls":["bzz-raw://b308f882e796f7b79c9502deacb0a62983035c6f6f4e962b319ba6a1f4a77d3d","dweb:/ipfs/QmaWCW7ahEQqFjwhSUhV7Ae7WhfNvzSpE7DQ58hvEooqPL"],"license":"MIT"},"node_modules/@openzeppelin/contracts/utils/Address.sol":{"keccak256":"0x0fa9e0d3a859900b5a46f70a03c73adf259603d5e05027a37fe0b45529d85346","urls":["bzz-raw://c2add4da0240c9f2ce47649c8bb6b11b40e98cf6f88b8bdc76b2704e89391710","dweb:/ipfs/QmNQTwF2uVzu4CRtNxr8bxyP9XuW6VsZuo2Nr4KR2bZr3d"],"license":"MIT"},"node_modules/@openzeppelin/contracts/utils/Context.sol":{"keccak256":"0x493033a8d1b176a037b2cc6a04dad01a5c157722049bbecf632ca876224dd4b2","urls":["bzz-raw://6a708e8a5bdb1011c2c381c9a5cfd8a9a956d7d0a9dc1bd8bcdaf52f76ef2f12","dweb:/ipfs/Qmax9WHBnVsZP46ZxEMNRQpLQnrdE4dK8LehML1Py8FowF"],"license":"MIT"},"node_modules/@openzeppelin/contracts/utils/Errors.sol":{"keccak256":"0x6afa713bfd42cf0f7656efa91201007ac465e42049d7de1d50753a373648c123","urls":["bzz-raw://ba1d02f4847670a1b83dec9f7d37f0b0418d6043447b69f3a29a5f9efc547fcf","dweb:/ipfs/QmQ7iH2keLNUKgq2xSWcRmuBE5eZ3F5whYAkAGzCNNoEWB"],"license":"MIT"},"node_modules/@openzeppelin/contracts/utils/LowLevelCall.sol":{"keccak256":"0x5b4802a4352474792df3107e961d1cc593e47b820c14f69d3505cb28f5a6a583","urls":["bzz-raw://a6f86fd01f829499fe0545ff5dda07d4521988e88bfe0bf801fc15650921ed56","dweb:/ipfs/QmUUKu4ZDffHAmfkf3asuQfmLTyfpuy2Amdncc3SqfzKPG"],"license":"MIT"},"node_modules/@openzeppelin/contracts/utils/Multicall.sol":{"keccak256":"0x72a5499dfae7676e4298a7299bccd3b27438ba1a4c72df5cd69c1c343c7ea20d","urls":["bzz-raw://de0fb51ccae3a0ff377ed185d187440fc612a71bf8e42fdb0e032ce747fa3eef","dweb:/ipfs/QmPNBaiVsAiUhz8qfXcSy27S7CqBbtSd8rPqmaykKBhw7Q"],"license":"MIT"},"node_modules/@openzeppelin/contracts/utils/TransientSlot.sol":{"keccak256":"0xac673fa1e374d9e6107504af363333e3e5f6344d2e83faf57d9bfd41d77cc946","urls":["bzz-raw://5982478dbbb218e9dd5a6e83f5c0e8d1654ddf20178484b43ef21dd2246809de","dweb:/ipfs/QmaB1hS68n2kG8vTbt7EPEzmrGhkUbfiFyykGGLsAr9X22"],"license":"MIT"},"node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol":{"keccak256":"0x2d9dc2fe26180f74c11c13663647d38e259e45f95eb88f57b61d2160b0109d3e","urls":["bzz-raw://81233d1f98060113d9922180bb0f14f8335856fe9f339134b09335e9f678c377","dweb:/ipfs/QmWh6R35SarhAn4z2wH8SU456jJSYL2FgucfTFgbHJJN4E"],"license":"MIT"},"node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol":{"keccak256":"0x8891738ffe910f0cf2da09566928589bf5d63f4524dd734fd9cedbac3274dd5c","urls":["bzz-raw://971f954442df5c2ef5b5ebf1eb245d7105d9fbacc7386ee5c796df1d45b21617","dweb:/ipfs/QmadRjHbkicwqwwh61raUEapaVEtaLMcYbQZWs9gUkgj3u"],"license":"MIT"},"node_modules/sp1-contracts/contracts/src/ISP1Verifier.sol":{"keccak256":"0x9e3ba64860bea920772dcf16be7946de2a2900d80bd51e9c0771184138f4f4d3","urls":["bzz-raw://0ec7230ca1fdd74edc6ab597d80bb345282aed3f0db4788ed96b4cc373ff46a3","dweb:/ipfs/QmXPuSS5gzxMhFKWr1gsxBVu6WHh53ZZEvWkGgzrkM6Y7Q"],"license":"MIT"}},"version":1},"id":38} \ No newline at end of file +{"abi":[{"type":"constructor","inputs":[{"name":"updateClientProgramVkey","type":"bytes32","internalType":"bytes32"},{"name":"membershipProgramVkey","type":"bytes32","internalType":"bytes32"},{"name":"updateClientAndMembershipProgramVkey","type":"bytes32","internalType":"bytes32"},{"name":"misbehaviourProgramVkey","type":"bytes32","internalType":"bytes32"},{"name":"sp1Verifier","type":"address","internalType":"address"},{"name":"_clientState","type":"bytes","internalType":"bytes"},{"name":"_consensusState","type":"bytes32","internalType":"bytes32"},{"name":"roleManager","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"type":"function","name":"ALLOWED_SP1_CLOCK_DRIFT","inputs":[],"outputs":[{"name":"","type":"uint16","internalType":"uint16"}],"stateMutability":"view"},{"type":"function","name":"DEFAULT_ADMIN_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"MEMBERSHIP_PROGRAM_VKEY","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"MISBEHAVIOUR_PROGRAM_VKEY","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"PROOF_SUBMITTER_ROLE","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"UPDATE_CLIENT_AND_MEMBERSHIP_PROGRAM_VKEY","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"UPDATE_CLIENT_PROGRAM_VKEY","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"VERIFIER","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract ISP1Verifier"}],"stateMutability":"view"},{"type":"function","name":"clientState","inputs":[],"outputs":[{"name":"chainId","type":"string","internalType":"string"},{"name":"trustLevel","type":"tuple","internalType":"struct IICS07TendermintMsgs.TrustThreshold","components":[{"name":"numerator","type":"uint8","internalType":"uint8"},{"name":"denominator","type":"uint8","internalType":"uint8"}]},{"name":"latestHeight","type":"tuple","internalType":"struct IICS02ClientMsgs.Height","components":[{"name":"revisionNumber","type":"uint64","internalType":"uint64"},{"name":"revisionHeight","type":"uint64","internalType":"uint64"}]},{"name":"trustingPeriod","type":"uint32","internalType":"uint32"},{"name":"unbondingPeriod","type":"uint32","internalType":"uint32"},{"name":"isFrozen","type":"bool","internalType":"bool"},{"name":"zkAlgorithm","type":"uint8","internalType":"enum IICS07TendermintMsgs.SupportedZkAlgorithm"}],"stateMutability":"view"},{"type":"function","name":"getClientState","inputs":[],"outputs":[{"name":"","type":"bytes","internalType":"bytes"}],"stateMutability":"view"},{"type":"function","name":"getConsensusStateHash","inputs":[{"name":"revisionHeight","type":"uint64","internalType":"uint64"}],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"getRoleAdmin","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"grantRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"hasRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"misbehaviour","inputs":[{"name":"misbehaviourMsg","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"multicall","inputs":[{"name":"data","type":"bytes[]","internalType":"bytes[]"}],"outputs":[{"name":"results","type":"bytes[]","internalType":"bytes[]"}],"stateMutability":"nonpayable"},{"type":"function","name":"renounceRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"callerConfirmation","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"revokeRole","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"supportsInterface","inputs":[{"name":"interfaceId","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"updateClient","inputs":[{"name":"updateMsg","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"","type":"uint8","internalType":"enum ILightClientMsgs.UpdateResult"}],"stateMutability":"nonpayable"},{"type":"function","name":"verifyMembership","inputs":[{"name":"msg_","type":"tuple","internalType":"struct ILightClientMsgs.MsgVerifyMembership","components":[{"name":"proof","type":"bytes","internalType":"bytes"},{"name":"proofHeight","type":"tuple","internalType":"struct IICS02ClientMsgs.Height","components":[{"name":"revisionNumber","type":"uint64","internalType":"uint64"},{"name":"revisionHeight","type":"uint64","internalType":"uint64"}]},{"name":"path","type":"bytes[]","internalType":"bytes[]"},{"name":"value","type":"bytes","internalType":"bytes"}]}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"nonpayable"},{"type":"function","name":"verifyNonMembership","inputs":[{"name":"msg_","type":"tuple","internalType":"struct ILightClientMsgs.MsgVerifyNonMembership","components":[{"name":"proof","type":"bytes","internalType":"bytes"},{"name":"proofHeight","type":"tuple","internalType":"struct IICS02ClientMsgs.Height","components":[{"name":"revisionNumber","type":"uint64","internalType":"uint64"},{"name":"revisionHeight","type":"uint64","internalType":"uint64"}]},{"name":"path","type":"bytes[]","internalType":"bytes[]"}]}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"nonpayable"},{"type":"event","name":"RoleAdminChanged","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"previousAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"newAdminRole","type":"bytes32","indexed":true,"internalType":"bytes32"}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"sender","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"error","name":"AccessControlBadConfirmation","inputs":[]},{"type":"error","name":"AccessControlUnauthorizedAccount","inputs":[{"name":"account","type":"address","internalType":"address"},{"name":"neededRole","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"AddressEmptyCode","inputs":[{"name":"target","type":"address","internalType":"address"}]},{"type":"error","name":"CannotHandleMisbehavior","inputs":[]},{"type":"error","name":"ChainIdMismatch","inputs":[{"name":"expected","type":"string","internalType":"string"},{"name":"actual","type":"string","internalType":"string"}]},{"type":"error","name":"ClientStateMismatch","inputs":[{"name":"expected","type":"bytes","internalType":"bytes"},{"name":"actual","type":"bytes","internalType":"bytes"}]},{"type":"error","name":"ConsensusStateHashMismatch","inputs":[{"name":"expected","type":"bytes32","internalType":"bytes32"},{"name":"actual","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"ConsensusStateNotFound","inputs":[]},{"type":"error","name":"ConsensusStateRootMismatch","inputs":[{"name":"expected","type":"bytes32","internalType":"bytes32"},{"name":"actual","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"EmptyValue","inputs":[]},{"type":"error","name":"FailedCall","inputs":[]},{"type":"error","name":"FeatureNotSupported","inputs":[]},{"type":"error","name":"FrozenClientState","inputs":[]},{"type":"error","name":"InvalidMembershipProof","inputs":[]},{"type":"error","name":"KeyValuePairNotInCache","inputs":[{"name":"path","type":"bytes[]","internalType":"bytes[]"},{"name":"value","type":"bytes","internalType":"bytes"}]},{"type":"error","name":"LengthIsOutOfRange","inputs":[{"name":"length","type":"uint256","internalType":"uint256"},{"name":"min","type":"uint256","internalType":"uint256"},{"name":"max","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"MembershipProofKeyNotFound","inputs":[{"name":"path","type":"bytes[]","internalType":"bytes[]"}]},{"type":"error","name":"MembershipProofValueMismatch","inputs":[{"name":"expected","type":"bytes","internalType":"bytes"},{"name":"actual","type":"bytes","internalType":"bytes"}]},{"type":"error","name":"ProofHeightMismatch","inputs":[{"name":"expectedRevisionNumber","type":"uint64","internalType":"uint64"},{"name":"expectedRevisionHeight","type":"uint64","internalType":"uint64"},{"name":"actualRevisionNumber","type":"uint64","internalType":"uint64"},{"name":"actualRevisionHeight","type":"uint64","internalType":"uint64"}]},{"type":"error","name":"ProofIsInTheFuture","inputs":[{"name":"now","type":"uint256","internalType":"uint256"},{"name":"proofTimestamp","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"ProofIsTooOld","inputs":[{"name":"now","type":"uint256","internalType":"uint256"},{"name":"proofTimestamp","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"TrustThresholdMismatch","inputs":[{"name":"expectedNumerator","type":"uint256","internalType":"uint256"},{"name":"expectedDenominator","type":"uint256","internalType":"uint256"},{"name":"actualNumerator","type":"uint256","internalType":"uint256"},{"name":"actualDenominator","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"TrustingPeriodMismatch","inputs":[{"name":"expected","type":"uint256","internalType":"uint256"},{"name":"actual","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"TrustingPeriodTooLong","inputs":[{"name":"trustingPeriod","type":"uint256","internalType":"uint256"},{"name":"unbondingPeriod","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"UnbondingPeriodMismatch","inputs":[{"name":"expected","type":"uint256","internalType":"uint256"},{"name":"actual","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"UnknownMembershipProofType","inputs":[{"name":"proofType","type":"uint8","internalType":"uint8"}]},{"type":"error","name":"UnknownZkAlgorithm","inputs":[{"name":"algorithm","type":"uint8","internalType":"uint8"}]},{"type":"error","name":"VerificationKeyMismatch","inputs":[{"name":"expected","type":"bytes32","internalType":"bytes32"},{"name":"actual","type":"bytes32","internalType":"bytes32"}]}],"bytecode":{"object":"0x61012060405234610541576137268038038061001a81610564565b928339810161010082820312610541578151916020810151604082015160608301519061004960808501610589565b60a08501519095906001600160401b0381116105415785019080601f8301121561054157815161007b9260200161059d565b9261008d60e060c08701519601610589565b9660805260a05260c05260e05280518101906020820190602081840312610541576020810151906001600160401b038211610541570191829003601f1981019061012013610541576040519160e083016001600160401b0381118482101761052d5760405260208401516001600160401b038111610541576020908501019080601f830112156105415781516101259260200161059d565b825260408112610541576040610139610545565b916101458286016105dd565b8352610153606086016105dd565b602084015260208401928352603f19011261054157610170610545565b61017c608085016105eb565b815261018a60a085016105eb565b6020820152604083019081526101a260c085016105ff565b90606084019182526101b660e086016105ff565b92608085019384526101008601519586151587036105415760a0860196875261012001519460028610156105415760c08101958652518051906001600160401b03821161052d57600154600181811c91168015610523575b602082101461050f57601f81116104ac575b50602090601f831160011461043f5763ffffffff95949392915f9183610434575b50508160011b915f199060031b1c1916176001555b5160ff81511661ff00602060025493015160081b169161ffff191617176002555160018060401b0381511660035491602068010000000000000000600160801b0391015160401b169160018060801b031916171760035551169267ffffffff00000000600454925160201b169051151560401b92519160028310156104205769ff00000000000000000068ff00000000000000009360481b169469ff000000000000000000199160018060481b0319161716179116171760045560018060401b0360035460401c165f52600560205260405f205560018060a01b03166101005260045463ffffffff8116610708810163ffffffff811161040c5763ffffffff809360201c1692839116116103f757826001600160a01b0381166103de575061037c610706565b505b604051612efd908161078982396080518181816105570152611445015260a0518181816101f90152611e01015260c051818181610cb30152612185015260e0518181816102a00152610ac1015261010051818181610c780152611a1a0152f35b806103eb6103f192610610565b50610686565b5061037e565b6333fae18560e21b5f5260045260245260445ffd5b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52602160045260245ffd5b015190505f80610241565b90601f1983169160015f52815f20925f5b818110610494575091600193918563ffffffff99989796941061047c575b505050811b01600155610256565b01515f1960f88460031b161c191690555f808061046e565b92936020600181928786015181550195019301610450565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c81019160208510610505575b601f0160051c01905b8181106104fa5750610220565b5f81556001016104ed565b90915081906104e4565b634e487b7160e01b5f52602260045260245ffd5b90607f169061020e565b634e487b7160e01b5f52604160045260245ffd5b5f80fd5b60408051919082016001600160401b0381118382101761052d57604052565b6040519190601f01601f191682016001600160401b0381118382101761052d57604052565b51906001600160a01b038216820361054157565b9192916001600160401b03821161052d576105c1601f8301601f1916602001610564565b938285528282011161054157815f926020928387015e84010152565b519060ff8216820361054157565b51906001600160401b038216820361054157565b519063ffffffff8216820361054157565b6001600160a01b0381165f9081525f5160206137065f395f51905f52602052604090205460ff16610681576001600160a01b03165f8181525f5160206137065f395f51905f5260205260408120805460ff191660011790553391905f5160206136865f395f51905f528180a4600190565b505f90565b6001600160a01b0381165f9081525f5160206136a65f395f51905f52602052604090205460ff16610681576001600160a01b03165f8181525f5160206136a65f395f51905f5260205260408120805460ff191660011790553391905f5160206136e65f395f51905f52905f5160206136865f395f51905f529080a4600190565b5f80525f5160206136a65f395f51905f526020525f5160206136c65f395f51905f525460ff16610784575f8080525f5160206136a65f395f51905f526020525f5160206136c65f395f51905f52805460ff1916600117905533905f5160206136e65f395f51905f525f5160206136865f395f51905f528280a4600190565b5f9056fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a714610cd6575080630225293e14610c9c57806308c84e7014610c4c5780630bece35614610b8957806323842fb814610b59578063248a9ca314610b2f5780632c3ee47414610b135780632f2ff15d14610ae4578063314d4dff14610aaa57806336568abe14610a4e5780634d6d9ffb1461096c5780635972185a14610932578063682ed5f01461080e57806391d14854146107c5578063a217fddf146107ab578063ac9650d81461066a578063bd3ce6b01461057a578063ca7242f914610540578063d547741f1461050a578063ddba65371461021c578063e45a6d0d146101e25763ef913a4b1461010e575f80fd5b346101de575f6003193601126101de576101da60405160208082015261012060408201526101c6816101436101608201610ec6565b60ff600254818116606085015260081c16608083015267ffffffffffffffff60035481811660a085015260401c1660c083015260ff60045463ffffffff811660e085015263ffffffff8160201c16610100850152818160401c16151561012085015260481c166101b28161105f565b61014083015203601f19810183528261103c565b604051918291602083526020830190610df8565b0390f35b5f80fd5b346101de575f6003193601126101de5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346101de5761022a36610d74565b6004549160ff8360401c166104e2575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06020527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac4754610298929060ff16156104d5575b8101906110d9565b6102c78151517f0000000000000000000000000000000000000000000000000000000000000000808214611189565b6020815101518051810160208101916020818303126101de57602081015167ffffffffffffffff81116101de57019061018090829003126101de576040519061030f82610fcc565b602081015167ffffffffffffffff81116101de57839082016020019061033491611260565b825261034260408201611348565b60208301908152906103578460608301611219565b604084019081529161036c8560a08401611219565b60608501908152946103818160e08501611365565b9260808601938452610140019061039791611365565b9360a081019485525190516fffffffffffffffffffffffffffffffff166103bd916126e8565b516040805182516fffffffffffffffffffffffffffffffff16602080830191825284015182840152919092015160608084019190915282529061040160808261103c565b51902090516020015167ffffffffffffffff1661041d90611649565b61042a919081811461187c565b516040805182516fffffffffffffffffffffffffffffffff16602080830191825284015182840152919092015160608084019190915282529061046e60808261103c565b51902090516020015167ffffffffffffffff1661048a90611649565b610497919081811461187c565b516104a190611a03565b7fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff1668010000000000000000176004555f80f35b6104dd61178e565b610290565b7f928b1233000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101de5761053e61051b36610dc5565b90610539610534825f525f602052600160405f20015490565b611816565b611ba5565b005b346101de575f6003193601126101de5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346101de575f6003193601126101de576040516105a18161059a81610ec6565b038261103c565b6101206040516105b081610f83565b60025460ff8116825260ff602083019160081c16815260ff6040516105d481610f83565b67ffffffffffffffff600354818116835281602084019160401c168152816004549385808660481c1697816106146040519d8d8f9e8f9081520190610df8565b9a511660208c0152511660408a0152511660608801525116608086015263ffffffff811660a086015263ffffffff8160201c1660c086015260401c16151560e08401526106608161105f565b6101008301520390f35b346101de5760206003193601126101de5760043567ffffffffffffffff81116101de57366023820112156101de57806004013567ffffffffffffffff81116101de57602482013660248360051b850101116101de5760405160206106ce818361103c565b5f825280820192601f1982013685376106e685611735565b956106f4604051978861103c565b858752601f1961070387611735565b01835f5b82811061079b575050505f5b868110156107885760019061076c61076661073660248460051b87010187611690565b9190888b846040519586948486013783018281015f81528d519283915e01015f815203601f19810183528261103c565b30612621565b610776828b61174d565b52610781818a61174d565b5001610713565b604051848152806101da8187018b610e1d565b606082828c010152018490610707565b346101de575f6003193601126101de5760206040515f8152f35b346101de576107d336610dc5565b905f525f60205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060ff60405f2054166040519015158152f35b346101de5760206003193601126101de5760043567ffffffffffffffff81116101de578060040160a060031983360301126101de5760ff60045460401c166104e2575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06020527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475460ff1615610925575b60848201916108b18383611690565b9050156108fd57602092826108c9816108f595611690565b60246108ed6108e66108de60648901876116e1565b979096611690565b3691611085565b950191611cee565b604051908152f35b7f1208b21b000000000000000000000000000000000000000000000000000000005f5260045ffd5b61092d61178e565b6108a2565b346101de575f6003193601126101de5760206040517fbd893629a699470e4ec82a5715bb4981fdaacc5d0a728bf5f55b801d8f4ef10b8152f35b346101de5760206003193601126101de5760043567ffffffffffffffff81116101de5780600401608060031983360301126101de5760ff60045460401c166104e2575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e060209081527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac475490926108f592909160ff1615610a41575b610a24610a178280611690565b91909260648501906116e1565b929091602460405195610a37898861103c565b5f87520191611cee565b610a4961178e565b610a0a565b346101de57610a5c36610dc5565b3373ffffffffffffffffffffffffffffffffffffffff821603610a825761053e91611ba5565b7f6697b232000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101de575f6003193601126101de5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346101de5761053e610af536610dc5565b90610b0e610534825f525f602052600160405f20015490565b611ad3565b346101de575f6003193601126101de5760206040516107088152f35b346101de5760206003193601126101de5760206108f56004355f525f602052600160405f20015490565b346101de5760206003193601126101de5760043567ffffffffffffffff811681036101de576108f5602091611649565b346101de57610b9736610d74565b60ff60045460401c166104e2575f80527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06020527f6e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac4754610bff929060ff1615610c3f57611431565b6040516003821015610c12576020918152f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b610c4761178e565b611431565b346101de575f6003193601126101de57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346101de575f6003193601126101de5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346101de5760206003193601126101de57600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101de57817f7965db0b0000000000000000000000000000000000000000000000000000000060209314908115610d4a575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483610d43565b9060206003198301126101de5760043567ffffffffffffffff81116101de57826023820112156101de5780600401359267ffffffffffffffff84116101de57602484830101116101de576024019190565b60031960409101126101de576004359060243573ffffffffffffffffffffffffffffffffffffffff811681036101de5790565b90601f19601f602080948051918291828752018686015e5f8582860101520116010190565b9080602083519182815201916020808360051b8301019401925f915b838310610e4857505050505090565b9091929394602080610e6683601f1986600196030187528951610df8565b97019301930191939290610e39565b90600182811c92168015610ebc575b6020831014610e8f57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691610e84565b6001545f9291610ed582610e75565b8082529160018116908115610f495750600114610ef0575050565b60015f9081529293509091907fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b838310610f2f575060209250010190565b600181602092949394548385870101520191019190610f1e565b60209495507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091509291921683830152151560051b010190565b6040810190811067ffffffffffffffff821117610f9f57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60c0810190811067ffffffffffffffff821117610f9f57604052565b6020810190811067ffffffffffffffff821117610f9f57604052565b6060810190811067ffffffffffffffff821117610f9f57604052565b60e0810190811067ffffffffffffffff821117610f9f57604052565b90601f601f19910116810190811067ffffffffffffffff821117610f9f57604052565b60021115610c1257565b67ffffffffffffffff8111610f9f57601f01601f191660200190565b92919261109182611069565b9161109f604051938461103c565b8294818452818301116101de578281602093845f960137010152565b9080601f830112156101de578160206110d693359101611085565b90565b6020818303126101de5780359067ffffffffffffffff82116101de5701906020828203126101de576040519161110e83610fe8565b80359067ffffffffffffffff82116101de57016060818303126101de576040519161113883611004565b81358352602082013567ffffffffffffffff81116101de578161115c9184016110bb565b6020840152604082013567ffffffffffffffff81116101de5761117f92016110bb565b6040820152815290565b15611192575050565b7fd56bdc26000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9291926111cc82611069565b916111da604051938461103c565b8294818452818301116101de578281602093845f96015e010152565b519060ff821682036101de57565b519067ffffffffffffffff821682036101de57565b91908260409103126101de5760405161123181610f83565b602061124a81839561124281611204565b855201611204565b910152565b519063ffffffff821682036101de57565b91908281039261012084126101de576040519161127c83611020565b8294825167ffffffffffffffff81116101de57830182601f820112156101de576040916112b284836020601f19955191016111c0565b865201126101de576112f7906040516112ca81610f83565b6112d6602085016111f6565b81526112e4604085016111f6565b6020820152602085015260608301611219565b604083015261130860a0820161124f565b606083015261131960c0820161124f565b608083015260e08101519081151582036101de576101009160a084015201519060028210156101de5760c00152565b51906fffffffffffffffffffffffffffffffff821682036101de57565b91908260609103126101de5760405161137d81611004565b604080829461138b81611348565b8452602081015160208501520151910152565b9190610180838203126101de57604051906113b882610fcc565b819380519167ffffffffffffffff83116101de57610140826113e18360a09661124a9601611260565b86526113f08360208301611365565b60208701526114028360808301611365565b604087015261141360e08201611348565b6060870152611426836101008301611219565b608087015201611219565b61143d918101906110d9565b61146c8151517f0000000000000000000000000000000000000000000000000000000000000000808214611189565b60208151015180518101906020818303126101de5760208101519167ffffffffffffffff83116101de576114a792602080920192010161139e565b906114b1826118b3565b6114ba82611946565b916003831015610c1257826115ec57908167ffffffffffffffff6020604060a06110d6960193845184848201511685600354851c168111611564575b505001516040516115498161153b858201948591909160408060608301946fffffffffffffffffffffffffffffffff8151168452602081015160208501520151910152565b03601f19810183528261103c565b51902092510151165f52600560205260405f20555b51611a03565b6115a3866115e593511667ffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000006003541617600355565b7fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff6fffffffffffffffff00000000000000006003549260401b16911617600355565b5f806114f6565b5060018203611631576110d690680100000000000000007fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff600454161760045561155e565b60028214611642576110d69061155e565b5050600290565b67ffffffffffffffff165f52600560205260405f205480156116685790565b7f5b48b457000000000000000000000000000000000000000000000000000000005f5260045ffd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156101de570180359067ffffffffffffffff82116101de576020019181360383136101de57565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156101de570180359067ffffffffffffffff82116101de57602001918160051b360383136101de57565b67ffffffffffffffff8111610f9f5760051b60200190565b80518210156117615760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b335f9081527f4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e0602052604090205460ff16156117c657565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f52336004527fbd893629a699470e4ec82a5715bb4981fdaacc5d0a728bf5f55b801d8f4ef10b60245260445ffd5b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260ff60405f2054161561184d5750565b7fe2517d3f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b15611885575050565b7f6d23e8a3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b611944906118d981516fffffffffffffffffffffffffffffffff606084015116906126e8565b61193c67ffffffffffffffff602060808185015160405161192e8161153b868201948591909160408060608301946fffffffffffffffffffffffffffffffff8151168452602081015160208501520151910152565b519020940151015116611649565b80821461187c565b565b67ffffffffffffffff602060a08301510151165f52600560205260405f205480155f146119735750505f90565b604082019081516040516119bc8161153b60208201948591909160408060608301946fffffffffffffffffffffffffffffffff8151168452602081015160208501520151910152565b51902014918215926119da575b5050156119d557600190565b600290565b6fffffffffffffffffffffffffffffffff91925060208291015151169151511611155f806119c9565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169080516040602083015192015192803b156101de575f92611a9b92611aad604051968795869485947f41493c600000000000000000000000000000000000000000000000000000000086526004860152606060248601526064850190610df8565b90600319848303016044850152610df8565b03915afa8015611ac857611abe5750565b5f6119449161103c565b6040513d5f823e3d90fd5b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f205416155f14611b9f57805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905573ffffffffffffffffffffffffffffffffffffffff339216907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d5f80a4600190565b50505f90565b805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260ff60405f2054165f14611b9f57805f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff83165f5260205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815416905573ffffffffffffffffffffffffffffffffffffffff339216907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b5f80a4600190565b3567ffffffffffffffff811681036101de5790565b929190611c8e81611735565b93611c9c604051958661103c565b602085838152019160051b8101918383116101de5781905b838210611cc2575050505050565b813567ffffffffffffffff81116101de57602091611ce387849387016110bb565b815201910190611cb4565b9094929193948015612568578101906020818303126101de5780359067ffffffffffffffff82116101de57016040818303126101de5760405191611d3183610f83565b813560028110156101de578352602082013567ffffffffffffffff81116101de57611d5c92016110bb565b90602081019182528051611d6f8161105f565b611d788161105f565b611fe5575051908151820160208101926020818303126101de57602081015167ffffffffffffffff81116101de570190608090829003126101de5760405192611dc084610f83565b602082015167ffffffffffffffff81116101de5782611de9836020604094611df1970101612a5a565b865201611365565b9460208301958652611e288351517f0000000000000000000000000000000000000000000000000000000000000000808214611189565b6020835101519182518301926020818503126101de5760208101519067ffffffffffffffff82116101de5701926040848203126101de5760405193611e6c85610f83565b6020810151855260408101519167ffffffffffffffff83116101de57611e99926020809201920101612ac0565b94611eb360208501968088525180151580611fd957612c0d565b5f805b87518051831015611fa657611ece83611ee19261174d565b5151611edb368888611c82565b90612da9565b15611f9c57508694611f40611f55956fffffffffffffffffffffffffffffffff9a9895611f3961155e966020633b9aca009f9d8198611f20915161174d565b51015190815181518082149182611f88575b5050612c4b565b6001612c99565b51950194611f4d86611c6d565b875191612e1b565b516001815111611f69575b50505151160490565b611f75611f8192611c6d565b90848451511691612eab565b5f80611f60565b909150898401209089830120145f80611f32565b9060010190611eb6565b5061155e92506020915094611f40611f55956fffffffffffffffffffffffffffffffff9a9895633b9aca009c9a98612c99565b5061ffff811115612c0d565b94906001869593949551611ff88161105f565b6120018161105f565b146120485760ff86516120138161105f565b61201c8161105f565b7fd3a2e6c9000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b90919293945051926060602060405161206081610f83565b60405161206c81610fcc565b60405161207881611020565b84815260405161208781610f83565b5f81525f858201528482015260405161209f81610f83565b5f81525f8582015260408201525f858201525f60808201525f60a08201525f60c082015281526120cd612a22565b838201526120d9612a22565b60408201525f848201526040516120ef81610f83565b5f81525f84820152608082015260405161210881610f83565b5f81525f8482015260a08201528152015283518401936020818603126101de5760208101519067ffffffffffffffff82116101de5701936020858203126101de576040519461215686610fe8565b60208101519067ffffffffffffffff82116101de57602061217f92816121ac9501920101612a5a565b808652517f0000000000000000000000000000000000000000000000000000000000000000808214611189565b602084510151948551860160208101966020818303126101de57602081015167ffffffffffffffff81116101de570190604090829003126101de57604051966121f488610f83565b602082015167ffffffffffffffff81116101de578160206122179285010161139e565b885260408201519167ffffffffffffffff83116101de5761223b9201602001612ac0565b9361225560208801958087525180151580611fd957612c0d565b602081019561226387611c6d565b67ffffffffffffffff60a08a5101519181602084015116918291161480612549575b61228e85611c6d565b9267ffffffffffffffff6122a18c611c6d565b91511691156124fb57505050506122bc9061155e89516118b3565b6122c68751611946565b6003811015610c1257806124ca57506122de86611c6d565b67ffffffffffffffff8060035460401c16911611612477575b506040865101516040516123408161153b60208201948591909160408060608301946fffffffffffffffffffffffffffffffff8151168452602081015160208501520151910152565b51902067ffffffffffffffff61235587611c6d565b165f52600560205260405f20555b5f805b8551805183101561244c57611ece8361237e9261174d565b156124425750633b9aca0096936fffffffffffffffffffffffffffffffff9693611f39879460206123b56123cd9660409b5161174d565b5101519081518151808214918261242c575050612c4b565b6123f48351858101519067ffffffffffffffff602060a08185015193015101511690612e1b565b51600181511161240a575b505051015151160490565b61241661242592611c6d565b90858585510151511691612eab565b5f806123ff565b9091506020840120906020830120145f80611f32565b9060010190612366565b5060409592506123cd9150936fffffffffffffffffffffffffffffffff9693633b9aca009895612c99565b6124836124b891611c6d565b67ffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000006003541617600355565b6124c46115a386611c6d565b5f6122f7565b6001915003612363577f59bc8fd3000000000000000000000000000000000000000000000000000000005f5260045ffd5b6084945067ffffffffffffffff9081604051957fb8d8167e00000000000000000000000000000000000000000000000000000000875216600486015216602484015260448301526064820152fd5b5061255384611c6d565b67ffffffffffffffff80845116911614612285565b5050909161257b60206125909201611c6d565b916040519461258986610f83565b3691611c82565b8352602083019182526040516125af8161153b86602083019586612954565b5190205c9151905182156125c9575050633b9aca00900490565b9061261d61260b926040519384937ff06fc33b000000000000000000000000000000000000000000000000000000008552604060048601526044850190610e1d565b90600319848303016024850152610df8565b0390fd5b905f8091602081519101845af480806126d5575b156126555750506040513d81523d5f602083013e60203d82010160405290565b1561269c5773ffffffffffffffffffffffffffffffffffffffff907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b3d156126ad576040513d5f823e3d90fd5b7fd6bda275000000000000000000000000000000000000000000000000000000005f5260045ffd5b503d1515806126355750813b1515612635565b906fffffffffffffffffffffffffffffffff633b9aca00911604428111612925578042034281116128f857610708106128c9575080515161272a600154610e75565b14806128a2575b815190156128625750602081015160ff815116906002549160ff8316928382149283612849575b6020015160ff169215612801575050505063ffffffff606082015116906004549163ffffffff83168082036127d357505063ffffffff608081920151169160201c168082036127a5575050565b7f1eb5c1eb000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f73b1bde3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b6084945060ff90604051947fd382033a000000000000000000000000000000000000000000000000000000008652600486015260081c16602484015260448301526064820152fd5b6020810151600883901c60ff9081169116149350612758565b61261d906040519182917ff6b6676b0000000000000000000000000000000000000000000000000000000083526040600484015261260b60448401610ec6565b508051602081519101206040516128bc8161059a81610ec6565b6020815191012014612731565b7f12e74add000000000000000000000000000000000000000000000000000000005f524260045260245260445ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f20daedb6000000000000000000000000000000000000000000000000000000005f524260045260245260445ffd5b9067ffffffffffffffff90939293168152604060208201526080810190835191604080830152825180915260a0820190602060a08260051b8501019401915f905b8282106129d9575050505060206110d6939401519060607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc082850301910152610df8565b90919294602080612a14837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6089600196030186528951610df8565b970192019201909291612995565b60405190612a2f82611004565b5f6040838281528260208201520152565b9080601f830112156101de5781516110d6926020016111c0565b91906060838203126101de5760405190612a7382611004565b819380518352602081015167ffffffffffffffff81116101de5782612a99918301612a40565b602084015260408101519167ffffffffffffffff83116101de5760409261124a9201612a40565b9080601f830112156101de57815191612ad883611735565b92612ae6604051948561103c565b80845260208085019160051b830101918383116101de5760208101915b838310612b1257505050505090565b825167ffffffffffffffff81116101de578201906040601f1983880301126101de5760405190612b4182610f83565b602083015167ffffffffffffffff81116101de5760209084010187601f820112156101de578051612b7181611735565b91612b7f604051938461103c565b81835260208084019260051b820101918a83116101de5760208201905b838210612bdf5750505050825260408301519167ffffffffffffffff83116101de57612bd088602080969581960101612a40565b83820152815201920191612b03565b815167ffffffffffffffff81116101de57602091612c028e848094880101612a40565b815201910190612b9c565b15612c155750565b7fb0369c31000000000000000000000000000000000000000000000000000000005f52600452600160245261ffff60445260645ffd5b91909115612c57575050565b9061261d61260b926040519384937f5f1ca381000000000000000000000000000000000000000000000000000000008552604060048601526044850190610df8565b91909115612ca5575050565b604051907ffef760c700000000000000000000000000000000000000000000000000000000825280602483016020600485015252604482019260448260051b84010191815f907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603015b838310612d1e5786860387fd5b90919293947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc8782030188528535828112156101de578301906020823592019167ffffffffffffffff81116101de5780360383136101de57602082601f19601f8480600198869897879852868601375f85828601015201160101970198019301919096939296612d11565b908151815103611b9f575f5b8251811015612e1357612dc8818461174d565b5151612dd4828461174d565b515103612e0c57612de5818461174d565b5160208151910120612df7828461174d565b516020815191012003612e0c57600101612db5565b5050505f90565b505050600190565b91612e7060209261193c60405185810190612e678161153b888591909160408060608301946fffffffffffffffffffffffffffffffff8151168452602081015160208501520151910152565b51902091611649565b0151808203612e7d575050565b7f4b2dfe98000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b929190925f5b8451811015612ee9578083612ec86001938861174d565b51604051612edf8161153b60208201948986612954565b5190205d01612eb1565b505050905056fea164736f6c634300081c000a2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d4c48d1d2b0f4f7485fc28e3db22341d96a20aa29e6efa8149da9751603abd4e06e0c24a6e293ff9b755263dbaa15ba3796b0b8d3fe17cfb4ddf8143b268eac47bd893629a699470e4ec82a5715bb4981fdaacc5d0a728bf5f55b801d8f4ef10bad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5"}} diff --git a/ibc-solidity/contracts/README.md b/ibc-solidity/contracts/README.md index 5aba1e2eb..21900cb09 100644 --- a/ibc-solidity/contracts/README.md +++ b/ibc-solidity/contracts/README.md @@ -22,9 +22,21 @@ This directory implements the IBC v2 protocol stack in Solidity. Most entrypoint ## Light clients (`light-clients/`) - `attestation/AttestationLightClient.sol` – m-of-n attestor-set light client using ECDSA signatures with role-gated proof submission. +- `besu/BesuIBFT2LightClient.sol` – Besu IBFT 2.0 light client for header-validator mode. Uses weak-subjectivity / trusting-period updates, verifies Besu commit seals under the existing YUI + prover sealing-header model plus EVM account/storage proofs, and proves Eureka commitments against the tracked counterparty `ICS26Router` storage. +- `besu/BesuQBFTLightClient.sol` – Besu QBFT light client for header-validator mode with the same proof model and storage verification surface as the IBFT2 wrapper, but QBFT-specific seal-digest rules within that same YUI + prover sealing-header model. - `ics02-wrapper/ICS02PrecompileWrapper.sol` – Thin adapter that exposes the `ILightClient` interface over the Cosmos EVM ICS02 precompile at a fixed address. - `sp1-ics07/SP1ICS07Tendermint.sol` – Tendermint light client verified via SP1 programs and verifier contract; supports update, (non)membership proofs, and misbehaviour handling. +### Besu light-client scope +- Supported: Besu **IBFT 2.0** and **QBFT** in **header-validator mode**. +- Verification model: weak subjectivity via **trusting period** and validator-set overlap checks. +- Commit-seal verification: follows the existing **YUI Solidity client + besu-ibc-relay-prover** sealing-header reconstruction model. +- Trusted overlap threshold: requires **strictly greater than one-third** overlap with the trusted validator set, implemented as `floor(n / 3) + 1`, which is intentionally stricter than the current upstream YUI check. +- Proof surface: Besu block headers, commit seals, Ethereum account proofs, and Ethereum storage proofs. +- Counterparty storage model: Eureka `ICS26Router` / `IBCStoreUpgradeable` commitments mapping. +- Not supported in v1: QBFT validator-contract mode, mode transitions, and misbehaviour handling. +- Current fixture status: `test/besu-bft/fixtures/` are synthetic regression fixtures; real Besu-derived golden fixtures remain a follow-up interoperability-confidence improvement. + ## Interchain Fungible Tokens (IFT) - Code reference: find the `contracts` IFT contract code [here](https://github.com/cosmos/solidity-ibc-eureka/tree/mariuszzak/ift/contracts). - IFT is an issuer-controlled ERC20 that bridges via ICS27-GMP instead of ICS20. The abstract `IFTBase` burns on send, constructs a mint call for the counterparty IFT, and tracks pending transfers keyed by (clientId, sequence). diff --git a/ibc-solidity/contracts/light-clients/besu/BesuIBFT2LightClient.sol b/ibc-solidity/contracts/light-clients/besu/BesuIBFT2LightClient.sol new file mode 100644 index 000000000..f0af3c454 --- /dev/null +++ b/ibc-solidity/contracts/light-clients/besu/BesuIBFT2LightClient.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.28; + +import { RLP } from "@openzeppelin-contracts/utils/RLP.sol"; + +import { BesuLightClientBase } from "./BesuLightClientBase.sol"; + +/// @title Besu IBFT2 Light Client +/// @notice Verifies Besu IBFT 2.0 headers and ICS26 router storage proofs. +contract BesuIBFT2LightClient is BesuLightClientBase { + /// @notice Creates a Besu IBFT2 light client from an initial trusted consensus state. + /// @param ibcRouter Counterparty ICS26 router address whose storage is proven. + /// @param initialTrustedHeight Initial trusted Besu height. + /// @param initialTrustedTimestamp Initial trusted header timestamp in seconds. + /// @param initialTrustedStorageRoot Initial trusted storage root of `ibcRouter`. + /// @param initialTrustedValidators Initial trusted validator set. + /// @param trustingPeriod Maximum age in seconds for trusted consensus states. + /// @param maxClockDrift Maximum allowed future drift in seconds for submitted headers. + /// @param roleManager Address that administers proof submission; if zero, proof submission is open. + constructor( + address ibcRouter, + uint64 initialTrustedHeight, + uint64 initialTrustedTimestamp, + bytes32 initialTrustedStorageRoot, + address[] memory initialTrustedValidators, + uint64 trustingPeriod, + uint64 maxClockDrift, + address roleManager + ) + BesuLightClientBase( + ibcRouter, + initialTrustedHeight, + initialTrustedTimestamp, + initialTrustedStorageRoot, + initialTrustedValidators, + trustingPeriod, + maxClockDrift, + roleManager + ) + { } + + /// @inheritdoc BesuLightClientBase + function _commitSealDigest(ParsedHeader memory header) internal pure override returns (bytes32) { + bytes[] memory extraItems = new bytes[](4); + extraItems[0] = _rlpItemBytes(header.extraDataItems[0]); + extraItems[1] = _rlpItemBytes(header.extraDataItems[1]); + extraItems[2] = _rlpItemBytes(header.extraDataItems[2]); + extraItems[3] = _rlpItemBytes(header.extraDataItems[3]); + + bytes memory signingExtraData = RLP.encode(extraItems); + bytes[] memory headerItems = new bytes[](header.headerItems.length); + for (uint256 i = 0; i < header.headerItems.length; ++i) { + headerItems[i] = i == 12 ? RLP.encode(signingExtraData) : _rlpItemBytes(header.headerItems[i]); + } + return keccak256(RLP.encode(headerItems)); + } +} diff --git a/ibc-solidity/contracts/light-clients/besu/BesuLightClientBase.sol b/ibc-solidity/contracts/light-clients/besu/BesuLightClientBase.sol new file mode 100644 index 000000000..dc3e40f27 --- /dev/null +++ b/ibc-solidity/contracts/light-clients/besu/BesuLightClientBase.sol @@ -0,0 +1,533 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.28; + +// solhint-disable gas-struct-packing, named-parameters-mapping, gas-strict-inequalities, code-complexity + +import { AccessControl } from "@openzeppelin-contracts/access/AccessControl.sol"; +import { Memory } from "@openzeppelin-contracts/utils/Memory.sol"; +import { RLP } from "@openzeppelin-contracts/utils/RLP.sol"; +import { SlotDerivation } from "@openzeppelin-contracts/utils/SlotDerivation.sol"; +import { ECDSA } from "@openzeppelin-contracts/utils/cryptography/ECDSA.sol"; + +import { ILightClient } from "../../interfaces/ILightClient.sol"; +import { ILightClientMsgs } from "../../msgs/ILightClientMsgs.sol"; +import { IICS02ClientMsgs } from "../../msgs/IICS02ClientMsgs.sol"; +import { IBesuLightClientMsgs } from "./msgs/IBesuLightClientMsgs.sol"; +import { IBesuLightClientErrors } from "./errors/IBesuLightClientErrors.sol"; +import { IBesuLightClient } from "./interfaces/IBesuLightClient.sol"; +import { MPTProof } from "./MPTProof.sol"; + +/// @title Besu Light Client Base +/// @notice Shared implementation for Besu BFT light clients that verify headers and EVM storage proofs. +abstract contract BesuLightClientBase is IBesuLightClient, IBesuLightClientErrors, IBesuLightClientMsgs, AccessControl { + using MPTProof for bytes; + using Memory for Memory.Slice; + using RLP for Memory.Slice; + using RLP for bytes; + using SlotDerivation for bytes32; + + /// @notice Decoded fields from a submitted Besu header. + /// @param headerItems Top-level RLP header fields. + /// @param extraDataItems Decoded Besu BFT `extraData` fields. + /// @param height Header block number. + /// @param stateRoot Header state root. + /// @param timestamp Header timestamp in seconds. + /// @param validators Validator set from `extraData`. + /// @param commitSeals Commit seals from `extraData`. + struct ParsedHeader { + Memory.Slice[] headerItems; + Memory.Slice[] extraDataItems; + uint64 height; + bytes32 stateRoot; + uint64 timestamp; + address[] validators; + bytes[] commitSeals; + } + + /// @notice Role allowed to submit client updates and proof verifications. + // natlint-disable-next-line MissingInheritdoc + bytes32 public constant PROOF_SUBMITTER_ROLE = keccak256("PROOF_SUBMITTER_ROLE"); + + /// @notice Besu BFT sentinel mix hash. + bytes32 internal constant BESU_BFT_MIX_HASH = 0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365; + /// @notice Empty ommers hash required by Besu BFT headers. + bytes32 internal constant EMPTY_OMMERS_HASH = 0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347; + /// @notice ERC-7201 storage slot used by `IBCStoreUpgradeable` commitments. + bytes32 internal constant IBCSTORE_STORAGE_SLOT = + 0x1260944489272988d9df285149b5aa1b0f48f2136d6f416159f840a3e0747600; + + /// @notice Current client state. + ClientState internal clientState; + /// @notice Trusted consensus states by revision height. + mapping(uint64 revisionHeight => ConsensusState) internal consensusStates; + + /// @notice Initializes shared Besu light client state. + /// @param ibcRouter Counterparty ICS26 router address whose storage is proven. + /// @param initialTrustedHeight Initial trusted Besu height. + /// @param initialTrustedTimestamp Initial trusted header timestamp in seconds. + /// @param initialTrustedStorageRoot Initial trusted storage root of `ibcRouter`. + /// @param initialTrustedValidators Initial trusted validator set. + /// @param trustingPeriod Maximum age in seconds for trusted consensus states. + /// @param maxClockDrift Maximum allowed future drift in seconds for submitted headers. + /// @param roleManager Address that administers proof submission; if zero, proof submission is open. + constructor( + address ibcRouter, + uint64 initialTrustedHeight, + uint64 initialTrustedTimestamp, + bytes32 initialTrustedStorageRoot, + address[] memory initialTrustedValidators, + uint64 trustingPeriod, + uint64 maxClockDrift, + address roleManager + ) { + if (initialTrustedHeight == 0) { + revert InvalidHeaderHeight(); + } + if (initialTrustedTimestamp == 0) { + revert InvalidHeaderTimestamp(initialTrustedTimestamp); + } + + _validateValidators(initialTrustedValidators); + + clientState = ClientState({ + ibcRouter: ibcRouter, + latestHeight: IICS02ClientMsgs.Height({ revisionNumber: 0, revisionHeight: initialTrustedHeight }), + trustingPeriod: trustingPeriod, + maxClockDrift: maxClockDrift + }); + + ConsensusState storage consensusState = consensusStates[initialTrustedHeight]; + consensusState.timestamp = initialTrustedTimestamp; + consensusState.storageRoot = initialTrustedStorageRoot; + consensusState.validators = initialTrustedValidators; + + if (roleManager == address(0)) { + _grantRole(PROOF_SUBMITTER_ROLE, address(0)); + } else { + _grantRole(DEFAULT_ADMIN_ROLE, roleManager); + _grantRole(PROOF_SUBMITTER_ROLE, roleManager); + } + } + + /// @inheritdoc ILightClient + function getClientState() external view returns (bytes memory) { + return abi.encode(clientState); + } + + /// @inheritdoc IBesuLightClient + function getConsensusState(uint64 revisionHeight) external view returns (bytes memory) { + ConsensusState storage consensusState = _getConsensusState(revisionHeight); + return abi.encode(consensusState.timestamp, consensusState.storageRoot, consensusState.validators); + } + + /// @inheritdoc ILightClient + function updateClient(bytes calldata updateMsg) + external + onlyProofSubmitter + returns (ILightClientMsgs.UpdateResult) + { + MsgUpdateClient memory msg_ = abi.decode(updateMsg, (MsgUpdateClient)); + _requireZeroRevision(msg_.trustedHeight.revisionNumber); + + ParsedHeader memory header = _parseHeader(msg_.headerRlp); + if (block.timestamp + clientState.maxClockDrift < header.timestamp) { + revert HeaderFromFuture(block.timestamp, header.timestamp, clientState.maxClockDrift); + } + + ConsensusState storage trustedConsensusState = _getConsensusState(msg_.trustedHeight.revisionHeight); + if (header.height <= msg_.trustedHeight.revisionHeight) { + revert InvalidHeaderHeight(); + } + if ( + clientState.trustingPeriod != 0 + && uint256(trustedConsensusState.timestamp) + clientState.trustingPeriod <= block.timestamp + ) { + revert ConsensusStateExpired(trustedConsensusState.timestamp, block.timestamp, clientState.trustingPeriod); + } + + address[] memory signers = _recoverSigners(_commitSealDigest(header), header.commitSeals); + _checkTrustedValidatorOverlap(signers, trustedConsensusState.validators); + _checkValidatorQuorum(signers, header.validators); + + bytes32 storageRoot = _verifyAccountProof(clientState.ibcRouter, header.stateRoot, msg_.accountProof); + + ConsensusState storage existingConsensusState = consensusStates[header.height]; + if (existingConsensusState.timestamp != 0) { + if (_isSameConsensusState(existingConsensusState, header.timestamp, storageRoot, header.validators)) { + return ILightClientMsgs.UpdateResult.NoOp; + } + revert ConflictingConsensusState(header.height); + } + + ConsensusState storage newConsensusState = consensusStates[header.height]; + newConsensusState.timestamp = header.timestamp; + newConsensusState.storageRoot = storageRoot; + newConsensusState.validators = header.validators; + + if (header.height > clientState.latestHeight.revisionHeight) { + clientState.latestHeight.revisionHeight = header.height; + } + + return ILightClientMsgs.UpdateResult.Update; + } + + /// @inheritdoc ILightClient + function verifyMembership(ILightClientMsgs.MsgVerifyMembership calldata msg_) + external + view + onlyProofSubmitter + returns (uint256) + { + _requireZeroRevision(msg_.proofHeight.revisionNumber); + if (msg_.path.length != 1) { + revert InvalidPathLength(1, msg_.path.length); + } + if (msg_.value.length != 32) { + revert InvalidValueLength(32, msg_.value.length); + } + + ConsensusState storage consensusState = _getConsensusState(msg_.proofHeight.revisionHeight); + bytes32 storageSlot = _commitmentStorageSlot(msg_.path[0]); + bytes32 expectedValue = abi.decode(msg_.value, (bytes32)); + (bool exists, bytes memory valueRlp) = + msg_.proof.verifyRLPProof(consensusState.storageRoot, keccak256(abi.encodePacked(storageSlot))); + if (!exists) { + revert InvalidCommitmentValue(expectedValue, bytes32(0)); + } + + bytes32 actualValue = bytes32(valueRlp.decodeUint256()); + if (actualValue != expectedValue) { + revert InvalidCommitmentValue(expectedValue, actualValue); + } + return consensusState.timestamp; + } + + /// @inheritdoc ILightClient + function verifyNonMembership(ILightClientMsgs.MsgVerifyNonMembership calldata msg_) + external + view + onlyProofSubmitter + returns (uint256) + { + _requireZeroRevision(msg_.proofHeight.revisionNumber); + if (msg_.path.length != 1) { + revert InvalidPathLength(1, msg_.path.length); + } + + ConsensusState storage consensusState = _getConsensusState(msg_.proofHeight.revisionHeight); + bytes32 storageSlot = _commitmentStorageSlot(msg_.path[0]); + (bool exists, bytes memory valueRlp) = + msg_.proof.verifyRLPProof(consensusState.storageRoot, keccak256(abi.encodePacked(storageSlot))); + if (exists) { + revert ValueExists(bytes32(valueRlp.decodeUint256())); + } + return consensusState.timestamp; + } + + /// @inheritdoc ILightClient + function misbehaviour(bytes calldata) external view onlyProofSubmitter { + revert UnsupportedMisbehaviour(); + } + + /// @notice Computes the protocol-specific commit seal digest for a parsed header. + /// @param header The parsed Besu header. + /// @return The digest signed by commit seals. + function _commitSealDigest(ParsedHeader memory header) internal pure virtual returns (bytes32); + + /// @notice Parses and validates common Besu BFT header fields. + /// @param headerRlp RLP-encoded Besu block header. + /// @return header The parsed header fields used by update and proof verification. + function _parseHeader(bytes memory headerRlp) internal pure returns (ParsedHeader memory header) { + header.headerItems = headerRlp.decodeList(); + if (header.headerItems.length < 15) { + revert InvalidHeaderFormat(header.headerItems.length); + } + + if (_readBytes32Strict(header.headerItems[1]) != EMPTY_OMMERS_HASH) { + revert InvalidOmmersHash(_readBytes32Strict(header.headerItems[1])); + } + if (header.headerItems[7].readUint256() != 1) { + revert InvalidDifficulty(header.headerItems[7].readUint256()); + } + if (_readBytes32Strict(header.headerItems[13]) != BESU_BFT_MIX_HASH) { + revert InvalidMixHash(_readBytes32Strict(header.headerItems[13])); + } + + bytes memory nonce = header.headerItems[14].readBytes(); + if (nonce.length != 8 || keccak256(nonce) != keccak256(hex"0000000000000000")) { + revert InvalidNonce(nonce); + } + + uint256 height = header.headerItems[8].readUint256(); + if (height == 0 || height > type(uint64).max) revert InvalidHeaderHeight(); + header.height = uint64(height); + header.stateRoot = _readBytes32Strict(header.headerItems[3]); + uint256 timestamp = header.headerItems[11].readUint256(); + if (timestamp == 0 || timestamp > type(uint64).max) revert InvalidHeaderTimestamp(timestamp); + header.timestamp = uint64(timestamp); + + bytes memory extraData = header.headerItems[12].readBytes(); + header.extraDataItems = extraData.decodeList(); + if (header.extraDataItems.length != 5) { + revert InvalidExtraDataFormat(header.extraDataItems.length); + } + uint256 vanityDataLength = header.extraDataItems[0].readBytes().length; + if (vanityDataLength != 32) revert InvalidVanityDataLength(vanityDataLength); + + Memory.Slice[] memory validatorItems = header.extraDataItems[1].readList(); + if (validatorItems.length == 0) { + revert EmptyValidatorSet(); + } + + header.validators = new address[](validatorItems.length); + for (uint256 i = 0; i < validatorItems.length; ++i) { + bytes memory validatorBytes = validatorItems[i].readBytes(); + if (validatorBytes.length != 20) { + revert InvalidValidatorAddressLength(validatorBytes.length); + } + + address validator = address(bytes20(validatorBytes)); + if (validator == address(0)) { + revert InvalidValidatorAddress(validator); + } + for (uint256 j = 0; j < i; ++j) { + if (header.validators[j] == validator) { + revert DuplicateValidator(validator); + } + } + header.validators[i] = validator; + } + + Memory.Slice[] memory sealItems = header.extraDataItems[4].readList(); + header.commitSeals = new bytes[](sealItems.length); + for (uint256 i = 0; i < sealItems.length; ++i) { + header.commitSeals[i] = sealItems[i].readBytes(); + } + } + + /// @notice Verifies the tracked account proof against a header state root. + /// @param account The account address being proven. + /// @param stateRoot The header state root. + /// @param accountProof RLP-encoded account proof. + /// @return The proven account storage root. + function _verifyAccountProof( + address account, + bytes32 stateRoot, + bytes memory accountProof + ) + internal + pure + returns (bytes32) + { + (bool exists, bytes memory accountRlp) = + accountProof.verifyRLPProof(stateRoot, keccak256(abi.encodePacked(account))); + if (!exists) revert AccountNotFound(account); + + Memory.Slice[] memory accountItems = accountRlp.decodeList(); + return _readBytes32Strict(accountItems[2]); + } + + /// @notice Computes the storage slot used for an IBC commitment path. + /// @param rawPath Raw commitment path bytes. + /// @return The storage slot for the commitment. + function _commitmentStorageSlot(bytes memory rawPath) internal pure returns (bytes32) { + return IBCSTORE_STORAGE_SLOT.deriveMapping(keccak256(rawPath)); + } + + /// @notice Recovers unique commit seal signers for a digest. + /// @param digest The commit seal digest. + /// @param seals The commit seals to recover. + /// @return signers The recovered signer addresses. + function _recoverSigners(bytes32 digest, bytes[] memory seals) internal pure returns (address[] memory signers) { + signers = new address[](seals.length); + for (uint256 i = 0; i < seals.length; ++i) { + address signer = _recoverSigner(digest, seals[i]); + for (uint256 j = 0; j < i; ++j) { + if (signers[j] == signer) { + revert DuplicateCommitSealSigner(signer); + } + } + signers[i] = signer; + } + } + + /// @notice Recovers one commit seal signer. + /// @param digest The commit seal digest. + /// @param seal The 65-byte ECDSA commit seal. + /// @return The recovered signer address. + function _recoverSigner(bytes32 digest, bytes memory seal) internal pure returns (address) { + if (seal.length != 65) { + revert InvalidECDSASignatureLength(seal.length); + } + if (uint8(seal[64]) < 27) { + seal[64] = bytes1(uint8(seal[64]) + 27); + } + (address signer, ECDSA.RecoverError err, bytes32 errorArgument) = ECDSA.tryRecover(digest, seal); + if (err != ECDSA.RecoverError.NoError || errorArgument != bytes32(0) || signer == address(0)) { + revert InvalidCommitSeal(); + } + return signer; + } + + /// @notice Checks that signers overlap enough with the trusted validator set. + /// @param signers The recovered commit seal signers. + /// @param trustedValidators The trusted validator set. + function _checkTrustedValidatorOverlap( + address[] memory signers, + address[] storage trustedValidators + ) + internal + view + { + uint256 actual = 0; + for (uint256 i = 0; i < signers.length; ++i) { + if (_containsStorage(trustedValidators, signers[i])) { + ++actual; + } + } + + uint256 required = trustedValidators.length / 3 + 1; + if (actual < required) { + revert InsufficientTrustedValidatorOverlap(actual, required); + } + } + + /// @notice Checks that signers meet quorum for the submitted header validator set. + /// @param signers The recovered commit seal signers. + /// @param validators The validator set from the submitted header. + function _checkValidatorQuorum(address[] memory signers, address[] memory validators) internal pure { + uint256 actual = 0; + for (uint256 i = 0; i < signers.length; ++i) { + if (_containsMemory(validators, signers[i])) { + ++actual; + } + } + + // Besu requires ceil(2n / 3), equivalently n - floor(n / 3). + uint256 required = validators.length - validators.length / 3; + if (actual < required) { + revert InsufficientValidatorQuorum(actual, required); + } + } + + /// @notice Validates that a validator set is non-empty and unique. + /// @param validators The validator set to validate. + function _validateValidators(address[] memory validators) internal pure { + if (validators.length == 0) { + revert EmptyValidatorSet(); + } + for (uint256 i = 0; i < validators.length; ++i) { + if (validators[i] == address(0)) { + revert InvalidValidatorAddress(validators[i]); + } + for (uint256 j = 0; j < i; ++j) { + if (validators[j] == validators[i]) { + revert DuplicateValidator(validators[i]); + } + } + } + } + + /// @notice Compares a stored consensus state with proposed fields. + /// @param consensusState The stored consensus state. + /// @param timestamp The proposed timestamp. + /// @param storageRoot The proposed storage root. + /// @param validators The proposed validator set. + /// @return True if all fields match. + function _isSameConsensusState( + ConsensusState storage consensusState, + uint64 timestamp, + bytes32 storageRoot, + address[] memory validators + ) + internal + view + returns (bool) + { + if (consensusState.timestamp != timestamp || consensusState.storageRoot != storageRoot) { + return false; + } + return keccak256(abi.encode(consensusState.validators)) == keccak256(abi.encode(validators)); + } + + /// @notice Returns a stored consensus state or reverts if it is missing. + /// @param revisionHeight The consensus state revision height. + /// @return consensusState The stored consensus state. + function _getConsensusState(uint64 revisionHeight) internal view returns (ConsensusState storage consensusState) { + consensusState = consensusStates[revisionHeight]; + if (consensusState.timestamp == 0) { + revert ConsensusStateNotFound(revisionHeight); + } + } + + /// @notice Reverts unless the revision number is zero. + /// @param revisionNumber The revision number to validate. + function _requireZeroRevision(uint64 revisionNumber) internal pure { + if (revisionNumber != 0) { + revert InvalidRevisionNumber(revisionNumber); + } + } + + /// @notice Checks whether a storage validator set contains a signer. + /// @param validators The storage validator set. + /// @param signer The signer to find. + /// @return True if `signer` is present. + function _containsStorage(address[] storage validators, address signer) internal view returns (bool) { + for (uint256 i = 0; i < validators.length; ++i) { + if (validators[i] == signer) { + return true; + } + } + return false; + } + + /// @notice Checks whether a memory validator set contains a signer. + /// @param validators The memory validator set. + /// @param signer The signer to find. + /// @return True if `signer` is present. + function _containsMemory(address[] memory validators, address signer) internal pure returns (bool) { + for (uint256 i = 0; i < validators.length; ++i) { + if (validators[i] == signer) { + return true; + } + } + return false; + } + + /// @notice Returns the full RLP bytes for an item. + /// @param item The RLP item. + /// @return The RLP-encoded bytes. + function _rlpItemBytes(Memory.Slice item) internal pure returns (bytes memory) { + return item.toBytes(); + } + + /// @notice Encodes raw bytes as an RLP string. + /// @param raw Raw bytes to encode. + /// @return The RLP-encoded string. + function _encodeRlpBytes(bytes memory raw) internal pure returns (bytes memory) { + return RLP.encode(raw); + } + + /// @notice Encodes pre-encoded RLP items as an RLP list. + /// @param items RLP-encoded list items. + /// @return The RLP-encoded list. + function _encodeRlpList(bytes[] memory items) internal pure returns (bytes memory) { + return RLP.encode(items); + } + + /// @notice Decodes a fixed-width 32-byte RLP data item. + /// @param item The encoded RLP item. + /// @return The decoded 32-byte value. + function _readBytes32Strict(Memory.Slice item) private pure returns (bytes32) { + if (item.length() != 33) revert RLP.RLPInvalidEncoding(); + return item.readBytes32(); + } + + /// @notice Restricts access to proof submitters unless submission is open to anyone. + modifier onlyProofSubmitter() { + if (!hasRole(PROOF_SUBMITTER_ROLE, address(0))) { + _checkRole(PROOF_SUBMITTER_ROLE); + } + _; + } +} diff --git a/ibc-solidity/contracts/light-clients/besu/BesuQBFTLightClient.sol b/ibc-solidity/contracts/light-clients/besu/BesuQBFTLightClient.sol new file mode 100644 index 000000000..5cef961a6 --- /dev/null +++ b/ibc-solidity/contracts/light-clients/besu/BesuQBFTLightClient.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.28; + +import { RLP } from "@openzeppelin-contracts/utils/RLP.sol"; + +import { BesuLightClientBase } from "./BesuLightClientBase.sol"; + +/// @title Besu QBFT Light Client +/// @notice Verifies Besu QBFT headers and ICS26 router storage proofs. +contract BesuQBFTLightClient is BesuLightClientBase { + /// @notice Creates a Besu QBFT light client from an initial trusted consensus state. + /// @param ibcRouter Counterparty ICS26 router address whose storage is proven. + /// @param initialTrustedHeight Initial trusted Besu height. + /// @param initialTrustedTimestamp Initial trusted header timestamp in seconds. + /// @param initialTrustedStorageRoot Initial trusted storage root of `ibcRouter`. + /// @param initialTrustedValidators Initial trusted validator set. + /// @param trustingPeriod Maximum age in seconds for trusted consensus states. + /// @param maxClockDrift Maximum allowed future drift in seconds for submitted headers. + /// @param roleManager Address that administers proof submission; if zero, proof submission is open. + constructor( + address ibcRouter, + uint64 initialTrustedHeight, + uint64 initialTrustedTimestamp, + bytes32 initialTrustedStorageRoot, + address[] memory initialTrustedValidators, + uint64 trustingPeriod, + uint64 maxClockDrift, + address roleManager + ) + BesuLightClientBase( + ibcRouter, + initialTrustedHeight, + initialTrustedTimestamp, + initialTrustedStorageRoot, + initialTrustedValidators, + trustingPeriod, + maxClockDrift, + roleManager + ) + { } + + /// @inheritdoc BesuLightClientBase + function _commitSealDigest(ParsedHeader memory header) internal pure override returns (bytes32) { + bytes[] memory extraItems = new bytes[](5); + extraItems[0] = _rlpItemBytes(header.extraDataItems[0]); + extraItems[1] = _rlpItemBytes(header.extraDataItems[1]); + extraItems[2] = _rlpItemBytes(header.extraDataItems[2]); + extraItems[3] = _rlpItemBytes(header.extraDataItems[3]); + extraItems[4] = hex"c0"; + + bytes memory signingExtraData = RLP.encode(extraItems); + bytes[] memory headerItems = new bytes[](header.headerItems.length); + for (uint256 i = 0; i < header.headerItems.length; ++i) { + headerItems[i] = i == 12 ? RLP.encode(signingExtraData) : _rlpItemBytes(header.headerItems[i]); + } + return keccak256(RLP.encode(headerItems)); + } +} diff --git a/ibc-solidity/contracts/light-clients/besu/MPTProof.sol b/ibc-solidity/contracts/light-clients/besu/MPTProof.sol new file mode 100644 index 000000000..0261de81d --- /dev/null +++ b/ibc-solidity/contracts/light-clients/besu/MPTProof.sol @@ -0,0 +1,344 @@ +// SPDX-License-Identifier: Apache-2.0 +// OpenZeppelin Contracts (last updated v5.6.0) (utils/cryptography/TrieProof.sol) +// Derived from OpenZeppelin Contracts v5.6.1 TrieProof.sol: +// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.6.1/contracts/utils/cryptography/TrieProof.sol +pragma solidity ^0.8.28; + +// Keep the upstream traversal structure easy to diff when upgrading OpenZeppelin. +// solhint-disable code-complexity, function-max-lines, gas-increment-by-one, gas-strict-inequalities, +// solhint-disable no-inline-assembly + +import { Bytes } from "@openzeppelin-contracts/utils/Bytes.sol"; +import { Memory } from "@openzeppelin-contracts/utils/Memory.sol"; +import { RLP } from "@openzeppelin-contracts/utils/RLP.sol"; + +/** + * @title Ethereum Merkle-Patricia trie proof verification + * @notice Library for verifying Ethereum Merkle-Patricia trie inclusion and exclusion proofs. + * + * This is a narrow fork of OpenZeppelin's `TrieProof` library. OpenZeppelin v5.6.1 only accepts + * inclusion proofs, while IBC non-membership verification also requires authenticated exclusion. + * The traversal therefore returns an explicit `exists` flag and accepts these exclusion terminals: + * + * * an empty trie, + * * an empty branch child or branch value, and + * * a compact leaf or extension path that diverges from the requested key. + * + * Exclusion is accepted only at the final supplied proof element. The proof wire format remains + * this light client's existing RLP-encoded list of RLP nodes. + */ +library MPTProof { + using Bytes for *; + using RLP for *; + using Memory for *; + + /// @notice Hex-prefix encodings for extension and leaf paths. + enum Prefix { + EXTENSION_EVEN, // 0 - Extension node with even length path + EXTENSION_ODD, // 1 - Extension node with odd length path + LEAF_EVEN, // 2 - Leaf node with even length path + LEAF_ODD // 3 - Leaf node with odd length path + } + + /// @notice Errors that can occur while traversing a trie proof. + enum ProofError { + NO_ERROR, // No error occurred during proof traversal + EMPTY_KEY, // The provided key is empty + INVALID_ROOT, // The validation of the root node failed + INVALID_LARGE_NODE, // The validation of a large node failed + INVALID_SHORT_NODE, // The validation of a short node failed + EMPTY_PATH, // The path in a leaf or extension node is empty + INVALID_PATH_REMAINDER, // The path remainder in a leaf or extension node is invalid + EMPTY_EXTENSION_PATH_REMAINDER, // The path remainder in an extension node is empty + INVALID_EXTRA_PROOF_ELEMENT, // A leaf value should be the last proof element + EMPTY_VALUE, // The leaf value is empty + MISMATCH_LEAF_PATH_KEY_REMAINDER, // The path remainder in a leaf node doesn't match the key remainder + UNKNOWN_NODE_PREFIX, // The node prefix is unknown + UNPARSEABLE_NODE, // The node cannot be parsed from RLP encoding + INVALID_PROOF // General failure during proof traversal + } + + /// @notice Indicates that trie proof traversal failed. + /// @param err The traversal error. + error TrieProofTraversalError(ProofError err); + + /// @notice The radix of the Ethereum trie. + uint256 internal constant EVM_TREE_RADIX = 16; + + /// @notice Number of items in a branch node (16 children and one value). + uint256 internal constant BRANCH_NODE_LENGTH = EVM_TREE_RADIX + 1; + + /// @notice Number of items in leaf or extension nodes. + uint256 internal constant LEAF_OR_EXTENSION_NODE_LENGTH = 2; + + /// @notice Root hash of the empty Ethereum Merkle-Patricia trie. + bytes32 internal constant EMPTY_TRIE_ROOT = 0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421; + + /// @notice Verifies an RLP-encoded proof and returns whether `key` exists and its value. + /// @dev Reverts with {TrieProofTraversalError} if the proof is malformed or not linked to `root`. + /// @param rlpProof An RLP list containing the encoded trie nodes. + /// @param root The expected trie root. + /// @param key The trie key to verify. + /// @return exists Whether the key is present in the trie. + /// @return value The value associated with the key, or empty bytes when it is absent. + function verifyRLPProof( + bytes memory rlpProof, + bytes32 root, + bytes32 key + ) + internal + pure + returns (bool exists, bytes memory value) + { + ProofError err; + (value, err) = _tryTraverse(root, abi.encodePacked(key), _decodeProof(rlpProof)); + require(err == ProofError.NO_ERROR, TrieProofTraversalError(err)); + exists = value.length != 0; + } + + /// @notice Traverses a proof and reports its value and error without reverting on traversal errors. + /// @dev This function may still revert if malformed input leads to RLP decoding errors. + /// @param root The expected trie root. + /// @param key The trie key to verify. + /// @param proof The encoded trie nodes, ordered from root to terminal node. + /// @return value The value associated with the key, or empty bytes when it is absent. + /// @return err The traversal error, or `NO_ERROR` for a valid inclusion or exclusion proof. + function _tryTraverse( + bytes32 root, + bytes memory key, + bytes[] memory proof + ) + private + pure + returns (bytes memory, ProofError) + { + if (key.length == 0) return (_emptyBytesMemory(), ProofError.EMPTY_KEY); + if (proof.length == 0) { + return root == EMPTY_TRIE_ROOT + ? (_emptyBytesMemory(), ProofError.NO_ERROR) + : (_emptyBytesMemory(), ProofError.INVALID_PROOF); + } + + // Expand the key + bytes memory keyExpanded = key.toNibbles(); + + // These are assigned before use whenever traversal advances beyond the root. + // slither-disable-next-line uninitialized-local + bytes32 currentNodeId; + // slither-disable-next-line uninitialized-local + uint256 currentNodeIdLength; + + // Free memory pointer cache + Memory.Pointer fmp = Memory.getFreeMemoryPointer(); + + // Traverse proof + uint256 keyIndex = 0; + for (uint256 i = 0; i < proof.length; ++i) { + // validates the encoded node matches the expected node id + bytes memory encoded = proof[i]; + if (keyIndex == 0) { + // Root node must match root hash + if (keccak256(encoded) != root) { + return (_emptyBytesMemory(), ProofError.INVALID_ROOT); + } + } else if (encoded.length >= 32) { + // Large nodes are stored as hashes + if (currentNodeIdLength != 32 || keccak256(encoded) != currentNodeId) { + return (_emptyBytesMemory(), ProofError.INVALID_LARGE_NODE); + } + } else { + // Short nodes must match directly + if (currentNodeIdLength != encoded.length || bytes32(encoded) != currentNodeId) { + return (_emptyBytesMemory(), ProofError.INVALID_SHORT_NODE); + } + } + + // decode the current node as an RLP list, and process it + for (Memory.Slice[] memory decoded = encoded.decodeList();;) { + if (decoded.length == BRANCH_NODE_LENGTH) { + // If we've consumed the entire key, the value must be in the last slot + // Otherwise, continue down the branch specified by the next nibble in the key + if (keyIndex == keyExpanded.length) { + return _validateLastItem(decoded[EVM_TREE_RADIX], proof.length, i, true); + } else { + bytes1 branchKey = keyExpanded[keyIndex]; + Memory.Slice childNode = decoded[uint8(branchKey)]; + if (_isEmpty(childNode)) { + return _validateExclusion(proof.length, i); + } + + (currentNodeId, currentNodeIdLength) = _getNodeId(childNode); + keyIndex += 1; + + if (currentNodeIdLength == 32 || _match(childNode, proof, i + 1)) { + break; + } + decoded = childNode.readList(); + } + } else if (decoded.length == LEAF_OR_EXTENSION_NODE_LENGTH) { + bytes[] memory proof_ = proof; + + bytes memory path = decoded[0].readBytes().toNibbles(); // expanded path + // The following is equivalent to path.length < 2 because toNibbles can't return odd-length buffers + if (path.length == 0) { + return (_emptyBytesMemory(), ProofError.EMPTY_PATH); + } + uint8 prefix = uint8(path[0]); // path encoding nibble (node type + parity), see {Prefix} + if (prefix > uint8(Prefix.LEAF_ODD)) { + return (_emptyBytesMemory(), ProofError.UNKNOWN_NODE_PREFIX); + } + + Memory.Slice keyRemainder = keyExpanded.asSlice().slice(keyIndex); // Remaining key to match + Memory.Slice pathRemainder = path.asSlice().slice(2 - (prefix % 2)); // Path after the prefix + uint256 pathRemainderLength = pathRemainder.length(); + + // pathRemainder must not be longer than keyRemainder and must match the start of keyRemainder + if ( + pathRemainderLength > keyRemainder.length() + || !pathRemainder.equal(keyRemainder.slice(0, pathRemainderLength)) + ) { + return _validateExclusion(proof_.length, i); + } + + if (prefix <= uint8(Prefix.EXTENSION_ODD)) { + // Eq to: prefix == EXTENSION_EVEN || prefix == EXTENSION_ODD + if (pathRemainderLength == 0) { + return (_emptyBytesMemory(), ProofError.EMPTY_EXTENSION_PATH_REMAINDER); + } + // Increment keyIndex by the number of nibbles consumed and continue traversal + Memory.Slice childNode = decoded[1]; + (currentNodeId, currentNodeIdLength) = _getNodeId(childNode); + keyIndex += pathRemainderLength; + + if (currentNodeIdLength == 32 || _match(childNode, proof_, i + 1)) { + break; + } + decoded = childNode.readList(); + } else if (prefix <= uint8(Prefix.LEAF_ODD)) { + // Eq to: prefix == LEAF_EVEN || prefix == LEAF_ODD + // + // Leaf node (terminal) - return its value if key matches completely + // we already know that pathRemainder is a prefix of keyRemainder, so checking the length + // sufficient + return pathRemainderLength == keyRemainder.length() + ? _validateLastItem(decoded[1], proof_.length, i, false) + : _validateExclusion(proof_.length, i); + } + } else { + return (_emptyBytesMemory(), ProofError.UNPARSEABLE_NODE); + } + } + // Reset memory before next iteration. Deallocates `decoded` and `path`. + Memory.unsafeSetFreeMemoryPointer(fmp); + } + + // If we've gone through all proof elements without finding a value, the proof is invalid + return (_emptyBytesMemory(), ProofError.INVALID_PROOF); + } + + /// @notice Validates that an exclusion terminal is the final proof element. + /// @param trieProofLength The total number of proof elements. + /// @param i The index of the current proof element. + /// @return value Always empty bytes because the key is absent. + /// @return err The validation error, or `NO_ERROR` for a valid exclusion terminal. + function _validateExclusion( + uint256 trieProofLength, + uint256 i + ) + private + pure + returns (bytes memory value, ProofError err) + { + return i == trieProofLength - 1 + ? (_emptyBytesMemory(), ProofError.NO_ERROR) + : (_emptyBytesMemory(), ProofError.INVALID_EXTRA_PROOF_ELEMENT); + } + + /// @notice Validates a terminal trie item and ensures it is the final proof element. + /// @dev Branch values may be empty to prove exclusion; leaf values may not be empty. + /// @param item The terminal branch or leaf item. + /// @param trieProofLength The total number of proof elements. + /// @param i The index of the current proof element. + /// @param emptyMeansAbsent Whether an empty item is a valid exclusion proof. + /// @return value The terminal value, or empty bytes when the key is absent. + /// @return err The validation error, or `NO_ERROR` for a valid terminal item. + function _validateLastItem( + Memory.Slice item, + uint256 trieProofLength, + uint256 i, + bool emptyMeansAbsent + ) + private + pure + returns (bytes memory, ProofError) + { + if (i != trieProofLength - 1) { + return (_emptyBytesMemory(), ProofError.INVALID_EXTRA_PROOF_ELEMENT); + } + bytes memory value = item.readBytes(); + if (value.length == 0) { + return emptyMeansAbsent + ? (_emptyBytesMemory(), ProofError.NO_ERROR) + : (_emptyBytesMemory(), ProofError.EMPTY_VALUE); + } + return (value, ProofError.NO_ERROR); + } + + /** + * @notice Extracts the node ID as a hash or raw data based on its size. + * @param node The encoded trie node. + * @return nodeId The hashed or inline node identifier. + * @return nodeIdLength The length of the inline identifier, or 32 for a hashed node. + * + * For short nodes (encoded length < 32 bytes) the node ID is the node content itself, + * For larger nodes, the node ID is the hash of the encoded node data. + * + * [NOTE] + * ==== + * If a 32-byte input is provided (can occur with inline child references), it is used directly (like short nodes). + * When `nodeIdLength == 32`, inline processing is skipped. The next traversal step then checks whether the next + * node is large and its hash matches those raw bytes. If that is not the case, it returns {INVALID_LARGE_NODE}. + * + * Empty branch children are handled as exclusion terminals before this function is called. + * ==== + */ + function _getNodeId(Memory.Slice node) private pure returns (bytes32 nodeId, uint256 nodeIdLength) { + uint256 nodeLength = node.length(); + return nodeLength < 33 ? (node.load(0), nodeLength) : (node.readBytes32(), 32); + } + + /// @notice Decodes the light client's RLP list of already RLP-encoded proof nodes. + /// @param rlpProof The RLP-encoded list of proof nodes. + /// @return proof The individual encoded proof nodes. + function _decodeProof(bytes memory rlpProof) private pure returns (bytes[] memory proof) { + Memory.Slice[] memory items = rlpProof.decodeList(); + proof = new bytes[](items.length); + for (uint256 i = 0; i < items.length; ++i) { + proof[i] = items[i].toBytes(); + } + } + + /// @notice Returns whether an RLP item is the canonical empty byte string. + /// @param item The RLP item to inspect. + /// @return Whether the item is the canonical empty byte string. + function _isEmpty(Memory.Slice item) private pure returns (bool) { + return item.length() == 1 && bytes1(item.load(0)) == 0x80; + } + + /// @notice Returns an empty byte array without allocating memory. + /// @return result The empty byte array. + function _emptyBytesMemory() private pure returns (bytes memory result) { + assembly ("memory-safe") { + result := 0x60 // mload(0x60) is always 0 + } + } + + /// @notice Returns whether a slice matches the array item at `index`. + /// @param slice The memory slice to compare. + /// @param array The byte-array collection containing the candidate item. + /// @param index The candidate item index. + /// @return Whether the index exists and the values match. + function _match(Memory.Slice slice, bytes[] memory array, uint256 index) private pure returns (bool) { + return index < array.length && slice.equal(array[index].asSlice()); + } +} diff --git a/ibc-solidity/contracts/light-clients/besu/README.md b/ibc-solidity/contracts/light-clients/besu/README.md new file mode 100644 index 000000000..65e7458e2 --- /dev/null +++ b/ibc-solidity/contracts/light-clients/besu/README.md @@ -0,0 +1,168 @@ +# Besu IBFT 2.0 / QBFT Light Clients + +This module contains two Solidity light clients for Besu BFT chains: + +- `BesuIBFT2LightClient.sol` +- `BesuQBFTLightClient.sol` + +Both wrappers share the same storage model and proof surface through `BesuLightClientBase.sol`. They differ only in how the commit-seal signing digest is reconstructed from the raw Besu header. + +## Verification model notes + +- Commit-seal verification follows the existing **YUI Solidity client + besu-ibc-relay-prover** model: reconstruct the sealing header by rewriting `extraData` into the protocol-specific signing form, then recover commit-seal signers from the `keccak256(RLP(header))` digest. +- This module does **not** claim to independently rederive a distinct Besu network-level consensus-message payload beyond that established YUI/prover model. +- Trusted overlap is intentionally **strictly greater than one-third** of the trusted validator set, implemented as `floor(n / 3) + 1`. This is intentionally stricter than the current upstream YUI overlap check. + +## Supported scope + +- Besu **IBFT 2.0** +- Besu **QBFT** +- **Header-validator mode only** +- Weak-subjectivity / **trusting-period** verification +- Ethereum **account proofs** and **storage proofs** +- Eureka commitment verification against the counterparty `ICS26Router` proxy account + +## Out of scope in v1 + +- QBFT validator-contract mode +- Mode transitions +- Misbehaviour evidence handling +- Frozen-client machinery + +## Constructor + +Both wrappers take the same constructor arguments: + +```solidity +constructor( + address ibcRouter, + uint64 initialTrustedHeight, + uint64 initialTrustedTimestamp, + bytes32 initialTrustedStorageRoot, + address[] memory initialTrustedValidators, + uint64 trustingPeriod, + uint64 maxClockDrift, + address roleManager +) +``` + +- `ibcRouter`: counterparty `ICS26Router` proxy address whose account/storage proofs are tracked. +- `initialTrustedHeight`: trusted Besu block number. Revision number is always `0`. +- `initialTrustedTimestamp`: trusted header timestamp in seconds. +- `initialTrustedStorageRoot`: storage root of the tracked `ICS26Router` account at `initialTrustedHeight`. +- `initialTrustedValidators`: validator set trusted at `initialTrustedHeight`. +- `trustingPeriod`: weak-subjectivity window in seconds. `0` disables expiry + and is unsuitable for production non-adjacent verification. +- `maxClockDrift`: allowed future drift for submitted headers in seconds. +- `roleManager`: if non-zero, receives admin and `PROOF_SUBMITTER_ROLE`; if zero, proof submission is open to anyone through the zero-address sentinel. + +## `updateClient(bytes)` ABI + +`updateClient` expects `abi.encode(IBesuLightClientMsgs.MsgUpdateClient)`: + +```solidity +struct MsgUpdateClient { + bytes headerRlp; + IICS02ClientMsgs.Height trustedHeight; + bytes accountProof; +} +``` + +- `headerRlp`: full raw Besu block header RLP, including `extraData` and commit seals. +- `trustedHeight`: must use `revisionNumber == 0` and be lower than the submitted header height. +- `accountProof`: raw RLP-encoded Ethereum account proof for the tracked `ICS26Router` account against the submitted header's `stateRoot`. + +On update, the contract: + +1. parses the full signed header and validates the fields required by this non-adjacent verification model, +2. reconstructs the protocol-specific commit-seal digest following the YUI + prover sealing-header model, +3. checks trusted-validator overlap and new-validator quorum, +4. verifies the tracked router account proof, +5. stores the router account `storageRoot` plus the new validator set. + +Non-adjacent updates are supported by design. The submitted height must be +strictly after the selected trusted height. If validator turnover prevents the +required overlap, the relayer must first submit one or more intermediate +headers; they do not need to be adjacent. + +The contract authenticates the complete header through its commit seals and +validates the fields used by this verifier. It does not re-execute source-chain +transactions; those semantics remain covered by the honest-validator +assumption of the trusting-period model. + +The parser accepts the standard 15 Ethereum header fields plus signed +fork-extension fields. Deployments must confirm that the configured Besu fork +keeps the standard fields at their expected indices. + +## Membership / non-membership proofs + +`verifyMembership` and `verifyNonMembership` expect the standard `ILightClientMsgs` payloads used by Eureka. + +For Besu / EVM counterparties, the expected merkle prefix is: + +```solidity +[bytes("")] +``` + +That means `msg_.path[0]` is the raw Eureka commitment path bytes. + +### Storage slot derivation + +The counterparty `ICS26Router` stores commitments in `IBCStoreUpgradeable` as: + +```solidity +mapping(bytes32 hashedPath => bytes32 commitment) commitments; +``` + +The proof key is derived as: + +```solidity +bytes32 hashedPath = keccak256(rawPath); +bytes32 storageSlot = keccak256(abi.encode(hashedPath, IBCSTORE_STORAGE_SLOT)); +``` + +where `IBCSTORE_STORAGE_SLOT` is the ERC-7201 namespace constant used by `IBCStoreUpgradeable`. + +### Membership + +- `msg_.proof` must be the raw RLP-encoded Ethereum storage proof for `storageSlot`. +- `msg_.value` must be exactly `abi.encodePacked(bytes32Commitment)`. +- The return value is the trusted consensus timestamp in seconds for `msg_.proofHeight`. + +### Non-membership + +- `msg_.proof` must be the raw RLP-encoded Ethereum storage proof for `storageSlot`. +- The proof must show that the slot is absent. +- The return value is the trusted consensus timestamp in seconds for `msg_.proofHeight`. + +### Trie proof implementation + +`MPTProof.sol` is a narrow fork of OpenZeppelin Contracts v5.6.1 +[`TrieProof.sol`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.6.1/contracts/utils/cryptography/TrieProof.sol). +The upstream library verifies inclusion only and its private traversal helpers +cannot be wrapped or inherited to add exclusion. + +The fork keeps OpenZeppelin's node-link validation, compact-path traversal, and +inline-node handling. Its local changes are limited to: + +1. decoding this client's existing RLP-encoded proof-list wire format, +2. returning an explicit `exists` flag, +3. accepting authenticated exclusion at an empty trie, empty branch child or + value, or divergent compact leaf/extension path, and +4. rejecting proof nodes supplied after any inclusion or exclusion terminal. + +When updating OpenZeppelin, diff `MPTProof.sol` against the pinned upstream file +above and run `forge test --match-path "test/besu-bft/*.sol"`. + +## Test fixtures + +The Foundry fixtures under `test/besu-bft/fixtures/` can be regenerated from the focused Besu↔Besu e2e flow: + +```sh +GENERATE_BESU_LIGHT_CLIENT_FIXTURES=true \ +just test-e2e TestWithBesuToBesuTestSuite/Test_ICS20TransferERC20FromChainAToChainB +``` + +This writes `test/besu-bft/fixtures/qbft.json` using live Besu QBFT headers, account proofs, and storage proofs captured during the e2e transfer flow. The negative cases in that fixture are still derived by deterministic off-chain header mutation so the contract tests can keep explicit overlap / quorum / conflict coverage. + +`ibft2.json` remains synthetic until an IBFT2-focused e2e fixture path is added. diff --git a/ibc-solidity/contracts/light-clients/besu/errors/IBesuLightClientErrors.sol b/ibc-solidity/contracts/light-clients/besu/errors/IBesuLightClientErrors.sol new file mode 100644 index 000000000..3806449a1 --- /dev/null +++ b/ibc-solidity/contracts/light-clients/besu/errors/IBesuLightClientErrors.sol @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.28; + +/// @title Besu Light Client Errors +/// @notice Error interface for Besu BFT light clients. +interface IBesuLightClientErrors { + /// @notice The revision number must be zero for Besu light client heights. + /// @param providedRevisionNumber The non-zero revision number. + error InvalidRevisionNumber(uint64 providedRevisionNumber); + /// @notice The submitted header has an invalid RLP item count. + /// @param itemsLength The decoded header item count. + error InvalidHeaderFormat(uint256 itemsLength); + /// @notice The submitted `extraData` field has an invalid RLP item count. + /// @param itemsLength The decoded `extraData` item count. + error InvalidExtraDataFormat(uint256 itemsLength); + /// @notice The submitted header height is zero, too large, or not after the selected trusted height. + error InvalidHeaderHeight(); + /// @notice The trusted or submitted header timestamp is zero or does not fit the consensus-state representation. + /// @param actualTimestamp The decoded timestamp. + error InvalidHeaderTimestamp(uint256 actualTimestamp); + /// @notice The submitted header timestamp is too far in the future. + /// @param currentTimestamp The current block timestamp. + /// @param headerTimestamp The submitted header timestamp. + /// @param maxClockDrift The configured maximum clock drift. + error HeaderFromFuture(uint256 currentTimestamp, uint256 headerTimestamp, uint256 maxClockDrift); + /// @notice No consensus state exists for the requested height. + /// @param revisionHeight The requested revision height. + error ConsensusStateNotFound(uint64 revisionHeight); + /// @notice The trusted consensus state is outside the trusting period. + /// @param trustedTimestamp Timestamp of the trusted consensus state. + /// @param currentTimestamp The current block timestamp. + /// @param trustingPeriod The configured trusting period. + error ConsensusStateExpired(uint64 trustedTimestamp, uint256 currentTimestamp, uint64 trustingPeriod); + /// @notice The Besu BFT mix hash is invalid. + /// @param actualMixHash The mix hash found in the header. + error InvalidMixHash(bytes32 actualMixHash); + /// @notice The Besu BFT difficulty is invalid. + /// @param actualDifficulty The difficulty found in the header. + error InvalidDifficulty(uint256 actualDifficulty); + /// @notice The Besu BFT nonce is invalid. + /// @param actualNonce The nonce found in the header. + error InvalidNonce(bytes actualNonce); + /// @notice The ommers hash is invalid. + /// @param actualOmmersHash The ommers hash found in the header. + error InvalidOmmersHash(bytes32 actualOmmersHash); + /// @notice The tracked account does not exist in the submitted state trie. + /// @param account The missing tracked account. + error AccountNotFound(address account); + /// @notice The BFT vanity data must be exactly 32 bytes. + /// @param length The decoded vanity-data length. + error InvalidVanityDataLength(uint256 length); + /// @notice The validator set is empty. + error EmptyValidatorSet(); + /// @notice A validator address has an invalid byte length. + /// @param length The decoded validator address length. + error InvalidValidatorAddressLength(uint256 length); + /// @notice A validator address is invalid. + /// @param validator The invalid validator address. + error InvalidValidatorAddress(address validator); + /// @notice A validator appears more than once. + /// @param validator The duplicate validator address. + error DuplicateValidator(address validator); + /// @notice A commit seal signer appears more than once. + /// @param signer The duplicate signer address. + error DuplicateCommitSealSigner(address signer); + /// @notice An ECDSA signature has an invalid length. + /// @param length The invalid signature length. + error InvalidECDSASignatureLength(uint256 length); + /// @notice A commit seal did not recover a valid signer. + error InvalidCommitSeal(); + /// @notice The submitted signers do not overlap enough with the trusted validator set. + /// @param actual The number of trusted validators that signed. + /// @param required The minimum required trusted signer count. + error InsufficientTrustedValidatorOverlap(uint256 actual, uint256 required); + /// @notice The submitted signers do not meet quorum for the new validator set. + /// @param actual The number of new validators that signed. + /// @param required The minimum required signer count. + error InsufficientValidatorQuorum(uint256 actual, uint256 required); + /// @notice A proof path has an invalid length. + /// @param expectedLength The expected path length. + /// @param actualLength The actual path length. + error InvalidPathLength(uint256 expectedLength, uint256 actualLength); + /// @notice A membership value has an invalid length. + /// @param expectedLength The expected value length. + /// @param actualLength The actual value length. + error InvalidValueLength(uint256 expectedLength, uint256 actualLength); + /// @notice A proven commitment value does not match the expected value. + /// @param expectedValue The expected commitment value. + /// @param actualValue The proven commitment value. + error InvalidCommitmentValue(bytes32 expectedValue, bytes32 actualValue); + /// @notice A non-membership proof found an existing value. + /// @param actualValue The value found at the proven storage slot. + error ValueExists(bytes32 actualValue); + /// @notice A different consensus state already exists at the submitted height. + /// @param revisionHeight The conflicting revision height. + error ConflictingConsensusState(uint64 revisionHeight); + /// @notice Misbehaviour handling is not supported by this client. + error UnsupportedMisbehaviour(); +} diff --git a/ibc-solidity/contracts/light-clients/besu/interfaces/IBesuLightClient.sol b/ibc-solidity/contracts/light-clients/besu/interfaces/IBesuLightClient.sol new file mode 100644 index 000000000..8374a32b6 --- /dev/null +++ b/ibc-solidity/contracts/light-clients/besu/interfaces/IBesuLightClient.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.28; + +import { ILightClient } from "../../../interfaces/ILightClient.sol"; + +/// @title IBesuLightClient +/// @notice Interface for Besu BFT light clients. +interface IBesuLightClient is ILightClient { + /// @notice Returns the trusted consensus state at a revision height. + /// @param revisionHeight The revision height to query. + /// @return The ABI-encoded consensus state. + function getConsensusState(uint64 revisionHeight) external view returns (bytes memory); +} diff --git a/ibc-solidity/contracts/light-clients/besu/msgs/IBesuLightClientMsgs.sol b/ibc-solidity/contracts/light-clients/besu/msgs/IBesuLightClientMsgs.sol new file mode 100644 index 000000000..5617e9f65 --- /dev/null +++ b/ibc-solidity/contracts/light-clients/besu/msgs/IBesuLightClientMsgs.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.28; + +import { IICS02ClientMsgs } from "../../../msgs/IICS02ClientMsgs.sol"; + +/// @title Besu Light Client Messages +/// @notice Defines shared message and state types for Besu BFT light clients. +interface IBesuLightClientMsgs { + /// @notice Client state for a Besu BFT light client. + /// @param ibcRouter Counterparty ICS26 router address whose storage is proven. + /// @param latestHeight Latest trusted Besu height. + /// @param trustingPeriod Maximum age in seconds for a trusted consensus state. + /// @param maxClockDrift Maximum allowed future drift in seconds for submitted headers. + struct ClientState { + address ibcRouter; + IICS02ClientMsgs.Height latestHeight; + uint64 trustingPeriod; + uint64 maxClockDrift; + } + + /// @notice Trusted consensus state for a Besu height. + /// @param timestamp Header timestamp in seconds. + /// @param storageRoot Storage root of the tracked ICS26 router account. + /// @param validators Validator set committed in the header. + struct ConsensusState { + uint64 timestamp; + bytes32 storageRoot; + address[] validators; + } + + /// @notice Update message containing a Besu header and account proof. + /// @param headerRlp RLP-encoded Besu block header. + /// @param trustedHeight Previously trusted height used for weak-subjectivity checks. + /// @param accountProof Ethereum account proof for the tracked ICS26 router. + struct MsgUpdateClient { + bytes headerRlp; + IICS02ClientMsgs.Height trustedHeight; + bytes accountProof; + } +} diff --git a/ibc-solidity/solidity.just b/ibc-solidity/solidity.just index 112c9f70f..ad04cdf7d 100644 --- a/ibc-solidity/solidity.just +++ b/ibc-solidity/solidity.just @@ -33,7 +33,7 @@ test-foundry testname=".\\*": test-benchmark testname=".\\*": forge test -vvv --show-progress --gas-report --match-path test/solidity-ibc/BenchmarkTest.t.sol --match-test {{testname}} -# Generate ABI/bin artifacts and Go abigen bindings +# Generate all tracked contract artifacts and Go abigen bindings [group('generate')] generate-abi: build-contracts mkdir -p tmp/abigen @@ -55,6 +55,8 @@ generate-abi: build-contracts jq -r '.bytecode.object' out/RelayerHelper.sol/RelayerHelper.json > tmp/abigen/RelayerHelper.bin jq '.abi' out/AttestationLightClient.sol/AttestationLightClient.json > abi/AttestationLightClient.json jq -r '.bytecode.object' out/AttestationLightClient.sol/AttestationLightClient.json > tmp/abigen/AttestationLightClient.bin + jq '.abi' out/BesuIBFT2LightClient.sol/BesuIBFT2LightClient.json > abi/BesuIBFT2LightClient.json + jq '.abi' out/BesuQBFTLightClient.sol/BesuQBFTLightClient.json > abi/BesuQBFTLightClient.json jq '.abi' out/IFTOwnable.sol/IFTOwnable.json > abi/IFTOwnable.json jq -r '.bytecode.object' out/IFTOwnable.sol/IFTOwnable.json > tmp/abigen/IFTOwnable.bin jq '.abi' out/ERC1967Proxy.sol/ERC1967Proxy.json > abi/ERC1967Proxy.json @@ -73,14 +75,14 @@ generate-abi: build-contracts abigen --abi abi/AttestationLightClient.json --bin tmp/abigen/AttestationLightClient.bin --pkg attestation --type Contract --out ../packages/go-abigen/attestation/contract.go abigen --abi abi/ERC1967Proxy.json --bin tmp/abigen/ERC1967Proxy.bin --pkg erc1967proxy --type Contract --out ../packages/go-abigen/erc1967proxy/contract.go abigen --abi abi/EVMIFTSendCallConstructor.json --bin tmp/abigen/EVMIFTSendCallConstructor.bin --pkg evmiftsendcall --type Contract --out ../packages/go-abigen/evmiftsendcall/contract.go + rm -rf abi/bytecode + mkdir -p abi/bytecode + jq -c '{abi, bytecode: {object: .bytecode.object}}' out/SP1ICS07Tendermint.sol/SP1ICS07Tendermint.json > abi/bytecode/SP1ICS07Tendermint.json + jq -c '{abi, bytecode: {object: .bytecode.object}}' out/AttestationLightClient.sol/AttestationLightClient.json > abi/bytecode/AttestationLightClient.json + jq -c '{abi, bytecode: {object: .bytecode.object}}' out/BesuIBFT2LightClient.sol/BesuIBFT2LightClient.json > abi/bytecode/BesuIBFT2LightClient.json + jq -c '{abi, bytecode: {object: .bytecode.object}}' out/BesuQBFTLightClient.sol/BesuQBFTLightClient.json > abi/bytecode/BesuQBFTLightClient.json rm -rf tmp/abigen -# Generate the ABI files with bytecode for the required contracts -[group('generate')] -generate-abi-bytecode: build-contracts - cp out/SP1ICS07Tendermint.sol/SP1ICS07Tendermint.json abi/bytecode - cp out/AttestationLightClient.sol/AttestationLightClient.json abi/bytecode - # Clean up the foundry cache and out directories [group('clean')] clean-foundry: diff --git a/ibc-solidity/test/besu-bft/BesuIBFT2LightClient.t.sol b/ibc-solidity/test/besu-bft/BesuIBFT2LightClient.t.sol new file mode 100644 index 000000000..6376c62c9 --- /dev/null +++ b/ibc-solidity/test/besu-bft/BesuIBFT2LightClient.t.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.28; + +import { IBesuLightClient } from "../../contracts/light-clients/besu/interfaces/IBesuLightClient.sol"; +import { BesuLightClientFixtureTestBase } from "./BesuLightClientFixtureTestBase.sol"; + +contract BesuIBFT2LightClientTest is BesuLightClientFixtureTestBase { + function _fixtureFile() internal pure override returns (string memory) { + return "ibft2.json"; + } + + function _deployPrimaryClient() internal override returns (IBesuLightClient) { + return _deployIBFT2(); + } + + function _deployWrongWrapper() internal override returns (IBesuLightClient) { + return _deployQBFT(); + } +} diff --git a/ibc-solidity/test/besu-bft/BesuLightClientFixtureTestBase.sol b/ibc-solidity/test/besu-bft/BesuLightClientFixtureTestBase.sol new file mode 100644 index 000000000..ee36e30ac --- /dev/null +++ b/ibc-solidity/test/besu-bft/BesuLightClientFixtureTestBase.sol @@ -0,0 +1,512 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.28; + +// solhint-disable gas-struct-packing + +import { Test } from "forge-std/Test.sol"; +import { stdJson } from "forge-std/StdJson.sol"; + +import { ILightClientMsgs } from "../../contracts/msgs/ILightClientMsgs.sol"; +import { IICS02ClientMsgs } from "../../contracts/msgs/IICS02ClientMsgs.sol"; +import { BesuIBFT2LightClient } from "../../contracts/light-clients/besu/BesuIBFT2LightClient.sol"; +import { BesuQBFTLightClient } from "../../contracts/light-clients/besu/BesuQBFTLightClient.sol"; +import { IBesuLightClient } from "../../contracts/light-clients/besu/interfaces/IBesuLightClient.sol"; +import { IBesuLightClientMsgs } from "../../contracts/light-clients/besu/msgs/IBesuLightClientMsgs.sol"; +import { IBesuLightClientErrors } from "../../contracts/light-clients/besu/errors/IBesuLightClientErrors.sol"; + +/// @dev Successful update input and expected consensus state. +struct BesuUpdateFixture { + uint64 height; + bytes headerRlp; + uint64 trustedHeight; + bytes accountProof; + uint64 expectedTimestamp; + bytes32 expectedStorageRoot; + address[] expectedValidators; +} + +/// @dev Update input expected to be rejected. +struct BesuRejectionUpdateFixture { + uint64 height; + bytes headerRlp; + uint64 trustedHeight; + bytes accountProof; +} + +/// @dev Membership or non-membership proof and expected timestamp. +struct BesuProofFixture { + bytes proof; + uint64 proofHeight; + bytes path; + bytes value; + uint64 expectedTimestamp; +} + +/// @dev Complete fixture shared by the Besu BFT light-client tests. +struct BesuFixture { + address routerAddress; + uint64 initialTrustedHeight; + uint64 initialTrustedTimestamp; + bytes32 initialTrustedStorageRoot; + address[] initialTrustedValidators; + uint64 trustingPeriod; + uint64 maxClockDrift; + BesuUpdateFixture adjacentUpdate; + BesuUpdateFixture nonAdjacentUpdate; + BesuRejectionUpdateFixture lowQuorumUpdate; + BesuRejectionUpdateFixture conflictingUpdate; + BesuRejectionUpdateFixture lowOverlapUpdate; + BesuProofFixture membership; + BesuProofFixture nonMembership; +} + +contract BesuHeaderTestHarness is BesuQBFTLightClient { + constructor(address[] memory validators) + BesuQBFTLightClient(address(1), 1, 1, bytes32(0), validators, 1, 1, address(0)) + { } + + function validateHeader(bytes calldata headerRlp) external pure { + _parseHeader(headerRlp); + } + + function replaceHeaderBytes( + bytes calldata headerRlp, + uint256 index, + bytes calldata rawValue + ) + external + pure + returns (bytes memory) + { + ParsedHeader memory header = _parseHeader(headerRlp); + bytes[] memory items = new bytes[](header.headerItems.length); + for (uint256 i = 0; i < items.length; ++i) { + items[i] = i == index ? _encodeRlpBytes(rawValue) : _rlpItemBytes(header.headerItems[i]); + } + return _encodeRlpList(items); + } + + function replaceExtraDataBytes( + bytes calldata headerRlp, + uint256 index, + bytes calldata rawValue + ) + external + pure + returns (bytes memory) + { + ParsedHeader memory header = _parseHeader(headerRlp); + bytes[] memory extraItems = new bytes[](header.extraDataItems.length); + for (uint256 i = 0; i < extraItems.length; ++i) { + extraItems[i] = i == index ? _encodeRlpBytes(rawValue) : _rlpItemBytes(header.extraDataItems[i]); + } + + bytes[] memory headerItems = new bytes[](header.headerItems.length); + for (uint256 i = 0; i < headerItems.length; ++i) { + headerItems[i] = + i == 12 ? _encodeRlpBytes(_encodeRlpList(extraItems)) : _rlpItemBytes(header.headerItems[i]); + } + return _encodeRlpList(headerItems); + } +} + +abstract contract BesuLightClientFixtureTestBase is Test { + using stdJson for string; + string internal constant FIXTURE_DIR = "/test/besu-bft/fixtures/"; + + BesuFixture internal fixture; + IBesuLightClient internal client; + IBesuLightClient internal wrongWrapper; + BesuHeaderTestHarness internal headerHarness; + + function setUp() public virtual { + fixture = _loadFixture(_fixtureFile()); + client = _deployPrimaryClient(); + wrongWrapper = _deployWrongWrapper(); + headerHarness = new BesuHeaderTestHarness(fixture.initialTrustedValidators); + } + + function fixtureUpdate() public view returns (BesuUpdateFixture[] memory updates) { + updates = new BesuUpdateFixture[](2); + updates[0] = fixture.adjacentUpdate; + updates[1] = fixture.nonAdjacentUpdate; + } + + function tableUpdateClientValid(BesuUpdateFixture memory update) public { + vm.warp(fixture.initialTrustedTimestamp + 1); + + ILightClientMsgs.UpdateResult result = client.updateClient(_encodeUpdate(update)); + + assertEq(uint8(result), uint8(ILightClientMsgs.UpdateResult.Update)); + _assertClientState(update); + } + + function test_updateClient_revertZeroTimestampWithoutStateChange() public { + IBesuLightClientMsgs.MsgUpdateClient memory update = + abi.decode(_encodeUpdate(fixture.nonAdjacentUpdate), (IBesuLightClientMsgs.MsgUpdateClient)); + update.headerRlp = headerHarness.replaceHeaderBytes(update.headerRlp, 11, hex"00"); + + bytes memory clientStateBefore = client.getClientState(); + bytes memory consensusStateBefore = client.getConsensusState(fixture.initialTrustedHeight); + + vm.expectRevert(abi.encodeWithSelector(IBesuLightClientErrors.InvalidHeaderTimestamp.selector, 0)); + client.updateClient(abi.encode(update)); + + assertEq(client.getClientState(), clientStateBefore); + assertEq(client.getConsensusState(fixture.initialTrustedHeight), consensusStateBefore); + } + + function test_updateClient_revertSubmittedHeightBeforeTrustedHeight() public { + vm.warp(fixture.initialTrustedTimestamp + 1); + client.updateClient(_encodeUpdate(fixture.nonAdjacentUpdate)); + + IBesuLightClientMsgs.MsgUpdateClient memory update = + abi.decode(_encodeUpdate(fixture.adjacentUpdate), (IBesuLightClientMsgs.MsgUpdateClient)); + update.trustedHeight.revisionHeight = fixture.nonAdjacentUpdate.height; + + vm.expectRevert(IBesuLightClientErrors.InvalidHeaderHeight.selector); + client.updateClient(abi.encode(update)); + } + + function test_updateClient_revertSubmittedHeightEqualsTrustedHeight() public { + vm.warp(fixture.initialTrustedTimestamp + 1); + client.updateClient(_encodeUpdate(fixture.nonAdjacentUpdate)); + + IBesuLightClientMsgs.MsgUpdateClient memory update = + abi.decode(_encodeUpdate(fixture.nonAdjacentUpdate), (IBesuLightClientMsgs.MsgUpdateClient)); + update.trustedHeight.revisionHeight = fixture.nonAdjacentUpdate.height; + + vm.expectRevert(IBesuLightClientErrors.InvalidHeaderHeight.selector); + client.updateClient(abi.encode(update)); + } + + function test_parseHeader_revertHeightOverflow() public { + bytes memory headerRlp = + headerHarness.replaceHeaderBytes(fixture.nonAdjacentUpdate.headerRlp, 8, hex"010000000000000000"); + + vm.expectRevert(IBesuLightClientErrors.InvalidHeaderHeight.selector); + headerHarness.validateHeader(headerRlp); + } + + function test_parseHeader_revertTimestampOverflow() public { + bytes memory headerRlp = + headerHarness.replaceHeaderBytes(fixture.nonAdjacentUpdate.headerRlp, 11, hex"010000000000000000"); + + vm.expectRevert( + abi.encodeWithSelector( + IBesuLightClientErrors.InvalidHeaderTimestamp.selector, uint256(type(uint64).max) + 1 + ) + ); + headerHarness.validateHeader(headerRlp); + } + + function test_parseHeader_revertInvalidVanityDataLength() public { + bytes memory headerRlp = + headerHarness.replaceExtraDataBytes(fixture.nonAdjacentUpdate.headerRlp, 0, new bytes(31)); + + vm.expectRevert(abi.encodeWithSelector(IBesuLightClientErrors.InvalidVanityDataLength.selector, 31)); + headerHarness.validateHeader(headerRlp); + } + + function test_verifyMembership_returnsStoredTimestamp() public { + vm.warp(fixture.initialTrustedTimestamp + 1); + client.updateClient(_encodeUpdate(fixture.nonAdjacentUpdate)); + + uint256 timestamp = client.verifyMembership( + ILightClientMsgs.MsgVerifyMembership({ + proof: fixture.membership.proof, + proofHeight: IICS02ClientMsgs.Height({ + revisionNumber: 0, revisionHeight: fixture.membership.proofHeight + }), + path: _singlePath(fixture.membership.path), + value: fixture.membership.value + }) + ); + + assertEq(timestamp, fixture.membership.expectedTimestamp); + } + + function test_verifyNonMembership_returnsStoredTimestamp() public { + vm.warp(fixture.initialTrustedTimestamp + 1); + client.updateClient(_encodeUpdate(fixture.nonAdjacentUpdate)); + + uint256 timestamp = client.verifyNonMembership( + ILightClientMsgs.MsgVerifyNonMembership({ + proof: fixture.nonMembership.proof, + proofHeight: IICS02ClientMsgs.Height({ + revisionNumber: 0, revisionHeight: fixture.nonMembership.proofHeight + }), + path: _singlePath(fixture.nonMembership.path) + }) + ); + + assertEq(timestamp, fixture.nonMembership.expectedTimestamp); + } + + function test_updateClient_revertExpiredTrustedState() public { + vm.warp(fixture.initialTrustedTimestamp + fixture.trustingPeriod + 1); + + vm.expectRevert( + abi.encodeWithSelector( + IBesuLightClientErrors.ConsensusStateExpired.selector, + fixture.initialTrustedTimestamp, + fixture.initialTrustedTimestamp + fixture.trustingPeriod + 1, + fixture.trustingPeriod + ) + ); + client.updateClient(_encodeUpdate(fixture.nonAdjacentUpdate)); + } + + function test_updateClient_revertInsufficientTrustedOverlap() public { + vm.warp(fixture.initialTrustedTimestamp + 1); + + vm.expectRevert( + abi.encodeWithSelector(IBesuLightClientErrors.InsufficientTrustedValidatorOverlap.selector, 1, 2) + ); + client.updateClient(_encodeUpdate(fixture.lowOverlapUpdate)); + } + + function test_updateClient_revertInsufficientNewValidatorQuorum() public { + vm.warp(fixture.initialTrustedTimestamp + 1); + + vm.expectRevert(abi.encodeWithSelector(IBesuLightClientErrors.InsufficientValidatorQuorum.selector, 2, 3)); + client.updateClient(_encodeUpdate(fixture.lowQuorumUpdate)); + } + + function test_updateClient_revertWrongRevisionNumber() public { + vm.warp(fixture.initialTrustedTimestamp + 1); + + IBesuLightClientMsgs.MsgUpdateClient memory update = + abi.decode(_encodeUpdate(fixture.nonAdjacentUpdate), (IBesuLightClientMsgs.MsgUpdateClient)); + update.trustedHeight.revisionNumber = 1; + + vm.expectRevert(abi.encodeWithSelector(IBesuLightClientErrors.InvalidRevisionNumber.selector, 1)); + client.updateClient(abi.encode(update)); + } + + function test_verifyMembership_revertWrongRevisionNumber() public { + vm.warp(fixture.initialTrustedTimestamp + 1); + client.updateClient(_encodeUpdate(fixture.nonAdjacentUpdate)); + + vm.expectRevert(abi.encodeWithSelector(IBesuLightClientErrors.InvalidRevisionNumber.selector, 1)); + client.verifyMembership( + ILightClientMsgs.MsgVerifyMembership({ + proof: fixture.membership.proof, + proofHeight: IICS02ClientMsgs.Height({ + revisionNumber: 1, revisionHeight: fixture.membership.proofHeight + }), + path: _singlePath(fixture.membership.path), + value: fixture.membership.value + }) + ); + } + + function test_verifyMembership_revertWrongPathShape() public { + vm.warp(fixture.initialTrustedTimestamp + 1); + client.updateClient(_encodeUpdate(fixture.nonAdjacentUpdate)); + + bytes[] memory path = new bytes[](2); + path[0] = fixture.membership.path; + path[1] = fixture.nonMembership.path; + + vm.expectRevert(abi.encodeWithSelector(IBesuLightClientErrors.InvalidPathLength.selector, 1, 2)); + client.verifyMembership( + ILightClientMsgs.MsgVerifyMembership({ + proof: fixture.membership.proof, + proofHeight: IICS02ClientMsgs.Height({ + revisionNumber: 0, revisionHeight: fixture.membership.proofHeight + }), + path: path, + value: fixture.membership.value + }) + ); + } + + function test_verifyMembership_revertWrongCommitmentValue() public { + vm.warp(fixture.initialTrustedTimestamp + 1); + client.updateClient(_encodeUpdate(fixture.nonAdjacentUpdate)); + + bytes memory wrongValue = abi.encodePacked(bytes32(uint256(1))); + vm.expectRevert( + abi.encodeWithSelector( + IBesuLightClientErrors.InvalidCommitmentValue.selector, + bytes32(uint256(1)), + abi.decode(fixture.membership.value, (bytes32)) + ) + ); + client.verifyMembership( + ILightClientMsgs.MsgVerifyMembership({ + proof: fixture.membership.proof, + proofHeight: IICS02ClientMsgs.Height({ + revisionNumber: 0, revisionHeight: fixture.membership.proofHeight + }), + path: _singlePath(fixture.membership.path), + value: wrongValue + }) + ); + } + + function test_updateClient_revertConflictingSameHeight() public { + vm.warp(fixture.initialTrustedTimestamp + 1); + client.updateClient(_encodeUpdate(fixture.nonAdjacentUpdate)); + + vm.expectRevert( + abi.encodeWithSelector( + IBesuLightClientErrors.ConflictingConsensusState.selector, fixture.conflictingUpdate.height + ) + ); + client.updateClient(_encodeUpdate(fixture.conflictingUpdate)); + } + + function test_misbehaviour_reverts() public { + vm.expectRevert(abi.encodeWithSelector(IBesuLightClientErrors.UnsupportedMisbehaviour.selector)); + client.misbehaviour(bytes("")); + } + + function test_updateClient_revertThroughWrongWrapper() public { + vm.warp(fixture.initialTrustedTimestamp + 1); + + vm.expectRevert( + abi.encodeWithSelector(IBesuLightClientErrors.InsufficientTrustedValidatorOverlap.selector, 0, 2) + ); + wrongWrapper.updateClient(_encodeUpdate(fixture.nonAdjacentUpdate)); + } + + function _assertClientState(BesuUpdateFixture memory update) internal view { + (address ibcRouter, IICS02ClientMsgs.Height memory latestHeight, uint64 trustingPeriod, uint64 maxClockDrift) = + abi.decode(client.getClientState(), (address, IICS02ClientMsgs.Height, uint64, uint64)); + assertEq(ibcRouter, fixture.routerAddress); + assertEq(latestHeight.revisionNumber, 0); + assertEq(latestHeight.revisionHeight, update.height); + assertEq(trustingPeriod, fixture.trustingPeriod); + assertEq(maxClockDrift, fixture.maxClockDrift); + + (uint64 timestamp, bytes32 storageRoot, address[] memory validators) = + abi.decode(client.getConsensusState(update.height), (uint64, bytes32, address[])); + assertEq(timestamp, update.expectedTimestamp); + assertEq(storageRoot, update.expectedStorageRoot); + + assertEq(validators.length, update.expectedValidators.length); + for (uint256 i = 0; i < update.expectedValidators.length; ++i) { + assertEq(validators[i], update.expectedValidators[i]); + } + } + + function _encodeUpdate(BesuUpdateFixture memory update) internal pure returns (bytes memory) { + return abi.encode( + IBesuLightClientMsgs.MsgUpdateClient({ + headerRlp: update.headerRlp, + trustedHeight: IICS02ClientMsgs.Height({ revisionNumber: 0, revisionHeight: update.trustedHeight }), + accountProof: update.accountProof + }) + ); + } + + function _singlePath(bytes memory path) internal pure returns (bytes[] memory out) { + out = new bytes[](1); + out[0] = path; + } + + function _loadFixture(string memory fileName) internal view returns (BesuFixture memory) { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, FIXTURE_DIR, fileName); + string memory json = vm.readFile(path); + + return BesuFixture({ + routerAddress: json.readAddress(".routerAddress"), + initialTrustedHeight: uint64(json.readUint(".initialTrustedHeight")), + initialTrustedTimestamp: uint64(json.readUint(".initialTrustedTimestamp")), + initialTrustedStorageRoot: json.readBytes32(".initialTrustedStorageRoot"), + initialTrustedValidators: abi.decode(json.parseRaw(".initialTrustedValidators"), (address[])), + trustingPeriod: uint64(json.readUint(".trustingPeriod")), + maxClockDrift: uint64(json.readUint(".maxClockDrift")), + adjacentUpdate: _readUpdate(json, ".adjacentUpdate"), + nonAdjacentUpdate: _readUpdate(json, ".nonAdjacentUpdate"), + lowQuorumUpdate: _readRejectionUpdate(json, ".lowQuorumUpdate"), + conflictingUpdate: _readRejectionUpdate(json, ".conflictingUpdate"), + lowOverlapUpdate: _readRejectionUpdate(json, ".lowOverlapUpdate"), + membership: _readProof(json, ".membership"), + nonMembership: _readProof(json, ".nonMembership") + }); + } + + function _readUpdate(string memory json, string memory path) internal view returns (BesuUpdateFixture memory) { + return BesuUpdateFixture({ + height: uint64(json.readUint(string.concat(path, ".height"))), + headerRlp: json.readBytes(string.concat(path, ".headerRlp")), + trustedHeight: uint64(json.readUint(string.concat(path, ".trustedHeight"))), + accountProof: json.readBytes(string.concat(path, ".accountProof")), + expectedTimestamp: uint64(json.readUint(string.concat(path, ".expectedTimestamp"))), + expectedStorageRoot: json.readBytes32(string.concat(path, ".expectedStorageRoot")), + expectedValidators: abi.decode(json.parseRaw(string.concat(path, ".expectedValidators")), (address[])) + }); + } + + function _readRejectionUpdate( + string memory json, + string memory path + ) + internal + view + returns (BesuRejectionUpdateFixture memory) + { + return BesuRejectionUpdateFixture({ + height: uint64(json.readUint(string.concat(path, ".height"))), + headerRlp: json.readBytes(string.concat(path, ".headerRlp")), + trustedHeight: uint64(json.readUint(string.concat(path, ".trustedHeight"))), + accountProof: json.readBytes(string.concat(path, ".accountProof")) + }); + } + + function _encodeUpdate(BesuRejectionUpdateFixture memory update) internal pure returns (bytes memory) { + return abi.encode( + IBesuLightClientMsgs.MsgUpdateClient({ + headerRlp: update.headerRlp, + trustedHeight: IICS02ClientMsgs.Height({ revisionNumber: 0, revisionHeight: update.trustedHeight }), + accountProof: update.accountProof + }) + ); + } + + function _readProof(string memory json, string memory path) internal view returns (BesuProofFixture memory) { + return BesuProofFixture({ + proof: json.readBytes(string.concat(path, ".proof")), + proofHeight: uint64(json.readUint(string.concat(path, ".proofHeight"))), + path: json.readBytes(string.concat(path, ".path")), + value: json.keyExists(string.concat(path, ".value")) + ? json.readBytes(string.concat(path, ".value")) + : bytes(""), + expectedTimestamp: uint64(json.readUint(string.concat(path, ".expectedTimestamp"))) + }); + } + + function _deployIBFT2() internal returns (IBesuLightClient) { + return new BesuIBFT2LightClient( + fixture.routerAddress, + fixture.initialTrustedHeight, + fixture.initialTrustedTimestamp, + fixture.initialTrustedStorageRoot, + fixture.initialTrustedValidators, + fixture.trustingPeriod, + fixture.maxClockDrift, + address(0) + ); + } + + function _deployQBFT() internal returns (IBesuLightClient) { + return new BesuQBFTLightClient( + fixture.routerAddress, + fixture.initialTrustedHeight, + fixture.initialTrustedTimestamp, + fixture.initialTrustedStorageRoot, + fixture.initialTrustedValidators, + fixture.trustingPeriod, + fixture.maxClockDrift, + address(0) + ); + } + + function _fixtureFile() internal pure virtual returns (string memory); + function _deployPrimaryClient() internal virtual returns (IBesuLightClient); + function _deployWrongWrapper() internal virtual returns (IBesuLightClient); +} diff --git a/ibc-solidity/test/besu-bft/BesuLightClientQuorum.t.sol b/ibc-solidity/test/besu-bft/BesuLightClientQuorum.t.sol new file mode 100644 index 000000000..6bc8b0298 --- /dev/null +++ b/ibc-solidity/test/besu-bft/BesuLightClientQuorum.t.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.28; + +import { Test } from "forge-std/Test.sol"; + +import { BesuLightClientBase } from "../../contracts/light-clients/besu/BesuLightClientBase.sol"; +import { IBesuLightClientErrors } from "../../contracts/light-clients/besu/errors/IBesuLightClientErrors.sol"; + +contract BesuLightClientQuorumHarness is BesuLightClientBase { + constructor( + uint64 initialTrustedTimestamp, + address[] memory initialValidators + ) + BesuLightClientBase(address(1), 1, initialTrustedTimestamp, bytes32(0), initialValidators, 0, 0, address(0)) + { } + + function checkValidatorQuorum(address[] calldata signers, address[] calldata validators) external pure { + _checkValidatorQuorum(signers, validators); + } + + function _commitSealDigest(ParsedHeader memory) internal pure override returns (bytes32) { + return bytes32(0); + } +} + +contract BesuLightClientQuorumTest is Test { + BesuLightClientQuorumHarness private harness; + + function setUp() public { + harness = new BesuLightClientQuorumHarness(1, _addresses(1)); + } + + function test_constructor_rejectsZeroTrustedTimestamp() public { + vm.expectRevert(abi.encodeWithSelector(IBesuLightClientErrors.InvalidHeaderTimestamp.selector, 0)); + new BesuLightClientQuorumHarness(0, _addresses(1)); + } + + function test_checkValidatorQuorum_acceptsBesuFourOfSixQuorum() public view { + harness.checkValidatorQuorum(_addresses(4), _addresses(6)); + } + + function test_checkValidatorQuorum_rejectsThreeOfSixValidators() public { + vm.expectRevert(abi.encodeWithSelector(IBesuLightClientErrors.InsufficientValidatorQuorum.selector, 3, 4)); + harness.checkValidatorQuorum(_addresses(3), _addresses(6)); + } + + function _addresses(uint256 length) private pure returns (address[] memory addresses) { + addresses = new address[](length); + for (uint256 i = 0; i < length; ++i) { + addresses[i] = address(uint160(i + 1)); + } + } +} diff --git a/ibc-solidity/test/besu-bft/BesuQBFTLightClient.t.sol b/ibc-solidity/test/besu-bft/BesuQBFTLightClient.t.sol new file mode 100644 index 000000000..1b67f785b --- /dev/null +++ b/ibc-solidity/test/besu-bft/BesuQBFTLightClient.t.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.28; + +import { IBesuLightClient } from "../../contracts/light-clients/besu/interfaces/IBesuLightClient.sol"; +import { BesuLightClientFixtureTestBase } from "./BesuLightClientFixtureTestBase.sol"; + +contract BesuQBFTLightClientTest is BesuLightClientFixtureTestBase { + function _fixtureFile() internal pure override returns (string memory) { + return "qbft.json"; + } + + function _deployPrimaryClient() internal override returns (IBesuLightClient) { + return _deployQBFT(); + } + + function _deployWrongWrapper() internal override returns (IBesuLightClient) { + return _deployIBFT2(); + } +} diff --git a/ibc-solidity/test/besu-bft/MPTProof.t.sol b/ibc-solidity/test/besu-bft/MPTProof.t.sol new file mode 100644 index 000000000..7ada41e84 --- /dev/null +++ b/ibc-solidity/test/besu-bft/MPTProof.t.sol @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.28; + +import { Test } from "forge-std/Test.sol"; + +import { RLP } from "@openzeppelin-contracts/utils/RLP.sol"; + +import { MPTProof } from "../../contracts/light-clients/besu/MPTProof.sol"; + +contract MPTProofHarness { + function verify(bytes calldata proof, bytes32 root, bytes32 key) external pure returns (bool, bytes memory) { + return MPTProof.verifyRLPProof(proof, root, key); + } +} + +contract MPTProofTest is Test { + bytes32 private constant EMPTY_TRIE_ROOT = 0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421; + + MPTProofHarness private harness; + + function setUp() public { + harness = new MPTProofHarness(); + } + + function test_inclusion() public view { + bytes32 key = bytes32(uint256(1)); + bytes memory value = hex"05"; + bytes memory leaf = _leaf(key, value); + + (bool exists, bytes memory actualValue) = harness.verify(_proof(leaf), keccak256(leaf), key); + + assertTrue(exists); + assertEq(actualValue, value); + } + + function test_exclusionEmptyTrie() public view { + (bool exists, bytes memory value) = harness.verify(RLP.encode(new bytes[](0)), EMPTY_TRIE_ROOT, bytes32(0)); + + assertFalse(exists); + assertEq(value, bytes("")); + } + + function test_exclusionEmptyBranchChild() public view { + bytes memory branch = _emptyBranch(); + + (bool exists, bytes memory value) = harness.verify(_proof(branch), keccak256(branch), bytes32(0)); + + assertFalse(exists); + assertEq(value, bytes("")); + } + + function test_exclusionEmptyBranchValue() public view { + bytes32 key = bytes32(uint256(1)); + bytes memory branch = _emptyBranch(); + bytes memory extension = _extension(key, branch); + + (bool exists, bytes memory value) = harness.verify(_proof(extension), keccak256(extension), key); + + assertFalse(exists); + assertEq(value, bytes("")); + } + + function test_exclusionDivergentLeaf() public view { + bytes32 targetKey; + bytes memory leaf = _leaf(bytes32(uint256(1) << 252), hex"05"); + + (bool exists, bytes memory value) = harness.verify(_proof(leaf), keccak256(leaf), targetKey); + + assertFalse(exists); + assertEq(value, bytes("")); + } + + function test_exclusionDivergentExtension() public view { + bytes32 targetKey; + bytes memory extension = _extension(bytes32(uint256(1) << 252), _emptyBranch()); + + (bool exists, bytes memory value) = harness.verify(_proof(extension), keccak256(extension), targetKey); + + assertFalse(exists); + assertEq(value, bytes("")); + } + + function test_revertExtraNodeAfterExclusion() public { + bytes memory branch = _emptyBranch(); + bytes[] memory nodes = new bytes[](2); + nodes[0] = branch; + nodes[1] = branch; + + vm.expectRevert( + abi.encodeWithSelector( + MPTProof.TrieProofTraversalError.selector, MPTProof.ProofError.INVALID_EXTRA_PROOF_ELEMENT + ) + ); + harness.verify(RLP.encode(nodes), keccak256(branch), bytes32(0)); + } + + function _leaf(bytes32 key, bytes memory value) private pure returns (bytes memory) { + bytes[] memory items = new bytes[](2); + items[0] = RLP.encode(abi.encodePacked(bytes1(0x20), key)); + items[1] = RLP.encode(value); + return RLP.encode(items); + } + + function _extension(bytes32 key, bytes memory child) private pure returns (bytes memory) { + bytes[] memory items = new bytes[](2); + items[0] = RLP.encode(abi.encodePacked(bytes1(0), key)); + items[1] = child; + return RLP.encode(items); + } + + function _emptyBranch() private pure returns (bytes memory) { + bytes[] memory items = new bytes[](17); + bytes memory empty = RLP.encode(bytes("")); + for (uint256 i = 0; i < items.length; ++i) { + items[i] = empty; + } + return RLP.encode(items); + } + + function _proof(bytes memory node) private pure returns (bytes memory) { + bytes[] memory nodes = new bytes[](1); + nodes[0] = node; + return RLP.encode(nodes); + } +} diff --git a/ibc-solidity/test/besu-bft/fixtures/ibft2.json b/ibc-solidity/test/besu-bft/fixtures/ibft2.json new file mode 100644 index 000000000..57136043b --- /dev/null +++ b/ibc-solidity/test/besu-bft/fixtures/ibft2.json @@ -0,0 +1,97 @@ +{ + "routerAddress": "0x1234567890AbcdEF1234567890aBcdef12345678", + "initialTrustedHeight": 10, + "initialTrustedTimestamp": 1000, + "initialTrustedStorageRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "initialTrustedValidators": [ + "0xFE3B557E8Fb62b89F4916B721be55cEb828dBd73", + "0x627306090abaB3A6e1400e9345bC60c78a8BEf57", + "0xf17f52151EbEF6C7334FAD080c5704D77216b732", + "0xa89F47C6b463f74d87572b058427dA0A13ec5425" + ], + "trustingPeriod": 1000, + "maxClockDrift": 30, + "adjacentUpdate": { + "height": 11, + "headerRlp": "0xf9033ca00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0f2081dd8c37a93ef3050951656b124dba1eb1e541e52e98c8bbbac27611bae73a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010b8401c9c380808203f2b90147f90144a00000000000000000000000000000000000000000000000000000000000000000f85494fe3b557e8fb62b89f4916b721be55ceb828dbd7394627306090abab3a6e1400e9345bc60c78a8bef5794f17f52151ebef6c7334fad080c5704d77216b73294a89f47c6b463f74d87572b058427da0a13ec54258080f8c9b8415c237229535cb5b756ac35933bd6460128d8358af7224b3d373bc1e58671b9e26ddd5f2f6318493978a02162192da231068943ef7d31f3d49a99912245c8933300b841737d327b80cc8c318cfc223a801b7d51f17a3e61a008ba796c9a8128c13f3a6f5d36764ac0aa1f4cf788d18831193962a7f4bd42e4356bc2d2cd6795d1cc29cd01b841681d75e13f57e972a3c7696b2ff358722ab0b5d0878095146fdb03a7a688975814d97fac43069952f0382aee020d77f554f4a31e502259e28c271f748e1c113e01a063746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365880000000000000000", + "trustedHeight": 10, + "accountProof": "0xf86cf86aa1205f6174255b44b7ca652c5289d2546de65e4394eb6aa52a40045e01237736d023b846f8440180a01429811e8e479d4d8d3862e6da4c368715f6574d307bb0ffbea0220c2351cfd4a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "expectedTimestamp": 1010, + "expectedStorageRoot": "0x1429811e8e479d4d8d3862e6da4c368715f6574d307bb0ffbea0220c2351cfd4", + "expectedValidators": [ + "0xFE3B557E8Fb62b89F4916B721be55cEb828dBd73", + "0x627306090abaB3A6e1400e9345bC60c78a8BEf57", + "0xf17f52151EbEF6C7334FAD080c5704D77216b732", + "0xa89F47C6b463f74d87572b058427dA0A13ec5425" + ] + }, + "nonAdjacentUpdate": { + "height": 12, + "headerRlp": "0xf9033ca00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0f4fb47fab37d2702f85f5562b52da4e7b5e4a677298193c9f797e467e9cc046aa00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010c8401c9c380808203fcb90147f90144a00000000000000000000000000000000000000000000000000000000000000000f85494fe3b557e8fb62b89f4916b721be55ceb828dbd7394627306090abab3a6e1400e9345bc60c78a8bef5794f17f52151ebef6c7334fad080c5704d77216b73294cbed645b1c1a6254f1149df51d3591c6b38030078080f8c9b84100eaa1df128060399277424940a4cccd0ceb29052f83358f1798cf9ad95c0f0c3e858beb37cd83332935b0927d2365e439a9b1c319bf0a0adaf2f62d61dff58901b841c4bf6688b64aa46676b969e679ed39c1a0b2ae13f8c7e49ff34629f49b03bb1336a7e049716855a50a637c49dbd01d576571ef9294335623d4d42ef3b184e73601b8412df49de5d8c13913300fd9ebd1d70d76ce9f73f26e122e451c464031744f079a438762535d0e5cc031383599d8b85ae91bff81d4d10980262f70ec6ed82666f700a063746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365880000000000000000", + "trustedHeight": 10, + "accountProof": "0xf86cf86aa1205f6174255b44b7ca652c5289d2546de65e4394eb6aa52a40045e01237736d023b846f8440180a04ec23ab75bd034f079225053b7f607981b27ad24a5e964743526eeccefc5f500a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "expectedTimestamp": 1020, + "expectedStorageRoot": "0x4ec23ab75bd034f079225053b7f607981b27ad24a5e964743526eeccefc5f500", + "expectedValidators": [ + "0xFE3B557E8Fb62b89F4916B721be55cEb828dBd73", + "0x627306090abaB3A6e1400e9345bC60c78a8BEf57", + "0xf17f52151EbEF6C7334FAD080c5704D77216b732", + "0xcBED645B1C1a6254f1149Df51d3591c6B3803007" + ] + }, + "lowQuorumUpdate": { + "height": 12, + "headerRlp": "0xf902f9a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0f4fb47fab37d2702f85f5562b52da4e7b5e4a677298193c9f797e467e9cc046aa00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010c8401c9c380808203fcb90104f90101a00000000000000000000000000000000000000000000000000000000000000000f85494fe3b557e8fb62b89f4916b721be55ceb828dbd7394627306090abab3a6e1400e9345bc60c78a8bef5794f17f52151ebef6c7334fad080c5704d77216b73294cbed645b1c1a6254f1149df51d3591c6b38030078080f886b84100eaa1df128060399277424940a4cccd0ceb29052f83358f1798cf9ad95c0f0c3e858beb37cd83332935b0927d2365e439a9b1c319bf0a0adaf2f62d61dff58901b841c4bf6688b64aa46676b969e679ed39c1a0b2ae13f8c7e49ff34629f49b03bb1336a7e049716855a50a637c49dbd01d576571ef9294335623d4d42ef3b184e73601a063746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365880000000000000000", + "trustedHeight": 10, + "accountProof": "0xf86cf86aa1205f6174255b44b7ca652c5289d2546de65e4394eb6aa52a40045e01237736d023b846f8440180a04ec23ab75bd034f079225053b7f607981b27ad24a5e964743526eeccefc5f500a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "expectedTimestamp": 1020, + "expectedStorageRoot": "0x4ec23ab75bd034f079225053b7f607981b27ad24a5e964743526eeccefc5f500", + "expectedValidators": [ + "0xFE3B557E8Fb62b89F4916B721be55cEb828dBd73", + "0x627306090abaB3A6e1400e9345bC60c78a8BEf57", + "0xf17f52151EbEF6C7334FAD080c5704D77216b732", + "0xcBED645B1C1a6254f1149Df51d3591c6B3803007" + ] + }, + "conflictingUpdate": { + "height": 12, + "headerRlp": "0xf9033ca00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a002920b43c148d62cc879e6d86a0fea5cb5f6e9d5bc65b85f012955ddcf82b134a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010c8401c9c380808203fdb90147f90144a00000000000000000000000000000000000000000000000000000000000000000f85494fe3b557e8fb62b89f4916b721be55ceb828dbd7394627306090abab3a6e1400e9345bc60c78a8bef5794f17f52151ebef6c7334fad080c5704d77216b73294cbed645b1c1a6254f1149df51d3591c6b38030078080f8c9b8416f5732f70922c0ca46fc2bd56db36c79b7cc9da2b73f56513703b8daaf75001a1907b11de095b3ba30413d17584b7d448414ea87872609d89f264d76eb3c2bd800b8411ef65e4f2a8d80933195e7b1a1451fa114e9cfb44fe6c89688a73f0a77b72f04701d0de8cb85fcc7347ba5dc6e066bb14ff77bdcc582ed1cba0cc902ba0c698d01b841464fc7ac400db011dbfe93fe8ff28dfc13f94074c5225bfd0b63827d5dc40eb335d3982bdf385f569d668844155121ce0b74d681e914d79392b492698d10611800a063746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365880000000000000000", + "trustedHeight": 10, + "accountProof": "0xf86cf86aa1205f6174255b44b7ca652c5289d2546de65e4394eb6aa52a40045e01237736d023b846f8440180a05cc3ae2f35df83cafbdd6f6220a2eceb3e7ef6c9e10df3787bd8e9d5deae1f92a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "expectedTimestamp": 1021, + "expectedStorageRoot": "0x5cc3ae2f35df83cafbdd6f6220a2eceb3e7ef6c9e10df3787bd8e9d5deae1f92", + "expectedValidators": [ + "0xFE3B557E8Fb62b89F4916B721be55cEb828dBd73", + "0x627306090abaB3A6e1400e9345bC60c78a8BEf57", + "0xf17f52151EbEF6C7334FAD080c5704D77216b732", + "0xcBED645B1C1a6254f1149Df51d3591c6B3803007" + ] + }, + "lowOverlapUpdate": { + "height": 13, + "headerRlp": "0xf9033ca00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a00d2546fbdd16af694bb1e7a28440bd1d56197e4eb349532dba3b0b71778ac051a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010d8401c9c38080820406b90147f90144a00000000000000000000000000000000000000000000000000000000000000000f85494fe3b557e8fb62b89f4916b721be55ceb828dbd7394cbed645b1c1a6254f1149df51d3591c6b38030079400731540cd6060991d6b9c57ce295998d9bc2fab947e5f4552091a69125d5dfcb7b8c2659029395bdf8080f8c9b841ae4e5c4cd1f82a1d962f8ffde7c51396f2ac85fe4d3cc9b9a5eb249c1c3850665faa295fa6c0444025cc66b4e7d18b4b8469f3f851e735744babc3a99a12b58201b84194c7c8462d7d74c9bfd80f0e62b76a49316f2a0075ec7df65fb207d2c0eb75801f01c30b6a4f0445cb1cb8936d9f27587575449c1e25b17338c91eba6ac6a43301b841b854f80b9675f6b1f403b0c415ea6780f46e76d7c744f2d4d93004f4cdc533420efd490dcb0a80f298e6046ce974c64a45dab9cf86022bd478588e4f405b3e3d00a063746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365880000000000000000", + "trustedHeight": 10, + "accountProof": "0xf86cf86aa1205f6174255b44b7ca652c5289d2546de65e4394eb6aa52a40045e01237736d023b846f8440180a05dd23a6a8429ec8af97267494c6fa465682207585232c1ac7cd53eb9fd1b0318a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "expectedTimestamp": 1030, + "expectedStorageRoot": "0x5dd23a6a8429ec8af97267494c6fa465682207585232c1ac7cd53eb9fd1b0318", + "expectedValidators": [ + "0xFE3B557E8Fb62b89F4916B721be55cEb828dBd73", + "0xcBED645B1C1a6254f1149Df51d3591c6B3803007", + "0x00731540cd6060991D6B9C57CE295998d9bC2faB", + "0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf" + ] + }, + "membership": { + "proof": "0xf846f844a1203bd6be3bff117383e9ac885fff068af75120fde9a2c812e23878d38cce456852a1a0ac99c4edfa8056f2d49a30515770881f02a4f118254da280fe00dbcd0f54e876", + "proofHeight": 12, + "path": "0x636c69656e742d6f6e2d62657375010000000000000007", + "value": "0xac99c4edfa8056f2d49a30515770881f02a4f118254da280fe00dbcd0f54e876", + "expectedTimestamp": 1020 + }, + "nonMembership": { + "proof": "0xf846f844a1203bd6be3bff117383e9ac885fff068af75120fde9a2c812e23878d38cce456852a1a0ac99c4edfa8056f2d49a30515770881f02a4f118254da280fe00dbcd0f54e876", + "proofHeight": 12, + "path": "0x636c69656e742d6f6e2d62657375020000000000000007", + "expectedTimestamp": 1020 + } +} diff --git a/ibc-solidity/test/besu-bft/fixtures/qbft.json b/ibc-solidity/test/besu-bft/fixtures/qbft.json new file mode 100644 index 000000000..6019bd0ca --- /dev/null +++ b/ibc-solidity/test/besu-bft/fixtures/qbft.json @@ -0,0 +1,73 @@ +{ + "routerAddress": "0x07A6F66Beb52276B247A79B7B9D43416F9855f42", + "initialTrustedHeight": 33, + "initialTrustedTimestamp": 1787357305, + "initialTrustedStorageRoot": "0x2f39a2a5a30e1d6251aa6cbe8e47d8f8e2f01ebf00fb76e96abf17f5555089fc", + "initialTrustedValidators": [ + "0x065f139d8A49E9926232Cc4435159024cb5064FC", + "0x0EB968DE631aBC65322EcDCa5DfDF9C6296e52f4", + "0x20C5eDBCf6263Cd9E30Df395A2B914F6E939B9Ba", + "0x543d3796700eE35803A1C43562a69FEc08E1e423" + ], + "trustingPeriod": 1209600, + "maxClockDrift": 15, + "adjacentUpdate": { + "height": 34, + "headerRlp": "0xf90385a07ee4185f15b458dcff8936e722e3792ddf28a3f6801ce06374969f54031b762aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479420c5edbcf6263cd9e30df395a2b914f6e939b9baa030defd9bc19472d5ccbb248e391b49320a77fd71652b0bafeddb78725ef28515a078e6f2f4fe203157e3d5c67a75ce82947103e360cc17f0a3d60e38b6c552a08aa00149f44a46b46c6429cf561eda5e72322b31debaa8ff69357298cb2e8206a524b901001000000000000000000000000004000000000000000000000000000000000000008000000000000010000000000000000000000000000000000000000020000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000002008000000000000000000000000020000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001228402faf08082b349846a88e87bb90147f90144a0000000000000000000000000000000000000000000626573752032362e342e30f85494065f139d8a49e9926232cc4435159024cb5064fc940eb968de631abc65322ecdca5dfdf9c6296e52f49420c5edbcf6263cd9e30df395a2b914f6e939b9ba94543d3796700ee35803a1c43562a69fec08e1e423c080f8c9b8410e4196ae86251b9ad1f92ccd0deb5c615f5d5f55d32fd232b303bdd8e18c6e806ee612e50f641ec37026ccfb294ed1631bf0c7eac49b710fe2e66fd4082d356401b841e0646ce5a4c2005b25d182bbdd0c22022156e007d243699b9f928d58e6cd9ffe6613aaf033ec261c48c224fa1cba87886161aae03362de1fcc3871b3da3c70f600b84142ce15667100923022aa210debed209729367078b1fc71108f8dcfaa7c102032012fb03c701e8c854062fb4281e9dda4509932121a33dbb79ec0a47a4f738ff800a063746963616c2062797a616e74696e65206661756c7420746f6c6572616e636588000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000", + "trustedHeight": 33, + "accountProof": "0xf902b2f901f1a0886aec3477fe3ac6276485bfaf3e5e1eea382e6911831691f50c734edcea799e80a08573bfe9264ed8b6afc58b400efeaae64f1d56bc8396d44a2dcfd17a9c14b7a2a092450fe708c280f7c52ea0eeb14974139fd3d4dcc7cc77a37fcafbe187480ea3a01d272d6cf8f93bc15533e54ea3f459a982fc32e1272d95cf1d0cde1361463cfda0682e0509d82289dcb84f9d366ed881bfe4655d3c15de298e3d6fe4183d7051cca0e8fbbb10bb2183848e739cd3654a1ff083ca953bee3b58fd56b063f810cf1722a074a59b1b84fc35ff94e4f762b894b113da5941ca99e21df30783140f4a33b1cca0014abed6a424575260405210754b1aa0d4cabe50e8616ac231e424973fc0a895a08d662e3f7d019145626a3d1e9d29c1ce0a98d49c8cd6a5c85398f6acbe83e23ea0397a811f344f0827d373cddaaac7063a83ed8a127e56864b2491774c97d01912a0ccca73c8748a8ec56ef293bee631a7d21ef1e1ec8b053e976f6ef3faa50187fba0613dbbef57a2660c21ec8c864749de69ac0bc4b59f6aef6477a090fdd51f467aa090c93d47b38631bbdc1156f9e0caa1eaaf5bd87827b8535e097ad48b274bc01ca05edc383ad614e86f1da2e1a91d7e85ae5ab1d098a0d47623ef13d49d02754f8ea0c345faa773370853ac7afa5d32956ce53465ceac1e060e424343b39d9793397680f8518080a065c2085561952935fde3dfd4a299d8d01d46529c6d3f69aaac4134c61e4cab3a808080808080808080a0df2fc47ed0c87770a1fbcd193fbba94e57e0aa2a3d3960a8daa84dd1fc39d76e80808080f869a020b221f4fe86714230ec6dfaf784ee106a9f8901d542e537af01e28564065574b846f8440180a02f39a2a5a30e1d6251aa6cbe8e47d8f8e2f01ebf00fb76e96abf17f5555089fca07f79b8b370510aa3a9ea8536a9459c92de9493272cd5fe45c02364cfe254a9a7", + "expectedTimestamp": 1787357307, + "expectedStorageRoot": "0x2f39a2a5a30e1d6251aa6cbe8e47d8f8e2f01ebf00fb76e96abf17f5555089fc", + "expectedValidators": [ + "0x065f139d8A49E9926232Cc4435159024cb5064FC", + "0x0EB968DE631aBC65322EcDCa5DfDF9C6296e52f4", + "0x20C5eDBCf6263Cd9E30Df395A2B914F6E939B9Ba", + "0x543d3796700eE35803A1C43562a69FEc08E1e423" + ] + }, + "nonAdjacentUpdate": { + "height": 35, + "headerRlp": "0xf90386a0e8eb81a5cc7e4bc105561f792aed8d6ed967305e1460902b48544d9198519a65a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794543d3796700ee35803a1c43562a69fec08e1e423a00bcab205a2b4819b25f76797dc4582c3818a56731f31904884f817a1a27fa442a0faa58af4eab20011acc6e66b20b1bc8a8d8b444e62e76b6e49fa790284a6538fa08e05526631e8b9e7f21d1d65cfdef62d8ac6d6d11050db08db39741243eed4eeb901001000000000000008800000000004000000000000000000001000000000000000008000000000000010000000000000400000040000000000000000000204000000000040000000000000020800100400800000000004100000000002000000000000000000000000800001000000000000000008000000000000001000000000000000000000100000080000000008000800000000008000000000000000000000000000000000000004000000000000000000000000000000000000000000000010000200000000000010004000000000000000000400000080000000004000000000000000000000000800000008000000000000000000000000000000000001238402faf0808306784b846a88e87db90147f90144a0000000000000000000000000000000000000000000626573752032362e342e30f85494065f139d8a49e9926232cc4435159024cb5064fc940eb968de631abc65322ecdca5dfdf9c6296e52f49420c5edbcf6263cd9e30df395a2b914f6e939b9ba94543d3796700ee35803a1c43562a69fec08e1e423c080f8c9b841eae1fc67c37231c16d0db99ee0b2ef4e72351cccfad04fac8cd3a425e4adf73660f50280839ad121cbc89d352bb2b199b4ee44edfe19db2321933daedd261d9900b841328d044bbe376b4be8495b33faebea0bbfaf40f9c37604ef9d8fe49243cf7f4f2274fafe780d9a0d63e5177f25ecb4fa40382e767856a424467102ef8795530a01b841ad76a8c3edacc84e6341df92e64b3e1756c90bd8cb0d5c9194bf330c80da5e217ec191891813deb925a4b2d012cf919e561ac37359f1788abc589042ac115d9001a063746963616c2062797a616e74696e65206661756c7420746f6c6572616e636588000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000", + "trustedHeight": 33, + "accountProof": "0xf902b2f901f1a0886aec3477fe3ac6276485bfaf3e5e1eea382e6911831691f50c734edcea799e80a08573bfe9264ed8b6afc58b400efeaae64f1d56bc8396d44a2dcfd17a9c14b7a2a0174fa4f59759c5446865fa6777e34929c1bc09c97412a84c064dd7864ed625e7a01d272d6cf8f93bc15533e54ea3f459a982fc32e1272d95cf1d0cde1361463cfda0682e0509d82289dcb84f9d366ed881bfe4655d3c15de298e3d6fe4183d7051cca0bbb94f73543a77ce1f2e90a6ab92e5a6911e5af84dc8e1bcc33a0b20e10a2c5ba0fd265a27de5e8596bb6acaaf60ace61e3a9e724f75a7543af8b738754199998fa0014abed6a424575260405210754b1aa0d4cabe50e8616ac231e424973fc0a895a060bd3b16ddfd75eae7933b7d0dbf717adb2c8b16573d4706eec89b33a71be71ca00e4d3a60002f359ab48688dc19ebd727bccb488984e27264d91bcba10302b7faa0ccca73c8748a8ec56ef293bee631a7d21ef1e1ec8b053e976f6ef3faa50187fba0613dbbef57a2660c21ec8c864749de69ac0bc4b59f6aef6477a090fdd51f467aa090c93d47b38631bbdc1156f9e0caa1eaaf5bd87827b8535e097ad48b274bc01ca05edc383ad614e86f1da2e1a91d7e85ae5ab1d098a0d47623ef13d49d02754f8ea0c345faa773370853ac7afa5d32956ce53465ceac1e060e424343b39d9793397680f8518080a090a8eabac86b7acb55ccec8235f1372ffaa1bd13b53a97089bc04c4f48fb0620808080808080808080a0df2fc47ed0c87770a1fbcd193fbba94e57e0aa2a3d3960a8daa84dd1fc39d76e80808080f869a020b221f4fe86714230ec6dfaf784ee106a9f8901d542e537af01e28564065574b846f8440180a04bbf8536a690306e276e29d183d17b249edb483a00dd9ad732552be38f8e6301a07f79b8b370510aa3a9ea8536a9459c92de9493272cd5fe45c02364cfe254a9a7", + "expectedTimestamp": 1787357309, + "expectedStorageRoot": "0x4bbf8536a690306e276e29d183d17b249edb483a00dd9ad732552be38f8e6301", + "expectedValidators": [ + "0x065f139d8A49E9926232Cc4435159024cb5064FC", + "0x0EB968DE631aBC65322EcDCa5DfDF9C6296e52f4", + "0x20C5eDBCf6263Cd9E30Df395A2B914F6E939B9Ba", + "0x543d3796700eE35803A1C43562a69FEc08E1e423" + ] + }, + "lowQuorumUpdate": { + "height": 35, + "headerRlp": "0xf90343a0e8eb81a5cc7e4bc105561f792aed8d6ed967305e1460902b48544d9198519a65a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794543d3796700ee35803a1c43562a69fec08e1e423a00bcab205a2b4819b25f76797dc4582c3818a56731f31904884f817a1a27fa442a0faa58af4eab20011acc6e66b20b1bc8a8d8b444e62e76b6e49fa790284a6538fa08e05526631e8b9e7f21d1d65cfdef62d8ac6d6d11050db08db39741243eed4eeb901001000000000000008800000000004000000000000000000001000000000000000008000000000000010000000000000400000040000000000000000000204000000000040000000000000020800100400800000000004100000000002000000000000000000000000800001000000000000000008000000000000001000000000000000000000100000080000000008000800000000008000000000000000000000000000000000000004000000000000000000000000000000000000000000000010000200000000000010004000000000000000000400000080000000004000000000000000000000000800000008000000000000000000000000000000000001238402faf0808306784b846a88e87db90104f90101a0000000000000000000000000000000000000000000626573752032362e342e30f85494065f139d8a49e9926232cc4435159024cb5064fc940eb968de631abc65322ecdca5dfdf9c6296e52f49420c5edbcf6263cd9e30df395a2b914f6e939b9ba94543d3796700ee35803a1c43562a69fec08e1e423c080f886b841eae1fc67c37231c16d0db99ee0b2ef4e72351cccfad04fac8cd3a425e4adf73660f50280839ad121cbc89d352bb2b199b4ee44edfe19db2321933daedd261d9900b841328d044bbe376b4be8495b33faebea0bbfaf40f9c37604ef9d8fe49243cf7f4f2274fafe780d9a0d63e5177f25ecb4fa40382e767856a424467102ef8795530a01a063746963616c2062797a616e74696e65206661756c7420746f6c6572616e636588000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000", + "trustedHeight": 33, + "accountProof": "0x" + }, + "conflictingUpdate": { + "height": 35, + "headerRlp": "0xf90386a084d5dbd206ef4a465f66c8b14ce809687baa221677a986bc15ec5b99b8579e8da01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794065f139d8a49e9926232cc4435159024cb5064fca02bbf0aa2342ab306dda9aa494f3ffe8a2fb2ebd327bf99fe2f4609e5d56a287fa0ede1198cf1f6072bfe88d1beabbbb3ceefda3094b5b6ca1aa0e50e5aa58d5aa0a0c2f035f70c9a89c2f0fbf3b4fad07d005b637eaaf0ae084de4a189de91414442b901000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000400000000000000000000000000204000000000000000000000000000008000000000000000004000000000002000000000000000000000000000000000000000200000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000100000000000004000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000004000000000200000000000000000000000000000000000000000000000000000000001238402faf080830b245a846a88e87fb90147f90144a0000000000000000000000000000000000000000000626573752032362e342e30f85494065f139d8a49e9926232cc4435159024cb5064fc940eb968de631abc65322ecdca5dfdf9c6296e52f49420c5edbcf6263cd9e30df395a2b914f6e939b9ba94543d3796700ee35803a1c43562a69fec08e1e423c080f8c9b841fa5785d98739747d89cb99b923440ce46a4d1c66c9cf9d1171a6b70bbaeeecf3000da2ce63d7c7e284da788bade5423ad89ca27b009cc5ab25f3d164e829b6bd01b841b05d0d27772ddb76da6b8094d099b4e6b158290825c7756f583be9fa887f0c9d528cb2cdfaa9147dbca6f947a97e488226bc4e0253a6f8a724b2b2a8eecd16fc00b8419e75966c499c86f1178194190c747387a0e70cdb7eb0a826896b66781fe381074df6b59ae6320464d9c5ad6417157390a8278bded19f5965b110edf22f684af500a063746963616c2062797a616e74696e65206661756c7420746f6c6572616e636588000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000", + "trustedHeight": 33, + "accountProof": "0xf902b2f901f1a0886aec3477fe3ac6276485bfaf3e5e1eea382e6911831691f50c734edcea799e80a08573bfe9264ed8b6afc58b400efeaae64f1d56bc8396d44a2dcfd17a9c14b7a2a0174fa4f59759c5446865fa6777e34929c1bc09c97412a84c064dd7864ed625e7a01d272d6cf8f93bc15533e54ea3f459a982fc32e1272d95cf1d0cde1361463cfda0682e0509d82289dcb84f9d366ed881bfe4655d3c15de298e3d6fe4183d7051cca0f9b17a214dc86111bc5c9310d57aac2486dd4eda6ae8da9caa0bb2185b4015b9a060613dc1091a24ed1576c9103e09c5267bf509441384562347123960d496cc8ba0014abed6a424575260405210754b1aa0d4cabe50e8616ac231e424973fc0a895a060bd3b16ddfd75eae7933b7d0dbf717adb2c8b16573d4706eec89b33a71be71ca00e4d3a60002f359ab48688dc19ebd727bccb488984e27264d91bcba10302b7faa0ccca73c8748a8ec56ef293bee631a7d21ef1e1ec8b053e976f6ef3faa50187fba0613dbbef57a2660c21ec8c864749de69ac0bc4b59f6aef6477a090fdd51f467aa034d7ac756aa6ef347f0e3dc9a6f4db4409baca5d1e7d75dbff0842795d3b3d11a05edc383ad614e86f1da2e1a91d7e85ae5ab1d098a0d47623ef13d49d02754f8ea0c345faa773370853ac7afa5d32956ce53465ceac1e060e424343b39d9793397680f8518080a0f3ae7979f8d7015e2141c041cec64bc388a9362583c0e9014baec75c098bbe24808080808080808080a0df2fc47ed0c87770a1fbcd193fbba94e57e0aa2a3d3960a8daa84dd1fc39d76e80808080f869a020b221f4fe86714230ec6dfaf784ee106a9f8901d542e537af01e28564065574b846f8440180a061734a2ddcb2c34ad14a2bb4f7326dc4fa7e4dd4c6be97ba2e2d2fdd03b77f20a07f79b8b370510aa3a9ea8536a9459c92de9493272cd5fe45c02364cfe254a9a7" + }, + "lowOverlapUpdate": { + "height": 36, + "headerRlp": "0xf90386a084d5dbd206ef4a465f66c8b14ce809687baa221677a986bc15ec5b99b8579e8da01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794065f139d8a49e9926232cc4435159024cb5064fca02bbf0aa2342ab306dda9aa494f3ffe8a2fb2ebd327bf99fe2f4609e5d56a287fa0ede1198cf1f6072bfe88d1beabbbb3ceefda3094b5b6ca1aa0e50e5aa58d5aa0a0c2f035f70c9a89c2f0fbf3b4fad07d005b637eaaf0ae084de4a189de91414442b901000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000400000000000000000000000000204000000000000000000000000000008000000000000000004000000000002000000000000000000000000000000000000000200000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000100000000000004000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000004000000000200000000000000000000000000000000000000000000000000000000001248402faf080830b245a846a88e87fb90147f90144a0000000000000000000000000000000000000000000626573752032362e342e30f85494065f139d8a49e9926232cc4435159024cb5064fc9446a5b7e742f9ad777ef8bb85aebc717e7433dc47946af3e238490ca4b6ae4f1efdf12c04cc160423c3941780ffe5324fe74e6f2ef012edc9bd205e74555bc080f8c9b8411abc319e0b1a343bf29a207a0369df6b6869c7cd07611807e5ad78e514033fa700cafa3268fba741f02366e7fa5fb7c86074a5edac1da2b602a77f3b81bb33fa00b841f58c52cac0586900e5222700194f1c1745d0d1840f8e7f69b9cc3739da58d67a680b35b14ca35a8cc997e8cc8f05a22503349d897eaec6343bd6255f8dcd349101b841a22b308f750cc54f70abbe43c53310e9c774d652ee79ef1f08ec0ae44d2204331bbb8944e223f0f79455dfa52dcf4af24ae16e333db6c859728253fb2dcb7e9401a063746963616c2062797a616e74696e65206661756c7420746f6c6572616e636588000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000", + "trustedHeight": 33, + "accountProof": "0x" + }, + "membership": { + "proof": "0xf90159f90111a02e5a83120837eb86e4961e217014c155f98adcc18a96478d4942be68d231ef1f80a04e510de4b9ef26070bc6f70273e868c69edbaf19a2517970a5dbd69902e1d434a0961d17be355042d27b605ef5f08628781620f7925927a3fb4beab2c3f6ce960aa0c8f60c0b856b9c536a919218ed7620e4f347b78938a758dfbb7e51cf2987edd0a0121c2d3eac0ec9178354c8715a2c353722e19f48e88691c2212e92d9cfb289d480a0f383029e86bd678ed67013dba1678e499669b01ce6670f925b415326d2b0243fa00e8d54ce26b8005c92ece298e21e9c7d1225e884addcdfbea2ead81c551df8928080808080a028d7dc5ba83020579a12100e30fafb74f3c03531f786808a733392cd565ef0668080f843a0369632698e78112a478dabed541f773d2f5a93186d9d3b9d9774b73bf9018b08a1a0d7d01afac573bfdecea02b26ffc115aab06e9b364869695b5e22775c252ba5e6", + "proofHeight": 35, + "path": "0x626573752d636861696e2d62010000000000000001", + "value": "0xd7d01afac573bfdecea02b26ffc115aab06e9b364869695b5e22775c252ba5e6", + "expectedTimestamp": 1787357309 + }, + "nonMembership": { + "proof": "0xf90167f90111a02e5a83120837eb86e4961e217014c155f98adcc18a96478d4942be68d231ef1f80a04e510de4b9ef26070bc6f70273e868c69edbaf19a2517970a5dbd69902e1d434a0961d17be355042d27b605ef5f08628781620f7925927a3fb4beab2c3f6ce960aa0c8f60c0b856b9c536a919218ed7620e4f347b78938a758dfbb7e51cf2987edd0a0121c2d3eac0ec9178354c8715a2c353722e19f48e88691c2212e92d9cfb289d480a0f383029e86bd678ed67013dba1678e499669b01ce6670f925b415326d2b0243fa00e8d54ce26b8005c92ece298e21e9c7d1225e884addcdfbea2ead81c551df8928080808080a028d7dc5ba83020579a12100e30fafb74f3c03531f786808a733392cd565ef0668080f85180808080a0875eb9f9e615bfe1bd0884f44df3e2d591dd593d8009f0580aab4465dde3c0518080808080808080a02e971ba04a6d372cbe0b0622575c81175795858250053878c51e727d46591fa8808080", + "proofHeight": 35, + "path": "0x626573752d636861696e2d61020000000000000001", + "expectedTimestamp": 1787357309 + } +} diff --git a/packages/proof-api/modules/besu-to-eth/Cargo.toml b/packages/proof-api/modules/besu-to-eth/Cargo.toml new file mode 100644 index 000000000..674b94e83 --- /dev/null +++ b/packages/proof-api/modules/besu-to-eth/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "proof-api-besu-to-eth" +version.workspace = true +edition.workspace = true +repository.workspace = true +license.workspace = true + +[dependencies] +alloy = { workspace = true, features = ["full"] } +alloy-rlp = { workspace = true } +anyhow = { workspace = true, features = ["std"] } +ethereum-apis = { workspace = true } +ethereum-light-client = { workspace = true } +proof-api-core = { workspace = true, default-features = false } +proof-api-lib = { workspace = true, default-features = false } +ibc-eureka-solidity-types = { workspace = true, features = ["rpc"] } +rlp = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } +tonic = { workspace = true, default-features = true } +tracing = { workspace = true, default-features = true } diff --git a/packages/proof-api/modules/besu-to-eth/src/lib.rs b/packages/proof-api/modules/besu-to-eth/src/lib.rs new file mode 100644 index 000000000..c5c5882de --- /dev/null +++ b/packages/proof-api/modules/besu-to-eth/src/lib.rs @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: Apache-2.0 + +//! One-sided Besu-to-Ethereum proof API module. + +#![deny(clippy::nursery, clippy::pedantic, warnings, unused_crate_dependencies)] +#![allow(missing_docs)] + +mod tx_builder; + +use std::collections::HashMap; + +use alloy::{ + primitives::{Address, TxHash}, + providers::{Provider, RootProvider}, +}; +use proof_api_core::{ + api::{self, proof_api_service_server::ProofApiService}, + modules::ProofApiModule, +}; +use proof_api_lib::{ + listener::{eth_eureka, ChainListenerService}, + service_utils::{parse_eth_tx_hashes, to_tonic_status}, + utils::RelayEventsParams, +}; +use tonic::{Request, Response}; +use tracing as _; +use tx_builder::TxBuilder; + +#[derive(Clone, Copy, Debug)] +pub struct BesuToEthProofApiModule; + +struct BesuToEthProofApiModuleService { + src_ics26_address: Address, + src_listener: eth_eureka::ChainListener, + dst_listener: eth_eureka::ChainListener, + tx_builder: TxBuilder, +} + +#[derive(Clone, Copy, Debug, serde::Deserialize, serde::Serialize)] +#[serde(rename_all = "snake_case")] +pub enum BesuConsensusType { + Qbft, + Ibft2, +} + +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +pub struct BesuToEthConfig { + pub src_rpc_url: String, + pub src_ics26_address: Address, + pub dst_rpc_url: String, + pub dst_ics26_address: Address, + pub consensus_type: BesuConsensusType, +} + +impl BesuToEthProofApiModuleService { + async fn new(config: BesuToEthConfig) -> anyhow::Result { + let src_provider = RootProvider::builder() + .connect(&config.src_rpc_url) + .await + .map_err(|e| anyhow::anyhow!("failed to create source provider: {e}"))?; + let dst_provider = RootProvider::builder() + .connect(&config.dst_rpc_url) + .await + .map_err(|e| anyhow::anyhow!("failed to create destination provider: {e}"))?; + + let src_listener = + eth_eureka::ChainListener::new(config.src_ics26_address, src_provider.clone()); + let dst_listener = + eth_eureka::ChainListener::new(config.dst_ics26_address, dst_provider.clone()); + let tx_builder = TxBuilder::new( + src_provider, + dst_provider, + config.src_ics26_address, + config.dst_ics26_address, + config.consensus_type, + ); + + Ok(Self { + src_ics26_address: config.src_ics26_address, + src_listener, + dst_listener, + tx_builder, + }) + } +} + +#[tonic::async_trait] +impl ProofApiService for BesuToEthProofApiModuleService { + async fn info( + &self, + request: Request, + ) -> Result, tonic::Status> { + let src_chain = request.into_inner().src_chain; + Ok(Response::new(api::InfoResponse { + target_chain: Some(api::Chain { + chain_id: self + .dst_listener + .chain_id() + .await + .map_err(to_tonic_status)?, + ibc_version: "2".to_string(), + ibc_contract: self.tx_builder.ics26_router_address().to_string(), + }), + source_chain: Some(api::Chain { + chain_id: src_chain, + ibc_version: "2".to_string(), + ibc_contract: self.src_ics26_address.to_string(), + }), + metadata: HashMap::default(), + })) + } + + async fn relay_by_tx( + &self, + request: Request, + ) -> Result, tonic::Status> { + let inner_req = request.into_inner(); + + let src_txs = parse_eth_tx_hashes(inner_req.source_tx_ids)? + .into_iter() + .map(TxHash::from) + .collect(); + let timeout_txs = parse_eth_tx_hashes(inner_req.timeout_tx_ids)? + .into_iter() + .map(TxHash::from) + .collect(); + + let src_events = self + .src_listener + .fetch_tx_events(src_txs) + .await + .map_err(to_tonic_status)?; + let timeout_events = self + .dst_listener + .fetch_tx_events(timeout_txs) + .await + .map_err(to_tonic_status)?; + + let timeout_relay_height = if timeout_events.is_empty() { + None + } else { + Some( + self.src_listener + .get_block_number() + .await + .map_err(to_tonic_status)?, + ) + }; + + let tx = self + .tx_builder + .relay_events(RelayEventsParams { + src_events, + target_events: timeout_events, + timeout_relay_height, + src_client_id: inner_req.src_client_id, + dst_client_id: inner_req.dst_client_id, + src_packet_seqs: inner_req.src_packet_sequences, + dst_packet_seqs: inner_req.dst_packet_sequences, + }) + .await + .map_err(to_tonic_status)?; + + Ok(Response::new(api::RelayByTxResponse { + tx, + address: self.tx_builder.ics26_router_address().to_string(), + })) + } + + async fn create_client( + &self, + request: Request, + ) -> Result, tonic::Status> { + let inner_req = request.into_inner(); + let tx = self + .tx_builder + .create_client(&inner_req.parameters) + .await + .map_err(to_tonic_status)?; + + Ok(Response::new(api::CreateClientResponse { + tx, + address: String::new(), + })) + } + + async fn update_client( + &self, + request: Request, + ) -> Result, tonic::Status> { + let inner_req = request.into_inner(); + let tx = self + .tx_builder + .update_client(&inner_req.dst_client_id) + .await + .map_err(to_tonic_status)?; + + Ok(Response::new(api::UpdateClientResponse { + tx, + address: self.tx_builder.ics26_router_address().to_string(), + })) + } +} + +#[tonic::async_trait] +impl ProofApiModule for BesuToEthProofApiModule { + fn name(&self) -> &'static str { + "besu_to_eth" + } + + async fn create_service( + &self, + config: serde_json::Value, + ) -> anyhow::Result> { + let config: BesuToEthConfig = serde_json::from_value(config)?; + let service = BesuToEthProofApiModuleService::new(config).await?; + Ok(Box::new(service)) + } +} + +#[cfg(test)] +mod tests { + use super::BesuToEthConfig; + + #[test] + fn obsolete_src_chain_id_is_ignored() { + let config: BesuToEthConfig = serde_json::from_value(serde_json::json!({ + "src_chain_id": "legacy", + "src_rpc_url": "http://localhost:8545", + "src_ics26_address": "0x0000000000000000000000000000000000000001", + "dst_rpc_url": "http://localhost:9545", + "dst_ics26_address": "0x0000000000000000000000000000000000000002", + "consensus_type": "qbft" + })) + .unwrap(); + + assert!( + serde_json::to_value(config).unwrap()["src_chain_id"].is_null(), + "obsolete field must be accepted but not emitted" + ); + } +} diff --git a/packages/proof-api/modules/besu-to-eth/src/tx_builder.rs b/packages/proof-api/modules/besu-to-eth/src/tx_builder.rs new file mode 100644 index 000000000..e100bb891 --- /dev/null +++ b/packages/proof-api/modules/besu-to-eth/src/tx_builder.rs @@ -0,0 +1,613 @@ +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + collections::{HashMap, HashSet}, + str::FromStr, + time::UNIX_EPOCH, +}; + +use alloy::{ + consensus::Header, + network::Ethereum, + primitives::{hex, Address, Bytes, B256, U256}, + providers::{Provider, RootProvider}, + rpc::types::{EIP1186AccountProofResponse, EIP1186StorageProof}, + sol_types::{SolCall, SolValue}, +}; +use alloy_rlp::Header as RlpHeader; +use anyhow::{anyhow, bail, Context, Result}; +use ethereum_apis::eth_api::client::EthApiClient; +use ethereum_light_client::membership::evm_ics26_commitment_path; +use ibc_eureka_solidity_types::{ + besu::{besu_ibft2_light_client, besu_qbft_light_client}, + ics26::{ + router::{multicallCall, routerCalls, routerInstance, updateClientCall}, + IICS02ClientMsgs::Height as RouterHeight, + ICS26_IBC_STORAGE_SLOT, + }, + msgs::{IBesuLightClientMsgs, IICS02ClientMsgs::Height as MsgHeight}, +}; +use proof_api_lib::utils::{ + eth_eureka::{src_events_to_recv_and_ack_msgs, target_events_to_timeout_msgs}, + RelayEventsParams, +}; +use rlp::Rlp; + +use crate::BesuConsensusType; + +pub struct TxBuilder { + src_provider: RootProvider, + dst_provider: RootProvider, + src_ics26_router: routerInstance, + dst_ics26_router: routerInstance, + consensus_type: BesuConsensusType, +} + +struct CreateClientParams { + trusting_period: u64, + max_clock_drift: u64, + trusted_height: Option, + role_manager: Address, +} + +const TRUSTING_PERIOD: &str = "trusting_period"; +const MAX_CLOCK_DRIFT: &str = "max_clock_drift"; +const TRUSTED_HEIGHT: &str = "trusted_height"; +const ROLE_MANAGER: &str = "role_manager"; + +impl TxBuilder { + pub fn new( + src_provider: RootProvider, + dst_provider: RootProvider, + src_ics26_address: Address, + dst_ics26_address: Address, + consensus_type: BesuConsensusType, + ) -> Self { + Self { + src_ics26_router: routerInstance::new(src_ics26_address, src_provider.clone()), + dst_ics26_router: routerInstance::new(dst_ics26_address, dst_provider.clone()), + src_provider, + dst_provider, + consensus_type, + } + } + + pub const fn ics26_router_address(&self) -> &Address { + self.dst_ics26_router.address() + } + + pub async fn create_client(&self, parameters: &HashMap) -> Result> { + let params = parse_create_client_params(parameters)?; + let trusted_height = match params.trusted_height { + Some(height) => height, + None => self + .src_provider + .get_block_number() + .await + .context("failed to fetch latest source block number")?, + }; + + let header = self + .fetch_source_header(trusted_height) + .await + .with_context(|| format!("failed to fetch source block at height {trusted_height}"))?; + let validators = + extract_validators_from_extra_data(&header.extra_data).with_context(|| { + format!("failed to extract validators from source block {trusted_height}") + })?; + let proof = self + .fetch_source_proofs(trusted_height, &[]) + .await + .with_context(|| { + format!( + "failed to fetch account proof for source router at height {trusted_height}" + ) + })?; + + let calldata = match self.consensus_type { + BesuConsensusType::Qbft => besu_qbft_light_client::BesuQBFTLightClient::deploy_builder( + self.dst_provider.clone(), + *self.src_ics26_router.address(), + trusted_height, + header.timestamp, + proof.storage_hash, + validators, + params.trusting_period, + params.max_clock_drift, + params.role_manager, + ) + .calldata() + .to_vec(), + BesuConsensusType::Ibft2 => { + besu_ibft2_light_client::BesuIBFT2LightClient::deploy_builder( + self.dst_provider.clone(), + *self.src_ics26_router.address(), + trusted_height, + header.timestamp, + proof.storage_hash, + validators, + params.trusting_period, + params.max_clock_drift, + params.role_manager, + ) + .calldata() + .to_vec() + } + }; + + Ok(calldata) + } + + pub async fn update_client(&self, dst_client_id: &str) -> Result> { + let client_state = self + .fetch_destination_client_state(dst_client_id) + .await + .with_context(|| { + format!("failed to decode destination Besu client state for client {dst_client_id}") + })?; + let trusted_height = client_state.latestHeight.revisionHeight; + let target_height = self + .src_provider + .get_block_number() + .await + .context("failed to fetch latest source block number")?; + let header = self + .fetch_source_header(target_height) + .await + .with_context(|| format!("failed to fetch source block at height {target_height}"))?; + let proof = self + .fetch_source_proofs(target_height, &[]) + .await + .with_context(|| { + format!("failed to fetch account proof for source router at height {target_height}") + })?; + + Ok(Self::build_update_client_calldata( + dst_client_id, + trusted_height, + header, + encode_rlp_node_list(&proof.account_proof), + )) + } + + pub async fn relay_events(&self, params: RelayEventsParams) -> Result> { + let proof_height = params + .src_events + .iter() + .map(|event| event.height) + .chain(params.timeout_relay_height) + .max() + .ok_or_else(|| anyhow!("no packets collected"))?; + let header = self + .fetch_source_header(proof_height) + .await + .with_context(|| format!("failed to fetch source block at height {proof_height}"))?; + let proof_timestamp = header.timestamp; + let now = std::time::SystemTime::now() + .duration_since(UNIX_EPOCH) + .context("failed to read system time")? + .as_secs(); + let proof_height_msg = RouterHeight { + revisionNumber: 0, + revisionHeight: proof_height, + }; + + let recv_and_ack_msgs = src_events_to_recv_and_ack_msgs( + params.src_events, + ¶ms.src_client_id, + ¶ms.dst_client_id, + ¶ms.src_packet_seqs, + ¶ms.dst_packet_seqs, + &proof_height_msg, + now, + )?; + let timeout_msgs = target_events_to_timeout_msgs( + params.target_events, + ¶ms.src_client_id, + ¶ms.dst_client_id, + ¶ms.dst_packet_seqs, + &proof_height_msg, + proof_timestamp, + ); + + let mut packet_calls: Vec<_> = recv_and_ack_msgs.into_iter().chain(timeout_msgs).collect(); + if packet_calls.is_empty() { + bail!("no packets collected") + } + + let client_state = self + .fetch_destination_client_state(¶ms.dst_client_id) + .await + .with_context(|| { + format!( + "failed to decode destination Besu client state for client {}", + params.dst_client_id + ) + })?; + let mut storage_keys = packet_calls + .iter() + .map(packet_storage_key) + .collect::>(); + storage_keys.sort_unstable(); + storage_keys.dedup(); + let proof = self + .fetch_source_proofs(proof_height, &storage_keys) + .await + .with_context(|| { + format!( + "failed to fetch account and storage proofs for source router at height {proof_height}" + ) + })?; + let account_proof = encode_rlp_node_list(&proof.account_proof); + let storage_proofs = map_storage_proofs(&storage_keys, proof.storage_proof)?; + let update_call = Self::build_update_client_calldata( + ¶ms.dst_client_id, + client_state.latestHeight.revisionHeight, + header, + account_proof, + ); + + attach_packet_proofs(&mut packet_calls, &storage_proofs)?; + + let all_calls: Vec = std::iter::once(update_call.into()) + .chain(packet_calls.into_iter().map(|call| match call { + routerCalls::ackPacket(call) => call.abi_encode().into(), + routerCalls::recvPacket(call) => call.abi_encode().into(), + routerCalls::timeoutPacket(call) => call.abi_encode().into(), + _ => unreachable!("only recv, ack, and timeout calls are constructed"), + })) + .collect(); + + Ok(multicallCall { data: all_calls }.abi_encode()) + } + + fn build_update_client_calldata( + dst_client_id: &str, + trusted_height: u64, + header: Header, + account_proof: Vec, + ) -> Vec { + let update_msg = IBesuLightClientMsgs::MsgUpdateClient { + headerRlp: alloy_rlp::encode(header).into(), + trustedHeight: MsgHeight { + revisionNumber: 0, + revisionHeight: trusted_height, + }, + accountProof: account_proof.into(), + }; + + updateClientCall { + clientId: dst_client_id.to_string(), + updateMsg: update_msg.abi_encode().into(), + } + .abi_encode() + } + + async fn fetch_source_header(&self, block_height: u64) -> Result
{ + let block = EthApiClient::new(self.src_provider.clone()) + .get_block(block_height) + .await + .with_context(|| format!("failed to fetch source block at height {block_height}"))?; + Ok(block.into_consensus_header()) + } + + async fn fetch_source_proofs( + &self, + block_height: u64, + storage_keys: &[B256], + ) -> Result { + Ok(EthApiClient::new(self.src_provider.clone()) + .get_proof( + &self.src_ics26_router.address().to_string(), + storage_keys + .iter() + .map(|key| format!("0x{}", hex::encode(key))) + .collect(), + format!("0x{block_height:x}"), + ) + .await?) + } + + async fn fetch_destination_client_state( + &self, + dst_client_id: &str, + ) -> Result { + let client_address = self + .dst_ics26_router + .getClient(dst_client_id.to_string()) + .call() + .await + .with_context(|| { + format!("failed to fetch destination client address for {dst_client_id}") + })?; + let client_state_bz: Bytes = besu_qbft_light_client::BesuQBFTLightClient::new( + client_address, + self.dst_provider.clone(), + ) + .getClientState() + .call() + .await + .with_context(|| format!("failed to fetch destination client state for {dst_client_id}"))?; + + IBesuLightClientMsgs::ClientState::abi_decode(client_state_bz.as_ref()).with_context(|| { + format!("failed to decode destination client state for {dst_client_id}") + }) + } +} + +fn packet_storage_key(call: &routerCalls) -> B256 { + let path = match call { + routerCalls::recvPacket(call) => call.msg_.packet.commitment_path(), + routerCalls::ackPacket(call) => call.msg_.packet.ack_commitment_path(), + routerCalls::timeoutPacket(call) => call.msg_.packet.receipt_commitment_path(), + _ => unreachable!("only recv, ack, and timeout calls are constructed"), + }; + evm_ics26_commitment_path(&path, U256::from_be_slice(&ICS26_IBC_STORAGE_SLOT)).into() +} + +fn attach_packet_proofs( + packet_calls: &mut [routerCalls], + storage_proofs: &HashMap>, +) -> Result<()> { + for call in packet_calls { + let storage_key = packet_storage_key(call); + let proof: Bytes = storage_proofs + .get(&storage_key) + .ok_or_else(|| anyhow!("missing storage proof for key {storage_key}"))? + .clone() + .into(); + match call { + routerCalls::recvPacket(call) => call.msg_.proofCommitment = proof, + routerCalls::ackPacket(call) => call.msg_.proofAcked = proof, + routerCalls::timeoutPacket(call) => call.msg_.proofTimeout = proof, + _ => unreachable!("only recv, ack, and timeout calls are constructed"), + } + } + Ok(()) +} + +fn map_storage_proofs( + expected_keys: &[B256], + storage_proofs: Vec, +) -> Result>> { + let expected_keys = expected_keys.iter().copied().collect::>(); + let mut proofs = HashMap::with_capacity(expected_keys.len()); + + for storage_proof in storage_proofs { + let key = storage_proof.key.as_b256(); + if !expected_keys.contains(&key) { + bail!("unexpected storage proof key {key}"); + } + if proofs + .insert(key, encode_rlp_node_list(&storage_proof.proof)) + .is_some() + { + bail!("duplicate storage proof key {key}"); + } + } + + if let Some(key) = expected_keys.iter().find(|key| !proofs.contains_key(*key)) { + bail!("missing storage proof for key {key}"); + } + Ok(proofs) +} + +fn parse_create_client_params(parameters: &HashMap) -> Result { + parameters + .keys() + .find(|key| { + ![TRUSTING_PERIOD, MAX_CLOCK_DRIFT, TRUSTED_HEIGHT, ROLE_MANAGER] + .contains(&key.as_str()) + }) + .map_or(Ok(()), |key| { + Err(anyhow!( + "unexpected parameter `{key}`, only `{TRUSTING_PERIOD}`, `{MAX_CLOCK_DRIFT}`, `{TRUSTED_HEIGHT}`, and `{ROLE_MANAGER}` are allowed" + )) + })?; + + Ok(CreateClientParams { + trusting_period: parameters + .get(TRUSTING_PERIOD) + .ok_or_else(|| anyhow!("missing `{TRUSTING_PERIOD}` parameter"))? + .parse() + .with_context(|| format!("failed to parse `{TRUSTING_PERIOD}` as decimal seconds"))?, + max_clock_drift: parameters + .get(MAX_CLOCK_DRIFT) + .ok_or_else(|| anyhow!("missing `{MAX_CLOCK_DRIFT}` parameter"))? + .parse() + .with_context(|| format!("failed to parse `{MAX_CLOCK_DRIFT}` as decimal seconds"))?, + trusted_height: parameters + .get(TRUSTED_HEIGHT) + .map(|value| { + value.parse().with_context(|| { + format!("failed to parse `{TRUSTED_HEIGHT}` as decimal block height") + }) + }) + .transpose()?, + role_manager: parameters + .get(ROLE_MANAGER) + .map_or(Ok(Address::ZERO), |value| { + Address::from_str(value) + .with_context(|| format!("failed to parse `{ROLE_MANAGER}` as hex address")) + })?, + }) +} + +fn encode_rlp_node_list(nodes: &[Bytes]) -> Vec { + let payload_length = nodes.iter().map(|node| node.len()).sum(); + let mut encoded = Vec::new(); + RlpHeader { + list: true, + payload_length, + } + .encode(&mut encoded); + for node in nodes { + encoded.extend_from_slice(node.as_ref()); + } + encoded +} + +fn extract_validators_from_extra_data(extra_data: &[u8]) -> Result> { + let extra_data = Rlp::new(extra_data); + let validators = extra_data + .at(1) + .context("failed to read validator list from extraData")?; + + let mut out = Vec::with_capacity( + validators + .item_count() + .context("failed to read validator count")?, + ); + for validator in &validators { + let validator = validator + .data() + .context("failed to decode validator address")?; + if validator.len() != 20 { + bail!("invalid validator address length: {}", validator.len()); + } + out.push(Address::from_slice(validator)); + } + Ok(out) +} + +#[cfg(test)] +mod tests { + use super::{encode_rlp_node_list, extract_validators_from_extra_data, map_storage_proofs}; + use alloy::{ + consensus::Header, + primitives::{hex, Address, Bytes, B256, U256}, + rpc::types::EIP1186StorageProof, + }; + use alloy_rlp::Decodable; + use serde::Deserialize; + use std::str::FromStr; + + #[derive(Debug, Deserialize)] + #[serde(rename_all = "camelCase")] + struct Fixture { + non_adjacent_update: UpdateFixture, + membership: ProofFixture, + non_membership: ProofFixture, + } + + #[derive(Debug, Deserialize)] + #[serde(rename_all = "camelCase")] + struct UpdateFixture { + header_rlp: String, + account_proof: String, + expected_validators: Vec, + } + + #[derive(Debug, Deserialize)] + #[serde(rename_all = "camelCase")] + struct ProofFixture { + proof: String, + } + + fn load_fixture() -> Fixture { + serde_json::from_str(include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../../../ibc-solidity/test/besu-bft/fixtures/qbft.json" + ))) + .unwrap() + } + + fn decode_hex_bytes(hex_value: &str) -> Vec { + hex::decode(hex_value.trim_start_matches("0x")).unwrap() + } + + fn decode_proof_nodes(proof_rlp: &[u8]) -> Vec { + let proof = rlp::Rlp::new(proof_rlp); + proof + .iter() + .map(|node| Bytes::copy_from_slice(node.as_raw())) + .collect() + } + + #[test] + fn extracts_validators_from_fixture_header() { + let fixture = load_fixture(); + let header_rlp = decode_hex_bytes(&fixture.non_adjacent_update.header_rlp); + let header = Header::decode(&mut header_rlp.as_slice()).unwrap(); + let validators = extract_validators_from_extra_data(&header.extra_data).unwrap(); + let expected = fixture + .non_adjacent_update + .expected_validators + .iter() + .map(|address| Address::from_str(address).unwrap()) + .collect::>(); + + assert_eq!(validators, expected); + } + + #[test] + fn packs_account_proof_nodes_without_reencoding_nodes() { + let fixture = load_fixture(); + let account_proof_rlp = decode_hex_bytes(&fixture.non_adjacent_update.account_proof); + let nodes = decode_proof_nodes(&account_proof_rlp); + + assert_eq!(encode_rlp_node_list(&nodes), account_proof_rlp); + } + + #[test] + fn packs_membership_and_non_membership_storage_proofs() { + let fixture = load_fixture(); + let membership_proof = decode_hex_bytes(&fixture.membership.proof); + let non_membership_proof = decode_hex_bytes(&fixture.non_membership.proof); + + let membership_nodes = decode_proof_nodes(&membership_proof); + let non_membership_nodes = decode_proof_nodes(&non_membership_proof); + + assert_eq!(encode_rlp_node_list(&membership_nodes), membership_proof); + assert_eq!( + encode_rlp_node_list(&non_membership_nodes), + non_membership_proof + ); + } + + #[test] + fn maps_storage_proofs_by_normalized_key_and_validates_the_response() { + let first = B256::from(U256::from(1)); + let second = B256::from(U256::from(2)); + let make_proof = |key, marker| EIP1186StorageProof { + key, + value: U256::ZERO, + proof: vec![Bytes::from(vec![marker])], + }; + + let mapped = map_storage_proofs( + &[first, second, first], + vec![ + make_proof(second.into(), 2), + make_proof(U256::from(1).into(), 1), + ], + ) + .unwrap(); + assert_eq!( + mapped[&first], + encode_rlp_node_list(&[Bytes::from(vec![1])]) + ); + assert_eq!( + mapped[&second], + encode_rlp_node_list(&[Bytes::from(vec![2])]) + ); + + assert!(map_storage_proofs(&[first], vec![]) + .unwrap_err() + .to_string() + .contains("missing storage proof")); + assert!(map_storage_proofs( + &[first], + vec![make_proof(first.into(), 1), make_proof(first.into(), 1)] + ) + .unwrap_err() + .to_string() + .contains("duplicate storage proof")); + assert!( + map_storage_proofs(&[first], vec![make_proof(second.into(), 2)]) + .unwrap_err() + .to_string() + .contains("unexpected storage proof") + ); + } +} diff --git a/packages/solidity/src/besu.rs b/packages/solidity/src/besu.rs new file mode 100644 index 000000000..576a72701 --- /dev/null +++ b/packages/solidity/src/besu.rs @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: Apache-2.0 + +pub mod besu_ibft2_light_client { + #[cfg(feature = "rpc")] + alloy_sol_types::sol!( + #[sol(rpc)] + #[allow(clippy::nursery, clippy::too_many_arguments)] + BesuIBFT2LightClient, + "../../ibc-solidity/abi/bytecode/BesuIBFT2LightClient.json" + ); + + #[cfg(not(feature = "rpc"))] + alloy_sol_types::sol!( + BesuIBFT2LightClient, + "../../ibc-solidity/abi/BesuIBFT2LightClient.json" + ); +} + +pub mod besu_qbft_light_client { + #[cfg(feature = "rpc")] + alloy_sol_types::sol!( + #[sol(rpc)] + #[allow(clippy::nursery, clippy::too_many_arguments)] + BesuQBFTLightClient, + "../../ibc-solidity/abi/bytecode/BesuQBFTLightClient.json" + ); + + #[cfg(not(feature = "rpc"))] + alloy_sol_types::sol!( + BesuQBFTLightClient, + "../../ibc-solidity/abi/BesuQBFTLightClient.json" + ); +} diff --git a/packages/solidity/src/lib.rs b/packages/solidity/src/lib.rs index 18f1cbcb8..aea6d3f49 100644 --- a/packages/solidity/src/lib.rs +++ b/packages/solidity/src/lib.rs @@ -5,6 +5,7 @@ #![deny(clippy::nursery, clippy::pedantic, warnings, unused_crate_dependencies)] pub mod attestation; +pub mod besu; pub mod ics26; pub mod msgs; pub mod sp1_ics07; diff --git a/packages/solidity/src/msgs.rs b/packages/solidity/src/msgs.rs index c0a867d2c..c775ce6f5 100644 --- a/packages/solidity/src/msgs.rs +++ b/packages/solidity/src/msgs.rs @@ -45,6 +45,9 @@ alloy_sol_types::sol!( alloy_sol_types::sol!( "../../ibc-solidity/contracts/light-clients/attestation/msgs/IAttestationLightClientMsgs.sol" ); +alloy_sol_types::sol!( + "../../ibc-solidity/contracts/light-clients/besu/msgs/IBesuLightClientMsgs.sol" +); #[cfg(feature = "rpc")] impl ISP1Msgs::SP1Proof { diff --git a/programs/proof-api/Cargo.toml b/programs/proof-api/Cargo.toml index 70427d9ff..4263d9d31 100644 --- a/programs/proof-api/Cargo.toml +++ b/programs/proof-api/Cargo.toml @@ -11,6 +11,7 @@ proof-api-eth-to-cosmos = { workspace = true, default-features = false } proof-api-eth-to-cosmos-compat = { workspace = true, default-features = false } proof-api-cosmos-to-eth = { workspace = true, default-features = false } proof-api-eth-to-eth = { workspace = true, default-features = false } +proof-api-besu-to-eth = { workspace = true, default-features = false } proof-api-cosmos-to-cosmos = { workspace = true, default-features = false } proof-api-solana-to-cosmos = { workspace = true, default-features = false } proof-api-cosmos-to-solana = { workspace = true, default-features = false } diff --git a/programs/proof-api/README.md b/programs/proof-api/README.md index 9bced7883..81072bccd 100644 --- a/programs/proof-api/README.md +++ b/programs/proof-api/README.md @@ -23,6 +23,7 @@ Each module runs in one direction and specializes in how it builds proofs and tr | `cosmos_to_eth` | Cosmos SDK | EVM | Parse Cosmos events, build EVM IBC txs | `sp1` — ZK proofs via SP1
`attested` — multisig attestations | | `eth_to_cosmos` | EVM | Cosmos SDK | Parse EVM events, build Cosmos IBC txs | `real` — ethereum mainnet beacon API proofs
`mock` — dev/test mode
`attested` — multisig attestations | | `eth_to_eth` | EVM | EVM | Parse EVM events, build attested txs | `attested` — multisig attestations | +| `besu_to_eth` | Besu BFT EVM | EVM | Parse EVM events, build EVM real-proof txs | direct Besu light-client updates + Besu account/storage proofs | | `cosmos_to_cosmos` | Cosmos SDK | Cosmos SDK | Parse Cosmos events, build Cosmos IBC txs | ICS-07 light client proofs only (validator signatures and merkle proofs) | | `cosmos_to_solana` | Cosmos SDK | Solana | Parse Cosmos events, build Solana IBC txs | ICS-07 light client proofs only (validator signatures and merkle proofs) | | `solana_to_cosmos` | Solana | Cosmos SDK | Parse Solana events, build Cosmos IBC txs | multisig attestations only | @@ -62,7 +63,7 @@ Key settings: - `observability.use_otel`: Enable OpenTelemetry export. - `observability.service_name`: Service name used in logs/traces. - `observability.otel_endpoint`: OpenTelemetry collector endpoint. -- `modules`: List of modules to run, each with `name`, `src_chain`, `dst_chain`, `config`, and optional `enabled` (defaults to true). For `eth_to_eth`, `Info` returns the routed `src_chain` as the source identity and the destination RPC chain ID as the target identity. +- `modules`: List of modules to run, each with `name`, `src_chain`, `dst_chain`, `config`, and optional `enabled` (defaults to true). For EVM-to-EVM modules, `Info` returns the routed `src_chain` as the source identity and the destination RPC chain ID as the target identity. Module configuration varies by module type. Mode-specific options are enumerated below. @@ -124,6 +125,12 @@ Module configuration varies by module type: - `mode.cache`: Optional cache config. - `mode.cache.state_cache_max_entries`. (default: 10000) - `mode.cache.packet_cache_max_entries`. (default: 10000) +- `besu_to_eth`: + - `src_rpc_url`: Source Besu RPC endpoint. + - `src_ics26_address`: Source IBC router contract address. + - `dst_rpc_url`: Destination EVM RPC endpoint. + - `dst_ics26_address`: Destination IBC router contract address. + - `consensus_type`: Source Besu consensus type, `qbft` or `ibft2`. - `cosmos_to_cosmos`: - `src_rpc_url`: RPC endpoint for the source chain. - `target_rpc_url`: RPC endpoint for the destination chain. @@ -142,6 +149,23 @@ Module configuration varies by module type: - `signer_address`: Cosmos address used for message construction metadata. - `solana_ics26_program_id`: Solana ICS26 router program ID. +## `besu_to_eth` create-client parameters + +`besu_to_eth` `CreateClient` returns only deployment calldata for `BesuQBFTLightClient` or `BesuIBFT2LightClient`. It does not call `ICS26Router.addClient(...)`. + +Required parameters: +- `trusting_period`: Decimal seconds for the weak-subjectivity window. +- `max_clock_drift`: Decimal seconds for allowed future header drift. + +Optional parameters: +- `trusted_height`: Decimal source block height. Defaults to the latest source block. +- `role_manager`: Hex address. Defaults to the zero address. + +Operational notes: +- `consensus_type` is fixed by module config and only affects `CreateClient` wrapper selection. +- `UpdateClient` is a single direct Besu update. No catch-up or intermediate-header search is performed. +- `RelayByTx` uses real Besu proofs: full header RLP, one account proof in the client update, and storage proofs for recv/ack/timeout packet verification. + ## Using the gRPC API After the service is running, use the gRPC endpoints defined in [`proto/proofapi/proofapi.proto`](../../proto/proofapi/proofapi.proto) to submit transaction hashes and retrieve the unsigned IBC transactions plus proofs. Typical usage is: diff --git a/programs/proof-api/config.example.json b/programs/proof-api/config.example.json index effcb2fc4..883a02bf9 100644 --- a/programs/proof-api/config.example.json +++ b/programs/proof-api/config.example.json @@ -146,6 +146,19 @@ "mode": "real" } }, + { + "name": "besu_to_eth", + "src_chain": "besu-a", + "dst_chain": "besu-b", + "enabled": false, + "config": { + "src_rpc_url": "http://127.0.0.1:8545", + "src_ics26_address": "0x4242424242424242424242424242424242424242", + "dst_rpc_url": "http://127.0.0.1:9545", + "dst_ics26_address": "0x4242424242424242424242424242424242424242", + "consensus_type": "qbft" + } + }, { "name": "cosmos_to_cosmos", "src_chain": "cosmoshub-4", diff --git a/programs/proof-api/src/bin/proof-api.rs b/programs/proof-api/src/bin/proof-api.rs index c247603c7..d9c151efe 100644 --- a/programs/proof-api/src/bin/proof-api.rs +++ b/programs/proof-api/src/bin/proof-api.rs @@ -5,6 +5,7 @@ use std::{net::SocketAddr, path::PathBuf}; use clap::Parser; use proof_api::cli::{Commands, ProofApiCli}; use proof_api::observability::init_observability; +use proof_api_besu_to_eth::BesuToEthProofApiModule; use proof_api_core::{builder::ProofApiBuilder, config::ProofApiConfig}; use proof_api_cosmos_to_cosmos::CosmosToCosmosProofApiModule; use proof_api_cosmos_to_eth::CosmosToEthProofApiModule; @@ -47,6 +48,7 @@ async fn main() -> anyhow::Result<()> { proof_api_builder.add_module(EthToCosmosProofApiModule); proof_api_builder.add_module(EthToCosmosCompatProofApiModule); proof_api_builder.add_module(EthToEthProofApiModule); + proof_api_builder.add_module(BesuToEthProofApiModule); proof_api_builder.add_module(SolanaToCosmosProofApiModule); proof_api_builder.add_module(CosmosToSolanaProofApiModule); proof_api_builder.add_module(EthToSolanaProofApiModule);