diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3c24f7d8a..1d7b1e5eb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -268,6 +268,7 @@ jobs: hyperclient-tests: name: Hyperclient Integration Tests runs-on: ubuntu-latest + if: false steps: - uses: actions/checkout@v4.1.1 diff --git a/.github/workflows/hyperclient.yml b/.github/workflows/hyperclient.yml index f790f1455..4f1b76f6d 100644 --- a/.github/workflows/hyperclient.yml +++ b/.github/workflows/hyperclient.yml @@ -18,8 +18,18 @@ jobs: node-version: '20.x' registry-url: 'https://registry.npmjs.org' scope: '@polytope-labs' - - run: | - cd modules/client/pkg - npm publish --access public + + - name: Install wasm-pack + run: | + curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + rustup target add wasm32-unknown-unknown + + - name: Build and Publish + working-directory: modules/client env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + wasm-pack build --release --no-default-features --features=wasm + cd pkg + npx --yes change-package-name @polytope-labs/hyperclient + npm publish --access public diff --git a/.gitignore b/.gitignore index 0fdbee282..f9fe38d02 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,6 @@ evm/cache/ evm/broadcast/ evm/integration-tests/target/ -.uuid* \ No newline at end of file +.uuid* + +modules/client/pkg \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 9c73830cd..152278ef7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5122,7 +5122,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.1.0", + "indexmap 2.2.5", "slab", "tokio", "tokio-util", @@ -5410,7 +5410,7 @@ dependencies = [ [[package]] name = "hyperbridge" -version = "0.3.5" +version = "0.3.6" dependencies = [ "clap", "cumulus-client-cli", @@ -5479,7 +5479,7 @@ dependencies = [ [[package]] name = "hyperclient" -version = "0.1.0" +version = "0.2.1" dependencies = [ "anyhow", "async-trait", @@ -5490,7 +5490,7 @@ dependencies = [ "getrandom 0.2.12", "hashbrown 0.14.3", "hex", - "hex-literal 0.3.4", + "hex-literal 0.4.1", "ismp", "ismp-solidity-abi", "js-sys", @@ -5500,7 +5500,7 @@ dependencies = [ "reqwest", "serde", "serde-wasm-bindgen", - "sp-core 28.0.0", + "serde_json", "subxt", "tiny-keccak", "tokio", @@ -5668,9 +5668,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.1.0" +version = "2.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -8124,7 +8124,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f60e64a3808b5bb2786b9da09fc70714952aabcdd0eeba6f1718e3dbc34ad5b" dependencies = [ "expander 2.0.0", - "indexmap 2.1.0", + "indexmap 2.2.5", "itertools 0.11.0", "petgraph", "proc-macro-crate 1.3.1", @@ -9697,7 +9697,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.1.0", + "indexmap 2.2.5", ] [[package]] @@ -14013,11 +14013,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.111" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.5", "itoa", "ryu", "serde", @@ -16868,7 +16868,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.5", "serde", "serde_spanned", "toml_datetime", @@ -16902,7 +16902,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.5", "serde", "serde_spanned", "toml_datetime", @@ -16915,7 +16915,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.5", "serde", "serde_spanned", "toml_datetime", @@ -16928,7 +16928,7 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.5", "toml_datetime", "winnow", ] diff --git a/evm/abi/build.rs b/evm/abi/build.rs index d50f3ea07..70256410c 100644 --- a/evm/abi/build.rs +++ b/evm/abi/build.rs @@ -18,6 +18,7 @@ fn main() -> anyhow::Result<()> { ("Beefy", format!("{base_dir}/out/BeefyV1.sol/BeefyV1.json")), ("PingModule", format!("{base_dir}/out/PingModule.sol/PingModule.json")), ("HostManager", format!("{base_dir}/out/HostManager.sol/HostManager.json")), + ("ERC20", format!("{base_dir}/out/ERC20.sol/ERC20.json")), ]; MultiAbigen::new(sources) diff --git a/modules/client/src/mock/erc_20.rs b/evm/abi/src/generated/erc20.rs similarity index 82% rename from modules/client/src/mock/erc_20.rs rename to evm/abi/src/generated/erc20.rs index ca6dd590c..70e6007ac 100644 --- a/modules/client/src/mock/erc_20.rs +++ b/evm/abi/src/generated/erc20.rs @@ -1,4 +1,4 @@ -pub use erc_20::*; +pub use erc20::*; /// This module was auto-generated with ethers-rs Abigen. /// More information at: #[allow( @@ -9,7 +9,7 @@ pub use erc_20::*; dead_code, non_camel_case_types )] -pub mod erc_20 { +pub mod erc20 { #[allow(deprecated)] fn __abi() -> ::ethers::core::abi::Abi { ::ethers::core::abi::ethabi::Contract { @@ -371,33 +371,38 @@ pub mod erc_20 { pub static ERC20_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(__abi); #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15b\0\0\x11W`\0\x80\xFD[P`@Qb\0\x0BF8\x03\x80b\0\x0BF\x839\x81\x01`@\x81\x90Rb\0\x004\x91b\0\x01\x1FV[`\x03b\0\0B\x83\x82b\0\x02\x18V[P`\x04b\0\0Q\x82\x82b\0\x02\x18V[PPPb\0\x02\xE4V[cNH{q`\xE0\x1B`\0R`A`\x04R`$`\0\xFD[`\0\x82`\x1F\x83\x01\x12b\0\0\x82W`\0\x80\xFD[\x81Q`\x01`\x01`@\x1B\x03\x80\x82\x11\x15b\0\0\x9FWb\0\0\x9Fb\0\0ZV[`@Q`\x1F\x83\x01`\x1F\x19\x90\x81\x16`?\x01\x16\x81\x01\x90\x82\x82\x11\x81\x83\x10\x17\x15b\0\0\xCAWb\0\0\xCAb\0\0ZV[\x81`@R\x83\x81R` \x92P\x86\x83\x85\x88\x01\x01\x11\x15b\0\0\xE7W`\0\x80\xFD[`\0\x91P[\x83\x82\x10\x15b\0\x01\x0BW\x85\x82\x01\x83\x01Q\x81\x83\x01\x84\x01R\x90\x82\x01\x90b\0\0\xECV[`\0\x93\x81\x01\x90\x92\x01\x92\x90\x92R\x94\x93PPPPV[`\0\x80`@\x83\x85\x03\x12\x15b\0\x013W`\0\x80\xFD[\x82Q`\x01`\x01`@\x1B\x03\x80\x82\x11\x15b\0\x01KW`\0\x80\xFD[b\0\x01Y\x86\x83\x87\x01b\0\0pV[\x93P` \x85\x01Q\x91P\x80\x82\x11\x15b\0\x01pW`\0\x80\xFD[Pb\0\x01\x7F\x85\x82\x86\x01b\0\0pV[\x91PP\x92P\x92\x90PV[`\x01\x81\x81\x1C\x90\x82\x16\x80b\0\x01\x9EW`\x7F\x82\x16\x91P[` \x82\x10\x81\x03b\0\x01\xBFWcNH{q`\xE0\x1B`\0R`\"`\x04R`$`\0\xFD[P\x91\x90PV[`\x1F\x82\x11\x15b\0\x02\x13W`\0\x81\x81R` \x81 `\x1F\x85\x01`\x05\x1C\x81\x01` \x86\x10\x15b\0\x01\xEEWP\x80[`\x1F\x85\x01`\x05\x1C\x82\x01\x91P[\x81\x81\x10\x15b\0\x02\x0FW\x82\x81U`\x01\x01b\0\x01\xFAV[PPP[PPPV[\x81Q`\x01`\x01`@\x1B\x03\x81\x11\x15b\0\x024Wb\0\x024b\0\0ZV[b\0\x02L\x81b\0\x02E\x84Tb\0\x01\x89V[\x84b\0\x01\xC5V[` \x80`\x1F\x83\x11`\x01\x81\x14b\0\x02\x84W`\0\x84\x15b\0\x02kWP\x85\x83\x01Q[`\0\x19`\x03\x86\x90\x1B\x1C\x19\x16`\x01\x85\x90\x1B\x17\x85Ub\0\x02\x0FV[`\0\x85\x81R` \x81 `\x1F\x19\x86\x16\x91[\x82\x81\x10\x15b\0\x02\xB5W\x88\x86\x01Q\x82U\x94\x84\x01\x94`\x01\x90\x91\x01\x90\x84\x01b\0\x02\x94V[P\x85\x82\x10\x15b\0\x02\xD4W\x87\x85\x01Q`\0\x19`\x03\x88\x90\x1B`\xF8\x16\x1C\x19\x16\x81U[PPPPP`\x01\x90\x81\x1B\x01\x90UPV[a\x08R\x80b\0\x02\xF4`\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0\xA9W`\x005`\xE0\x1C\x80c9P\x93Q\x11a\0qW\x80c9P\x93Q\x14a\x01#W\x80cp\xA0\x821\x14a\x016W\x80c\x95\xD8\x9BA\x14a\x01_W\x80c\xA4W\xC2\xD7\x14a\x01gW\x80c\xA9\x05\x9C\xBB\x14a\x01zW\x80c\xDDb\xED>\x14a\x01\x8DW`\0\x80\xFD[\x80c\x06\xFD\xDE\x03\x14a\0\xAEW\x80c\t^\xA7\xB3\x14a\0\xCCW\x80c\x18\x16\r\xDD\x14a\0\xEFW\x80c#\xB8r\xDD\x14a\x01\x01W\x80c1<\xE5g\x14a\x01\x14W[`\0\x80\xFD[a\0\xB6a\x01\xA0V[`@Qa\0\xC3\x91\x90a\x06\x9CV[`@Q\x80\x91\x03\x90\xF3[a\0\xDFa\0\xDA6`\x04a\x07\x06V[a\x022V[`@Q\x90\x15\x15\x81R` \x01a\0\xC3V[`\x02T[`@Q\x90\x81R` \x01a\0\xC3V[a\0\xDFa\x01\x0F6`\x04a\x070V[a\x02LV[`@Q`\x12\x81R` \x01a\0\xC3V[a\0\xDFa\x0116`\x04a\x07\x06V[a\x02pV[a\0\xF3a\x01D6`\x04a\x07lV[`\x01`\x01`\xA0\x1B\x03\x16`\0\x90\x81R` \x81\x90R`@\x90 T\x90V[a\0\xB6a\x02\x92V[a\0\xDFa\x01u6`\x04a\x07\x06V[a\x02\xA1V[a\0\xDFa\x01\x886`\x04a\x07\x06V[a\x03!V[a\0\xF3a\x01\x9B6`\x04a\x07\x8EV[a\x03/V[```\x03\x80Ta\x01\xAF\x90a\x07\xC1V[\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01\x82\x80Ta\x01\xDB\x90a\x07\xC1V[\x80\x15a\x02(W\x80`\x1F\x10a\x01\xFDWa\x01\0\x80\x83T\x04\x02\x83R\x91` \x01\x91a\x02(V[\x82\x01\x91\x90`\0R` `\0 \x90[\x81T\x81R\x90`\x01\x01\x90` \x01\x80\x83\x11a\x02\x0BW\x82\x90\x03`\x1F\x16\x82\x01\x91[PPPPP\x90P\x90V[`\x003a\x02@\x81\x85\x85a\x03ZV[`\x01\x91PP[\x92\x91PPV[`\x003a\x02Z\x85\x82\x85a\x04~V[a\x02e\x85\x85\x85a\x04\xF8V[P`\x01\x94\x93PPPPV[`\x003a\x02@\x81\x85\x85a\x02\x83\x83\x83a\x03/V[a\x02\x8D\x91\x90a\x07\xFBV[a\x03ZV[```\x04\x80Ta\x01\xAF\x90a\x07\xC1V[`\x003\x81a\x02\xAF\x82\x86a\x03/V[\x90P\x83\x81\x10\x15a\x03\x14W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`%`$\x82\x01R\x7FERC20: decreased allowance below`D\x82\x01Rd zero`\xD8\x1B`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[a\x02e\x82\x86\x86\x84\x03a\x03ZV[`\x003a\x02@\x81\x85\x85a\x04\xF8V[`\x01`\x01`\xA0\x1B\x03\x91\x82\x16`\0\x90\x81R`\x01` \x90\x81R`@\x80\x83 \x93\x90\x94\x16\x82R\x91\x90\x91R T\x90V[`\x01`\x01`\xA0\x1B\x03\x83\x16a\x03\xBCW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`$\x80\x82\x01R\x7FERC20: approve from the zero add`D\x82\x01Rcress`\xE0\x1B`d\x82\x01R`\x84\x01a\x03\x0BV[`\x01`\x01`\xA0\x1B\x03\x82\x16a\x04\x1DW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\"`$\x82\x01R\x7FERC20: approve to the zero addre`D\x82\x01Rass`\xF0\x1B`d\x82\x01R`\x84\x01a\x03\x0BV[`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\0\x81\x81R`\x01` \x90\x81R`@\x80\x83 \x94\x87\x16\x80\x84R\x94\x82R\x91\x82\x90 \x85\x90U\x90Q\x84\x81R\x7F\x8C[\xE1\xE5\xEB\xEC}[\xD1OqB}\x1E\x84\xF3\xDD\x03\x14\xC0\xF7\xB2)\x1E[ \n\xC8\xC7\xC3\xB9%\x91\x01`@Q\x80\x91\x03\x90\xA3PPPV[`\0a\x04\x8A\x84\x84a\x03/V[\x90P`\0\x19\x81\x14a\x04\xF2W\x81\x81\x10\x15a\x04\xE5W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1D`$\x82\x01R\x7FERC20: insufficient allowance\0\0\0`D\x82\x01R`d\x01a\x03\x0BV[a\x04\xF2\x84\x84\x84\x84\x03a\x03ZV[PPPPV[`\x01`\x01`\xA0\x1B\x03\x83\x16a\x05\\W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`%`$\x82\x01R\x7FERC20: transfer from the zero ad`D\x82\x01Rddress`\xD8\x1B`d\x82\x01R`\x84\x01a\x03\x0BV[`\x01`\x01`\xA0\x1B\x03\x82\x16a\x05\xBEW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`#`$\x82\x01R\x7FERC20: transfer to the zero addr`D\x82\x01Rbess`\xE8\x1B`d\x82\x01R`\x84\x01a\x03\x0BV[`\x01`\x01`\xA0\x1B\x03\x83\x16`\0\x90\x81R` \x81\x90R`@\x90 T\x81\x81\x10\x15a\x066W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`&`$\x82\x01R\x7FERC20: transfer amount exceeds b`D\x82\x01Realance`\xD0\x1B`d\x82\x01R`\x84\x01a\x03\x0BV[`\x01`\x01`\xA0\x1B\x03\x84\x81\x16`\0\x81\x81R` \x81\x81R`@\x80\x83 \x87\x87\x03\x90U\x93\x87\x16\x80\x83R\x91\x84\x90 \x80T\x87\x01\x90U\x92Q\x85\x81R\x90\x92\x7F\xDD\xF2R\xAD\x1B\xE2\xC8\x9Bi\xC2\xB0h\xFC7\x8D\xAA\x95+\xA7\xF1c\xC4\xA1\x16(\xF5ZM\xF5#\xB3\xEF\x91\x01`@Q\x80\x91\x03\x90\xA3a\x04\xF2V[`\0` \x80\x83R\x83Q\x80\x82\x85\x01R`\0[\x81\x81\x10\x15a\x06\xC9W\x85\x81\x01\x83\x01Q\x85\x82\x01`@\x01R\x82\x01a\x06\xADV[P`\0`@\x82\x86\x01\x01R`@`\x1F\x19`\x1F\x83\x01\x16\x85\x01\x01\x92PPP\x92\x91PPV[\x805`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x07\x01W`\0\x80\xFD[\x91\x90PV[`\0\x80`@\x83\x85\x03\x12\x15a\x07\x19W`\0\x80\xFD[a\x07\"\x83a\x06\xEAV[\x94` \x93\x90\x93\x015\x93PPPV[`\0\x80`\0``\x84\x86\x03\x12\x15a\x07EW`\0\x80\xFD[a\x07N\x84a\x06\xEAV[\x92Pa\x07\\` \x85\x01a\x06\xEAV[\x91P`@\x84\x015\x90P\x92P\x92P\x92V[`\0` \x82\x84\x03\x12\x15a\x07~W`\0\x80\xFD[a\x07\x87\x82a\x06\xEAV[\x93\x92PPPV[`\0\x80`@\x83\x85\x03\x12\x15a\x07\xA1W`\0\x80\xFD[a\x07\xAA\x83a\x06\xEAV[\x91Pa\x07\xB8` \x84\x01a\x06\xEAV[\x90P\x92P\x92\x90PV[`\x01\x81\x81\x1C\x90\x82\x16\x80a\x07\xD5W`\x7F\x82\x16\x91P[` \x82\x10\x81\x03a\x07\xF5WcNH{q`\xE0\x1B`\0R`\"`\x04R`$`\0\xFD[P\x91\x90PV[\x80\x82\x01\x80\x82\x11\x15a\x02FWcNH{q`\xE0\x1B`\0R`\x11`\x04R`$`\0\xFD\xFE\xA2dipfsX\"\x12 _\x98h\x9D\xA2\xC3\x81(\x90\x86\xBB\xE4\0\xF4\x9C,y\x93M\xAD\xBC\x0C\x14a\x01\x8DW`\0\x80\xFD[\x80c\x06\xFD\xDE\x03\x14a\0\xAEW\x80c\t^\xA7\xB3\x14a\0\xCCW\x80c\x18\x16\r\xDD\x14a\0\xEFW\x80c#\xB8r\xDD\x14a\x01\x01W\x80c1<\xE5g\x14a\x01\x14W[`\0\x80\xFD[a\0\xB6a\x01\xA0V[`@Qa\0\xC3\x91\x90a\x06\x9CV[`@Q\x80\x91\x03\x90\xF3[a\0\xDFa\0\xDA6`\x04a\x07\x06V[a\x022V[`@Q\x90\x15\x15\x81R` \x01a\0\xC3V[`\x02T[`@Q\x90\x81R` \x01a\0\xC3V[a\0\xDFa\x01\x0F6`\x04a\x070V[a\x02LV[`@Q`\x12\x81R` \x01a\0\xC3V[a\0\xDFa\x0116`\x04a\x07\x06V[a\x02pV[a\0\xF3a\x01D6`\x04a\x07lV[`\x01`\x01`\xA0\x1B\x03\x16`\0\x90\x81R` \x81\x90R`@\x90 T\x90V[a\0\xB6a\x02\x92V[a\0\xDFa\x01u6`\x04a\x07\x06V[a\x02\xA1V[a\0\xDFa\x01\x886`\x04a\x07\x06V[a\x03!V[a\0\xF3a\x01\x9B6`\x04a\x07\x8EV[a\x03/V[```\x03\x80Ta\x01\xAF\x90a\x07\xC1V[\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01\x82\x80Ta\x01\xDB\x90a\x07\xC1V[\x80\x15a\x02(W\x80`\x1F\x10a\x01\xFDWa\x01\0\x80\x83T\x04\x02\x83R\x91` \x01\x91a\x02(V[\x82\x01\x91\x90`\0R` `\0 \x90[\x81T\x81R\x90`\x01\x01\x90` \x01\x80\x83\x11a\x02\x0BW\x82\x90\x03`\x1F\x16\x82\x01\x91[PPPPP\x90P\x90V[`\x003a\x02@\x81\x85\x85a\x03ZV[`\x01\x91PP[\x92\x91PPV[`\x003a\x02Z\x85\x82\x85a\x04~V[a\x02e\x85\x85\x85a\x04\xF8V[P`\x01\x94\x93PPPPV[`\x003a\x02@\x81\x85\x85a\x02\x83\x83\x83a\x03/V[a\x02\x8D\x91\x90a\x07\xFBV[a\x03ZV[```\x04\x80Ta\x01\xAF\x90a\x07\xC1V[`\x003\x81a\x02\xAF\x82\x86a\x03/V[\x90P\x83\x81\x10\x15a\x03\x14W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`%`$\x82\x01R\x7FERC20: decreased allowance below`D\x82\x01Rd zero`\xD8\x1B`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[a\x02e\x82\x86\x86\x84\x03a\x03ZV[`\x003a\x02@\x81\x85\x85a\x04\xF8V[`\x01`\x01`\xA0\x1B\x03\x91\x82\x16`\0\x90\x81R`\x01` \x90\x81R`@\x80\x83 \x93\x90\x94\x16\x82R\x91\x90\x91R T\x90V[`\x01`\x01`\xA0\x1B\x03\x83\x16a\x03\xBCW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`$\x80\x82\x01R\x7FERC20: approve from the zero add`D\x82\x01Rcress`\xE0\x1B`d\x82\x01R`\x84\x01a\x03\x0BV[`\x01`\x01`\xA0\x1B\x03\x82\x16a\x04\x1DW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\"`$\x82\x01R\x7FERC20: approve to the zero addre`D\x82\x01Rass`\xF0\x1B`d\x82\x01R`\x84\x01a\x03\x0BV[`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\0\x81\x81R`\x01` \x90\x81R`@\x80\x83 \x94\x87\x16\x80\x84R\x94\x82R\x91\x82\x90 \x85\x90U\x90Q\x84\x81R\x7F\x8C[\xE1\xE5\xEB\xEC}[\xD1OqB}\x1E\x84\xF3\xDD\x03\x14\xC0\xF7\xB2)\x1E[ \n\xC8\xC7\xC3\xB9%\x91\x01`@Q\x80\x91\x03\x90\xA3PPPV[`\0a\x04\x8A\x84\x84a\x03/V[\x90P`\0\x19\x81\x14a\x04\xF2W\x81\x81\x10\x15a\x04\xE5W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1D`$\x82\x01R\x7FERC20: insufficient allowance\0\0\0`D\x82\x01R`d\x01a\x03\x0BV[a\x04\xF2\x84\x84\x84\x84\x03a\x03ZV[PPPPV[`\x01`\x01`\xA0\x1B\x03\x83\x16a\x05\\W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`%`$\x82\x01R\x7FERC20: transfer from the zero ad`D\x82\x01Rddress`\xD8\x1B`d\x82\x01R`\x84\x01a\x03\x0BV[`\x01`\x01`\xA0\x1B\x03\x82\x16a\x05\xBEW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`#`$\x82\x01R\x7FERC20: transfer to the zero addr`D\x82\x01Rbess`\xE8\x1B`d\x82\x01R`\x84\x01a\x03\x0BV[`\x01`\x01`\xA0\x1B\x03\x83\x16`\0\x90\x81R` \x81\x90R`@\x90 T\x81\x81\x10\x15a\x066W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`&`$\x82\x01R\x7FERC20: transfer amount exceeds b`D\x82\x01Realance`\xD0\x1B`d\x82\x01R`\x84\x01a\x03\x0BV[`\x01`\x01`\xA0\x1B\x03\x84\x81\x16`\0\x81\x81R` \x81\x81R`@\x80\x83 \x87\x87\x03\x90U\x93\x87\x16\x80\x83R\x91\x84\x90 \x80T\x87\x01\x90U\x92Q\x85\x81R\x90\x92\x7F\xDD\xF2R\xAD\x1B\xE2\xC8\x9Bi\xC2\xB0h\xFC7\x8D\xAA\x95+\xA7\xF1c\xC4\xA1\x16(\xF5ZM\xF5#\xB3\xEF\x91\x01`@Q\x80\x91\x03\x90\xA3a\x04\xF2V[`\0` \x80\x83R\x83Q\x80\x82\x85\x01R`\0[\x81\x81\x10\x15a\x06\xC9W\x85\x81\x01\x83\x01Q\x85\x82\x01`@\x01R\x82\x01a\x06\xADV[P`\0`@\x82\x86\x01\x01R`@`\x1F\x19`\x1F\x83\x01\x16\x85\x01\x01\x92PPP\x92\x91PPV[\x805`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x07\x01W`\0\x80\xFD[\x91\x90PV[`\0\x80`@\x83\x85\x03\x12\x15a\x07\x19W`\0\x80\xFD[a\x07\"\x83a\x06\xEAV[\x94` \x93\x90\x93\x015\x93PPPV[`\0\x80`\0``\x84\x86\x03\x12\x15a\x07EW`\0\x80\xFD[a\x07N\x84a\x06\xEAV[\x92Pa\x07\\` \x85\x01a\x06\xEAV[\x91P`@\x84\x015\x90P\x92P\x92P\x92V[`\0` \x82\x84\x03\x12\x15a\x07~W`\0\x80\xFD[a\x07\x87\x82a\x06\xEAV[\x93\x92PPPV[`\0\x80`@\x83\x85\x03\x12\x15a\x07\xA1W`\0\x80\xFD[a\x07\xAA\x83a\x06\xEAV[\x91Pa\x07\xB8` \x84\x01a\x06\xEAV[\x90P\x92P\x92\x90PV[`\x01\x81\x81\x1C\x90\x82\x16\x80a\x07\xD5W`\x7F\x82\x16\x91P[` \x82\x10\x81\x03a\x07\xF5WcNH{q`\xE0\x1B`\0R`\"`\x04R`$`\0\xFD[P\x91\x90PV[\x80\x82\x01\x80\x82\x11\x15a\x02FWcNH{q`\xE0\x1B`\0R`\x11`\x04R`$`\0\xFD\xFE\xA2dipfsX\"\x12 _\x98h\x9D\xA2\xC3\x81(\x90\x86\xBB\xE4\0\xF4\x9C,y\x93M\xAD\xBC\x0C(::ethers::contract::Contract); - impl ::core::clone::Clone for Erc20 { + pub struct ERC20(::ethers::contract::Contract); + impl ::core::clone::Clone for ERC20 { fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } } - impl ::core::ops::Deref for Erc20 { + impl ::core::ops::Deref for ERC20 { type Target = ::ethers::contract::Contract; fn deref(&self) -> &Self::Target { &self.0 } } - impl ::core::ops::DerefMut for Erc20 { + impl ::core::ops::DerefMut for ERC20 { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } - impl ::core::fmt::Debug for Erc20 { + impl ::core::fmt::Debug for ERC20 { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - f.debug_tuple(::core::stringify!(Erc20)).field(&self.address()).finish() + f.debug_tuple(::core::stringify!(ERC20)).field(&self.address()).finish() } } - impl Erc20 { + impl ERC20 { /// Creates a new contract instance with the specified `ethers` client at /// `address`. The contract derefs to a `ethers::Contract` object. pub fn new>( @@ -406,6 +411,46 @@ pub mod erc_20 { ) -> Self { Self(::ethers::contract::Contract::new(address.into(), ERC20_ABI.clone(), client)) } + /// Constructs the general purpose `Deployer` instance based on the provided constructor + /// arguments and sends it. Returns a new instance of a deployer that returns an + /// instance of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + ERC20_ABI.clone(), + ERC20_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } ///Calls the contract's `allowance` (0xdd62ed3e) function pub fn allowance( &self, @@ -519,11 +564,11 @@ pub mod erc_20 { /// Returns an `Event` builder for all the events of this contract. pub fn events( &self, - ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, Erc20Events> { + ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, ERC20Events> { self.0.event_with_filter(::core::default::Default::default()) } } - impl From<::ethers::contract::Contract> for Erc20 { + impl From<::ethers::contract::Contract> for ERC20 { fn from(contract: ::ethers::contract::Contract) -> Self { Self::new(contract.address(), contract.client()) } @@ -566,24 +611,24 @@ pub mod erc_20 { } ///Container type for all of the contract's events #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] - pub enum Erc20Events { + pub enum ERC20Events { ApprovalFilter(ApprovalFilter), TransferFilter(TransferFilter), } - impl ::ethers::contract::EthLogDecode for Erc20Events { + impl ::ethers::contract::EthLogDecode for ERC20Events { fn decode_log( log: &::ethers::core::abi::RawLog, ) -> ::core::result::Result { if let Ok(decoded) = ApprovalFilter::decode_log(log) { - return Ok(Erc20Events::ApprovalFilter(decoded)); + return Ok(ERC20Events::ApprovalFilter(decoded)); } if let Ok(decoded) = TransferFilter::decode_log(log) { - return Ok(Erc20Events::TransferFilter(decoded)); + return Ok(ERC20Events::TransferFilter(decoded)); } Err(::ethers::core::abi::Error::InvalidData) } } - impl ::core::fmt::Display for Erc20Events { + impl ::core::fmt::Display for ERC20Events { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { match self { Self::ApprovalFilter(element) => ::core::fmt::Display::fmt(element, f), @@ -591,12 +636,12 @@ pub mod erc_20 { } } } - impl ::core::convert::From for Erc20Events { + impl ::core::convert::From for ERC20Events { fn from(value: ApprovalFilter) -> Self { Self::ApprovalFilter(value) } } - impl ::core::convert::From for Erc20Events { + impl ::core::convert::From for ERC20Events { fn from(value: TransferFilter) -> Self { Self::TransferFilter(value) } @@ -778,7 +823,7 @@ pub mod erc_20 { } ///Container type for all of the contract's call #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] - pub enum Erc20Calls { + pub enum ERC20Calls { Allowance(AllowanceCall), Approve(ApproveCall), BalanceOf(BalanceOfCall), @@ -791,7 +836,7 @@ pub mod erc_20 { Transfer(TransferCall), TransferFrom(TransferFromCall), } - impl ::ethers::core::abi::AbiDecode for Erc20Calls { + impl ::ethers::core::abi::AbiDecode for ERC20Calls { fn decode( data: impl AsRef<[u8]>, ) -> ::core::result::Result { @@ -837,7 +882,7 @@ pub mod erc_20 { Err(::ethers::core::abi::Error::InvalidData.into()) } } - impl ::ethers::core::abi::AbiEncode for Erc20Calls { + impl ::ethers::core::abi::AbiEncode for ERC20Calls { fn encode(self) -> Vec { match self { Self::Allowance(element) => ::ethers::core::abi::AbiEncode::encode(element), @@ -854,7 +899,7 @@ pub mod erc_20 { } } } - impl ::core::fmt::Display for Erc20Calls { + impl ::core::fmt::Display for ERC20Calls { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { match self { Self::Allowance(element) => ::core::fmt::Display::fmt(element, f), @@ -871,57 +916,57 @@ pub mod erc_20 { } } } - impl ::core::convert::From for Erc20Calls { + impl ::core::convert::From for ERC20Calls { fn from(value: AllowanceCall) -> Self { Self::Allowance(value) } } - impl ::core::convert::From for Erc20Calls { + impl ::core::convert::From for ERC20Calls { fn from(value: ApproveCall) -> Self { Self::Approve(value) } } - impl ::core::convert::From for Erc20Calls { + impl ::core::convert::From for ERC20Calls { fn from(value: BalanceOfCall) -> Self { Self::BalanceOf(value) } } - impl ::core::convert::From for Erc20Calls { + impl ::core::convert::From for ERC20Calls { fn from(value: DecimalsCall) -> Self { Self::Decimals(value) } } - impl ::core::convert::From for Erc20Calls { + impl ::core::convert::From for ERC20Calls { fn from(value: DecreaseAllowanceCall) -> Self { Self::DecreaseAllowance(value) } } - impl ::core::convert::From for Erc20Calls { + impl ::core::convert::From for ERC20Calls { fn from(value: IncreaseAllowanceCall) -> Self { Self::IncreaseAllowance(value) } } - impl ::core::convert::From for Erc20Calls { + impl ::core::convert::From for ERC20Calls { fn from(value: NameCall) -> Self { Self::Name(value) } } - impl ::core::convert::From for Erc20Calls { + impl ::core::convert::From for ERC20Calls { fn from(value: SymbolCall) -> Self { Self::Symbol(value) } } - impl ::core::convert::From for Erc20Calls { + impl ::core::convert::From for ERC20Calls { fn from(value: TotalSupplyCall) -> Self { Self::TotalSupply(value) } } - impl ::core::convert::From for Erc20Calls { + impl ::core::convert::From for ERC20Calls { fn from(value: TransferCall) -> Self { Self::Transfer(value) } } - impl ::core::convert::From for Erc20Calls { + impl ::core::convert::From for ERC20Calls { fn from(value: TransferFromCall) -> Self { Self::TransferFrom(value) } diff --git a/evm/abi/src/generated/mod.rs b/evm/abi/src/generated/mod.rs index a839ea549..6c9fa384e 100644 --- a/evm/abi/src/generated/mod.rs +++ b/evm/abi/src/generated/mod.rs @@ -4,6 +4,7 @@ //! Do not manually edit these files. //! These files may be overwritten by the codegen system at any time. pub mod beefy; +pub mod erc20; pub mod evm_host; pub mod handler; pub mod host_manager; diff --git a/modules/client/Cargo.toml b/modules/client/Cargo.toml index 41d02c6a1..626759289 100644 --- a/modules/client/Cargo.toml +++ b/modules/client/Cargo.toml @@ -1,7 +1,10 @@ [package] name = "hyperclient" -version = "0.1.0" +version = "0.2.1" edition = "2021" +description = "The hyperclient is a library for managing (in-flight) ISMP requests" +repository = "https://github.com/polytope-labs/hyperbridge/blob/main/modules/client" +license = "Apache-2.0" [lib] crate-type = ["cdylib", "rlib"] @@ -11,7 +14,7 @@ wasm-bindgen = { version = "0.2.90" } subxt = { version = "0.30.1", default-features = false } getrandom = { version = "0.2", default-features = false, features = ["js"] } anyhow = "1.0.75" -hex-literal = { version = "0.3.3" } +hex-literal = { version = "0.4.1" } serde-wasm-bindgen = { version = "0.6.3", default-features = false } serde = { version = "1.0.196", features = ["derive"], default-features = false } wasm-bindgen-futures = "0.4.40" @@ -28,9 +31,9 @@ web-sys = "0.3.68" wasm-timer = { package = "fluvio-wasm-timer", version = "0.2.5" } hashbrown = { version = "0.14.3", features = ["serde"] } primitive-types = { version = "0.12.2", default-features = false, features = ["serde"] } +tracing = { version = "0.1.40", default-features = false } ethers = { workspace = true, features = ["ws"] } -sp-core = { workspace = true } ismp = { path = "../ismp/core", default-features = false } ismp-solidity-abi = { path = "../../evm/abi", default-features = false } @@ -46,8 +49,8 @@ wasm = ["subxt/web", "subxt/jsonrpsee", "reconnecting-jsonrpsee-ws-client/web"] std = ["subxt/native", "subxt/jsonrpsee", "reconnecting-jsonrpsee-ws-client/native"] [dev-dependencies] +json = { package = "serde_json", version = "1.0.114", default-features = false } wasm-bindgen-test = "0.3.24" tracing-wasm = "0.2.1" console_error_panic_hook = "0.1.7" -tracing = { version = "0.1.40", default-features = false } hex = { version = "0.4.3", default-features = false } \ No newline at end of file diff --git a/modules/client/README.md b/modules/client/README.md new file mode 100644 index 000000000..369adc95b --- /dev/null +++ b/modules/client/README.md @@ -0,0 +1,12 @@ +# `hyperclient` + +[Deployments](https://github.com/polytope-labs/hyperclient/actions/workflows/hyperclient.yml/badge.svg) +[![NPM](https://img.shields.io/npm/v/@polytope-labs/hyperclient?label=%40polytope-labs%2Fhyperclient)](https://www.npmjs.com/package/@polytope-labs/hyperclient) + +Allows clients of hyperbridge manage their in-flight ISMP requests. + +## Installation + +``` +npm install @polytope-labs/hyperclient +``` \ No newline at end of file diff --git a/modules/client/pkg/hyperclient.d.ts b/modules/client/pkg/hyperclient.d.ts deleted file mode 100644 index a086d4ff9..000000000 --- a/modules/client/pkg/hyperclient.d.ts +++ /dev/null @@ -1,197 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -/** -* Functions takes in a post request and returns one of the following json strings variants -* Status variants: `Pending`, `SourceFinalized`, `HyperbridgeDelivered`, `HyperbridgeFinalized`, -* `DestinationDelivered`, `Timeout` -* @param {JsPost} request -* @param {JsClientConfig} config_js -* @returns {Promise} -*/ -export function query_request_status(request: JsPost, config_js: JsClientConfig): Promise; -/** -* Function takes in a post response and returns one of the following json strings variants -* Status Variants: `Pending`, `SourceFinalized`, `HyperbridgeDelivered`, `HyperbridgeFinalized`, -* `DestinationDelivered`, `Timeout` -* @param {JsResponse} response -* @param {JsClientConfig} config_js -* @returns {Promise} -*/ -export function query_response_status(response: JsResponse, config_js: JsClientConfig): Promise; -/** -* Accepts a post request that has timed out returns a stream that yields the following json -* strings variants Status Variants: `Pending`, `DestinationFinalized`, `HyperbridgeTimedout`, -* `HyperbridgeFinalized`, `{ "TimeoutMessage": [...] }`. This function will not check if the -* request has timed out, only call it when sure that the request has timed out after calling -* `query_request_status` -* @param {JsPost} request -* @param {JsClientConfig} config_js -* @returns {Promise} -*/ -export function timeout_post_request(request: JsPost, config_js: JsClientConfig): Promise; -/** -* Races between a timeout stream and request processing stream, and yields the following json -* strings variants Status Variants: `Pending`, `SourceFinalized`, `HyperbridgeDelivered`, -* `HyperbridgeFinalized`, `DestinationDelivered`, `Timeout` -* @param {JsPost} request -* @param {JsClientConfig} config_js -* @param {bigint} post_request_height -* @returns {Promise} -*/ -export function subscribe_to_request_status(request: JsPost, config_js: JsClientConfig, post_request_height: bigint): Promise; -/** -*/ -export class IntoUnderlyingByteSource { - free(): void; -/** -* @param {ReadableByteStreamController} controller -*/ - start(controller: ReadableByteStreamController): void; -/** -* @param {ReadableByteStreamController} controller -* @returns {Promise} -*/ - pull(controller: ReadableByteStreamController): Promise; -/** -*/ - cancel(): void; -/** -*/ - readonly autoAllocateChunkSize: number; -/** -*/ - readonly type: string; -} -/** -*/ -export class IntoUnderlyingSink { - free(): void; -/** -* @param {any} chunk -* @returns {Promise} -*/ - write(chunk: any): Promise; -/** -* @returns {Promise} -*/ - close(): Promise; -/** -* @param {any} reason -* @returns {Promise} -*/ - abort(reason: any): Promise; -} -/** -*/ -export class IntoUnderlyingSource { - free(): void; -/** -* @param {ReadableStreamDefaultController} controller -* @returns {Promise} -*/ - pull(controller: ReadableStreamDefaultController): Promise; -/** -*/ - cancel(): void; -} -/** -*/ -export class JsChainConfig { - free(): void; -/** -*/ - consensus_state_id: Uint8Array; -/** -*/ - handler_address: Uint8Array; -/** -*/ - host_address: Uint8Array; -/** -*/ - rpc_url: string; -/** -*/ - state_machine: string; -} -/** -*/ -export class JsClientConfig { - free(): void; -/** -*/ - dest: JsChainConfig; -/** -*/ - hyperbridge: JsHyperbridgeConfig; -/** -*/ - source: JsChainConfig; -} -/** -*/ -export class JsHyperbridgeConfig { - free(): void; -/** -*/ - rpc_url: string; -} -/** -*/ -export class JsPost { - free(): void; -/** -* Encoded Request. -*/ - data: Uint8Array; -/** -* The destination state machine of this request. -*/ - dest: string; -/** -* Module Id of the sending module -*/ - from: Uint8Array; -/** -* Gas limit for executing the request on destination -* This value should be zero if destination module is not a contract -*/ - gas_limit: bigint; -/** -* The nonce of this request on the source chain -*/ - nonce: bigint; -/** -* The source state machine of this request. -*/ - source: string; -/** -* Timestamp which this request expires in seconds. -*/ - timeout_timestamp: bigint; -/** -* Module ID of the receiving module -*/ - to: Uint8Array; -} -/** -*/ -export class JsResponse { - free(): void; -/** -* Gas limit for executing the response on destination, only used for solidity modules. -*/ - gas_limit: bigint; -/** -* The request that triggered this response. -*/ - post: JsPost; -/** -* The response message. -*/ - response: Uint8Array; -/** -* Timestamp at which this response expires in seconds. -*/ - timeout_timestamp: bigint; -} diff --git a/modules/client/pkg/hyperclient.js b/modules/client/pkg/hyperclient.js deleted file mode 100644 index bb8342446..000000000 --- a/modules/client/pkg/hyperclient.js +++ /dev/null @@ -1,4 +0,0 @@ -import * as wasm from "./hyperclient_bg.wasm"; -import { __wbg_set_wasm } from "./hyperclient_bg.js"; -__wbg_set_wasm(wasm); -export * from "./hyperclient_bg.js"; diff --git a/modules/client/pkg/hyperclient_bg.js b/modules/client/pkg/hyperclient_bg.js deleted file mode 100644 index 0972d1c0d..000000000 --- a/modules/client/pkg/hyperclient_bg.js +++ /dev/null @@ -1,1629 +0,0 @@ -let wasm; -export function __wbg_set_wasm(val) { - wasm = val; -} - - -const heap = new Array(128).fill(undefined); - -heap.push(undefined, null, true, false); - -function getObject(idx) { return heap[idx]; } - -let heap_next = heap.length; - -function dropObject(idx) { - if (idx < 132) return; - heap[idx] = heap_next; - heap_next = idx; -} - -function takeObject(idx) { - const ret = getObject(idx); - dropObject(idx); - return ret; -} - -function addHeapObject(obj) { - if (heap_next === heap.length) heap.push(heap.length + 1); - const idx = heap_next; - heap_next = heap[idx]; - - heap[idx] = obj; - return idx; -} - -const lTextDecoder = typeof TextDecoder === 'undefined' ? (0, module.require)('util').TextDecoder : TextDecoder; - -let cachedTextDecoder = new lTextDecoder('utf-8', { ignoreBOM: true, fatal: true }); - -cachedTextDecoder.decode(); - -let cachedUint8Memory0 = null; - -function getUint8Memory0() { - if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) { - cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer); - } - return cachedUint8Memory0; -} - -function getStringFromWasm0(ptr, len) { - ptr = ptr >>> 0; - return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); -} - -let WASM_VECTOR_LEN = 0; - -const lTextEncoder = typeof TextEncoder === 'undefined' ? (0, module.require)('util').TextEncoder : TextEncoder; - -let cachedTextEncoder = new lTextEncoder('utf-8'); - -const encodeString = (typeof cachedTextEncoder.encodeInto === 'function' - ? function (arg, view) { - return cachedTextEncoder.encodeInto(arg, view); -} - : function (arg, view) { - const buf = cachedTextEncoder.encode(arg); - view.set(buf); - return { - read: arg.length, - written: buf.length - }; -}); - -function passStringToWasm0(arg, malloc, realloc) { - - if (realloc === undefined) { - const buf = cachedTextEncoder.encode(arg); - const ptr = malloc(buf.length, 1) >>> 0; - getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf); - WASM_VECTOR_LEN = buf.length; - return ptr; - } - - let len = arg.length; - let ptr = malloc(len, 1) >>> 0; - - const mem = getUint8Memory0(); - - let offset = 0; - - for (; offset < len; offset++) { - const code = arg.charCodeAt(offset); - if (code > 0x7F) break; - mem[ptr + offset] = code; - } - - if (offset !== len) { - if (offset !== 0) { - arg = arg.slice(offset); - } - ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; - const view = getUint8Memory0().subarray(ptr + offset, ptr + len); - const ret = encodeString(arg, view); - - offset += ret.written; - ptr = realloc(ptr, len, offset, 1) >>> 0; - } - - WASM_VECTOR_LEN = offset; - return ptr; -} - -function isLikeNone(x) { - return x === undefined || x === null; -} - -let cachedInt32Memory0 = null; - -function getInt32Memory0() { - if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) { - cachedInt32Memory0 = new Int32Array(wasm.memory.buffer); - } - return cachedInt32Memory0; -} - -function debugString(val) { - // primitive types - const type = typeof val; - if (type == 'number' || type == 'boolean' || val == null) { - return `${val}`; - } - if (type == 'string') { - return `"${val}"`; - } - if (type == 'symbol') { - const description = val.description; - if (description == null) { - return 'Symbol'; - } else { - return `Symbol(${description})`; - } - } - if (type == 'function') { - const name = val.name; - if (typeof name == 'string' && name.length > 0) { - return `Function(${name})`; - } else { - return 'Function'; - } - } - // objects - if (Array.isArray(val)) { - const length = val.length; - let debug = '['; - if (length > 0) { - debug += debugString(val[0]); - } - for(let i = 1; i < length; i++) { - debug += ', ' + debugString(val[i]); - } - debug += ']'; - return debug; - } - // Test for built-in - const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val)); - let className; - if (builtInMatches.length > 1) { - className = builtInMatches[1]; - } else { - // Failed to match the standard '[object ClassName]' - return toString.call(val); - } - if (className == 'Object') { - // we're a user defined class or Object - // JSON.stringify avoids problems with cycles, and is generally much - // easier than looping through ownProperties of `val`. - try { - return 'Object(' + JSON.stringify(val) + ')'; - } catch (_) { - return 'Object'; - } - } - // errors - if (val instanceof Error) { - return `${val.name}: ${val.message}\n${val.stack}`; - } - // TODO we could test for more things here, like `Set`s and `Map`s. - return className; -} - -const CLOSURE_DTORS = (typeof FinalizationRegistry === 'undefined') - ? { register: () => {}, unregister: () => {} } - : new FinalizationRegistry(state => { - wasm.__wbindgen_export_2.get(state.dtor)(state.a, state.b) -}); - -function makeMutClosure(arg0, arg1, dtor, f) { - const state = { a: arg0, b: arg1, cnt: 1, dtor }; - const real = (...args) => { - // First up with a closure we increment the internal reference - // count. This ensures that the Rust closure environment won't - // be deallocated while we're invoking it. - state.cnt++; - const a = state.a; - state.a = 0; - try { - return f(a, state.b, ...args); - } finally { - if (--state.cnt === 0) { - wasm.__wbindgen_export_2.get(state.dtor)(a, state.b); - CLOSURE_DTORS.unregister(state); - } else { - state.a = a; - } - } - }; - real.original = state; - CLOSURE_DTORS.register(real, state, state); - return real; -} -function __wbg_adapter_32(arg0, arg1) { - wasm.wasm_bindgen__convert__closures__invoke0_mut__hdc28361670d72cce(arg0, arg1); -} - -function __wbg_adapter_35(arg0, arg1, arg2) { - wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h367ff8bffb6f7b2e(arg0, arg1, addHeapObject(arg2)); -} - -function __wbg_adapter_40(arg0, arg1) { - wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h9aae2ac53c63e19e(arg0, arg1); -} - -function __wbg_adapter_45(arg0, arg1) { - wasm.wasm_bindgen__convert__closures__invoke0_mut__h3c8b3f369d6af9ec(arg0, arg1); -} - -function __wbg_adapter_48(arg0, arg1, arg2) { - wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hb494be3815513233(arg0, arg1, addHeapObject(arg2)); -} - -function getArrayU8FromWasm0(ptr, len) { - ptr = ptr >>> 0; - return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len); -} - -function passArray8ToWasm0(arg, malloc) { - const ptr = malloc(arg.length * 1, 1) >>> 0; - getUint8Memory0().set(arg, ptr / 1); - WASM_VECTOR_LEN = arg.length; - return ptr; -} - -function _assertClass(instance, klass) { - if (!(instance instanceof klass)) { - throw new Error(`expected instance of ${klass.name}`); - } - return instance.ptr; -} -/** -* Functions takes in a post request and returns one of the following json strings variants -* Status variants: `Pending`, `SourceFinalized`, `HyperbridgeDelivered`, `HyperbridgeFinalized`, -* `DestinationDelivered`, `Timeout` -* @param {JsPost} request -* @param {JsClientConfig} config_js -* @returns {Promise} -*/ -export function query_request_status(request, config_js) { - _assertClass(request, JsPost); - var ptr0 = request.__destroy_into_raw(); - _assertClass(config_js, JsClientConfig); - var ptr1 = config_js.__destroy_into_raw(); - const ret = wasm.query_request_status(ptr0, ptr1); - return takeObject(ret); -} - -/** -* Function takes in a post response and returns one of the following json strings variants -* Status Variants: `Pending`, `SourceFinalized`, `HyperbridgeDelivered`, `HyperbridgeFinalized`, -* `DestinationDelivered`, `Timeout` -* @param {JsResponse} response -* @param {JsClientConfig} config_js -* @returns {Promise} -*/ -export function query_response_status(response, config_js) { - _assertClass(response, JsResponse); - var ptr0 = response.__destroy_into_raw(); - _assertClass(config_js, JsClientConfig); - var ptr1 = config_js.__destroy_into_raw(); - const ret = wasm.query_response_status(ptr0, ptr1); - return takeObject(ret); -} - -/** -* Accepts a post request that has timed out returns a stream that yields the following json -* strings variants Status Variants: `Pending`, `DestinationFinalized`, `HyperbridgeTimedout`, -* `HyperbridgeFinalized`, `{ "TimeoutMessage": [...] }`. This function will not check if the -* request has timed out, only call it when sure that the request has timed out after calling -* `query_request_status` -* @param {JsPost} request -* @param {JsClientConfig} config_js -* @returns {Promise} -*/ -export function timeout_post_request(request, config_js) { - _assertClass(request, JsPost); - var ptr0 = request.__destroy_into_raw(); - _assertClass(config_js, JsClientConfig); - var ptr1 = config_js.__destroy_into_raw(); - const ret = wasm.timeout_post_request(ptr0, ptr1); - return takeObject(ret); -} - -/** -* Races between a timeout stream and request processing stream, and yields the following json -* strings variants Status Variants: `Pending`, `SourceFinalized`, `HyperbridgeDelivered`, -* `HyperbridgeFinalized`, `DestinationDelivered`, `Timeout` -* @param {JsPost} request -* @param {JsClientConfig} config_js -* @param {bigint} post_request_height -* @returns {Promise} -*/ -export function subscribe_to_request_status(request, config_js, post_request_height) { - _assertClass(request, JsPost); - var ptr0 = request.__destroy_into_raw(); - _assertClass(config_js, JsClientConfig); - var ptr1 = config_js.__destroy_into_raw(); - const ret = wasm.subscribe_to_request_status(ptr0, ptr1, post_request_height); - return takeObject(ret); -} - -function handleError(f, args) { - try { - return f.apply(this, args); - } catch (e) { - wasm.__wbindgen_exn_store(addHeapObject(e)); - } -} -function __wbg_adapter_229(arg0, arg1, arg2, arg3) { - wasm.wasm_bindgen__convert__closures__invoke2_mut__h124eb194c086a246(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3)); -} - -const IntoUnderlyingByteSourceFinalization = (typeof FinalizationRegistry === 'undefined') - ? { register: () => {}, unregister: () => {} } - : new FinalizationRegistry(ptr => wasm.__wbg_intounderlyingbytesource_free(ptr >>> 0)); -/** -*/ -export class IntoUnderlyingByteSource { - - __destroy_into_raw() { - const ptr = this.__wbg_ptr; - this.__wbg_ptr = 0; - IntoUnderlyingByteSourceFinalization.unregister(this); - return ptr; - } - - free() { - const ptr = this.__destroy_into_raw(); - wasm.__wbg_intounderlyingbytesource_free(ptr); - } - /** - * @returns {string} - */ - get type() { - let deferred1_0; - let deferred1_1; - try { - const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); - wasm.intounderlyingbytesource_type(retptr, this.__wbg_ptr); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; - deferred1_0 = r0; - deferred1_1 = r1; - return getStringFromWasm0(r0, r1); - } finally { - wasm.__wbindgen_add_to_stack_pointer(16); - wasm.__wbindgen_free(deferred1_0, deferred1_1, 1); - } - } - /** - * @returns {number} - */ - get autoAllocateChunkSize() { - const ret = wasm.intounderlyingbytesource_autoAllocateChunkSize(this.__wbg_ptr); - return ret >>> 0; - } - /** - * @param {ReadableByteStreamController} controller - */ - start(controller) { - wasm.intounderlyingbytesource_start(this.__wbg_ptr, addHeapObject(controller)); - } - /** - * @param {ReadableByteStreamController} controller - * @returns {Promise} - */ - pull(controller) { - const ret = wasm.intounderlyingbytesource_pull(this.__wbg_ptr, addHeapObject(controller)); - return takeObject(ret); - } - /** - */ - cancel() { - const ptr = this.__destroy_into_raw(); - wasm.intounderlyingbytesource_cancel(ptr); - } -} - -const IntoUnderlyingSinkFinalization = (typeof FinalizationRegistry === 'undefined') - ? { register: () => {}, unregister: () => {} } - : new FinalizationRegistry(ptr => wasm.__wbg_intounderlyingsink_free(ptr >>> 0)); -/** -*/ -export class IntoUnderlyingSink { - - __destroy_into_raw() { - const ptr = this.__wbg_ptr; - this.__wbg_ptr = 0; - IntoUnderlyingSinkFinalization.unregister(this); - return ptr; - } - - free() { - const ptr = this.__destroy_into_raw(); - wasm.__wbg_intounderlyingsink_free(ptr); - } - /** - * @param {any} chunk - * @returns {Promise} - */ - write(chunk) { - const ret = wasm.intounderlyingsink_write(this.__wbg_ptr, addHeapObject(chunk)); - return takeObject(ret); - } - /** - * @returns {Promise} - */ - close() { - const ptr = this.__destroy_into_raw(); - const ret = wasm.intounderlyingsink_close(ptr); - return takeObject(ret); - } - /** - * @param {any} reason - * @returns {Promise} - */ - abort(reason) { - const ptr = this.__destroy_into_raw(); - const ret = wasm.intounderlyingsink_abort(ptr, addHeapObject(reason)); - return takeObject(ret); - } -} - -const IntoUnderlyingSourceFinalization = (typeof FinalizationRegistry === 'undefined') - ? { register: () => {}, unregister: () => {} } - : new FinalizationRegistry(ptr => wasm.__wbg_intounderlyingsource_free(ptr >>> 0)); -/** -*/ -export class IntoUnderlyingSource { - - static __wrap(ptr) { - ptr = ptr >>> 0; - const obj = Object.create(IntoUnderlyingSource.prototype); - obj.__wbg_ptr = ptr; - IntoUnderlyingSourceFinalization.register(obj, obj.__wbg_ptr, obj); - return obj; - } - - __destroy_into_raw() { - const ptr = this.__wbg_ptr; - this.__wbg_ptr = 0; - IntoUnderlyingSourceFinalization.unregister(this); - return ptr; - } - - free() { - const ptr = this.__destroy_into_raw(); - wasm.__wbg_intounderlyingsource_free(ptr); - } - /** - * @param {ReadableStreamDefaultController} controller - * @returns {Promise} - */ - pull(controller) { - const ret = wasm.intounderlyingsource_pull(this.__wbg_ptr, addHeapObject(controller)); - return takeObject(ret); - } - /** - */ - cancel() { - const ptr = this.__destroy_into_raw(); - wasm.intounderlyingsource_cancel(ptr); - } -} - -const JsChainConfigFinalization = (typeof FinalizationRegistry === 'undefined') - ? { register: () => {}, unregister: () => {} } - : new FinalizationRegistry(ptr => wasm.__wbg_jschainconfig_free(ptr >>> 0)); -/** -*/ -export class JsChainConfig { - - static __wrap(ptr) { - ptr = ptr >>> 0; - const obj = Object.create(JsChainConfig.prototype); - obj.__wbg_ptr = ptr; - JsChainConfigFinalization.register(obj, obj.__wbg_ptr, obj); - return obj; - } - - __destroy_into_raw() { - const ptr = this.__wbg_ptr; - this.__wbg_ptr = 0; - JsChainConfigFinalization.unregister(this); - return ptr; - } - - free() { - const ptr = this.__destroy_into_raw(); - wasm.__wbg_jschainconfig_free(ptr); - } - /** - * @returns {string} - */ - get rpc_url() { - let deferred1_0; - let deferred1_1; - try { - const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); - wasm.__wbg_get_jschainconfig_rpc_url(retptr, this.__wbg_ptr); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; - deferred1_0 = r0; - deferred1_1 = r1; - return getStringFromWasm0(r0, r1); - } finally { - wasm.__wbindgen_add_to_stack_pointer(16); - wasm.__wbindgen_free(deferred1_0, deferred1_1, 1); - } - } - /** - * @param {string} arg0 - */ - set rpc_url(arg0) { - const ptr0 = passStringToWasm0(arg0, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len0 = WASM_VECTOR_LEN; - wasm.__wbg_set_jschainconfig_rpc_url(this.__wbg_ptr, ptr0, len0); - } - /** - * @returns {string} - */ - get state_machine() { - let deferred1_0; - let deferred1_1; - try { - const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); - wasm.__wbg_get_jschainconfig_state_machine(retptr, this.__wbg_ptr); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; - deferred1_0 = r0; - deferred1_1 = r1; - return getStringFromWasm0(r0, r1); - } finally { - wasm.__wbindgen_add_to_stack_pointer(16); - wasm.__wbindgen_free(deferred1_0, deferred1_1, 1); - } - } - /** - * @param {string} arg0 - */ - set state_machine(arg0) { - const ptr0 = passStringToWasm0(arg0, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len0 = WASM_VECTOR_LEN; - wasm.__wbg_set_jschainconfig_state_machine(this.__wbg_ptr, ptr0, len0); - } - /** - * @returns {Uint8Array} - */ - get host_address() { - try { - const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); - wasm.__wbg_get_jschainconfig_host_address(retptr, this.__wbg_ptr); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; - var v1 = getArrayU8FromWasm0(r0, r1).slice(); - wasm.__wbindgen_free(r0, r1 * 1, 1); - return v1; - } finally { - wasm.__wbindgen_add_to_stack_pointer(16); - } - } - /** - * @param {Uint8Array} arg0 - */ - set host_address(arg0) { - const ptr0 = passArray8ToWasm0(arg0, wasm.__wbindgen_malloc); - const len0 = WASM_VECTOR_LEN; - wasm.__wbg_set_jschainconfig_host_address(this.__wbg_ptr, ptr0, len0); - } - /** - * @returns {Uint8Array} - */ - get handler_address() { - try { - const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); - wasm.__wbg_get_jschainconfig_handler_address(retptr, this.__wbg_ptr); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; - var v1 = getArrayU8FromWasm0(r0, r1).slice(); - wasm.__wbindgen_free(r0, r1 * 1, 1); - return v1; - } finally { - wasm.__wbindgen_add_to_stack_pointer(16); - } - } - /** - * @param {Uint8Array} arg0 - */ - set handler_address(arg0) { - const ptr0 = passArray8ToWasm0(arg0, wasm.__wbindgen_malloc); - const len0 = WASM_VECTOR_LEN; - wasm.__wbg_set_jschainconfig_handler_address(this.__wbg_ptr, ptr0, len0); - } - /** - * @returns {Uint8Array} - */ - get consensus_state_id() { - try { - const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); - wasm.__wbg_get_jschainconfig_consensus_state_id(retptr, this.__wbg_ptr); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; - var v1 = getArrayU8FromWasm0(r0, r1).slice(); - wasm.__wbindgen_free(r0, r1 * 1, 1); - return v1; - } finally { - wasm.__wbindgen_add_to_stack_pointer(16); - } - } - /** - * @param {Uint8Array} arg0 - */ - set consensus_state_id(arg0) { - const ptr0 = passArray8ToWasm0(arg0, wasm.__wbindgen_malloc); - const len0 = WASM_VECTOR_LEN; - wasm.__wbg_set_jschainconfig_consensus_state_id(this.__wbg_ptr, ptr0, len0); - } -} - -const JsClientConfigFinalization = (typeof FinalizationRegistry === 'undefined') - ? { register: () => {}, unregister: () => {} } - : new FinalizationRegistry(ptr => wasm.__wbg_jsclientconfig_free(ptr >>> 0)); -/** -*/ -export class JsClientConfig { - - __destroy_into_raw() { - const ptr = this.__wbg_ptr; - this.__wbg_ptr = 0; - JsClientConfigFinalization.unregister(this); - return ptr; - } - - free() { - const ptr = this.__destroy_into_raw(); - wasm.__wbg_jsclientconfig_free(ptr); - } - /** - * @returns {JsChainConfig} - */ - get source() { - const ret = wasm.__wbg_get_jsclientconfig_source(this.__wbg_ptr); - return JsChainConfig.__wrap(ret); - } - /** - * @param {JsChainConfig} arg0 - */ - set source(arg0) { - _assertClass(arg0, JsChainConfig); - var ptr0 = arg0.__destroy_into_raw(); - wasm.__wbg_set_jsclientconfig_source(this.__wbg_ptr, ptr0); - } - /** - * @returns {JsChainConfig} - */ - get dest() { - const ret = wasm.__wbg_get_jsclientconfig_dest(this.__wbg_ptr); - return JsChainConfig.__wrap(ret); - } - /** - * @param {JsChainConfig} arg0 - */ - set dest(arg0) { - _assertClass(arg0, JsChainConfig); - var ptr0 = arg0.__destroy_into_raw(); - wasm.__wbg_set_jsclientconfig_dest(this.__wbg_ptr, ptr0); - } - /** - * @returns {JsHyperbridgeConfig} - */ - get hyperbridge() { - const ret = wasm.__wbg_get_jsclientconfig_hyperbridge(this.__wbg_ptr); - return JsHyperbridgeConfig.__wrap(ret); - } - /** - * @param {JsHyperbridgeConfig} arg0 - */ - set hyperbridge(arg0) { - _assertClass(arg0, JsHyperbridgeConfig); - var ptr0 = arg0.__destroy_into_raw(); - wasm.__wbg_set_jsclientconfig_hyperbridge(this.__wbg_ptr, ptr0); - } -} - -const JsHyperbridgeConfigFinalization = (typeof FinalizationRegistry === 'undefined') - ? { register: () => {}, unregister: () => {} } - : new FinalizationRegistry(ptr => wasm.__wbg_jshyperbridgeconfig_free(ptr >>> 0)); -/** -*/ -export class JsHyperbridgeConfig { - - static __wrap(ptr) { - ptr = ptr >>> 0; - const obj = Object.create(JsHyperbridgeConfig.prototype); - obj.__wbg_ptr = ptr; - JsHyperbridgeConfigFinalization.register(obj, obj.__wbg_ptr, obj); - return obj; - } - - __destroy_into_raw() { - const ptr = this.__wbg_ptr; - this.__wbg_ptr = 0; - JsHyperbridgeConfigFinalization.unregister(this); - return ptr; - } - - free() { - const ptr = this.__destroy_into_raw(); - wasm.__wbg_jshyperbridgeconfig_free(ptr); - } - /** - * @returns {string} - */ - get rpc_url() { - let deferred1_0; - let deferred1_1; - try { - const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); - wasm.__wbg_get_jschainconfig_rpc_url(retptr, this.__wbg_ptr); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; - deferred1_0 = r0; - deferred1_1 = r1; - return getStringFromWasm0(r0, r1); - } finally { - wasm.__wbindgen_add_to_stack_pointer(16); - wasm.__wbindgen_free(deferred1_0, deferred1_1, 1); - } - } - /** - * @param {string} arg0 - */ - set rpc_url(arg0) { - const ptr0 = passStringToWasm0(arg0, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len0 = WASM_VECTOR_LEN; - wasm.__wbg_set_jschainconfig_rpc_url(this.__wbg_ptr, ptr0, len0); - } -} - -const JsPostFinalization = (typeof FinalizationRegistry === 'undefined') - ? { register: () => {}, unregister: () => {} } - : new FinalizationRegistry(ptr => wasm.__wbg_jspost_free(ptr >>> 0)); -/** -*/ -export class JsPost { - - static __wrap(ptr) { - ptr = ptr >>> 0; - const obj = Object.create(JsPost.prototype); - obj.__wbg_ptr = ptr; - JsPostFinalization.register(obj, obj.__wbg_ptr, obj); - return obj; - } - - __destroy_into_raw() { - const ptr = this.__wbg_ptr; - this.__wbg_ptr = 0; - JsPostFinalization.unregister(this); - return ptr; - } - - free() { - const ptr = this.__destroy_into_raw(); - wasm.__wbg_jspost_free(ptr); - } - /** - * The source state machine of this request. - * @returns {string} - */ - get source() { - let deferred1_0; - let deferred1_1; - try { - const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); - wasm.__wbg_get_jspost_source(retptr, this.__wbg_ptr); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; - deferred1_0 = r0; - deferred1_1 = r1; - return getStringFromWasm0(r0, r1); - } finally { - wasm.__wbindgen_add_to_stack_pointer(16); - wasm.__wbindgen_free(deferred1_0, deferred1_1, 1); - } - } - /** - * The source state machine of this request. - * @param {string} arg0 - */ - set source(arg0) { - const ptr0 = passStringToWasm0(arg0, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len0 = WASM_VECTOR_LEN; - wasm.__wbg_set_jspost_source(this.__wbg_ptr, ptr0, len0); - } - /** - * The destination state machine of this request. - * @returns {string} - */ - get dest() { - let deferred1_0; - let deferred1_1; - try { - const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); - wasm.__wbg_get_jspost_dest(retptr, this.__wbg_ptr); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; - deferred1_0 = r0; - deferred1_1 = r1; - return getStringFromWasm0(r0, r1); - } finally { - wasm.__wbindgen_add_to_stack_pointer(16); - wasm.__wbindgen_free(deferred1_0, deferred1_1, 1); - } - } - /** - * The destination state machine of this request. - * @param {string} arg0 - */ - set dest(arg0) { - const ptr0 = passStringToWasm0(arg0, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len0 = WASM_VECTOR_LEN; - wasm.__wbg_set_jspost_dest(this.__wbg_ptr, ptr0, len0); - } - /** - * The nonce of this request on the source chain - * @returns {bigint} - */ - get nonce() { - const ret = wasm.__wbg_get_jspost_nonce(this.__wbg_ptr); - return BigInt.asUintN(64, ret); - } - /** - * The nonce of this request on the source chain - * @param {bigint} arg0 - */ - set nonce(arg0) { - wasm.__wbg_set_jspost_nonce(this.__wbg_ptr, arg0); - } - /** - * Module Id of the sending module - * @returns {Uint8Array} - */ - get from() { - try { - const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); - wasm.__wbg_get_jspost_from(retptr, this.__wbg_ptr); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; - var v1 = getArrayU8FromWasm0(r0, r1).slice(); - wasm.__wbindgen_free(r0, r1 * 1, 1); - return v1; - } finally { - wasm.__wbindgen_add_to_stack_pointer(16); - } - } - /** - * Module Id of the sending module - * @param {Uint8Array} arg0 - */ - set from(arg0) { - const ptr0 = passArray8ToWasm0(arg0, wasm.__wbindgen_malloc); - const len0 = WASM_VECTOR_LEN; - wasm.__wbg_set_jspost_from(this.__wbg_ptr, ptr0, len0); - } - /** - * Module ID of the receiving module - * @returns {Uint8Array} - */ - get to() { - try { - const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); - wasm.__wbg_get_jspost_to(retptr, this.__wbg_ptr); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; - var v1 = getArrayU8FromWasm0(r0, r1).slice(); - wasm.__wbindgen_free(r0, r1 * 1, 1); - return v1; - } finally { - wasm.__wbindgen_add_to_stack_pointer(16); - } - } - /** - * Module ID of the receiving module - * @param {Uint8Array} arg0 - */ - set to(arg0) { - const ptr0 = passArray8ToWasm0(arg0, wasm.__wbindgen_malloc); - const len0 = WASM_VECTOR_LEN; - wasm.__wbg_set_jspost_to(this.__wbg_ptr, ptr0, len0); - } - /** - * Timestamp which this request expires in seconds. - * @returns {bigint} - */ - get timeout_timestamp() { - const ret = wasm.__wbg_get_jspost_timeout_timestamp(this.__wbg_ptr); - return BigInt.asUintN(64, ret); - } - /** - * Timestamp which this request expires in seconds. - * @param {bigint} arg0 - */ - set timeout_timestamp(arg0) { - wasm.__wbg_set_jspost_timeout_timestamp(this.__wbg_ptr, arg0); - } - /** - * Encoded Request. - * @returns {Uint8Array} - */ - get data() { - try { - const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); - wasm.__wbg_get_jspost_data(retptr, this.__wbg_ptr); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; - var v1 = getArrayU8FromWasm0(r0, r1).slice(); - wasm.__wbindgen_free(r0, r1 * 1, 1); - return v1; - } finally { - wasm.__wbindgen_add_to_stack_pointer(16); - } - } - /** - * Encoded Request. - * @param {Uint8Array} arg0 - */ - set data(arg0) { - const ptr0 = passArray8ToWasm0(arg0, wasm.__wbindgen_malloc); - const len0 = WASM_VECTOR_LEN; - wasm.__wbg_set_jspost_data(this.__wbg_ptr, ptr0, len0); - } - /** - * Gas limit for executing the request on destination - * This value should be zero if destination module is not a contract - * @returns {bigint} - */ - get gas_limit() { - const ret = wasm.__wbg_get_jspost_gas_limit(this.__wbg_ptr); - return BigInt.asUintN(64, ret); - } - /** - * Gas limit for executing the request on destination - * This value should be zero if destination module is not a contract - * @param {bigint} arg0 - */ - set gas_limit(arg0) { - wasm.__wbg_set_jspost_gas_limit(this.__wbg_ptr, arg0); - } -} - -const JsResponseFinalization = (typeof FinalizationRegistry === 'undefined') - ? { register: () => {}, unregister: () => {} } - : new FinalizationRegistry(ptr => wasm.__wbg_jsresponse_free(ptr >>> 0)); -/** -*/ -export class JsResponse { - - __destroy_into_raw() { - const ptr = this.__wbg_ptr; - this.__wbg_ptr = 0; - JsResponseFinalization.unregister(this); - return ptr; - } - - free() { - const ptr = this.__destroy_into_raw(); - wasm.__wbg_jsresponse_free(ptr); - } - /** - * The request that triggered this response. - * @returns {JsPost} - */ - get post() { - const ret = wasm.__wbg_get_jsresponse_post(this.__wbg_ptr); - return JsPost.__wrap(ret); - } - /** - * The request that triggered this response. - * @param {JsPost} arg0 - */ - set post(arg0) { - _assertClass(arg0, JsPost); - var ptr0 = arg0.__destroy_into_raw(); - wasm.__wbg_set_jsresponse_post(this.__wbg_ptr, ptr0); - } - /** - * The response message. - * @returns {Uint8Array} - */ - get response() { - try { - const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); - wasm.__wbg_get_jsresponse_response(retptr, this.__wbg_ptr); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; - var v1 = getArrayU8FromWasm0(r0, r1).slice(); - wasm.__wbindgen_free(r0, r1 * 1, 1); - return v1; - } finally { - wasm.__wbindgen_add_to_stack_pointer(16); - } - } - /** - * The response message. - * @param {Uint8Array} arg0 - */ - set response(arg0) { - const ptr0 = passArray8ToWasm0(arg0, wasm.__wbindgen_malloc); - const len0 = WASM_VECTOR_LEN; - wasm.__wbg_set_jsresponse_response(this.__wbg_ptr, ptr0, len0); - } - /** - * Timestamp at which this response expires in seconds. - * @returns {bigint} - */ - get timeout_timestamp() { - const ret = wasm.__wbg_get_jspost_nonce(this.__wbg_ptr); - return BigInt.asUintN(64, ret); - } - /** - * Timestamp at which this response expires in seconds. - * @param {bigint} arg0 - */ - set timeout_timestamp(arg0) { - wasm.__wbg_set_jspost_nonce(this.__wbg_ptr, arg0); - } - /** - * Gas limit for executing the response on destination, only used for solidity modules. - * @returns {bigint} - */ - get gas_limit() { - const ret = wasm.__wbg_get_jspost_timeout_timestamp(this.__wbg_ptr); - return BigInt.asUintN(64, ret); - } - /** - * Gas limit for executing the response on destination, only used for solidity modules. - * @param {bigint} arg0 - */ - set gas_limit(arg0) { - wasm.__wbg_set_jspost_timeout_timestamp(this.__wbg_ptr, arg0); - } -} - -export function __wbindgen_object_drop_ref(arg0) { - takeObject(arg0); -}; - -export function __wbindgen_as_number(arg0) { - const ret = +getObject(arg0); - return ret; -}; - -export function __wbindgen_object_clone_ref(arg0) { - const ret = getObject(arg0); - return addHeapObject(ret); -}; - -export function __wbindgen_cb_drop(arg0) { - const obj = takeObject(arg0).original; - if (obj.cnt-- == 1) { - obj.a = 0; - return true; - } - const ret = false; - return ret; -}; - -export function __wbindgen_string_new(arg0, arg1) { - const ret = getStringFromWasm0(arg0, arg1); - return addHeapObject(ret); -}; - -export function __wbindgen_error_new(arg0, arg1) { - const ret = new Error(getStringFromWasm0(arg0, arg1)); - return addHeapObject(ret); -}; - -export function __wbindgen_is_object(arg0) { - const val = getObject(arg0); - const ret = typeof(val) === 'object' && val !== null; - return ret; -}; - -export function __wbindgen_string_get(arg0, arg1) { - const obj = getObject(arg1); - const ret = typeof(obj) === 'string' ? obj : undefined; - var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - var len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; -}; - -export function __wbindgen_number_new(arg0) { - const ret = arg0; - return addHeapObject(ret); -}; - -export function __wbg_set_f975102236d3c502(arg0, arg1, arg2) { - getObject(arg0)[takeObject(arg1)] = takeObject(arg2); -}; - -export function __wbg_newwithintounderlyingsource_a03a82aa1bbbb292(arg0, arg1) { - const ret = new ReadableStream(IntoUnderlyingSource.__wrap(arg0), takeObject(arg1)); - return addHeapObject(ret); -}; - -export function __wbg_sethighWaterMark_ea50ed3ec2143088(arg0, arg1) { - getObject(arg0).highWaterMark = arg1; -}; - -export function __wbindgen_is_string(arg0) { - const ret = typeof(getObject(arg0)) === 'string'; - return ret; -}; - -export function __wbg_clearTimeout_76877dbc010e786d(arg0) { - const ret = clearTimeout(takeObject(arg0)); - return addHeapObject(ret); -}; - -export function __wbg_setTimeout_75cb9b6991a4031d() { return handleError(function (arg0, arg1) { - const ret = setTimeout(getObject(arg0), arg1); - return addHeapObject(ret); -}, arguments) }; - -export function __wbg_fetch_6a2624d7f767e331(arg0) { - const ret = fetch(getObject(arg0)); - return addHeapObject(ret); -}; - -export function __wbg_queueMicrotask_f61ee94ee663068b(arg0) { - queueMicrotask(getObject(arg0)); -}; - -export function __wbg_queueMicrotask_f82fc5d1e8f816ae(arg0) { - const ret = getObject(arg0).queueMicrotask; - return addHeapObject(ret); -}; - -export function __wbindgen_is_function(arg0) { - const ret = typeof(getObject(arg0)) === 'function'; - return ret; -}; - -export function __wbg_instanceof_Window_cee7a886d55e7df5(arg0) { - let result; - try { - result = getObject(arg0) instanceof Window; - } catch (_) { - result = false; - } - const ret = result; - return ret; -}; - -export function __wbg_performance_4ca1873776fdb3d2(arg0) { - const ret = getObject(arg0).performance; - return isLikeNone(ret) ? 0 : addHeapObject(ret); -}; - -export function __wbg_setTimeout_6ed7182ebad5d297() { return handleError(function (arg0, arg1, arg2) { - const ret = getObject(arg0).setTimeout(getObject(arg1), arg2); - return ret; -}, arguments) }; - -export function __wbg_fetch_10edd7d7da150227(arg0, arg1) { - const ret = getObject(arg0).fetch(getObject(arg1)); - return addHeapObject(ret); -}; - -export function __wbg_byobRequest_643426f0037311f0(arg0) { - const ret = getObject(arg0).byobRequest; - return isLikeNone(ret) ? 0 : addHeapObject(ret); -}; - -export function __wbg_close_0b618a762cdb578b() { return handleError(function (arg0) { - getObject(arg0).close(); -}, arguments) }; - -export function __wbg_instanceof_Response_b5451a06784a2404(arg0) { - let result; - try { - result = getObject(arg0) instanceof Response; - } catch (_) { - result = false; - } - const ret = result; - return ret; -}; - -export function __wbg_url_e319aee56d26ddf1(arg0, arg1) { - const ret = getObject(arg1).url; - const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; -}; - -export function __wbg_status_bea567d1049f0b6a(arg0) { - const ret = getObject(arg0).status; - return ret; -}; - -export function __wbg_headers_96d9457941f08a33(arg0) { - const ret = getObject(arg0).headers; - return addHeapObject(ret); -}; - -export function __wbg_arrayBuffer_eb2005809be09726() { return handleError(function (arg0) { - const ret = getObject(arg0).arrayBuffer(); - return addHeapObject(ret); -}, arguments) }; - -export function __wbg_new_4db22fd5d40c5665() { return handleError(function () { - const ret = new Headers(); - return addHeapObject(ret); -}, arguments) }; - -export function __wbg_append_b2e8ed692fc5eb6e() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { - getObject(arg0).append(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); -}, arguments) }; - -export function __wbg_now_ef71656beb948bc8(arg0) { - const ret = getObject(arg0).now(); - return ret; -}; - -export function __wbg_close_23aa806471e38253() { return handleError(function (arg0) { - getObject(arg0).close(); -}, arguments) }; - -export function __wbg_enqueue_fe9e340e2bc8714b() { return handleError(function (arg0, arg1) { - getObject(arg0).enqueue(getObject(arg1)); -}, arguments) }; - -export function __wbg_readyState_2599ffe07703eeea(arg0) { - const ret = getObject(arg0).readyState; - return ret; -}; - -export function __wbg_setbinaryType_bfaa2b91f5e49737(arg0, arg1) { - getObject(arg0).binaryType = takeObject(arg1); -}; - -export function __wbg_new_d3ba66fcfe3ebcc6() { return handleError(function (arg0, arg1) { - const ret = new WebSocket(getStringFromWasm0(arg0, arg1)); - return addHeapObject(ret); -}, arguments) }; - -export function __wbg_close_85838c8d50b026da() { return handleError(function (arg0) { - getObject(arg0).close(); -}, arguments) }; - -export function __wbg_send_115b7e92eb793bd9() { return handleError(function (arg0, arg1, arg2) { - getObject(arg0).send(getStringFromWasm0(arg1, arg2)); -}, arguments) }; - -export function __wbg_send_8e8f1c88be375fc1() { return handleError(function (arg0, arg1, arg2) { - getObject(arg0).send(getArrayU8FromWasm0(arg1, arg2)); -}, arguments) }; - -export function __wbg_wasClean_06aba8a282b21973(arg0) { - const ret = getObject(arg0).wasClean; - return ret; -}; - -export function __wbg_code_c25ac89aa8108189(arg0) { - const ret = getObject(arg0).code; - return ret; -}; - -export function __wbg_reason_ab96417c470b0f79(arg0, arg1) { - const ret = getObject(arg1).reason; - const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; -}; - -export function __wbg_newwitheventinitdict_ff303f34f1b980fa() { return handleError(function (arg0, arg1, arg2) { - const ret = new CloseEvent(getStringFromWasm0(arg0, arg1), getObject(arg2)); - return addHeapObject(ret); -}, arguments) }; - -export function __wbg_data_bbdd2d77ab2f7e78(arg0) { - const ret = getObject(arg0).data; - return addHeapObject(ret); -}; - -export function __wbg_view_38a0bacb59ad00ee(arg0) { - const ret = getObject(arg0).view; - return isLikeNone(ret) ? 0 : addHeapObject(ret); -}; - -export function __wbg_respond_fee44bba73c2fc8a() { return handleError(function (arg0, arg1) { - getObject(arg0).respond(arg1 >>> 0); -}, arguments) }; - -export function __wbg_addEventListener_f984e99465a6a7f4() { return handleError(function (arg0, arg1, arg2, arg3) { - getObject(arg0).addEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3)); -}, arguments) }; - -export function __wbg_addEventListener_bc4a7ad4cc72c6bf() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { - getObject(arg0).addEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), getObject(arg4)); -}, arguments) }; - -export function __wbg_dispatchEvent_1dc222127c2ec453() { return handleError(function (arg0, arg1) { - const ret = getObject(arg0).dispatchEvent(getObject(arg1)); - return ret; -}, arguments) }; - -export function __wbg_removeEventListener_acfc154b998d806b() { return handleError(function (arg0, arg1, arg2, arg3) { - getObject(arg0).removeEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3)); -}, arguments) }; - -export function __wbg_signal_8fbb4942ce477464(arg0) { - const ret = getObject(arg0).signal; - return addHeapObject(ret); -}; - -export function __wbg_new_92cc7d259297256c() { return handleError(function () { - const ret = new AbortController(); - return addHeapObject(ret); -}, arguments) }; - -export function __wbg_abort_510372063dd66b29(arg0) { - getObject(arg0).abort(); -}; - -export function __wbg_newwithstrandinit_11fbc38beb4c26b0() { return handleError(function (arg0, arg1, arg2) { - const ret = new Request(getStringFromWasm0(arg0, arg1), getObject(arg2)); - return addHeapObject(ret); -}, arguments) }; - -export function __wbg_new_75208e29bddfd88c() { - const ret = new Array(); - return addHeapObject(ret); -}; - -export function __wbg_newnoargs_cfecb3965268594c(arg0, arg1) { - const ret = new Function(getStringFromWasm0(arg0, arg1)); - return addHeapObject(ret); -}; - -export function __wbg_next_586204376d2ed373(arg0) { - const ret = getObject(arg0).next; - return addHeapObject(ret); -}; - -export function __wbg_next_b2d3366343a208b3() { return handleError(function (arg0) { - const ret = getObject(arg0).next(); - return addHeapObject(ret); -}, arguments) }; - -export function __wbg_done_90b14d6f6eacc42f(arg0) { - const ret = getObject(arg0).done; - return ret; -}; - -export function __wbg_value_3158be908c80a75e(arg0) { - const ret = getObject(arg0).value; - return addHeapObject(ret); -}; - -export function __wbg_iterator_40027cdd598da26b() { - const ret = Symbol.iterator; - return addHeapObject(ret); -}; - -export function __wbg_get_3fddfed2c83f434c() { return handleError(function (arg0, arg1) { - const ret = Reflect.get(getObject(arg0), getObject(arg1)); - return addHeapObject(ret); -}, arguments) }; - -export function __wbg_call_3f093dd26d5569f8() { return handleError(function (arg0, arg1) { - const ret = getObject(arg0).call(getObject(arg1)); - return addHeapObject(ret); -}, arguments) }; - -export function __wbg_new_632630b5cec17f21() { - const ret = new Object(); - return addHeapObject(ret); -}; - -export function __wbg_self_05040bd9523805b9() { return handleError(function () { - const ret = self.self; - return addHeapObject(ret); -}, arguments) }; - -export function __wbg_window_adc720039f2cb14f() { return handleError(function () { - const ret = window.window; - return addHeapObject(ret); -}, arguments) }; - -export function __wbg_globalThis_622105db80c1457d() { return handleError(function () { - const ret = globalThis.globalThis; - return addHeapObject(ret); -}, arguments) }; - -export function __wbg_global_f56b013ed9bcf359() { return handleError(function () { - const ret = global.global; - return addHeapObject(ret); -}, arguments) }; - -export function __wbindgen_is_undefined(arg0) { - const ret = getObject(arg0) === undefined; - return ret; -}; - -export function __wbg_set_79c308ecd9a1d091(arg0, arg1, arg2) { - getObject(arg0)[arg1 >>> 0] = takeObject(arg2); -}; - -export function __wbg_instanceof_ArrayBuffer_9221fa854ffb71b5(arg0) { - let result; - try { - result = getObject(arg0) instanceof ArrayBuffer; - } catch (_) { - result = false; - } - const ret = result; - return ret; -}; - -export function __wbg_instanceof_Error_5869c4f17aac9eb2(arg0) { - let result; - try { - result = getObject(arg0) instanceof Error; - } catch (_) { - result = false; - } - const ret = result; - return ret; -}; - -export function __wbg_new_73a5987615ec8862(arg0, arg1) { - const ret = new Error(getStringFromWasm0(arg0, arg1)); - return addHeapObject(ret); -}; - -export function __wbg_message_2a19bb5b62cf8e22(arg0) { - const ret = getObject(arg0).message; - return addHeapObject(ret); -}; - -export function __wbg_name_405bb0aa047a1bf5(arg0) { - const ret = getObject(arg0).name; - return addHeapObject(ret); -}; - -export function __wbg_toString_07f01913ec9af122(arg0) { - const ret = getObject(arg0).toString(); - return addHeapObject(ret); -}; - -export function __wbg_call_67f2111acd2dfdb6() { return handleError(function (arg0, arg1, arg2) { - const ret = getObject(arg0).call(getObject(arg1), getObject(arg2)); - return addHeapObject(ret); -}, arguments) }; - -export function __wbg_new_70828a4353259d4b(arg0, arg1) { - try { - var state0 = {a: arg0, b: arg1}; - var cb0 = (arg0, arg1) => { - const a = state0.a; - state0.a = 0; - try { - return __wbg_adapter_229(a, state0.b, arg0, arg1); - } finally { - state0.a = a; - } - }; - const ret = new Promise(cb0); - return addHeapObject(ret); - } finally { - state0.a = state0.b = 0; - } -}; - -export function __wbg_resolve_5da6faf2c96fd1d5(arg0) { - const ret = Promise.resolve(getObject(arg0)); - return addHeapObject(ret); -}; - -export function __wbg_then_f9e58f5a50f43eae(arg0, arg1) { - const ret = getObject(arg0).then(getObject(arg1)); - return addHeapObject(ret); -}; - -export function __wbg_then_20a5920e447d1cb1(arg0, arg1, arg2) { - const ret = getObject(arg0).then(getObject(arg1), getObject(arg2)); - return addHeapObject(ret); -}; - -export function __wbg_buffer_b914fb8b50ebbc3e(arg0) { - const ret = getObject(arg0).buffer; - return addHeapObject(ret); -}; - -export function __wbg_newwithbyteoffsetandlength_0de9ee56e9f6ee6e(arg0, arg1, arg2) { - const ret = new Uint8Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0); - return addHeapObject(ret); -}; - -export function __wbg_new_b1f2d6842d615181(arg0) { - const ret = new Uint8Array(getObject(arg0)); - return addHeapObject(ret); -}; - -export function __wbg_set_7d988c98e6ced92d(arg0, arg1, arg2) { - getObject(arg0).set(getObject(arg1), arg2 >>> 0); -}; - -export function __wbg_length_21c4b0ae73cba59d(arg0) { - const ret = getObject(arg0).length; - return ret; -}; - -export function __wbg_buffer_67e624f5a0ab2319(arg0) { - const ret = getObject(arg0).buffer; - return addHeapObject(ret); -}; - -export function __wbg_byteLength_4f4b58172d990c0a(arg0) { - const ret = getObject(arg0).byteLength; - return ret; -}; - -export function __wbg_byteOffset_adbd2a554609eb4e(arg0) { - const ret = getObject(arg0).byteOffset; - return ret; -}; - -export function __wbg_stringify_865daa6fb8c83d5a() { return handleError(function (arg0) { - const ret = JSON.stringify(getObject(arg0)); - return addHeapObject(ret); -}, arguments) }; - -export function __wbg_has_ad45eb020184f624() { return handleError(function (arg0, arg1) { - const ret = Reflect.has(getObject(arg0), getObject(arg1)); - return ret; -}, arguments) }; - -export function __wbg_set_961700853a212a39() { return handleError(function (arg0, arg1, arg2) { - const ret = Reflect.set(getObject(arg0), getObject(arg1), getObject(arg2)); - return ret; -}, arguments) }; - -export function __wbindgen_debug_string(arg0, arg1) { - const ret = debugString(getObject(arg1)); - const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; -}; - -export function __wbindgen_throw(arg0, arg1) { - throw new Error(getStringFromWasm0(arg0, arg1)); -}; - -export function __wbindgen_memory() { - const ret = wasm.memory; - return addHeapObject(ret); -}; - -export function __wbindgen_closure_wrapper2392(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 1028, __wbg_adapter_32); - return addHeapObject(ret); -}; - -export function __wbindgen_closure_wrapper2921(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 1190, __wbg_adapter_35); - return addHeapObject(ret); -}; - -export function __wbindgen_closure_wrapper2923(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 1190, __wbg_adapter_35); - return addHeapObject(ret); -}; - -export function __wbindgen_closure_wrapper2925(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 1190, __wbg_adapter_40); - return addHeapObject(ret); -}; - -export function __wbindgen_closure_wrapper2927(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 1190, __wbg_adapter_35); - return addHeapObject(ret); -}; - -export function __wbindgen_closure_wrapper3396(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 1396, __wbg_adapter_45); - return addHeapObject(ret); -}; - -export function __wbindgen_closure_wrapper3492(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 1450, __wbg_adapter_48); - return addHeapObject(ret); -}; - diff --git a/modules/client/pkg/hyperclient_bg.wasm b/modules/client/pkg/hyperclient_bg.wasm deleted file mode 100644 index 146f14821..000000000 Binary files a/modules/client/pkg/hyperclient_bg.wasm and /dev/null differ diff --git a/modules/client/pkg/hyperclient_bg.wasm.d.ts b/modules/client/pkg/hyperclient_bg.wasm.d.ts deleted file mode 100644 index 4b6ec9116..000000000 --- a/modules/client/pkg/hyperclient_bg.wasm.d.ts +++ /dev/null @@ -1,79 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -export const memory: WebAssembly.Memory; -export function __wbg_jschainconfig_free(a: number): void; -export function __wbg_get_jschainconfig_rpc_url(a: number, b: number): void; -export function __wbg_set_jschainconfig_rpc_url(a: number, b: number, c: number): void; -export function __wbg_get_jschainconfig_state_machine(a: number, b: number): void; -export function __wbg_set_jschainconfig_state_machine(a: number, b: number, c: number): void; -export function __wbg_get_jschainconfig_host_address(a: number, b: number): void; -export function __wbg_set_jschainconfig_host_address(a: number, b: number, c: number): void; -export function __wbg_get_jschainconfig_handler_address(a: number, b: number): void; -export function __wbg_set_jschainconfig_handler_address(a: number, b: number, c: number): void; -export function __wbg_get_jschainconfig_consensus_state_id(a: number, b: number): void; -export function __wbg_set_jschainconfig_consensus_state_id(a: number, b: number, c: number): void; -export function __wbg_jshyperbridgeconfig_free(a: number): void; -export function __wbg_jsclientconfig_free(a: number): void; -export function __wbg_get_jsclientconfig_source(a: number): number; -export function __wbg_set_jsclientconfig_source(a: number, b: number): void; -export function __wbg_get_jsclientconfig_dest(a: number): number; -export function __wbg_set_jsclientconfig_dest(a: number, b: number): void; -export function __wbg_get_jsclientconfig_hyperbridge(a: number): number; -export function __wbg_set_jsclientconfig_hyperbridge(a: number, b: number): void; -export function __wbg_jspost_free(a: number): void; -export function __wbg_get_jspost_source(a: number, b: number): void; -export function __wbg_set_jspost_source(a: number, b: number, c: number): void; -export function __wbg_get_jspost_dest(a: number, b: number): void; -export function __wbg_set_jspost_dest(a: number, b: number, c: number): void; -export function __wbg_get_jspost_nonce(a: number): number; -export function __wbg_set_jspost_nonce(a: number, b: number): void; -export function __wbg_get_jspost_from(a: number, b: number): void; -export function __wbg_set_jspost_from(a: number, b: number, c: number): void; -export function __wbg_get_jspost_to(a: number, b: number): void; -export function __wbg_set_jspost_to(a: number, b: number, c: number): void; -export function __wbg_get_jspost_timeout_timestamp(a: number): number; -export function __wbg_set_jspost_timeout_timestamp(a: number, b: number): void; -export function __wbg_get_jspost_data(a: number, b: number): void; -export function __wbg_set_jspost_data(a: number, b: number, c: number): void; -export function __wbg_get_jspost_gas_limit(a: number): number; -export function __wbg_set_jspost_gas_limit(a: number, b: number): void; -export function __wbg_jsresponse_free(a: number): void; -export function __wbg_get_jsresponse_post(a: number): number; -export function __wbg_set_jsresponse_post(a: number, b: number): void; -export function __wbg_get_jsresponse_response(a: number, b: number): void; -export function __wbg_set_jsresponse_response(a: number, b: number, c: number): void; -export function __wbg_set_jsresponse_timeout_timestamp(a: number, b: number): void; -export function __wbg_set_jsresponse_gas_limit(a: number, b: number): void; -export function __wbg_get_jsresponse_timeout_timestamp(a: number): number; -export function __wbg_get_jsresponse_gas_limit(a: number): number; -export function __wbg_get_jshyperbridgeconfig_rpc_url(a: number, b: number): void; -export function __wbg_set_jshyperbridgeconfig_rpc_url(a: number, b: number, c: number): void; -export function query_request_status(a: number, b: number): number; -export function query_response_status(a: number, b: number): number; -export function timeout_post_request(a: number, b: number): number; -export function subscribe_to_request_status(a: number, b: number, c: number): number; -export function __wbg_intounderlyingsink_free(a: number): void; -export function intounderlyingsink_write(a: number, b: number): number; -export function intounderlyingsink_close(a: number): number; -export function intounderlyingsink_abort(a: number, b: number): number; -export function __wbg_intounderlyingbytesource_free(a: number): void; -export function intounderlyingbytesource_type(a: number, b: number): void; -export function intounderlyingbytesource_autoAllocateChunkSize(a: number): number; -export function intounderlyingbytesource_start(a: number, b: number): void; -export function intounderlyingbytesource_pull(a: number, b: number): number; -export function intounderlyingbytesource_cancel(a: number): void; -export function __wbg_intounderlyingsource_free(a: number): void; -export function intounderlyingsource_pull(a: number, b: number): number; -export function intounderlyingsource_cancel(a: number): void; -export function __wbindgen_malloc(a: number, b: number): number; -export function __wbindgen_realloc(a: number, b: number, c: number, d: number): number; -export const __wbindgen_export_2: WebAssembly.Table; -export function wasm_bindgen__convert__closures__invoke0_mut__hdc28361670d72cce(a: number, b: number): void; -export function _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h367ff8bffb6f7b2e(a: number, b: number, c: number): void; -export function _dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h9aae2ac53c63e19e(a: number, b: number): void; -export function wasm_bindgen__convert__closures__invoke0_mut__h3c8b3f369d6af9ec(a: number, b: number): void; -export function _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hb494be3815513233(a: number, b: number, c: number): void; -export function __wbindgen_add_to_stack_pointer(a: number): number; -export function __wbindgen_free(a: number, b: number, c: number): void; -export function __wbindgen_exn_store(a: number): void; -export function wasm_bindgen__convert__closures__invoke2_mut__h124eb194c086a246(a: number, b: number, c: number, d: number): void; diff --git a/modules/client/pkg/package.json b/modules/client/pkg/package.json deleted file mode 100644 index b1b209ed6..000000000 --- a/modules/client/pkg/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "hyperclient", - "version": "0.1.0", - "files": [ - "hyperclient_bg.wasm", - "hyperclient.js", - "hyperclient_bg.js", - "hyperclient.d.ts" - ], - "module": "hyperclient.js", - "types": "hyperclient.d.ts", - "sideEffects": [ - "./hyperclient.js", - "./snippets/*" - ] -} \ No newline at end of file diff --git a/modules/client/src/interfaces.rs b/modules/client/src/interfaces.rs index 2c151fe1f..754160f3c 100644 --- a/modules/client/src/interfaces.rs +++ b/modules/client/src/interfaces.rs @@ -121,6 +121,8 @@ pub struct JsPost { /// Gas limit for executing the request on destination /// This value should be zero if destination module is not a contract pub gas_limit: u64, + /// Height at which this request was emitted on the source chain + pub height: u64, } impl TryFrom for Post { @@ -266,6 +268,7 @@ mod tests { timeout_timestamp: 1_600_000, data: vec![40; 256], gas_limit: 5000, + height: 0, }, response: vec![80; 256], timeout_timestamp: 4_500_000, diff --git a/modules/client/src/internals.rs b/modules/client/src/internals.rs index 511194478..8ca4d4841 100644 --- a/modules/client/src/internals.rs +++ b/modules/client/src/internals.rs @@ -1,10 +1,12 @@ +///! This module contains the internal implementation of HyperClient. use crate::{ - providers::global::{wait_for_challenge_period, Client}, + providers::interface::RequestOrResponse, + providers::interface::{wait_for_challenge_period, Client}, types::{BoxStream, ClientConfig, MessageStatus, TimeoutStatus}, + types::{MessageStatusWithMetadata, PostStreamState}, Keccak256, }; use anyhow::anyhow; -///! This module contains the internal implementation of HyperClient. use ethers::prelude::H160; use futures::{stream, StreamExt}; use ismp::{ @@ -14,6 +16,9 @@ use ismp::{ util::hash_request, }; +use ismp::events::Event; +use std::time::Duration; + /// `query_request_status_internal` is an internal function that /// checks the status of a message pub async fn query_request_status_internal( @@ -135,14 +140,14 @@ pub async fn timeout_request_stream( match event { Ok(ev) => { let state_machine_height = StateMachineHeight { - id: ev.state_machine_id, - height: ev.latest_height, + id: ev.event.state_machine_id, + height: ev.event.latest_height, }; let commitment = hyperbridge_client .query_state_machine_commitment(state_machine_height) .await?; if commitment.timestamp > post.timeout_timestamp { - valid_proof_height = Some(ev.latest_height); + valid_proof_height = Some(ev); break } }, @@ -155,16 +160,18 @@ pub async fn timeout_request_stream( ))), } } - Ok(valid_proof_height.map(|height| { + Ok(valid_proof_height.map(|ev| { ( - Ok(TimeoutStatus::DestinationFinalized), - TimeoutStreamState::DestinationFinalized(height), + Ok(TimeoutStatus::DestinationFinalized { meta: ev.meta }), + TimeoutStreamState::DestinationFinalized( + ev.event.latest_height, + ), ) })) } else { let height = hyperbridge_client.query_latest_block_height().await?; Ok(Some(( - Ok(TimeoutStatus::HyperbridgeTimedout), + Ok(TimeoutStatus::HyperbridgeTimedout { meta: Default::default() }), TimeoutStreamState::HyperbridgeTimedout(height), ))) } @@ -194,11 +201,10 @@ pub async fn timeout_request_stream( challenge_period, ) .await?; - hyperbridge_client.submit(message).await?; - let next_height = hyperbridge_client.query_latest_block_height().await?; + let meta = hyperbridge_client.submit(message).await?; Ok(Some(( - Ok(TimeoutStatus::HyperbridgeTimedout), - TimeoutStreamState::HyperbridgeTimedout(next_height), + Ok(TimeoutStatus::HyperbridgeTimedout { meta }), + TimeoutStreamState::HyperbridgeTimedout(meta.block_number), ))) }, TimeoutStreamState::HyperbridgeTimedout(hyperbridge_height) => { @@ -213,16 +219,16 @@ pub async fn timeout_request_stream( match event { Ok(ev) => { let state_machine_height = StateMachineHeight { - id: ev.state_machine_id, - height: ev.latest_height, + id: ev.event.state_machine_id, + height: ev.event.latest_height, }; let commitment = source_client .query_state_machine_commitment(state_machine_height) .await?; if commitment.timestamp > post.timeout_timestamp && - ev.latest_height >= hyperbridge_height + ev.event.latest_height >= hyperbridge_height { - valid_proof_height = Some(ev.latest_height); + valid_proof_height = Some(ev); break } }, @@ -233,10 +239,11 @@ pub async fn timeout_request_stream( ))), } } - Ok(valid_proof_height.map(|height| { + + Ok(valid_proof_height.map(|event| { ( - Ok(TimeoutStatus::HyperbridgeFinalized), - TimeoutStreamState::HyperbridgeFinalized(height), + Ok(TimeoutStatus::HyperbridgeFinalized { meta: event.meta }), + TimeoutStreamState::HyperbridgeFinalized(event.event.latest_height), ) })) }, @@ -262,9 +269,10 @@ pub async fn timeout_request_stream( source_client.query_state_machine_update_time(height).await?; wait_for_challenge_period(&source_client, update_time, challenge_period) .await?; - let message = source_client.encode(message)?; + let calldata = source_client.encode(message)?; + Ok(Some(( - Ok(TimeoutStatus::TimeoutMessage(message)), + Ok(TimeoutStatus::TimeoutMessage { calldata }), TimeoutStreamState::End, ))) }, @@ -282,3 +290,310 @@ pub async fn timeout_request_stream( Ok(Box::pin(stream)) } + +/// returns the query stream for a post +pub async fn request_status_stream( + post: Post, + source_client: impl Client, + dest_client: impl Client, + hyperbridge_client: impl Client, + post_request_height: u64, +) -> BoxStream { + let stream = stream::unfold(PostStreamState::Pending, move |post_request_status| { + let dest_client = dest_client.clone(); + let hyperbridge_client = hyperbridge_client.clone(); + let source_client = source_client.clone(); + let req = Request::Post(post.clone()); + let hash = hash_request::(&req); + let post = post.clone(); + async move { + let lambda = || async { + match post_request_status { + PostStreamState::Pending => { + let destination_current_timestamp = dest_client.query_timestamp().await?; + let relayer_address = dest_client.query_request_receipt(hash).await?; + + if relayer_address != H160::zero() { + // This means the message has gotten to the destination chain + return Ok::< + Option<(Result<_, anyhow::Error>, PostStreamState)>, + anyhow::Error, + >(Some(( + Ok(MessageStatusWithMetadata::DestinationDelivered { + meta: Default::default(), + }), + PostStreamState::End, + ))) + } + + if destination_current_timestamp.as_secs() >= post.timeout_timestamp { + // Checking to see if the message has timed-out + return Ok(Some(( + Ok(MessageStatusWithMetadata::Timeout), + PostStreamState::End, + ))) + } + + let hyperbridge_current_timestamp = + hyperbridge_client.query_timestamp().await?; + let relayer = hyperbridge_client.query_request_receipt(hash).await?; + + if relayer != H160::zero() { + // This means the message has gotten to the destination chain + return Ok::< + Option<(Result<_, anyhow::Error>, PostStreamState)>, + anyhow::Error, + >(Some(( + Ok(MessageStatusWithMetadata::HyperbridgeDelivered { + meta: Default::default(), + }), + PostStreamState::HyperbridgeDelivered( + hyperbridge_client.query_latest_block_height().await?, + ), + ))) + } + + if hyperbridge_current_timestamp.as_secs() >= post.timeout_timestamp { + // Checking to see if the message has timed-out + return Ok(Some(( + Ok(MessageStatusWithMetadata::Timeout), + PostStreamState::End, + ))) + } + + let mut state_machine_updated_stream = hyperbridge_client + .state_machine_update_notification(source_client.state_machine_id()) + .await?; + + while let Some(item) = state_machine_updated_stream.next().await { + match item { + Ok(state_machine_update) => { + if state_machine_update.event.latest_height >= + post_request_height && + state_machine_update.event.state_machine_id.state_id == + post.source + { + return Ok(Some(( + Ok(MessageStatusWithMetadata::SourceFinalized { + meta: state_machine_update.meta, + }), + PostStreamState::SourceFinalized( + state_machine_update.meta.block_number, + ), + ))) + } + }, + Err(e) => + return Ok(Some(( + Err(anyhow!( + "Encountered an error {:?}: in {:?}", + PostStreamState::Pending, + e + )), + post_request_status, + ))), + }; + } + + Ok(None) + }, + + PostStreamState::SourceFinalized(finalized_height) => { + let relayer = hyperbridge_client.query_request_receipt(hash).await?; + + if relayer != H160::zero() { + let latest_height = + hyperbridge_client.query_latest_block_height().await?; + + let meta = dest_client + .query_ismp_event(finalized_height..=latest_height) + .await? + .into_iter() + .find_map(|event| match event.event { + Event::PostRequest(post_event) + if post.source == post_event.source && + post.nonce == post_event.nonce => + Some(event.meta), + _ => None, + }); + + return Ok(Some(( + Ok(MessageStatusWithMetadata::HyperbridgeDelivered { + meta: meta.unwrap_or_default(), + }), + PostStreamState::HyperbridgeDelivered( + meta.map(|m| m.block_number).unwrap_or(latest_height), + ), + ))); + } + + let mut stream = hyperbridge_client + .ismp_events_stream(RequestOrResponse::Request(post.clone())) + .await?; + while let Some(event) = stream.next().await { + match event { + Ok(event) => { + return Ok(Some(( + Ok(MessageStatusWithMetadata::HyperbridgeDelivered { + meta: event.meta.clone(), + }), + PostStreamState::HyperbridgeDelivered( + event.meta.block_number, + ), + ))); + }, + Err(e) => tracing::info!( + "Encountered waiting for message on hyperbridge: {e:?}" + ), + } + } + + Ok(None) + }, + PostStreamState::HyperbridgeDelivered(height) => { + let res = dest_client.query_request_receipt(hash).await?; + if res != H160::zero() { + return Ok(Some(( + Ok(MessageStatusWithMetadata::DestinationDelivered { + meta: Default::default(), + }), + PostStreamState::End, + ))); + } + + let mut stream = dest_client + .state_machine_update_notification( + hyperbridge_client.state_machine_id(), + ) + .await?; + while let Some(update) = stream.next().await { + match update { + Ok(event) => + if event.event.latest_height >= height { + return Ok(Some(( + Ok(MessageStatusWithMetadata::HyperbridgeFinalized { + meta: event.meta, + }), + PostStreamState::HyperbridgeFinalized( + event.meta.block_number, + ), + ))); + } else { + continue + }, + Err(e) => + return Ok(Some(( + Err(anyhow!( + "Encountered an error {:?}: in {:?}", + PostStreamState::HyperbridgeDelivered(height), + e + )), + post_request_status, + ))), + } + } + Ok(None) + }, + PostStreamState::HyperbridgeFinalized(finalized_height) => { + let res = dest_client.query_request_receipt(hash).await?; + if res != H160::zero() { + let latest_height = dest_client.query_latest_block_height().await?; + let meta = dest_client + .query_ismp_event(finalized_height..=latest_height) + .await? + .into_iter() + .find_map(|event| match event.event { + Event::PostRequest(post_event) + if post.source == post_event.source && + post.nonce == post_event.nonce => + Some(event.meta), + _ => None, + }) + .unwrap_or_default(); + return Ok(Some(( + Ok(MessageStatusWithMetadata::DestinationDelivered { meta }), + PostStreamState::DestinationDelivered, + ))); + } + let mut stream = dest_client.post_request_handled_stream(hash).await?; + + while let Some(event) = stream.next().await { + match event { + Ok(event) => return Ok(Some(( + Ok(MessageStatusWithMetadata::DestinationDelivered { + meta: event.meta, + }), + PostStreamState::DestinationDelivered, + ))), + Err(e) => tracing::info!( + "Encountered an error waiting for message delivery to destination {e:?}", + ), + } + } + + Ok(None) + }, + + PostStreamState::DestinationDelivered | PostStreamState::End => + Ok::, PostStreamState)>, anyhow::Error>(None), + } + }; + + let response = lambda().await; + match response { + Ok(res) => res, + Err(e) => Some(( + Err(anyhow!("Encountered an error in stream {e:?}")), + post_request_status, + )), + } + } + }); + + Box::pin(stream) +} + +/// This returns a stream that yields when the provided timeout value is reached on the chain for +/// the provided [`Client`] +pub async fn request_timeout_stream( + timeout: u64, + client: impl Client + Clone, +) -> BoxStream { + let stream = stream::unfold((), move |_| { + let client_moved = client.clone(); + + async move { + let lambda = || async { + let current_timestamp = client_moved.query_timestamp().await?.as_secs(); + + return if current_timestamp > timeout { + Ok(true) + } else { + let sleep_time = timeout - current_timestamp; + let _ = wasm_timer::Delay::new(Duration::from_secs(sleep_time)).await; + Ok::<_, anyhow::Error>(false) + }; + }; + + let response = lambda().await; + + let value = match response { + Ok(true) => Some((Ok(Some(MessageStatusWithMetadata::Timeout)), ())), + Ok(false) => Some((Ok(None), ())), + Err(e) => + Some((Err(anyhow!("Encountered an error in timeout stream: {:?}", e)), ())), + }; + + return value + } + }) + .filter_map(|item| async move { + match item { + Ok(None) => None, + Ok(Some(event)) => Some(Ok(event)), + Err(err) => Some(Err(err)), + } + }); + + Box::pin(stream) +} diff --git a/modules/client/src/lib.rs b/modules/client/src/lib.rs index 486cb719b..df332c120 100644 --- a/modules/client/src/lib.rs +++ b/modules/client/src/lib.rs @@ -1,45 +1,67 @@ -mod internals; -#[cfg(test)] -mod mock; -mod providers; -mod runtime; -mod streams; -mod types; - -mod interfaces; -#[cfg(test)] -mod tests; +//! The hyperclient. Allows clients of hyperbridge manage their in-flight ISMP requests. + +pub mod internals; +pub mod providers; +pub mod runtime; +pub mod types; + +pub mod interfaces; extern crate alloc; extern crate core; use crate::{ internals::{query_request_status_internal, query_response_status_internal}, - streams::{query_request_status_stream, timeout_stream}, types::ClientConfig, }; use crate::{ interfaces::{JsClientConfig, JsPost, JsResponse}, internals::timeout_request_stream, + types::{MessageStatusWithMetadata, TimeoutStatus}, }; use ethers::{types::H256, utils::keccak256}; -use futures::{stream, StreamExt}; +use futures::StreamExt; use ismp::router::{Post, PostResponse}; use wasm_bindgen::prelude::*; use wasm_streams::ReadableStream; -/// Functions takes in a post request and returns one of the following json strings variants -/// Status variants: `Pending`, `SourceFinalized`, `HyperbridgeDelivered`, `HyperbridgeFinalized`, -/// `DestinationDelivered`, `Timeout` +/// Accepts a post request and returns a `MessageStatus` where +/// type MessageStatus = SourceFinalized | HyperbridgeDelivered | HyperbridgeFinalized | +/// DestinationDelivered | Timeout; +/// +/// // This event is emitted on hyperbridge +/// interface SourceFinalized { +/// kind: "SourceFinalized"; +/// } +/// +/// // This event is emitted on hyperbridge +/// interface HyperbridgeDelivered { +/// kind: "HyperbridgeDelivered"; +/// } +/// +/// // This event is emitted on the destination chain +/// interface HyperbridgeFinalized { +/// kind: "HyperbridgeFinalized"; +/// } +/// +/// // This event is emitted on the destination chain +/// interface DestinationDelivered { +/// kind: "DestinationDelivered"; +/// } +/// +/// // The request has now timed out +/// interface Timeout { +/// kind: "Timeout"; +/// } #[wasm_bindgen] pub async fn query_request_status( request: JsPost, - config_js: JsClientConfig, + config: JsClientConfig, ) -> Result { let post: Post = request.try_into().map_err(|_| JsError::new("deserialization error"))?; let config: ClientConfig = - config_js.try_into().map_err(|_| JsError::new("deserialization error"))?; + config.try_into().map_err(|_| JsError::new("deserialization error"))?; let response = query_request_status_internal(post, config) .await @@ -48,18 +70,43 @@ pub async fn query_request_status( serde_wasm_bindgen::to_value(&response).map_err(|_| JsError::new("deserialization error")) } -/// Function takes in a post response and returns one of the following json strings variants -/// Status Variants: `Pending`, `SourceFinalized`, `HyperbridgeDelivered`, `HyperbridgeFinalized`, -/// `DestinationDelivered`, `Timeout` +/// Accepts a post response and returns a `MessageStatus` where +/// type MessageStatus = SourceFinalized | HyperbridgeDelivered | HyperbridgeFinalized | +/// DestinationDelivered | Timeout; +/// +/// // This event is emitted on hyperbridge +/// interface SourceFinalized { +/// kind: "SourceFinalized"; +/// } +/// +/// // This event is emitted on hyperbridge +/// interface HyperbridgeDelivered { +/// kind: "HyperbridgeDelivered"; +/// } +/// +/// // This event is emitted on the destination chain +/// interface HyperbridgeFinalized { +/// kind: "HyperbridgeFinalized"; +/// } +/// +/// // This event is emitted on the destination chain +/// interface DestinationDelivered { +/// kind: "DestinationDelivered"; +/// } +/// +/// // The request has now timed out +/// interface Timeout { +/// kind: "Timeout"; +/// } #[wasm_bindgen] pub async fn query_response_status( response: JsResponse, - config_js: JsClientConfig, + config: JsClientConfig, ) -> Result { let post_response: PostResponse = response.try_into().map_err(|_| JsError::new("deserialization error"))?; let config: ClientConfig = - config_js.try_into().map_err(|_| JsError::new("deserialization error"))?; + config.try_into().map_err(|_| JsError::new("deserialization error"))?; let response = query_response_status_internal(config, post_response) .await .map_err(|e| JsError::new(e.to_string().as_str()))?; @@ -67,19 +114,67 @@ pub async fn query_response_status( serde_wasm_bindgen::to_value(&response).map_err(|_| JsError::new("deserialization error")) } -/// Accepts a post request that has timed out returns a stream that yields the following json -/// strings variants Status Variants: `Pending`, `DestinationFinalized`, `HyperbridgeTimedout`, -/// `HyperbridgeFinalized`, `{ "TimeoutMessage": [...] }`. This function will not check if the -/// request has timed out, only call it when sure that the request has timed out after calling -/// `query_request_status` +/// Accepts a post request that has timed out returns a `ReadableStream` that yields a +/// `TimeoutStatus` where type TimeoutStatus = DestinationFinalized | HyperbridgeTimedout | +/// HyperbridgeFinalized | TimeoutMessage | Error; +/// +/// // This event is emitted on hyperbridge +/// interface DestinationFinalized { +/// kind: "DestinationFinalized"; +/// // The hash of the block where the event was emitted +/// block_hash: H256, +/// // The hash of the extrinsic responsible for the event +/// transaction_hash: H256, +/// // The block number where the event was emitted +/// block_number: u64, +/// } +/// +/// // This event is emitted on hyperbridge +/// interface HyperbridgeTimedout { +/// kind: "HyperbridgeTimedout"; +/// // The hash of the block where the event was emitted +/// block_hash: H256, +/// // The hash of the extrinsic responsible for the event +/// transaction_hash: H256, +/// // The block number where the event was emitted +/// block_number: u64, +/// } +/// +/// // This event is emitted on the source chain +/// interface HyperbridgeFinalized { +/// kind: "HyperbridgeFinalized"; +/// // The hash of the block where the event was emitted +/// block_hash: H256, +/// // The hash of the extrinsic responsible for the event +/// transaction_hash: H256, +/// // The block number where the event was emitted +/// block_number: u64, +/// } +/// +/// // This event is emitted on the destination chain +/// interface TimeoutMessage { +/// kind: "TimeoutMessage"; +/// // encoded call for HandlerV1.handlePostRequestTimeouts +/// calldata: Vec, +/// } +/// +/// // An error was encountered in the stream, errors are recoverable so it's safe to continue +/// polling. interface Error { +/// kind: "Error"; +/// // error description +/// description: string +/// } +/// +/// This function will not check if the request has timed out, only call it when sure that the +/// request has timed out after calling `query_request_status` #[wasm_bindgen] pub async fn timeout_post_request( request: JsPost, - config_js: JsClientConfig, + config: JsClientConfig, ) -> Result { let post: Post = request.try_into().map_err(|_| JsError::new("deserialization error"))?; let config: ClientConfig = - config_js.try_into().map_err(|_| JsError::new("deserialization error"))?; + config.try_into().map_err(|_| JsError::new("deserialization error"))?; let stream = timeout_request_stream(post, config) .await @@ -87,29 +182,89 @@ pub async fn timeout_post_request( .map(|value| { value .map(|status| serde_wasm_bindgen::to_value(&status).expect("Infallible")) - .map_err(|e| JsValue::from_str(alloc::format!("{e:?}").as_str())) + .map_err(|e| { + serde_wasm_bindgen::to_value(&TimeoutStatus::Error { + description: alloc::format!("{e:?}"), + }) + .expect("Infallible") + }) }); let js_stream = ReadableStream::from_stream(stream); Ok(js_stream.into_raw()) } -// ===================================== -// Stream Functions -// ===================================== - -/// Races between a timeout stream and request processing stream, and yields the following json -/// strings variants Status Variants: `Pending`, `SourceFinalized`, `HyperbridgeDelivered`, -/// `HyperbridgeFinalized`, `DestinationDelivered`, `Timeout` +/// Accepts a PostRequest and returns a `ReadableStream` that yields a `MessageStatus` where: +/// type MessageStatus = SourceFinalized | HyperbridgeDelivered | HyperbridgeFinalized | +/// DestinationDelivered | Timeout | Error; +/// +/// // This event is emitted on hyperbridge +/// interface SourceFinalized { +/// kind: "SourceFinalized"; +/// // The hash of the block where the event was emitted +/// block_hash: H256, +/// // The hash of the extrinsic responsible for the event +/// transaction_hash: H256, +/// // The block number where the event was emitted +/// block_number: u64, +/// } +/// +/// // This event is emitted on hyperbridge +/// interface HyperbridgeDelivered { +/// kind: "HyperbridgeDelivered"; +/// // The hash of the block where the event was emitted +/// block_hash: H256, +/// // The hash of the extrinsic responsible for the event +/// transaction_hash: H256, +/// // The block number where the event was emitted +/// block_number: u64, +/// } +/// +/// // This event is emitted on the destination chain +/// interface HyperbridgeFinalized { +/// kind: "HyperbridgeFinalized"; +/// // The hash of the block where the event was emitted +/// block_hash: H256, +/// // The hash of the extrinsic responsible for the event +/// transaction_hash: H256, +/// // The block number where the event was emitted +/// block_number: u64, +/// } +/// +/// // This event is emitted on the destination chain +/// interface DestinationDelivered { +/// kind: "DestinationDelivered"; +/// // The hash of the block where the event was emitted +/// block_hash: H256, +/// // The hash of the extrinsic responsible for the event +/// transaction_hash: H256, +/// // The block number where the event was emitted +/// block_number: u64, +/// } +/// +/// // The request has now timed out +/// interface Timeout { +/// kind: "Timeout"; +/// } +/// +/// // An error was encountered in the stream, errors are recoverable so it's safe to continue +/// polling. interface Error { +/// kind: "Error"; +/// // error description +/// description: string +/// } #[wasm_bindgen] -pub async fn subscribe_to_request_status( +pub async fn request_status_stream( request: JsPost, - config_js: JsClientConfig, - post_request_height: u64, + config: JsClientConfig, ) -> Result { - let post: Post = request.try_into().map_err(|_| JsError::new("deserialization error"))?; - let config: ClientConfig = - config_js.try_into().map_err(|_| JsError::new("deserialization error"))?; + let post: Post = request + .clone() + .try_into() + .map_err(|_err| JsError::new("deserialization error: {_err:?}"))?; + let config: ClientConfig = config + .try_into() + .map_err(|_err| JsError::new("deserialization error: {_err:?}"))?; let source_client = config.source_chain().await.map_err(|e| JsError::new(e.to_string().as_str()))?; let dest_client = @@ -119,32 +274,27 @@ pub async fn subscribe_to_request_status( .await .map_err(|e| JsError::new(e.to_string().as_str()))?; - let stream = stream::unfold((), move |_| { - let dest_client = dest_client.clone(); - let hyperbridge_client = hyperbridge_client.clone(); - let source_client = source_client.clone(); - let post = post.clone(); - async move { - // Obtaining the request stream and the timeout stream - let mut timed_out = timeout_stream(post.timeout_timestamp, source_client.clone()).await; - let mut request_status = query_request_status_stream( - post, - source_client.clone(), - dest_client, - hyperbridge_client, - post_request_height, - ) - .await; - - tokio::select! { - result = timed_out.next() => { - return result.map(|val| (val.map(|status| serde_wasm_bindgen::to_value(&status).expect("Infallible")).map_err(|e| JsValue::from_str(alloc::format!("{e:?}").as_str())), ())) - } - result = request_status.next() => { - return result.map(|val| (val.map(|status| serde_wasm_bindgen::to_value(&status).expect("Infallible")).map_err(|e| JsValue::from_str(alloc::format!("{e:?}").as_str())), ())) - } - } - } + // Obtaining the request stream and the timeout stream + let timed_out = + internals::request_timeout_stream(post.timeout_timestamp, source_client.clone()).await; + + let request_status = internals::request_status_stream( + post, + source_client.clone(), + dest_client, + hyperbridge_client, + request.height, + ) + .await; + + let stream = futures::stream::select(request_status, timed_out).map(|res| { + res.map(|status| serde_wasm_bindgen::to_value(&status).expect("Infallible")) + .map_err(|e| { + serde_wasm_bindgen::to_value(&MessageStatusWithMetadata::Error { + description: alloc::format!("{e:?}"), + }) + .expect("Infallible") + }) }); // Wrapping the main stream in a readable stream diff --git a/modules/client/src/mock/mod.rs b/modules/client/src/mock/mod.rs deleted file mode 100644 index 28a20e13e..000000000 --- a/modules/client/src/mock/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -#![allow(clippy::all)] - -pub mod erc_20; diff --git a/modules/client/src/providers/evm_chain.rs b/modules/client/src/providers/evm.rs similarity index 84% rename from modules/client/src/providers/evm_chain.rs rename to modules/client/src/providers/evm.rs index d40b0913b..ee0354d94 100644 --- a/modules/client/src/providers/evm_chain.rs +++ b/modules/client/src/providers/evm.rs @@ -1,11 +1,13 @@ use crate::{ - providers::global::{Client, RequestOrResponse}, + providers::interface::{Client, RequestOrResponse}, types::BoxStream, }; use ethers::prelude::Middleware; -use super::StreamItem; -use crate::types::{EvmStateProof, SubstrateStateProof}; +use crate::{ + providers::interface::WithMetadata, + types::{EventMetadata, EvmStateProof, SubstrateStateProof}, +}; use anyhow::{anyhow, Context, Error}; use core::time::Duration; use ethers::{ @@ -25,7 +27,7 @@ use ismp_solidity_abi::{ evm_host::{EvmHost, EvmHostEvents, GetRequest, PostRequestHandledFilter}, handler::{GetTimeoutMessage, Handler, PostRequestTimeoutMessage, PostResponseTimeoutMessage}, }; -use std::{collections::BTreeMap, sync::Arc}; +use std::{collections::BTreeMap, ops::RangeInclusive, sync::Arc}; // ======================================= // CONSTANTS = @@ -163,17 +165,43 @@ impl Client for EvmClient { Ok(response_receipt.relayer) } + async fn query_ismp_event( + &self, + range: RangeInclusive, + ) -> Result>, anyhow::Error> { + let contract = EvmHost::new(self.host_address, self.client.clone()); + contract + .events() + .address(self.host_address.into()) + .from_block(*range.start()) + .to_block(*range.end()) + .query_with_meta() + .await? + .into_iter() + .map(|(event, meta)| { + Ok(WithMetadata { + meta: EventMetadata { + block_hash: meta.block_hash, + transaction_hash: meta.transaction_hash, + block_number: meta.block_number.as_u64(), + }, + event: event.try_into()?, + }) + }) + .collect::, _>>() + } + async fn ismp_events_stream( &self, _item: RequestOrResponse, - ) -> Result, Error> { + ) -> Result>, Error> { Err(anyhow!("Ismp stream unavailable for evm client")) } async fn post_request_handled_stream( &self, commitment: H256, - ) -> Result, Error> { + ) -> Result>, Error> { let initial_height = self.client.get_block_number().await?.as_u64(); let client = self.clone(); let interval = wasm_timer::Interval::new(Duration::from_secs(30)); @@ -195,7 +223,7 @@ impl Client for EvmClient { // in case we get old heights, best to ignore them if block_number < latest_height { - return Some((Ok(StreamItem::NoOp), (block_number, interval, client))) + return Some((Ok(None), (block_number, interval, client))) } let contract = EvmHost::new(client.host_address, client.client.clone()); @@ -204,7 +232,7 @@ impl Client for EvmClient { .address(client.host_address.into()) .from_block(latest_height) .to_block(block_number) - .query() + .query_with_meta() .await { Ok(events) => events, @@ -218,28 +246,29 @@ impl Client for EvmClient { let events = results .into_iter() - .filter_map(|ev| match ev { + .filter_map(|(ev, meta)| match ev { EvmHostEvents::PostRequestHandledFilter(filter) if filter.commitment == commitment.0 => - Some(filter), + Some(WithMetadata { + meta: EventMetadata { + block_hash: meta.block_hash, + transaction_hash: meta.transaction_hash, + block_number: meta.block_number.as_u64(), + }, + event: filter, + }), _ => None, }) - .collect::>(); + .collect::>(); // we only want the highest event - let value = if let Some(event) = events.last() { - StreamItem::Item(event.clone()) - } else { - StreamItem::NoOp - }; - - Some((Ok(value), (block_number + 1, interval, client))) + Some((Ok(events.last().cloned()), (block_number + 1, interval, client))) }, ) .filter_map(|item| async move { match item { - Ok(StreamItem::NoOp) => None, - Ok(StreamItem::Item(event)) => Some(Ok(event)), + Ok(None) => None, + Ok(Some(event)) => Some(Ok(event)), Err(err) => Some(Err(err)), } }); @@ -250,7 +279,7 @@ impl Client for EvmClient { async fn state_machine_update_notification( &self, _counterparty_state_id: StateMachineId, - ) -> Result, Error> { + ) -> Result>, Error> { let initial_height = self.client.get_block_number().await?.as_u64(); let interval = wasm_timer::Interval::new(Duration::from_secs(30)); let stream = stream::unfold( @@ -271,7 +300,7 @@ impl Client for EvmClient { // in case we get old heights, best to ignore them if block_number < latest_height { - return Some((Ok(StreamItem::NoOp), (block_number, interval, client))) + return Some((Ok(None), (block_number, interval, client))) } let contract = Handler::new(client.ismp_handler, client.client.clone()); @@ -280,7 +309,7 @@ impl Client for EvmClient { .address(client.ismp_handler.into()) .from_block(latest_height) .to_block(block_number) - .query() + .query_with_meta() .await { Ok(events) => events, @@ -291,24 +320,27 @@ impl Client for EvmClient { (latest_height, interval, client), )), }; - let mut events = - results.into_iter().map(|ev| ev.into()).collect::>(); + let mut events = results + .into_iter() + .map(|(ev, meta)| WithMetadata { + meta: EventMetadata { + block_hash: meta.block_hash, + transaction_hash: meta.transaction_hash, + block_number: meta.block_number.as_u64(), + }, + event: StateMachineUpdated::from(ev), + }) + .collect::>(); // we only want the highest event - events.sort_by(|a, b| a.latest_height.cmp(&b.latest_height)); + events.sort_by(|a, b| a.event.latest_height.cmp(&b.event.latest_height)); // we only want the highest event - let value = if let Some(event) = events.last() { - StreamItem::Item(event.clone()) - } else { - StreamItem::NoOp - }; - - Some((Ok(value), (block_number + 1, interval, client))) + Some((Ok(events.last().cloned()), (block_number + 1, interval, client))) }, ) .filter_map(|item| async move { match item { - Ok(StreamItem::NoOp) => None, - Ok(StreamItem::Item(event)) => Some(Ok(event)), + Ok(None) => None, + Ok(Some(event)) => Some(Ok(event)), Err(err) => Some(Err(err)), } }); @@ -442,7 +474,7 @@ impl Client for EvmClient { } } - async fn submit(&self, _msg: Message) -> Result<(), Error> { + async fn submit(&self, _msg: Message) -> Result { Err(anyhow!("Client cannot submit messages")) } diff --git a/modules/client/src/providers/global.rs b/modules/client/src/providers/interface.rs similarity index 80% rename from modules/client/src/providers/global.rs rename to modules/client/src/providers/interface.rs index 674ebf854..f247be5e8 100644 --- a/modules/client/src/providers/global.rs +++ b/modules/client/src/providers/interface.rs @@ -1,4 +1,6 @@ -use crate::types::BoxStream; +#![allow(async_fn_in_trait)] + +use crate::types::{BoxStream, EventMetadata}; use core::time::Duration; use ethers::{prelude::H256, types::H160}; use ismp::{ @@ -8,6 +10,8 @@ use ismp::{ router::{Post, PostResponse}, }; use ismp_solidity_abi::evm_host::PostRequestHandledFilter; +use serde::{Deserialize, Serialize}; +use std::ops::RangeInclusive; #[derive(Eq, PartialEq, Clone)] pub enum RequestOrResponse { @@ -15,60 +19,65 @@ pub enum RequestOrResponse { Response(PostResponse), } -// #[async_trait::async_trait] +/// Holds an event along with relevant metadata about the event +#[derive(Serialize, Deserialize, Clone)] +pub struct WithMetadata { + /// The event metdata + pub meta: EventMetadata, + /// The event in question + pub event: T, +} + pub trait Client: Clone + Send + Sync + 'static { - /// Query the latest block height of a Chain (State Machine) - #[allow(async_fn_in_trait)] + /// Query the latest block height async fn query_latest_block_height(&self) -> Result; /// Returns the State Machine ID fn state_machine_id(&self) -> StateMachineId; /// Returns the timestamp from the ISMP host of a State machine - #[allow(async_fn_in_trait)] async fn query_timestamp(&self) -> Result; /// Query request receipt from a ISMP host given the hash of the request - #[allow(async_fn_in_trait)] async fn query_request_receipt(&self, request_hash: H256) -> Result; // Queries state proof for some keys - #[allow(async_fn_in_trait)] async fn query_state_proof(&self, at: u64, key: Vec>) -> Result, anyhow::Error>; // Query the response receipt from the ISMP host on the destination chain - #[allow(async_fn_in_trait)] async fn query_response_receipt(&self, request_commitment: H256) -> Result; // Returns the event stream of this chain that yields when it finds an event that contains the // given post or response - #[allow(async_fn_in_trait)] async fn ismp_events_stream( &self, item: RequestOrResponse, - ) -> Result, anyhow::Error>; + ) -> Result>, anyhow::Error>; + + /// Should return all the events emitted between the given block range + async fn query_ismp_event( + &self, + range: RangeInclusive, + ) -> Result>, anyhow::Error>; // Returns a stream of the PostRequestHandled on the ISMP host of this chain - #[allow(async_fn_in_trait)] async fn post_request_handled_stream( &self, commitment: H256, - ) -> Result, anyhow::Error>; + ) -> Result>, anyhow::Error>; - #[allow(async_fn_in_trait)] async fn query_state_machine_commitment( &self, id: StateMachineHeight, ) -> Result; // Get state machine hyperbridge consensus state machine height - #[allow(async_fn_in_trait)] async fn state_machine_update_notification( &self, counterparty_state_id: StateMachineId, - ) -> Result, anyhow::Error>; + ) -> Result>, anyhow::Error>; /// This method should return the key used to be used to query the state proof for the request /// commitment @@ -87,22 +96,18 @@ pub trait Client: Clone + Send + Sync + 'static { fn response_receipt_full_key(&self, commitment: H256) -> Vec; /// Return the encoded unsigned transaction bytes for this message - #[allow(async_fn_in_trait)] fn encode(&self, msg: Message) -> Result, anyhow::Error>; /// Submit message to chain - #[allow(async_fn_in_trait)] - async fn submit(&self, msg: Message) -> Result<(), anyhow::Error>; + async fn submit(&self, msg: Message) -> Result; /// Query the timestamp at which the client was last updated - #[allow(async_fn_in_trait)] async fn query_state_machine_update_time( &self, height: StateMachineHeight, ) -> Result; /// Query the challenge period for client - #[allow(async_fn_in_trait)] async fn query_challenge_period(&self, id: ConsensusStateId) -> Result; } @@ -121,5 +126,6 @@ pub async fn wait_for_challenge_period( let current_timestamp = client.query_timestamp().await?; delay = current_timestamp.saturating_sub(last_consensus_update); } + Ok(()) } diff --git a/modules/client/src/providers/mod.rs b/modules/client/src/providers/mod.rs index 1ad59c371..fadad2e0c 100644 --- a/modules/client/src/providers/mod.rs +++ b/modules/client/src/providers/mod.rs @@ -1,9 +1,3 @@ -pub mod evm_chain; -pub mod global; -pub mod rpc_wrapper; +pub mod evm; +pub mod interface; pub mod substrate; - -pub enum StreamItem { - NoOp, - Item(T), -} diff --git a/modules/client/src/providers/rpc_wrapper.rs b/modules/client/src/providers/rpc_wrapper.rs deleted file mode 100644 index ebd7ea6f0..000000000 --- a/modules/client/src/providers/rpc_wrapper.rs +++ /dev/null @@ -1,57 +0,0 @@ -use futures::{StreamExt, TryStreamExt}; -use reconnecting_jsonrpsee_ws_client::{Client, SubscriptionId}; -use std::ops::Deref; -use subxt::{ - error::RpcError, - rpc::{RawValue, RpcClientT, RpcFuture, RpcSubscription}, -}; - -pub struct ClientWrapper(pub Client); - -impl Deref for ClientWrapper { - type Target = Client; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl RpcClientT for ClientWrapper { - fn request_raw<'a>( - &'a self, - method: &'a str, - params: Option>, - ) -> RpcFuture<'a, Box> { - Box::pin(async move { - let res = self - .0 - .request_raw(method.to_string(), params) - .await - .map_err(|e| RpcError::ClientError(Box::new(e)))?; - Ok(res) - }) - } - - fn subscribe_raw<'a>( - &'a self, - sub: &'a str, - params: Option>, - unsub: &'a str, - ) -> RpcFuture<'a, RpcSubscription> { - Box::pin(async move { - let stream = self - .0 - .subscribe_raw(sub.to_string(), params, unsub.to_string()) - .await - .map_err(|e| RpcError::ClientError(Box::new(e)))?; - - let id = match stream.id() { - SubscriptionId::Str(id) => Some(id.clone().into_owned()), - SubscriptionId::Num(id) => Some(id.to_string()), - }; - - let stream = stream.map_err(|e| RpcError::ClientError(Box::new(e))).boxed(); - Ok(RpcSubscription { stream, id }) - }) - } -} diff --git a/modules/client/src/providers/substrate.rs b/modules/client/src/providers/substrate.rs index 40d147bbb..aedad41b6 100644 --- a/modules/client/src/providers/substrate.rs +++ b/modules/client/src/providers/substrate.rs @@ -1,14 +1,13 @@ -use super::StreamItem; use crate::{ - providers::global::{Client, RequestOrResponse}, + providers::interface::{Client, RequestOrResponse, WithMetadata}, runtime::{self}, - types::{BoxStream, Extrinsic, HashAlgorithm, SubstrateStateProof}, + types::{BoxStream, EventMetadata, Extrinsic, HashAlgorithm, SubstrateStateProof}, }; use anyhow::{anyhow, Error}; use codec::{Decode, Encode}; use core::time::Duration; use ethers::prelude::{H160, H256}; -use futures::{stream, StreamExt}; +use futures::{stream, StreamExt, TryStreamExt}; use hashbrown::HashMap; use hex_literal::hex; use ismp::{ @@ -18,12 +17,18 @@ use ismp::{ messaging::Message, }; use ismp_solidity_abi::evm_host::PostRequestHandledFilter; -use reconnecting_jsonrpsee_ws_client::Client as ReconnectClient; +use reconnecting_jsonrpsee_ws_client::{Client as ReconnectClient, SubscriptionId}; use serde::{Deserialize, Serialize}; -use std::sync::Arc; -use subxt::{config::Header, rpc_params, OnlineClient}; - -use super::rpc_wrapper::ClientWrapper; +use std::{ + ops::{Deref, RangeInclusive}, + sync::Arc, +}; +use subxt::{ + config::Header, + error::RpcError, + rpc::{RawValue, RpcClientT, RpcFuture, RpcSubscription}, + rpc_params, OnlineClient, +}; #[derive(Debug, Clone)] pub struct SubstrateClient { @@ -35,8 +40,10 @@ pub struct SubstrateClient { pub client: OnlineClient, pub hashing: HashAlgorithm, } - -impl SubstrateClient { +impl SubstrateClient +where + C: subxt::Config + Clone, +{ pub async fn new( rpc_url: String, hashing: HashAlgorithm, @@ -78,7 +85,7 @@ impl SubstrateClient { &self, previous_height: u64, latest_height: u64, - ) -> Result, Error> { + ) -> Result>, Error> { let range = (previous_height + 1)..=latest_height; if range.is_empty() { return Ok(Default::default()); @@ -97,8 +104,8 @@ impl SubstrateClient { BlockNumberOrHash::::Number(previous_height.saturating_add(1) as u32), BlockNumberOrHash::::Number(latest_height as u32) ]; - let response: HashMap> = - self.client.rpc().request("ismp_queryEvents", params).await?; + let response: HashMap>> = + self.client.rpc().request("ismp_queryEventsWithMetadata", params).await?; let events = response.values().into_iter().cloned().flatten().collect(); Ok(events) } @@ -155,7 +162,10 @@ impl Client for SubstrateClient { } } - async fn ismp_events_stream(&self, item: RequestOrResponse) -> Result, Error> { + async fn ismp_events_stream( + &self, + item: RequestOrResponse, + ) -> Result>, Error> { let subscription = self.client.rpc().subscribe_finalized_block_headers().await?; let initial_height: u64 = self.client.blocks().at_latest().await?.number().into(); let stream = stream::unfold( @@ -167,13 +177,10 @@ impl Client for SubstrateClient { let header = match subscription.next().await { Some(Ok(header)) => header, Some(Err(_err)) => { - // log::error!( - // "Error encountered while watching finalized heads: {err:?}" - // ); - return Some(( - Ok(StreamItem::NoOp), - (latest_height, subscription, client), - )) + tracing::error!( + "Error encountered while watching finalized heads: {_err:?}" + ); + return Some((Ok(None), (latest_height, subscription, client))) }, None => return None, }; @@ -184,17 +191,15 @@ impl Client for SubstrateClient { { Ok(e) => e, Err(_err) => { - // log::error!("Error encountered while querying ismp events - // {err:?}"); - return Some(( - Ok(StreamItem::NoOp), - (latest_height, subscription, client), - )) + tracing::error!( + "Error encountered while querying ismp events {_err:?}" + ); + return Some((Ok(None), (latest_height, subscription, client))) }, }; let event = events.into_iter().find_map(|event| { - let value = match event.clone() { + let value = match event.event.clone() { Event::PostRequest(post) => Some(RequestOrResponse::Request(post)), Event::PostResponse(resp) => Some(RequestOrResponse::Response(resp)), @@ -210,13 +215,11 @@ impl Client for SubstrateClient { let value = match event { Some(event) => Some(( - Ok(StreamItem::Item(event)), - (header.number().into(), subscription, client), - )), - None => Some(( - Ok(StreamItem::NoOp), + Ok(Some(event)), (header.number().into(), subscription, client), )), + None => + Some((Ok(None), (header.number().into(), subscription, client))), }; return value; @@ -226,8 +229,8 @@ impl Client for SubstrateClient { ) .filter_map(|item| async move { match item { - Ok(StreamItem::NoOp) => None, - Ok(StreamItem::Item(event)) => Some(Ok(event)), + Ok(None) => None, + Ok(Some(event)) => Some(Ok(event)), Err(err) => Some(Err(err)), } }); @@ -238,7 +241,7 @@ impl Client for SubstrateClient { async fn post_request_handled_stream( &self, _commitment: H256, - ) -> Result, Error> { + ) -> Result>, Error> { Err(anyhow!("Post request handled stream is currently unavailable")) } @@ -267,58 +270,62 @@ impl Client for SubstrateClient { async fn state_machine_update_notification( &self, counterparty_state_id: StateMachineId, - ) -> Result, Error> { + ) -> Result>, Error> { let subscription = self.client.rpc().subscribe_finalized_block_headers().await?; let initial_height: u64 = self.client.blocks().at_latest().await?.number().into(); let stream = stream::unfold( (initial_height, subscription, self.clone()), - move |(mut latest_height, mut subscription, client)| async move { - loop { - let header = match subscription.next().await { - Some(Ok(header)) => header, - Some(Err(_err)) => { - // log::error!( - // "Error encountered while watching finalized heads: {err:?}" - // ); - continue; - }, - None => return None, - }; - - let events = match client - .query_ismp_events(latest_height, header.number().into()) - .await - { - Ok(e) => e, - Err(_err) => { - // log::error!("Error encountered while querying ismp events {err:?}"); - continue; - }, - }; - - let event = events - .into_iter() - .filter_map(|event| match event { - Event::StateMachineUpdated(e) - if e.state_machine_id == counterparty_state_id => - Some(e), - _ => None, - }) - .max_by(|x, y| x.latest_height.cmp(&y.latest_height)); - - let value = match event { - Some(event) => - Some((Ok(event), (header.number().into(), subscription, client))), - None => { - latest_height = header.number().into(); - continue; - }, - }; - - return value; - } + move |(latest_height, mut subscription, client)| async move { + let header = match subscription.next().await { + Some(Ok(header)) => header, + Some(Err(_err)) => { + tracing::error!( + "Error encountered while fetching finalized header: {_err:?}" + ); + return Some((Ok(None), (latest_height, subscription, client))) + }, + None => return None, + }; + + let events = match client + .query_ismp_events(latest_height, header.number().into()) + .await + { + Ok(e) => e, + Err(_err) => { + tracing::error!("Error encountered while querying ismp events {_err:?}"); + return Some((Ok(None), (latest_height, subscription, client))) + }, + }; + + let event = events + .into_iter() + .filter_map(|event| match event.event { + Event::StateMachineUpdated(e) + if e.state_machine_id == counterparty_state_id => + Some((e, event.meta)), + _ => None, + }) + .max_by(|x, y| x.0.latest_height.cmp(&y.0.latest_height)); + + let value = match event { + Some((event, meta)) => Some(( + Ok(Some(WithMetadata { event, meta })), + (header.number().into(), subscription, client), + )), + None => Some((Ok(None), (header.number().into(), subscription, client))), + }; + + return value; }, - ); + ) + .filter_map(|item| async move { + match item { + Ok(None) => None, + Ok(Some(event)) => Some(Ok(event)), + Err(err) => Some(Err(err)), + } + }); Ok(Box::pin(stream)) } @@ -350,12 +357,34 @@ impl Client for SubstrateClient { Ok(ext.into_encoded()) } - async fn submit(&self, msg: Message) -> Result<(), Error> { + async fn query_ismp_event( + &self, + range: RangeInclusive, + ) -> Result>, anyhow::Error> { + self.query_ismp_events(*range.start(), *range.end()).await + } + + async fn submit(&self, msg: Message) -> Result { let call = vec![msg].encode(); let hyper_bridge_timeout_extrinsic = Extrinsic::new("Ismp", "handle", call); let ext = self.client.tx().create_unsigned(&hyper_bridge_timeout_extrinsic)?; - let _ = ext.submit_and_watch().await?.wait_for_in_block().await?; - Ok(()) + let in_block = ext.submit_and_watch().await?.wait_for_in_block().await?; + in_block.wait_for_success().await?; + + let header = self + .client + .rpc() + .header(Some(in_block.block_hash())) + .await? + .ok_or_else(|| anyhow!("Inconsistent node state."))?; + + let event = EventMetadata { + block_hash: H256::from_slice(in_block.block_hash().as_ref()), + transaction_hash: H256::from_slice(in_block.extrinsic_hash().as_ref()), + block_number: header.number().into(), + }; + + Ok(event) } async fn query_state_machine_update_time( @@ -379,6 +408,57 @@ impl Client for SubstrateClient { } } +/// Adapter client for suxt +pub struct ClientWrapper(pub ReconnectClient); + +impl Deref for ClientWrapper { + type Target = ReconnectClient; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl RpcClientT for ClientWrapper { + fn request_raw<'a>( + &'a self, + method: &'a str, + params: Option>, + ) -> RpcFuture<'a, Box> { + Box::pin(async move { + let res = self + .0 + .request_raw(method.to_string(), params) + .await + .map_err(|e| RpcError::ClientError(Box::new(e)))?; + Ok(res) + }) + } + + fn subscribe_raw<'a>( + &'a self, + sub: &'a str, + params: Option>, + unsub: &'a str, + ) -> RpcFuture<'a, RpcSubscription> { + Box::pin(async move { + let stream = self + .0 + .subscribe_raw(sub.to_string(), params, unsub.to_string()) + .await + .map_err(|e| RpcError::ClientError(Box::new(e)))?; + + let id = match stream.id() { + SubscriptionId::Str(id) => Some(id.clone().into_owned()), + SubscriptionId::Num(id) => Some(id.to_string()), + }; + + let stream = stream.map_err(|e| RpcError::ClientError(Box::new(e))).boxed(); + Ok(RpcSubscription { stream, id }) + }) + } +} + impl From for StateCommitment { fn from(commitment: runtime::api::runtime_types::ismp::consensus::StateCommitment) -> Self { StateCommitment { diff --git a/modules/client/src/streams.rs b/modules/client/src/streams.rs deleted file mode 100644 index 3301d0626..000000000 --- a/modules/client/src/streams.rs +++ /dev/null @@ -1,275 +0,0 @@ -use crate::{ - providers::{ - global::{Client, RequestOrResponse}, - StreamItem, - }, - types::{BoxStream, MessageStatus, PostStreamState}, - Keccak256, -}; -use anyhow::{anyhow, Error}; -use ethers::prelude::H160; -use futures::{stream, StreamExt}; -use ismp::{ - router::{Post, Request}, - util::hash_request, -}; -use std::time::Duration; - -/// returns the query stream for a post -pub async fn query_request_status_stream( - post: Post, - source_client: impl Client, - dest_client: impl Client, - hyperbridge_client: impl Client, - post_request_height: u64, -) -> BoxStream { - let stream = stream::unfold(PostStreamState::Pending, move |post_request_status| { - let dest_client = dest_client.clone(); - let hyperbridge_client = hyperbridge_client.clone(); - let source_client = source_client.clone(); - let req = Request::Post(post.clone()); - let hash = hash_request::(&req); - let post = post.clone(); - async move { - let lambda = || async { - match post_request_status { - PostStreamState::Pending => { - let destination_current_timestamp = dest_client.query_timestamp().await?; - let relayer_address = dest_client.query_request_receipt(hash).await?; - - if relayer_address != H160::zero() { - // This means the message has gotten to the destination chain - return Ok::, PostStreamState)>, Error>(Some(( - Ok(MessageStatus::DestinationDelivered), - PostStreamState::End, - ))) - } - - if destination_current_timestamp.as_secs() >= post.timeout_timestamp { - // Checking to see if the message has timed-out - return Ok(Some((Ok(MessageStatus::Timeout), PostStreamState::End))) - } - - let hyperbridge_current_timestamp = - hyperbridge_client.query_timestamp().await?; - let relayer = hyperbridge_client.query_request_receipt(hash).await?; - - if relayer != H160::zero() { - // This means the message has gotten to the destination chain - return Ok::, PostStreamState)>, Error>(Some(( - Ok(MessageStatus::HyperbridgeDelivered), - PostStreamState::HyperbridgeDelivered( - hyperbridge_client.query_latest_block_height().await?, - ), - ))) - } - - if hyperbridge_current_timestamp.as_secs() >= post.timeout_timestamp { - // Checking to see if the message has timed-out - return Ok(Some((Ok(MessageStatus::Timeout), PostStreamState::End))) - } - - let mut state_machine_updated_stream = hyperbridge_client - .state_machine_update_notification(source_client.state_machine_id()) - .await?; - - while let Some(item) = state_machine_updated_stream.next().await { - match item { - Ok(state_machine_update) => { - if state_machine_update.latest_height >= post_request_height && - state_machine_update.state_machine_id.state_id == - post.source - { - return Ok(Some(( - Ok(MessageStatus::SourceFinalized), - PostStreamState::SourceFinalized, - ))) - } - }, - Err(e) => - return Ok(Some(( - Err(anyhow!( - "Encountered an error {:?}: in {:?}", - PostStreamState::Pending, - e - )), - post_request_status, - ))), - }; - } - - Ok(None) - }, - - PostStreamState::SourceFinalized => { - let hyperbridge_request_response = - hyperbridge_client.query_request_receipt(hash).await?; - if hyperbridge_request_response != H160::zero() { - let hyperbridge_height = - hyperbridge_client.query_latest_block_height().await?; - - return Ok(Some(( - Ok(MessageStatus::HyperbridgeDelivered), - PostStreamState::HyperbridgeDelivered(hyperbridge_height.into()), - ))); - } - - let mut stream = hyperbridge_client - .ismp_events_stream(RequestOrResponse::Request(post.clone())) - .await?; - while let Some(event) = stream.next().await { - match event { - Ok(_) => { - let hyperbridge_height = - hyperbridge_client.query_latest_block_height().await?; - return Ok(Some(( - Ok(MessageStatus::HyperbridgeDelivered), - PostStreamState::HyperbridgeDelivered( - hyperbridge_height.into(), - ), - ))); - }, - Err(e) => - return Ok(Some(( - Err(anyhow!( - "Encountered an error {:?}: in {:?}", - PostStreamState::SourceFinalized, - e - )), - post_request_status, - ))), - } - } - - Ok(None) - }, - PostStreamState::HyperbridgeDelivered(height) => { - let res = dest_client.query_request_receipt(hash).await?; - if res != H160::zero() { - return Ok(Some(( - Ok(MessageStatus::DestinationDelivered), - PostStreamState::End, - ))); - } - - let mut stream = dest_client - .state_machine_update_notification( - hyperbridge_client.state_machine_id(), - ) - .await?; - while let Some(update) = stream.next().await { - match update { - Ok(event) => - if event.latest_height >= height { - return Ok(Some(( - Ok(MessageStatus::HyperbridgeFinalized), - PostStreamState::HyperbridgeFinalized, - ))); - } else { - continue - }, - Err(e) => - return Ok(Some(( - Err(anyhow!( - "Encountered an error {:?}: in {:?}", - PostStreamState::HyperbridgeDelivered(height), - e - )), - post_request_status, - ))), - } - } - Ok(None) - }, - PostStreamState::HyperbridgeFinalized => { - let res = dest_client.query_request_receipt(hash).await?; - if res != H160::zero() { - return Ok(Some(( - Ok(MessageStatus::DestinationDelivered), - PostStreamState::DestinationDelivered, - ))); - } - let mut stream = dest_client.post_request_handled_stream(hash).await?; - - while let Some(event) = stream.next().await { - match event { - Ok(_) => { - return Ok(Some(( - Ok(MessageStatus::DestinationDelivered), - PostStreamState::DestinationDelivered, - ))); - }, - Err(e) => - return Ok(Some(( - Err(anyhow!( - "Encountered an error {:?}: in {:?}", - PostStreamState::HyperbridgeFinalized, - e - )), - post_request_status, - ))), - } - } - Ok(None) - }, - - PostStreamState::DestinationDelivered | PostStreamState::End => - Ok::, PostStreamState)>, Error>(None), - } - }; - - let response = lambda().await; - match response { - Ok(res) => res, - Err(e) => Some(( - Err(anyhow!("Encountered an error in stream {e:?}")), - post_request_status, - )), - } - } - }); - - Box::pin(stream) -} - -/// This function returns a stream that yields when the timeout -/// time of a request is reached -pub async fn timeout_stream(timeout: u64, client: impl Client + Clone) -> BoxStream { - let stream = stream::unfold((), move |_| { - let client_moved = client.clone(); - - async move { - let lambda = || async { - let current_timestamp = client_moved.query_timestamp().await?.as_secs(); - - return if current_timestamp > timeout { - Ok(true) - } else { - let sleep_time = timeout - current_timestamp; - let _ = wasm_timer::Delay::new(Duration::from_secs(sleep_time)).await; - Ok::<_, Error>(false) - }; - }; - - let response = lambda().await; - - let value = match response { - Ok(true) => Some((Ok(StreamItem::Item(MessageStatus::Timeout)), ())), - Ok(false) => Some((Ok(StreamItem::NoOp), ())), - Err(e) => - Some((Err(anyhow!("Encountered an error in timeout stream: {:?}", e)), ())), - }; - - return value - } - }) - .filter_map(|item| async move { - match item { - Ok(StreamItem::NoOp) => None, - Ok(StreamItem::Item(event)) => Some(Ok(event)), - Err(err) => Some(Err(err)), - } - }); - - Box::pin(stream) -} diff --git a/modules/client/src/tests/mod.rs b/modules/client/src/tests/mod.rs deleted file mode 100644 index 7b8772754..000000000 --- a/modules/client/src/tests/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod streams; diff --git a/modules/client/src/types.rs b/modules/client/src/types.rs index 3c643862b..b6ed62b31 100644 --- a/modules/client/src/types.rs +++ b/modules/client/src/types.rs @@ -1,4 +1,4 @@ -use crate::providers::{evm_chain::EvmClient, global::Client, substrate::SubstrateClient}; +use crate::providers::{evm::EvmClient, interface::Client, substrate::SubstrateClient}; use alloc::collections::BTreeMap; use anyhow::anyhow; use codec::Encode; @@ -108,10 +108,21 @@ pub struct ClientConfig { pub hyperbridge: ChainConfig, } -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, Copy)] +#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq, Default, Copy)] +pub struct EventMetadata { + /// The hash of the block where the event was emitted + pub block_hash: H256, + /// The hash of the extrinsic responsible for the event + pub transaction_hash: H256, + /// The block number where the event was emitted + pub block_number: u64, +} + +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] +#[serde(tag = "kind")] pub enum MessageStatus { Pending, - /// Source state machine has been finalized on hyperbridge + /// Source state machine has been finalized on hyperbridge. SourceFinalized, /// Message has been delivered to hyperbridge HyperbridgeDelivered, @@ -123,16 +134,54 @@ pub enum MessageStatus { Timeout, } +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] +#[serde(tag = "kind")] +pub enum MessageStatusWithMetadata { + Pending, + /// Source state machine has been finalized on hyperbridge. + SourceFinalized { + /// Metadata about the event on hyperbridge + #[serde(flatten)] + meta: EventMetadata, + }, + /// Message has been delivered to hyperbridge + HyperbridgeDelivered { + /// Metadata about the event on hyperbridge + #[serde(flatten)] + meta: EventMetadata, + }, + /// Messaged has been finalized on hyperbridge + HyperbridgeFinalized { + /// Metadata about the event on the destination chain + #[serde(flatten)] + meta: EventMetadata, + }, + /// Delivered to destination + DestinationDelivered { + /// Metadata about the event on the destination chain + #[serde(flatten)] + meta: EventMetadata, + }, + /// An error was encountered in the stream + Error { + /// Error description + description: String, + }, + /// Message has timed out + Timeout, +} + #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum PostStreamState { /// Message has been finalized on source chain Pending, - /// Source state machine has been updated on hyperbridge - SourceFinalized, - /// Message has been delivered to hyperbridge - HyperbridgeDelivered(u64), + /// Source state machine has been updated on hyperbridge, holds the block number at which the + /// source was finalized on hyperbridge + SourceFinalized(u64), /// Message has been finalized by hyperbridge - HyperbridgeFinalized, + HyperbridgeFinalized(u64), + /// Message has been delivered to hyperbridge, holds the block where the message was delivered + HyperbridgeDelivered(u64), /// Message has been delivered to destination DestinationDelivered, /// Stream has ended, check the message status @@ -142,14 +191,34 @@ pub enum PostStreamState { #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub enum TimeoutStatus { Pending, - /// Destination state machine has been finalized on hyperbridge - DestinationFinalized, + /// Destination state machine has been finalized the timeout on hyperbridge + DestinationFinalized { + /// Metadata about the event on hyperbridge + #[serde(flatten)] + meta: EventMetadata, + }, /// Message has been timed out on hyperbridge - HyperbridgeTimedout, - /// Hyperbridge has been finalized on source state machine - HyperbridgeFinalized, + HyperbridgeTimedout { + /// Metadata about the event on hyperbridge + #[serde(flatten)] + meta: EventMetadata, + }, + /// Hyperbridge has been finalized the timeout on source state machine + HyperbridgeFinalized { + /// Metadata about the event on the destination + #[serde(flatten)] + meta: EventMetadata, + }, + /// An error was encountered in the stream + Error { + /// Error description + description: String, + }, /// Encoded call data to be submitted to source chain - TimeoutMessage(Vec), + TimeoutMessage { + /// Calldata that encodes the proof for the timeout message on the source. + calldata: Vec, + }, } /// Implements [`TxPayload`] for extrinsic encoding @@ -252,3 +321,21 @@ impl ClientConfig { } } } + +#[cfg(test)] +mod tests { + use crate::types::{MessageStatus, MessageStatusWithMetadata}; + + #[test] + fn test_serialization() -> Result<(), anyhow::Error> { + assert_eq!( + r#"{"kind":"DestinationDelivered","block_hash":"0x0000000000000000000000000000000000000000000000000000000000000000","transaction_hash":"0x0000000000000000000000000000000000000000000000000000000000000000","block_number":0}"#, + json::to_string(&MessageStatusWithMetadata::DestinationDelivered { + meta: Default::default() + })? + ); + assert_eq!(r#"{"kind":"Timeout"}"#, json::to_string(&MessageStatus::Timeout)?); + + Ok(()) + } +} diff --git a/modules/client/src/tests/streams.rs b/modules/client/tests/streams.rs similarity index 81% rename from modules/client/src/tests/streams.rs rename to modules/client/tests/streams.rs index b2c3a4034..5105cbf8b 100644 --- a/modules/client/src/tests/streams.rs +++ b/modules/client/tests/streams.rs @@ -1,40 +1,41 @@ #![cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; -use crate::{ - internals::timeout_request_stream, mock::erc_20::Erc20, streams::query_request_status_stream, - types::ClientConfig, -}; use anyhow::Context; use ethers::{ + contract::parse_log, core::k256::SecretKey, - prelude::{LocalWallet, Middleware, MiddlewareBuilder, Provider, Signer, U256}, + prelude::{ + transaction::eip2718::TypedTransaction, LocalWallet, Middleware, MiddlewareBuilder, + NameOrAddress, Provider, Signer, TransactionRequest, U256, + }, providers::{Http, ProviderExt}, types::H160, -}; - -use crate::{ - internals::query_request_status_internal, - providers::global::Client, - types::{ChainConfig, EvmConfig, HashAlgorithm, MessageStatus, SubstrateConfig, TimeoutStatus}, -}; -use ethers::{ - contract::parse_log, - prelude::{transaction::eip2718::TypedTransaction, NameOrAddress, TransactionRequest}, utils::hex, }; + use futures::StreamExt; use hex_literal::hex; +use hyperclient::{ + internals, + internals::{request_status_stream, timeout_request_stream}, + providers::interface::Client, + types::{ + ChainConfig, ClientConfig, EvmConfig, HashAlgorithm, MessageStatusWithMetadata, + SubstrateConfig, TimeoutStatus, + }, +}; use ismp::{ consensus::StateMachineId, host::{Ethereum, StateMachine}, router, }; use ismp_solidity_abi::{ + erc20::ERC20, evm_host::{EvmHost, PostRequestEventFilter}, ping_module::{PingMessage, PingModule}, }; -use std::{sync::Arc, time::Duration}; +use std::sync::Arc; const OP_HOST: H160 = H160(hex!("39f3D7a7783653a04e2970e35e5f32F0e720daeB")); const OP_HANDLER: H160 = H160(hex!("8738b27E29Af7c92ba2AF72B2fcF01C8934e3Db0")); @@ -64,6 +65,8 @@ async fn subscribe_to_request_status() -> Result<(), anyhow::Error> { let bsc_url = env!("BSC_URL").to_string(); let op_url = env!("OP_URL").to_string(); + tracing::info!("\n\n\n\nStarting request status subscription\n\n\n\n"); + let source_chain = EvmConfig { rpc_url: bsc_url.clone(), state_machine: StateMachine::Bsc, @@ -81,7 +84,8 @@ async fn subscribe_to_request_status() -> Result<(), anyhow::Error> { }; let hyperbrige_config = SubstrateConfig { - rpc_url: "wss://hyperbridge-gargantua-rpc.blockops.network:443".to_string(), + // rpc_url: "wss://hyperbridge-gargantua-rpc.blockops.network:443".to_string(), + rpc_url: "ws://127.0.0.1:9944".to_string(), consensus_state_id: *b"PARA", hash_algo: HashAlgorithm::Keccak, }; @@ -103,7 +107,7 @@ async fn subscribe_to_request_status() -> Result<(), anyhow::Error> { let host_addr = ping.host().await.context(format!("Error in {chain:?}"))?; let host = EvmHost::new(host_addr, client.clone()); let erc_20 = - Erc20::new(host.dai().await.context(format!("Error in {chain:?}"))?, client.clone()); + ERC20::new(host.dai().await.context(format!("Error in {chain:?}"))?, client.clone()); let call = erc_20.approve(host_addr, U256::max_value()); let gas = call.estimate_gas().await.context(format!("Error in {chain:?}"))?; @@ -143,7 +147,7 @@ async fn subscribe_to_request_status() -> Result<(), anyhow::Error> { let source_client = config.source_chain().await?; let dest_client = config.dest_chain().await?; let hyperbridge_client = config.hyperbridge_client().await?; - let mut stream = query_request_status_stream( + let mut stream = request_status_stream( post, source_client, dest_client, @@ -169,6 +173,8 @@ async fn subscribe_to_request_status() -> Result<(), anyhow::Error> { async fn test_timeout_request() -> Result<(), anyhow::Error> { init_tracing(); + tracing::info!("\n\n\n\nStarting timeout request test\n\n\n\n"); + let signing_key = env!("SIGNING_KEY").to_string(); let bsc_url = env!("BSC_URL").to_string(); let sepolia_url = env!("SEPOLIA_URL").to_string(); @@ -189,7 +195,8 @@ async fn test_timeout_request() -> Result<(), anyhow::Error> { }; let hyperbrige_config = SubstrateConfig { - rpc_url: "wss://hyperbridge-gargantua-rpc.blockops.network:443".to_string(), + // rpc_url: "wss://hyperbridge-gargantua-rpc.blockops.network:443".to_string(), + rpc_url: "ws://127.0.0.1:9944".to_string(), consensus_state_id: *b"PARA", hash_algo: HashAlgorithm::Keccak, }; @@ -212,7 +219,7 @@ async fn test_timeout_request() -> Result<(), anyhow::Error> { tracing::info!("{:#?}", host.host_params().await?); let erc_20 = - Erc20::new(host.dai().await.context(format!("Error in {chain:?}"))?, client.clone()); + ERC20::new(host.dai().await.context(format!("Error in {chain:?}"))?, client.clone()); let call = erc_20.approve(host_addr, U256::max_value()); let gas = call.estimate_gas().await.context(format!("Error in {chain:?}"))?; @@ -244,7 +251,7 @@ async fn test_timeout_request() -> Result<(), anyhow::Error> { let call = ping.ping(PingMessage { dest: dest_chain.state_machine.to_string().as_bytes().to_vec().into(), module: PING_MODULE.clone().into(), - timeout: 5 * 60, + timeout: 6 * 60, fee: U256::from(0u128), count: U256::from(1), }); @@ -260,26 +267,48 @@ async fn test_timeout_request() -> Result<(), anyhow::Error> { let block = receipt.block_number.unwrap(); tracing::info!("\n\nTx block: {block}\n\n"); + let post: router::Post = receipt .logs .into_iter() .find_map(|log| parse_log::(log).ok()) .expect("Tx should emit post request") .try_into()?; - tracing::info!("Got PostRequest {post:#?}"); + tracing::info!("PostRequest {post:#?}"); let block = receipt.block_number.unwrap(); tracing::info!("\n\nTx block: {block}\n\n"); - loop { - let status = query_request_status_internal(post.clone(), config.clone()).await?; - tracing::info!("Got Status {status:?}"); - if status == MessageStatus::Timeout { - break - } else { - let delay = Duration::from_secs(60); - tracing::info!("Waiting for {delay:?}"); - wasm_timer::Delay::new(delay).await?; + let source_client = config.source_chain().await?; + let dest_client = config.dest_chain().await?; + + let request_status = request_status_stream( + post.clone(), + source_client.clone(), + dest_client.clone(), + hyperbridge_client.clone(), + block.low_u64(), + ) + .await; + + // Obtaining the request stream and the timeout stream + let timed_out = + internals::request_timeout_stream(post.timeout_timestamp, source_client.clone()).await; + + let mut stream = futures::stream::select(request_status, timed_out); + + while let Some(item) = stream.next().await { + match item { + Ok(status) => { + tracing::info!("Got Status {status:?}"); + match status { + MessageStatusWithMetadata::Timeout => break, + _ => {}, + }; + }, + Err(err) => { + tracing::error!("Got error in request_status_stream: {err:?}") + }, } } @@ -290,7 +319,7 @@ async fn test_timeout_request() -> Result<(), anyhow::Error> { Ok(status) => { tracing::info!("Got Status {:?}", status); match status { - TimeoutStatus::TimeoutMessage(call_data) => { + TimeoutStatus::TimeoutMessage { calldata } => { let gas_price = client.get_gas_price().await?; tracing::info!("Sending timeout to BSC"); let receipt = client @@ -300,7 +329,7 @@ async fn test_timeout_request() -> Result<(), anyhow::Error> { to: Some(NameOrAddress::Address(source_chain.handler_address)), value: Some(Default::default()), gas_price: Some(gas_price * 5), // experiment with higher? - data: Some(call_data.into()), + data: Some(calldata.into()), ..Default::default() }), None, diff --git a/modules/ismp/pallet/rpc/src/lib.rs b/modules/ismp/pallet/rpc/src/lib.rs index 7f818de61..3c2ff0f6d 100644 --- a/modules/ismp/pallet/rpc/src/lib.rs +++ b/modules/ismp/pallet/rpc/src/lib.rs @@ -23,7 +23,7 @@ use jsonrpsee::{ types::{error::CallError, ErrorObject}, }; -use codec::Encode; +use codec::{Decode, Encode}; use ismp::{ consensus::{ConsensusClientId, StateMachineId}, events::{Event, StateMachineUpdated}, @@ -39,8 +39,11 @@ use sc_client_api::{BlockBackend, ProofProvider}; use serde::{Deserialize, Serialize}; use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_blockchain::HeaderBackend; -use sp_core::offchain::{storage::OffchainDb, OffchainDbExt, OffchainStorage}; -use sp_runtime::traits::{Block as BlockT, Header}; +use sp_core::{ + offchain::{storage::OffchainDb, OffchainDbExt, OffchainStorage}, + H256, +}; +use sp_runtime::traits::{Block as BlockT, Hash, Header}; use std::{collections::HashMap, fmt::Display, sync::Arc}; /// A type that could be a block number or a block hash @@ -91,6 +94,26 @@ fn runtime_error_into_rpc_error(e: impl std::fmt::Display) -> RpcError { ))) } +/// Relevant transaction metadata for an event +#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq, Default)] +pub struct EventMetadata { + /// The hash of the block where the event was emitted + pub block_hash: H256, + /// The hash of the extrinsic responsible for the event + pub transaction_hash: H256, + /// The block number where the event was emitted + pub block_number: u64, +} + +/// Holds an event along with relevant metadata about the event +#[derive(Serialize, Deserialize)] +pub struct EventWithMetadata { + /// The event metdata + pub meta: EventMetadata, + /// The event in question + pub event: Event, +} + /// ISMP RPC methods. #[rpc(client, server)] pub trait IsmpApi @@ -141,6 +164,15 @@ where from: BlockNumberOrHash, to: BlockNumberOrHash, ) -> Result>>; + + /// Query ISMP Events that were deposited in a series of blocks + /// Using String keys because HashMap fails to deserialize when key is not a String + #[method(name = "ismp_queryEventsWithMetadata")] + fn query_events_with_metadata( + &self, + from: BlockNumberOrHash, + to: BlockNumberOrHash, + ) -> Result>>; } /// An implementation of ISMP specific RPC methods. @@ -169,6 +201,8 @@ where + ProofProvider + BlockBackend, C::Api: IsmpRuntimeApi, + Block::Hash: Into, + u64: From<::Number>, { fn query_requests(&self, query: Vec) -> Result> { let mut api = self.client.runtime_api(); @@ -295,9 +329,11 @@ where .header(to) .map_err(|e| runtime_error_into_rpc_error(e.to_string()))? .ok_or_else(|| runtime_error_into_rpc_error("Invalid block number or hash provided"))?; + + let mut api = self.client.runtime_api(); + api.register_extension(OffchainDbExt::new(self.offchain_db.clone())); + while header.number() >= from_block.number() { - let mut api = self.client.runtime_api(); - api.register_extension(OffchainDbExt::new(self.offchain_db.clone())); let at = header.hash(); let mut request_commitments = vec![]; @@ -359,4 +395,131 @@ where } Ok(events) } + + fn query_events_with_metadata( + &self, + from: BlockNumberOrHash, + to: BlockNumberOrHash, + ) -> Result>> { + let mut events = HashMap::new(); + let to = + match to { + BlockNumberOrHash::Hash(block_hash) => block_hash, + BlockNumberOrHash::Number(block_number) => + self.client.block_hash(block_number.into()).ok().flatten().ok_or_else(|| { + runtime_error_into_rpc_error("Invalid block number provided") + })?, + }; + + let from = + match from { + BlockNumberOrHash::Hash(block_hash) => block_hash, + BlockNumberOrHash::Number(block_number) => + self.client.block_hash(block_number.into()).ok().flatten().ok_or_else(|| { + runtime_error_into_rpc_error("Invalid block number provided") + })?, + }; + + let from_block = self + .client + .header(from) + .map_err(|e| runtime_error_into_rpc_error(e.to_string()))? + .ok_or_else(|| runtime_error_into_rpc_error("Invalid block number or hash provided"))?; + + let mut header = self + .client + .header(to) + .map_err(|e| runtime_error_into_rpc_error(e.to_string()))? + .ok_or_else(|| runtime_error_into_rpc_error("Invalid block number or hash provided"))?; + + let mut api = self.client.runtime_api(); + api.register_extension(OffchainDbExt::new(self.offchain_db.clone())); + + while header.number() >= from_block.number() { + let at = header.hash(); + + let block_events = api.block_events_with_metadata(at).map_err(|e| { + runtime_error_into_rpc_error(format!("failed to read block events {:?}", e)) + })?; + + let mut temp = vec![]; + + for (event, index) in block_events { + let event = match event { + pallet_ismp::events::Event::Request { commitment, .. } => api + .get_requests(at, vec![commitment]) + .map_err(|_| runtime_error_into_rpc_error("Error fetching requests"))? + .into_iter() + .map(|req| match req { + Request::Post(post) => Event::PostRequest(post), + Request::Get(get) => Event::GetRequest(get), + }) + .next(), + pallet_ismp::events::Event::Response { commitment, .. } => api + .get_responses(at, vec![commitment]) + .map_err(|_| runtime_error_into_rpc_error("Error fetching response"))? + .into_iter() + .filter_map(|res| match res { + Response::Post(post) => Some(Event::PostResponse(post)), + _ => None, + }) + .next(), + pallet_ismp::events::Event::StateMachineUpdated { + state_machine_id, + latest_height, + } => Some(Event::StateMachineUpdated(StateMachineUpdated { + state_machine_id, + latest_height, + })), + }; + + if let Some(event) = event { + // get the block extrinsics + let extrinsic = self + .client + .block_body(at) + .map_err(|err| { + runtime_error_into_rpc_error(format!( + "Error fetching extrinsic for block {at:?}: {err:?}" + )) + })? + .ok_or_else(|| { + runtime_error_into_rpc_error(format!( + "No extrinsics found for block {at:?}" + )) + })? + // using swap remove should be fine unless the node is in an inconsistent + // state + .swap_remove(index as usize); + + let extrinsic = + Vec::::decode(&mut extrinsic.encode().as_slice()).map_err(|err| { + runtime_error_into_rpc_error(format!( + "Could not decode extrinsic with index {index:?}: {err:?}" + )) + })?; + let extrinsic_hash = + ::Hashing::hash(extrinsic.as_slice()); + temp.push(EventWithMetadata { + meta: EventMetadata { + block_hash: at.into(), + transaction_hash: extrinsic_hash.into(), + block_number: u64::from(*header.number()), + }, + event, + }); + } + } + + events.insert(header.hash().to_string(), temp); + header = self + .client + .header(*header.parent_hash()) + .map_err(|e| runtime_error_into_rpc_error(e.to_string()))? + .ok_or_else(|| { + runtime_error_into_rpc_error("Invalid block number or hash provided") + })?; + } + Ok(events) + } } diff --git a/modules/ismp/pallet/runtime-api/src/lib.rs b/modules/ismp/pallet/runtime-api/src/lib.rs index e692f1943..3d9166b2f 100644 --- a/modules/ismp/pallet/runtime-api/src/lib.rs +++ b/modules/ismp/pallet/runtime-api/src/lib.rs @@ -48,6 +48,9 @@ sp_api::decl_runtime_apis! { /// Fetch all ISMP events fn block_events() -> Vec; + /// Fetch all ISMP events and their extrinsic metadata + fn block_events_with_metadata() -> Vec<(pallet_ismp::events::Event, u32)>; + /// Return the scale encoded consensus state fn consensus_state(id: ConsensusClientId) -> Option>; diff --git a/parachain/node/Cargo.toml b/parachain/node/Cargo.toml index 1c05fd26d..996043c62 100644 --- a/parachain/node/Cargo.toml +++ b/parachain/node/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hyperbridge" -version = "0.3.5" +version = "0.3.6" authors = ["Polytope Labs "] description = "The Hyperbridge coprocessor node" repository = "https://github.com/polytope-labs/hyperbridge" diff --git a/parachain/runtimes/gargantua/src/lib.rs b/parachain/runtimes/gargantua/src/lib.rs index 0808e0151..7e803a6f3 100644 --- a/parachain/runtimes/gargantua/src/lib.rs +++ b/parachain/runtimes/gargantua/src/lib.rs @@ -66,7 +66,7 @@ use frame_support::{ }; use frame_system::{ limits::{BlockLength, BlockWeights}, - EnsureRoot, + EnsureRoot, Phase, }; use pallet_ismp::{ mmr_primitives::{Leaf, LeafIndex}, @@ -212,7 +212,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("gargantua"), impl_name: create_runtime_str!("gargantua"), authoring_version: 1, - spec_version: 210, + spec_version: 220, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -772,6 +772,27 @@ impl_runtime_apis! { }).collect() } + /// Fetch all ISMP events and their extrinsic metadata + fn block_events_with_metadata() -> Vec<(pallet_ismp::events::Event, u32)> { + let raw_events = frame_system::Pallet::::read_events_no_consensus().into_iter(); + raw_events.filter_map(|e| { + let frame_system::EventRecord { event, phase, ..} = *e; + let Phase::ApplyExtrinsic(index) = phase else { + unreachable!("ISMP events are always dispatched by extrinsics"); + }; + + match event { + RuntimeEvent::Ismp(event) => { + pallet_ismp::events::to_core_protocol_event(event) + .map(|event| { + (event, index) + }) + }, + _ => None + } + }).collect() + } + /// Return the scale encoded consensus state fn consensus_state(id: ConsensusClientId) -> Option> { Ismp::consensus_states(id) diff --git a/parachain/runtimes/messier/src/lib.rs b/parachain/runtimes/messier/src/lib.rs index a27df1485..575ebcbe1 100644 --- a/parachain/runtimes/messier/src/lib.rs +++ b/parachain/runtimes/messier/src/lib.rs @@ -775,7 +775,7 @@ impl_runtime_apis! { Ismp::get_challenge_period(consensus_state_id) } -/// Generate a proof for the provided leaf indices + /// Generate a proof for the provided leaf indices fn generate_proof( keys: ProofKeys ) -> Result<(Vec, Proof<::Hash>), pallet_ismp::primitives::Error> { @@ -797,6 +797,27 @@ impl_runtime_apis! { }).collect() } + /// Fetch all ISMP events and their extrinsic metadata + fn block_events_with_metadata() -> Vec<(pallet_ismp::events::Event, u32)> { + let raw_events = frame_system::Pallet::::read_events_no_consensus().into_iter(); + raw_events.filter_map(|e| { + let frame_system::EventRecord { event, phase, ..} = *e; + let frame_system::Phase::ApplyExtrinsic(index) = phase else { + unreachable!("ISMP events are always dispatched by extrinsics"); + }; + + match event { + RuntimeEvent::Ismp(event) => { + pallet_ismp::events::to_core_protocol_event(event) + .map(|event| { + (event, index) + }) + }, + _ => None + } + }).collect() + } + /// Return the scale encoded consensus state fn consensus_state(id: ConsensusClientId) -> Option> { Ismp::consensus_states(id) diff --git a/parachain/runtimes/nexus/src/lib.rs b/parachain/runtimes/nexus/src/lib.rs index ee4685ba6..64e8c7b4a 100644 --- a/parachain/runtimes/nexus/src/lib.rs +++ b/parachain/runtimes/nexus/src/lib.rs @@ -67,7 +67,7 @@ use frame_support::{ }; use frame_system::{ limits::{BlockLength, BlockWeights}, - EnsureRoot, + EnsureRoot, Phase, }; use pallet_ismp::{ mmr_primitives::{Leaf, LeafIndex}, @@ -775,13 +775,34 @@ impl_runtime_apis! { Ismp::get_challenge_period(consensus_state_id) } -/// Generate a proof for the provided leaf indices + /// Generate a proof for the provided leaf indices fn generate_proof( keys: ProofKeys ) -> Result<(Vec, Proof<::Hash>), pallet_ismp::primitives::Error> { Ismp::generate_proof(keys) } + /// Fetch all ISMP events and their extrinsic metadata + fn block_events_with_metadata() -> Vec<(pallet_ismp::events::Event, u32)> { + let raw_events = frame_system::Pallet::::read_events_no_consensus().into_iter(); + raw_events.filter_map(|e| { + let frame_system::EventRecord { event, phase, ..} = *e; + let Phase::ApplyExtrinsic(index) = phase else { + unreachable!("ISMP events are always dispatched by extrinsics"); + }; + + match event { + RuntimeEvent::Ismp(event) => { + pallet_ismp::events::to_core_protocol_event(event) + .map(|event| { + (event, index) + }) + }, + _ => None + } + }).collect() + } + /// Fetch all ISMP events fn block_events() -> Vec { let raw_events = frame_system::Pallet::::read_events_no_consensus().into_iter();