From 704dda5585c322eef34655ae3f8873ae2485d97a Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 9 Feb 2024 15:30:57 +0100 Subject: [PATCH 01/44] Add ibc-callbacks contract --- contracts/ibc-callbacks/.cargo/config | 6 + contracts/ibc-callbacks/Cargo.lock | 2001 +++++++++++++++++ contracts/ibc-callbacks/Cargo.toml | 37 + contracts/ibc-callbacks/README.md | 8 + .../ibc-callbacks/schema/ibc-callbacks.json | 257 +++ .../ibc-callbacks/schema/raw/execute.json | 20 + .../ibc-callbacks/schema/raw/instantiate.json | 6 + contracts/ibc-callbacks/schema/raw/query.json | 20 + .../raw/response_to_callback_stats.json | 202 ++ contracts/ibc-callbacks/src/bin/schema.rs | 12 + contracts/ibc-callbacks/src/contract.rs | 172 ++ contracts/ibc-callbacks/src/lib.rs | 3 + contracts/ibc-callbacks/src/msg.rs | 19 + contracts/ibc-callbacks/src/state.rs | 39 + 14 files changed, 2802 insertions(+) create mode 100644 contracts/ibc-callbacks/.cargo/config create mode 100644 contracts/ibc-callbacks/Cargo.lock create mode 100644 contracts/ibc-callbacks/Cargo.toml create mode 100644 contracts/ibc-callbacks/README.md create mode 100644 contracts/ibc-callbacks/schema/ibc-callbacks.json create mode 100644 contracts/ibc-callbacks/schema/raw/execute.json create mode 100644 contracts/ibc-callbacks/schema/raw/instantiate.json create mode 100644 contracts/ibc-callbacks/schema/raw/query.json create mode 100644 contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json create mode 100644 contracts/ibc-callbacks/src/bin/schema.rs create mode 100644 contracts/ibc-callbacks/src/contract.rs create mode 100644 contracts/ibc-callbacks/src/lib.rs create mode 100644 contracts/ibc-callbacks/src/msg.rs create mode 100644 contracts/ibc-callbacks/src/state.rs diff --git a/contracts/ibc-callbacks/.cargo/config b/contracts/ibc-callbacks/.cargo/config new file mode 100644 index 0000000000..f5174787c2 --- /dev/null +++ b/contracts/ibc-callbacks/.cargo/config @@ -0,0 +1,6 @@ +[alias] +wasm = "build --release --lib --target wasm32-unknown-unknown" +wasm-debug = "build --lib --target wasm32-unknown-unknown" +unit-test = "test --lib" +integration-test = "test --test integration" +schema = "run --bin schema" diff --git a/contracts/ibc-callbacks/Cargo.lock b/contracts/ibc-callbacks/Cargo.lock new file mode 100644 index 0000000000..954bd7a9c6 --- /dev/null +++ b/contracts/ibc-callbacks/Cargo.lock @@ -0,0 +1,2001 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a2e47a1fbe209ee101dd6d61285226744c6c8d3c21c8dc878ba6cb9f467f3a" +dependencies = [ + "gimli 0.24.0", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom 0.2.3", + "once_cell", + "version_check", +] + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7815ea54e4d821e791162e078acbebfd6d8c8939cd559c9335dceb1c8ca7282" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" + +[[package]] +name = "base64ct" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea908e7347a8c64e378c17e30ef880ad73e3b4498346b055c2c00ea342f3179" + +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bnum" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56953345e39537a3e18bdaeba4cb0c58a78c1f61f361dc0fa7c5c7340ae87c5f" + +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + +[[package]] +name = "bytecheck" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13fe11640a23eb24562225322cd3e452b93a3d4091d62fab69c70542fcd17d1f" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31225543cb46f81a7e224762764f4a6a0f097b1db0b175f69e8065efaa42de5" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "cc" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clru" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8191fa7302e03607ff0e237d4246cc043ff5b3cb9409d995172ba3bea16b807" + +[[package]] +name = "const-oid" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "795bc6e66a8e340f075fcf6227e417a2dc976b92b91f3cdc778bb858778b6747" + +[[package]] +name = "corosensei" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9847f90f32a50b0dcbd68bc23ff242798b13080b97b0569f6ed96a45ce4cf2cd" +dependencies = [ + "autocfg", + "cfg-if", + "libc", + "scopeguard", + "windows-sys", +] + +[[package]] +name = "cosmwasm-crypto" +version = "2.0.0-beta.1" +dependencies = [ + "digest 0.10.7", + "ecdsa", + "ed25519-zebra", + "k256", + "rand_core 0.6.4", + "thiserror", +] + +[[package]] +name = "cosmwasm-derive" +version = "2.0.0-beta.1" +dependencies = [ + "syn 1.0.109", +] + +[[package]] +name = "cosmwasm-schema" +version = "2.0.0-beta.1" +dependencies = [ + "cosmwasm-schema-derive", + "schemars", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cosmwasm-schema-derive" +version = "2.0.0-beta.1" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "cosmwasm-std" +version = "2.0.0-beta.1" +dependencies = [ + "base64", + "bech32", + "bnum", + "cosmwasm-crypto", + "cosmwasm-derive", + "derivative", + "forward_ref", + "hex", + "schemars", + "serde", + "serde-json-wasm", + "sha2 0.10.3", + "static_assertions", + "thiserror", +] + +[[package]] +name = "cosmwasm-vm" +version = "2.0.0-beta.1" +dependencies = [ + "bech32", + "bitflags", + "bytecheck", + "bytes", + "clru", + "cosmwasm-crypto", + "cosmwasm-std", + "crc32fast", + "derivative", + "hex", + "schemars", + "serde", + "serde_json", + "sha2 0.10.3", + "strum", + "thiserror", + "wasmer", + "wasmer-middlewares", +] + +[[package]] +name = "cpufeatures" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + +[[package]] +name = "cranelift-bforest" +version = "0.91.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2ab4512dfd3a6f4be184403a195f76e81a8a9f9e6c898e19d2dc3ce20e0115" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-codegen" +version = "0.91.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98b022ed2a5913a38839dfbafe6cf135342661293b08049843362df4301261dc" +dependencies = [ + "arrayvec", + "bumpalo", + "cranelift-bforest", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-egraph", + "cranelift-entity", + "cranelift-isle", + "gimli 0.26.1", + "log", + "regalloc2", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.91.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "639307b45434ad112a98f8300c0f0ab085cbefcd767efcdef9ef19d4c0756e74" +dependencies = [ + "cranelift-codegen-shared", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.91.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "278e52e29c53fcf32431ef08406c295699a70306d05a0715c5b1bf50e33a9ab7" + +[[package]] +name = "cranelift-egraph" +version = "0.91.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624b54323b06e675293939311943ba82d323bb340468ce1889be5da7932c8d73" +dependencies = [ + "cranelift-entity", + "fxhash", + "hashbrown", + "indexmap", + "log", + "smallvec", +] + +[[package]] +name = "cranelift-entity" +version = "0.91.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a59bcbca89c3f1b70b93ab3cbba5e5e0cbf3e63dadb23c7525cb142e21a9d4c" + +[[package]] +name = "cranelift-frontend" +version = "0.91.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d70abacb8cfef3dc8ff7e8836e9c1d70f7967dfdac824a4cd5e30223415aca6" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-isle" +version = "0.91.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "393bc73c451830ff8dbb3a07f61843d6cb41a084f9996319917c0b291ed785bb" + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset 0.6.4", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "639891fde0dbea823fc3d798a0fdf9d2f9440a42d64a78ab3488b0ca025117b3" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "darling" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "syn 2.0.37", +] + +[[package]] +name = "darling_macro" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.37", +] + +[[package]] +name = "dashmap" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" +dependencies = [ + "cfg-if", + "hashbrown", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "der" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7ed52955ce76b1554f509074bb357d3fb8ac9b51288a65a3fd480d1dfba946" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.2", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dyn-clone" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf" + +[[package]] +name = "dynasm" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add9a102807b524ec050363f09e06f1504214b0e1c7797f64261c891022dce8b" +dependencies = [ + "bitflags", + "byteorder", + "lazy_static", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "dynasmrt" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64fba5a42bd76a17cad4bfa00de168ee1cbfa06a5e8ce992ae880218c05641a9" +dependencies = [ + "byteorder", + "dynasm", + "memmap2 0.5.0", +] + +[[package]] +name = "ecdsa" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519-zebra" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403ef3e961ab98f0ba902771d29f842058578bb1ce7e3c59dad5a6a93e784c69" +dependencies = [ + "curve25519-dalek", + "hex", + "rand_core 0.6.4", + "serde", + "sha2 0.9.5", + "thiserror", + "zeroize", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "elliptic-curve" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "enum-iterator" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eeac5c5edb79e4e39fe8439ef35207780a11f69c52cbe424ce3dfad4cb78de6" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c134c37760b27a871ba422106eedbb8247da973a09e82558bf26d619c882b159" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "enumset" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e875f1719c16de097dee81ed675e2d9bb63096823ed3f0ca827b7dea3028bbbb" +dependencies = [ + "enumset_derive", +] + +[[package]] +name = "enumset_derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.37", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "forward_ref" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e" + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.10.2+wasi-snapshot-preview1", +] + +[[package]] +name = "gimli" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189" + +[[package]] +name = "gimli" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "ibc-callbacks" +version = "0.0.0" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cosmwasm-vm", + "schemars", + "serde", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" + +[[package]] +name = "js-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2 0.10.3", + "signature", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "leb128" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "memmap2" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4647a11b578fead29cdbb34d4adef8dd3dc35b876c9c6d5240d83f205abfe96e" +dependencies = [ + "libc", +] + +[[package]] +name = "memmap2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d28bba84adfe6646737845bc5ebbfa2c08424eb1c37e94a1fd2a82adb56a872" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + +[[package]] +name = "more-asserts" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0debeb9fcf88823ea64d64e4a815ab1643f33127d995978e099942ce38f25238" + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38f2be3697a57b4060074ff41b44c16870d916ad7877c17696e063257482bc7" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "parking_lot_core" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "pin-project-lite" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.3", +] + +[[package]] +name = "rayon" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regalloc2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300d4fbfb40c1c66a78ba3ddd41c1110247cf52f97b87d0f2fc9209bd49b030c" +dependencies = [ + "fxhash", + "log", + "slice-group-by", + "smallvec", +] + +[[package]] +name = "region" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76e189c2369884dce920945e2ddf79b3dff49e071a167dd1817fa9c4c00d512e" +dependencies = [ + "bitflags", + "libc", + "mach", + "winapi", +] + +[[package]] +name = "rend" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581008d2099240d37fb08d77ad713bcaec2c4d89d50b5b21a8bb1996bbab68ab" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rkyv" +version = "0.7.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21499ed91807f07ae081880aabb2ccc0235e9d88011867d984525e9a4c3cfa3e" +dependencies = [ + "bytecheck", + "hashbrown", + "indexmap", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1c672430eb41556291981f45ca900a0239ad007242d1cb4b4167af842db666" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dead70b0b5e03e9c814bcb6b01e03e68f7c57a80aa48c72ec92152ab3e818d49" + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "schemars" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 1.0.109", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "self_cell" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c309e515543e67811222dbc9e3dd7e1056279b782e1dacffe4242b718734fb6" + +[[package]] +name = "serde" +version = "1.0.192" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-json-wasm" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05da0d153dd4595bdffd5099dc0e9ce425b205ee648eb93437ff7302af8c9a5" +dependencies = [ + "serde", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde_derive" +version = "1.0.192" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "serde_json" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures 0.1.5", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899bf02746a2c92bf1053d9327dadb252b01af1f81f90cdb902411f518bc7215" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.2", + "digest 0.10.7", +] + +[[package]] +name = "shared-buffer" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6c99835bad52957e7aa241d3975ed17c1e5f8c92026377d117a606f36b84b16" +dependencies = [ + "bytes", + "memmap2 0.6.2", +] + +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "simdutf8" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" + +[[package]] +name = "slice-group-by" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" + +[[package]] +name = "smallvec" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" + +[[package]] +name = "spki" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.37", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "target-lexicon" +version = "0.12.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd1ba337640d60c3e96bc6f0638a939b9c9a7f2c316a1598c279828b3d1dc8c5" + +[[package]] +name = "thiserror" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tracing" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "tracing-core" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9ff14f98b1a4b289c6248a023c1c2fa1491062964e9fed67ab29c4e4da4a052" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "wasm-bindgen" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 1.0.109", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" + +[[package]] +name = "wasmer" +version = "4.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5467c7a23f9be04d5691590bea509dbea27e5ba5810d0020bef908456a495f33" +dependencies = [ + "bytes", + "cfg-if", + "derivative", + "indexmap", + "js-sys", + "more-asserts", + "rustc-demangle", + "serde", + "serde-wasm-bindgen", + "shared-buffer", + "target-lexicon", + "thiserror", + "wasm-bindgen", + "wasmer-compiler", + "wasmer-compiler-cranelift", + "wasmer-compiler-singlepass", + "wasmer-derive", + "wasmer-types", + "wasmer-vm", + "winapi", +] + +[[package]] +name = "wasmer-compiler" +version = "4.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "510ad01a668d774f3a103a7c219bbc0970be93e8f1b27e2fdb48d1f4ccd1deff" +dependencies = [ + "backtrace", + "bytes", + "cfg-if", + "enum-iterator", + "enumset", + "lazy_static", + "leb128", + "memmap2 0.5.0", + "more-asserts", + "region", + "rkyv", + "self_cell", + "shared-buffer", + "smallvec", + "thiserror", + "wasmer-types", + "wasmer-vm", + "wasmparser", + "winapi", +] + +[[package]] +name = "wasmer-compiler-cranelift" +version = "4.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54bf93078990d83960d798de3c5935bddaba771fc2fefb9ed6bab9c0bbdea5c1" +dependencies = [ + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "gimli 0.26.1", + "more-asserts", + "rayon", + "smallvec", + "target-lexicon", + "tracing", + "wasmer-compiler", + "wasmer-types", +] + +[[package]] +name = "wasmer-compiler-singlepass" +version = "4.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f4d6359d66a8bcefac26d48fcb0f3f0882bdf122b52121a1ae21f918706e040" +dependencies = [ + "byteorder", + "dynasm", + "dynasmrt", + "enumset", + "gimli 0.26.1", + "lazy_static", + "more-asserts", + "rayon", + "smallvec", + "wasmer-compiler", + "wasmer-types", +] + +[[package]] +name = "wasmer-derive" +version = "4.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b374fd34d97b1c091d8675f9bc472df52dc6787d139d3762d42c7dc84813a9b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "wasmer-middlewares" +version = "4.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aab1347a1f81bf5929289db82b4f3966e9aecc4f874115110b6c0894ee8d9e77" +dependencies = [ + "wasmer", + "wasmer-types", + "wasmer-vm", +] + +[[package]] +name = "wasmer-types" +version = "4.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0caf1c87937b52aba8e9f920a278e1beda282f7439612c0b48f51a58e7a87bab" +dependencies = [ + "bytecheck", + "enum-iterator", + "enumset", + "indexmap", + "more-asserts", + "rkyv", + "target-lexicon", + "thiserror", +] + +[[package]] +name = "wasmer-vm" +version = "4.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58315c25492bc72a33f47a7d7fb0869a0106fc0164ec051e349a9e1eddba9a01" +dependencies = [ + "backtrace", + "cc", + "cfg-if", + "corosensei", + "crossbeam-queue", + "dashmap", + "derivative", + "enum-iterator", + "fnv", + "indexmap", + "lazy_static", + "libc", + "mach", + "memoffset 0.9.0", + "more-asserts", + "region", + "scopeguard", + "thiserror", + "wasmer-types", + "winapi", +] + +[[package]] +name = "wasmparser" +version = "0.95.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ea896273ea99b15132414be1da01ab0d8836415083298ecaffbe308eaac87a" +dependencies = [ + "indexmap", + "url", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43dbb096663629518eb1dfa72d80243ca5a6aca764cae62a2df70af760a9be75" +dependencies = [ + "windows_aarch64_msvc 0.33.0", + "windows_i686_gnu 0.33.0", + "windows_i686_msvc 0.33.0", + "windows_x86_64_gnu 0.33.0", + "windows_x86_64_msvc 0.33.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd761fd3eb9ab8cc1ed81e56e567f02dd82c4c837e48ac3b2181b9ffc5060807" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab0cf703a96bab2dc0c02c0fa748491294bf9b7feb27e1f4f96340f208ada0e" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cfdbe89cc9ad7ce618ba34abc34bbb6c36d99e96cae2245b7943cd75ee773d0" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4dd9b0c0e9ece7bb22e84d70d01b71c6d6248b81a3c60d11869451b4cb24784" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff1e4aa646495048ec7f3ffddc411e1d829c026a2ec62b39da15c1055e406eaa" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "zeroize" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" diff --git a/contracts/ibc-callbacks/Cargo.toml b/contracts/ibc-callbacks/Cargo.toml new file mode 100644 index 0000000000..f45204c680 --- /dev/null +++ b/contracts/ibc-callbacks/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "ibc-callbacks" +version = "0.0.0" +authors = ["Christoph Otter "] +edition = "2021" +publish = false +license = "Apache-2.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +crate-type = ["cdylib", "rlib"] + +[profile.release] +opt-level = 3 +debug = false +rpath = false +lto = true +debug-assertions = false +codegen-units = 1 +panic = 'abort' +incremental = false +overflow-checks = true + +[features] +default = [] +# Use cranelift backend instead of singlepass. +cranelift = ["cosmwasm-vm/cranelift"] + +[dependencies] +cosmwasm-schema = { path = "../../packages/schema" } +cosmwasm-std = { path = "../../packages/std", features = ["iterator", "stargate"] } +schemars = "0.8.3" +serde = { version = "1.0.103", default-features = false, features = ["derive"] } + +[dev-dependencies] +cosmwasm-vm = { path = "../../packages/vm", default-features = false, features = ["iterator", "stargate"] } diff --git a/contracts/ibc-callbacks/README.md b/contracts/ibc-callbacks/README.md new file mode 100644 index 0000000000..50e6c3561b --- /dev/null +++ b/contracts/ibc-callbacks/README.md @@ -0,0 +1,8 @@ +# Ibc Reflect Contract + +This is a simple contract to demonstrate [IBC Callbacks]. It sends an ICS-20 +transfer message to a remote chain and writes to storage which callbacks were +called. This can then be queried using the `CallbackStats` query. + +[ibc callbacks]: + https://github.com/cosmos/ibc-go/blob/main/docs/architecture/adr-008-app-caller-cbs.md diff --git a/contracts/ibc-callbacks/schema/ibc-callbacks.json b/contracts/ibc-callbacks/schema/ibc-callbacks.json new file mode 100644 index 0000000000..1b511c102b --- /dev/null +++ b/contracts/ibc-callbacks/schema/ibc-callbacks.json @@ -0,0 +1,257 @@ +{ + "contract_name": "ibc-callbacks", + "contract_version": "0.0.0", + "idl_version": "1.0.0", + "instantiate": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "InstantiateMsg", + "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", + "type": "object" + }, + "execute": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "type": "object", + "required": [ + "channel_id", + "to_address" + ], + "properties": { + "channel_id": { + "description": "The channel to send the packet through", + "type": "string" + }, + "to_address": { + "description": "Address on the destination chain", + "type": "string" + } + }, + "additionalProperties": false + }, + "query": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "QueryMsg", + "oneOf": [ + { + "description": "Returns stats about what callbacks have been received", + "type": "object", + "required": [ + "callback_stats" + ], + "properties": { + "callback_stats": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] + }, + "migrate": null, + "sudo": null, + "responses": { + "callback_stats": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "CallbackStats", + "description": "A counter for the number of times the respective callback has been called", + "type": "object", + "required": [ + "ibc_ack_callbacks", + "ibc_timeout_callbacks" + ], + "properties": { + "ibc_ack_callbacks": { + "type": "array", + "items": { + "$ref": "#/definitions/IbcPacketAckMsg" + } + }, + "ibc_timeout_callbacks": { + "type": "array", + "items": { + "$ref": "#/definitions/IbcPacketTimeoutMsg" + } + } + }, + "additionalProperties": false, + "definitions": { + "Addr": { + "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", + "type": "string" + }, + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", + "type": "string" + }, + "IbcAcknowledgement": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/definitions/Binary" + } + } + }, + "IbcEndpoint": { + "type": "object", + "required": [ + "channel_id", + "port_id" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "port_id": { + "type": "string" + } + } + }, + "IbcPacket": { + "type": "object", + "required": [ + "data", + "dest", + "sequence", + "src", + "timeout" + ], + "properties": { + "data": { + "description": "The raw data sent from the other side in the packet", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "dest": { + "description": "identifies the channel and port on the receiving chain.", + "allOf": [ + { + "$ref": "#/definitions/IbcEndpoint" + } + ] + }, + "sequence": { + "description": "The sequence number of the packet on the given channel", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "src": { + "description": "identifies the channel and port on the sending chain.", + "allOf": [ + { + "$ref": "#/definitions/IbcEndpoint" + } + ] + }, + "timeout": { + "$ref": "#/definitions/IbcTimeout" + } + } + }, + "IbcPacketAckMsg": { + "description": "The message that is passed into `ibc_packet_ack`", + "type": "object", + "required": [ + "acknowledgement", + "original_packet", + "relayer" + ], + "properties": { + "acknowledgement": { + "$ref": "#/definitions/IbcAcknowledgement" + }, + "original_packet": { + "$ref": "#/definitions/IbcPacket" + }, + "relayer": { + "$ref": "#/definitions/Addr" + } + } + }, + "IbcPacketTimeoutMsg": { + "description": "The message that is passed into `ibc_packet_timeout`", + "type": "object", + "required": [ + "packet", + "relayer" + ], + "properties": { + "packet": { + "$ref": "#/definitions/IbcPacket" + }, + "relayer": { + "$ref": "#/definitions/Addr" + } + } + }, + "IbcTimeout": { + "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.", + "type": "object", + "properties": { + "block": { + "anyOf": [ + { + "$ref": "#/definitions/IbcTimeoutBlock" + }, + { + "type": "null" + } + ] + }, + "timestamp": { + "anyOf": [ + { + "$ref": "#/definitions/Timestamp" + }, + { + "type": "null" + } + ] + } + } + }, + "IbcTimeoutBlock": { + "description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)", + "type": "object", + "required": [ + "height", + "revision" + ], + "properties": { + "height": { + "description": "block height after which the packet times out. the height within the given revision", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "revision": { + "description": "the version that the client is currently on (e.g. after resetting the chain this could increment 1 as height drops to 0)", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + } + } + } + } +} diff --git a/contracts/ibc-callbacks/schema/raw/execute.json b/contracts/ibc-callbacks/schema/raw/execute.json new file mode 100644 index 0000000000..8fef4af7fa --- /dev/null +++ b/contracts/ibc-callbacks/schema/raw/execute.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "type": "object", + "required": [ + "channel_id", + "to_address" + ], + "properties": { + "channel_id": { + "description": "The channel to send the packet through", + "type": "string" + }, + "to_address": { + "description": "Address on the destination chain", + "type": "string" + } + }, + "additionalProperties": false +} diff --git a/contracts/ibc-callbacks/schema/raw/instantiate.json b/contracts/ibc-callbacks/schema/raw/instantiate.json new file mode 100644 index 0000000000..5f6dfaf43c --- /dev/null +++ b/contracts/ibc-callbacks/schema/raw/instantiate.json @@ -0,0 +1,6 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "InstantiateMsg", + "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", + "type": "object" +} diff --git a/contracts/ibc-callbacks/schema/raw/query.json b/contracts/ibc-callbacks/schema/raw/query.json new file mode 100644 index 0000000000..cb4a315dbe --- /dev/null +++ b/contracts/ibc-callbacks/schema/raw/query.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "QueryMsg", + "oneOf": [ + { + "description": "Returns stats about what callbacks have been received", + "type": "object", + "required": [ + "callback_stats" + ], + "properties": { + "callback_stats": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] +} diff --git a/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json new file mode 100644 index 0000000000..cceaa53af7 --- /dev/null +++ b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json @@ -0,0 +1,202 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "CallbackStats", + "description": "A counter for the number of times the respective callback has been called", + "type": "object", + "required": [ + "ibc_ack_callbacks", + "ibc_timeout_callbacks" + ], + "properties": { + "ibc_ack_callbacks": { + "type": "array", + "items": { + "$ref": "#/definitions/IbcPacketAckMsg" + } + }, + "ibc_timeout_callbacks": { + "type": "array", + "items": { + "$ref": "#/definitions/IbcPacketTimeoutMsg" + } + } + }, + "additionalProperties": false, + "definitions": { + "Addr": { + "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", + "type": "string" + }, + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", + "type": "string" + }, + "IbcAcknowledgement": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/definitions/Binary" + } + } + }, + "IbcEndpoint": { + "type": "object", + "required": [ + "channel_id", + "port_id" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "port_id": { + "type": "string" + } + } + }, + "IbcPacket": { + "type": "object", + "required": [ + "data", + "dest", + "sequence", + "src", + "timeout" + ], + "properties": { + "data": { + "description": "The raw data sent from the other side in the packet", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "dest": { + "description": "identifies the channel and port on the receiving chain.", + "allOf": [ + { + "$ref": "#/definitions/IbcEndpoint" + } + ] + }, + "sequence": { + "description": "The sequence number of the packet on the given channel", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "src": { + "description": "identifies the channel and port on the sending chain.", + "allOf": [ + { + "$ref": "#/definitions/IbcEndpoint" + } + ] + }, + "timeout": { + "$ref": "#/definitions/IbcTimeout" + } + } + }, + "IbcPacketAckMsg": { + "description": "The message that is passed into `ibc_packet_ack`", + "type": "object", + "required": [ + "acknowledgement", + "original_packet", + "relayer" + ], + "properties": { + "acknowledgement": { + "$ref": "#/definitions/IbcAcknowledgement" + }, + "original_packet": { + "$ref": "#/definitions/IbcPacket" + }, + "relayer": { + "$ref": "#/definitions/Addr" + } + } + }, + "IbcPacketTimeoutMsg": { + "description": "The message that is passed into `ibc_packet_timeout`", + "type": "object", + "required": [ + "packet", + "relayer" + ], + "properties": { + "packet": { + "$ref": "#/definitions/IbcPacket" + }, + "relayer": { + "$ref": "#/definitions/Addr" + } + } + }, + "IbcTimeout": { + "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.", + "type": "object", + "properties": { + "block": { + "anyOf": [ + { + "$ref": "#/definitions/IbcTimeoutBlock" + }, + { + "type": "null" + } + ] + }, + "timestamp": { + "anyOf": [ + { + "$ref": "#/definitions/Timestamp" + }, + { + "type": "null" + } + ] + } + } + }, + "IbcTimeoutBlock": { + "description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)", + "type": "object", + "required": [ + "height", + "revision" + ], + "properties": { + "height": { + "description": "block height after which the packet times out. the height within the given revision", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "revision": { + "description": "the version that the client is currently on (e.g. after resetting the chain this could increment 1 as height drops to 0)", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + } + } +} diff --git a/contracts/ibc-callbacks/src/bin/schema.rs b/contracts/ibc-callbacks/src/bin/schema.rs new file mode 100644 index 0000000000..f25266eaec --- /dev/null +++ b/contracts/ibc-callbacks/src/bin/schema.rs @@ -0,0 +1,12 @@ +use cosmwasm_schema::write_api; +use cosmwasm_std::Empty; +use ibc_callbacks::msg::{ExecuteMsg, QueryMsg}; + +fn main() { + // Clear & write standard API + write_api! { + instantiate: Empty, + query: QueryMsg, + execute: ExecuteMsg, + } +} diff --git a/contracts/ibc-callbacks/src/contract.rs b/contracts/ibc-callbacks/src/contract.rs new file mode 100644 index 0000000000..18e9df7d8a --- /dev/null +++ b/contracts/ibc-callbacks/src/contract.rs @@ -0,0 +1,172 @@ +use cosmwasm_std::{ + entry_point, to_json_binary, to_json_string, Addr, Binary, Deps, DepsMut, Empty, Env, + IbcBasicResponse, IbcMsg, IbcPacketAckMsg, IbcPacketTimeoutMsg, IbcTimeout, MessageInfo, + Response, StdError, StdResult, +}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +use crate::msg::{ExecuteMsg, QueryMsg}; +use crate::state::{load_stats, save_stats, CallbackStats}; + +#[entry_point] +pub fn instantiate( + deps: DepsMut, + _env: Env, + _info: MessageInfo, + _msg: Empty, +) -> StdResult { + // initialize counts + let counts = CallbackStats::default(); + save_stats(deps.storage, &counts)?; + + Ok(Response::new().add_attribute("action", "instantiate")) +} + +/// Sends an `IbcMsg::Transfer` to the given `to_address` on the given `channel_id`. +#[entry_point] +pub fn execute( + _deps: DepsMut, + env: Env, + info: MessageInfo, + msg: ExecuteMsg, +) -> StdResult { + let transfer_msg = match &*info.funds { + [coin] if !coin.amount.is_zero() => IbcMsg::Transfer { + to_address: msg.to_address, + timeout: IbcTimeout::with_timestamp(env.block.time.plus_seconds(5)), // TODO: how much time? + channel_id: msg.channel_id.clone(), + amount: coin.clone(), + memo: Some(to_json_string(&IbcCallbackData::source(IbcSrcCallback { + address: env.contract.address.clone(), + gas_limit: None, + }))?), + }, + _ => { + return Err(StdError::generic_err( + "Must send exactly one denom to trigger ics-20 transfer", + )) + } + }; + + Ok(Response::new() + .add_message(transfer_msg) + .add_attribute("action", "execute")) +} + +#[entry_point] +pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { + match msg { + QueryMsg::CallbackStats {} => to_json_binary(&load_stats(deps.storage)?), + } +} + +/// This is the entrypoint that is called by the source chain when a callbacks-enabled IBC message +/// is acknowledged or times out. +// #[entry_point] +pub fn ibc_source_chain_callback( + deps: DepsMut, + _env: Env, + msg: IbcSourceChainCallback, +) -> StdResult { + let mut counts = load_stats(deps.storage)?; + + match msg { + IbcSourceChainCallback::Acknowledgement(ack) => { + // increment the counter + counts.ibc_ack_callbacks.push(ack); + } + IbcSourceChainCallback::Timeout(timeout) => { + // increment the counter + counts.ibc_timeout_callbacks.push(timeout); + } + } + + save_stats(deps.storage, &counts)?; + + Ok(IbcBasicResponse::new().add_attribute("action", "ibc_source_chain_callback")) +} + +// TODO: move all the types below to cosmwasm-std when the everything is ready + +/// This is just a type representing the data that has to be sent with the IBC message to receive +/// callbacks. It should be serialized to JSON and sent with the IBC message. +/// The specific field to send it in can vary depending on the IBC message, +/// but is usually the `memo` field by convention. +/// +/// See [`IbcSourceChainCallback`] for more details. +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +pub struct IbcCallbackData { + // using private fields to force use of the constructors + src_callback: Option, + dst_callback: Option, +} + +impl IbcCallbackData { + /// Use this if you want to execute callbacks on both the source and destination chain. + /// + /// In the first prototype, we only support receiving callbacks on the source chain. + pub fn both(src_callback: IbcSrcCallback, dst_callback: IbcDstCallback) -> Self { + IbcCallbackData { + src_callback: Some(src_callback), + dst_callback: Some(dst_callback), + } + } + + /// Use this if you want to execute callbacks on the source chain, but not the destination chain. + pub fn source(src_callback: IbcSrcCallback) -> Self { + IbcCallbackData { + src_callback: Some(src_callback), + dst_callback: None, + } + } + + /// Use this if you want to execute callbacks on the destination chain, but not the source chain. + /// + /// In the first prototype, we only support receiving callbacks on the source chain. + pub fn destination(dst_callback: IbcDstCallback) -> Self { + IbcCallbackData { + src_callback: None, + dst_callback: Some(dst_callback), + } + } +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +pub struct IbcSrcCallback { + /// The source chain address that should receive the callback. + /// You probably want to put `env.contract.address` here. + pub address: Addr, + /// Optional gas limit for the callback (in Cosmos SDK gas units) + pub gas_limit: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +pub struct IbcDstCallback { + /// The destination chain address that should receive the callback. + pub address: String, + /// Optional gas limit for the callback (in Cosmos SDK gas units) + pub gas_limit: Option, +} + +/// The type of IBC callback that is being called. +/// +/// IBC callbacks are needed for cases where your contract triggers the sending of an IBC packet +/// through some other message (i.e. not through [`IbcMsg::SendPacket`]) and needs to know whether +/// or not the packet was successfully received on the other chain. +/// A prominent example is the [`IbcMsg::Transfer`] message. Without callbacks, you cannot know +/// whether the transfer was successful or not. +/// +/// Note that there are some prerequisites that need to be fulfilled to receive source chain callbacks: +/// - The contract must implement the `ibc_source_chain_callback` entrypoint. +/// - The module that sends the packet must be wrapped by an `IBCMiddleware` +/// (i.e. the source chain needs to support callbacks for the message you are sending). +/// - You have to add json-encoded [`IbcCallbackData`] to a specific field of the message. +/// For `IbcMsg::Transfer`, this is the `memo` field. +/// - The receiver of the callback must also be the sender of the message. +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +pub enum IbcSourceChainCallback { + Acknowledgement(IbcPacketAckMsg), + Timeout(IbcPacketTimeoutMsg), + // TODO: should this be non-exhaustive? +} diff --git a/contracts/ibc-callbacks/src/lib.rs b/contracts/ibc-callbacks/src/lib.rs new file mode 100644 index 0000000000..4934c19d5b --- /dev/null +++ b/contracts/ibc-callbacks/src/lib.rs @@ -0,0 +1,3 @@ +pub mod contract; +pub mod msg; +pub mod state; diff --git a/contracts/ibc-callbacks/src/msg.rs b/contracts/ibc-callbacks/src/msg.rs new file mode 100644 index 0000000000..687a81e75e --- /dev/null +++ b/contracts/ibc-callbacks/src/msg.rs @@ -0,0 +1,19 @@ +use cosmwasm_schema::{cw_serde, QueryResponses}; + +use crate::state::CallbackStats; + +#[cw_serde] +#[derive(QueryResponses)] +pub enum QueryMsg { + /// Returns stats about what callbacks have been received + #[returns(CallbackStats)] + CallbackStats {}, +} + +#[cw_serde] +pub struct ExecuteMsg { + /// Address on the destination chain + pub to_address: String, + /// The channel to send the packet through + pub channel_id: String, +} diff --git a/contracts/ibc-callbacks/src/state.rs b/contracts/ibc-callbacks/src/state.rs new file mode 100644 index 0000000000..1ba645cb62 --- /dev/null +++ b/contracts/ibc-callbacks/src/state.rs @@ -0,0 +1,39 @@ +use std::any::type_name; + +use cosmwasm_schema::cw_serde; +use cosmwasm_std::{ + from_json, storage_keys::to_length_prefixed, to_json_vec, IbcPacketAckMsg, IbcPacketTimeoutMsg, + StdError, StdResult, Storage, +}; +use serde::{de::DeserializeOwned, Serialize}; + +pub const KEY_STATS: &[u8] = b"counts"; + +/// A counter for the number of times the respective callback has been called +#[cw_serde] +#[derive(Default)] +pub struct CallbackStats { + pub ibc_ack_callbacks: Vec, + pub ibc_timeout_callbacks: Vec, + // pub ibc_receive_callback: u32, +} + +pub fn load_stats(storage: &dyn Storage) -> StdResult { + load_item(storage, KEY_STATS) +} + +pub fn save_stats(storage: &mut dyn Storage, counts: &CallbackStats) -> StdResult<()> { + save_item(storage, KEY_STATS, counts) +} + +fn load_item(storage: &dyn Storage, key: &[u8]) -> StdResult { + storage + .get(&to_length_prefixed(key)) + .ok_or_else(|| StdError::not_found(type_name::())) + .and_then(from_json) +} + +fn save_item(storage: &mut dyn Storage, key: &[u8], item: &T) -> StdResult<()> { + storage.set(&to_length_prefixed(key), &to_json_vec(item)?); + Ok(()) +} From 83e08ba1c73967e5b0291f40f4b792696f0125d6 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 9 Feb 2024 15:48:43 +0100 Subject: [PATCH 02/44] Fix gas limit type --- contracts/ibc-callbacks/src/contract.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/contracts/ibc-callbacks/src/contract.rs b/contracts/ibc-callbacks/src/contract.rs index 18e9df7d8a..83a8461f2d 100644 --- a/contracts/ibc-callbacks/src/contract.rs +++ b/contracts/ibc-callbacks/src/contract.rs @@ -1,7 +1,7 @@ use cosmwasm_std::{ entry_point, to_json_binary, to_json_string, Addr, Binary, Deps, DepsMut, Empty, Env, IbcBasicResponse, IbcMsg, IbcPacketAckMsg, IbcPacketTimeoutMsg, IbcTimeout, MessageInfo, - Response, StdError, StdResult, + Response, StdError, StdResult, Uint64, }; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -138,7 +138,8 @@ pub struct IbcSrcCallback { /// You probably want to put `env.contract.address` here. pub address: Addr, /// Optional gas limit for the callback (in Cosmos SDK gas units) - pub gas_limit: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub gas_limit: Option, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] @@ -146,7 +147,8 @@ pub struct IbcDstCallback { /// The destination chain address that should receive the callback. pub address: String, /// Optional gas limit for the callback (in Cosmos SDK gas units) - pub gas_limit: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub gas_limit: Option, } /// The type of IBC callback that is being called. From e56e52c9403931c4984eb47c359d68de07e01945 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Wed, 14 Feb 2024 18:03:28 +0100 Subject: [PATCH 03/44] Add callback entrypoint to cosmwasm-std --- contracts/ibc-callbacks/src/contract.rs | 106 +++------------------- contracts/ibc-callbacks/src/msg.rs | 3 + packages/std/src/exports.rs | 51 ++++++++++- packages/std/src/ibc.rs | 3 + packages/std/src/ibc/callbacks.rs | 115 ++++++++++++++++++++++++ packages/std/src/lib.rs | 13 +-- 6 files changed, 189 insertions(+), 102 deletions(-) create mode 100644 packages/std/src/ibc/callbacks.rs diff --git a/contracts/ibc-callbacks/src/contract.rs b/contracts/ibc-callbacks/src/contract.rs index 83a8461f2d..53ac6ac8ff 100644 --- a/contracts/ibc-callbacks/src/contract.rs +++ b/contracts/ibc-callbacks/src/contract.rs @@ -1,10 +1,8 @@ use cosmwasm_std::{ - entry_point, to_json_binary, to_json_string, Addr, Binary, Deps, DepsMut, Empty, Env, - IbcBasicResponse, IbcMsg, IbcPacketAckMsg, IbcPacketTimeoutMsg, IbcTimeout, MessageInfo, - Response, StdError, StdResult, Uint64, + entry_point, to_json_binary, to_json_string, Binary, Deps, DepsMut, Empty, Env, + IbcBasicResponse, IbcCallbackData, IbcMsg, IbcSourceChainCallbackMsg, IbcSrcCallback, + IbcTimeout, MessageInfo, Response, StdError, StdResult, }; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; use crate::msg::{ExecuteMsg, QueryMsg}; use crate::state::{load_stats, save_stats, CallbackStats}; @@ -34,7 +32,9 @@ pub fn execute( let transfer_msg = match &*info.funds { [coin] if !coin.amount.is_zero() => IbcMsg::Transfer { to_address: msg.to_address, - timeout: IbcTimeout::with_timestamp(env.block.time.plus_seconds(5)), // TODO: how much time? + timeout: IbcTimeout::with_timestamp( + env.block.time.plus_seconds(msg.timeout_seconds.u64()), + ), channel_id: msg.channel_id.clone(), amount: coin.clone(), memo: Some(to_json_string(&IbcCallbackData::source(IbcSrcCallback { @@ -63,20 +63,20 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { /// This is the entrypoint that is called by the source chain when a callbacks-enabled IBC message /// is acknowledged or times out. -// #[entry_point] +#[entry_point] pub fn ibc_source_chain_callback( deps: DepsMut, _env: Env, - msg: IbcSourceChainCallback, + msg: IbcSourceChainCallbackMsg, ) -> StdResult { let mut counts = load_stats(deps.storage)?; match msg { - IbcSourceChainCallback::Acknowledgement(ack) => { + IbcSourceChainCallbackMsg::Acknowledgement(ack) => { // increment the counter counts.ibc_ack_callbacks.push(ack); } - IbcSourceChainCallback::Timeout(timeout) => { + IbcSourceChainCallbackMsg::Timeout(timeout) => { // increment the counter counts.ibc_timeout_callbacks.push(timeout); } @@ -86,89 +86,3 @@ pub fn ibc_source_chain_callback( Ok(IbcBasicResponse::new().add_attribute("action", "ibc_source_chain_callback")) } - -// TODO: move all the types below to cosmwasm-std when the everything is ready - -/// This is just a type representing the data that has to be sent with the IBC message to receive -/// callbacks. It should be serialized to JSON and sent with the IBC message. -/// The specific field to send it in can vary depending on the IBC message, -/// but is usually the `memo` field by convention. -/// -/// See [`IbcSourceChainCallback`] for more details. -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] -pub struct IbcCallbackData { - // using private fields to force use of the constructors - src_callback: Option, - dst_callback: Option, -} - -impl IbcCallbackData { - /// Use this if you want to execute callbacks on both the source and destination chain. - /// - /// In the first prototype, we only support receiving callbacks on the source chain. - pub fn both(src_callback: IbcSrcCallback, dst_callback: IbcDstCallback) -> Self { - IbcCallbackData { - src_callback: Some(src_callback), - dst_callback: Some(dst_callback), - } - } - - /// Use this if you want to execute callbacks on the source chain, but not the destination chain. - pub fn source(src_callback: IbcSrcCallback) -> Self { - IbcCallbackData { - src_callback: Some(src_callback), - dst_callback: None, - } - } - - /// Use this if you want to execute callbacks on the destination chain, but not the source chain. - /// - /// In the first prototype, we only support receiving callbacks on the source chain. - pub fn destination(dst_callback: IbcDstCallback) -> Self { - IbcCallbackData { - src_callback: None, - dst_callback: Some(dst_callback), - } - } -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] -pub struct IbcSrcCallback { - /// The source chain address that should receive the callback. - /// You probably want to put `env.contract.address` here. - pub address: Addr, - /// Optional gas limit for the callback (in Cosmos SDK gas units) - #[serde(skip_serializing_if = "Option::is_none")] - pub gas_limit: Option, -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] -pub struct IbcDstCallback { - /// The destination chain address that should receive the callback. - pub address: String, - /// Optional gas limit for the callback (in Cosmos SDK gas units) - #[serde(skip_serializing_if = "Option::is_none")] - pub gas_limit: Option, -} - -/// The type of IBC callback that is being called. -/// -/// IBC callbacks are needed for cases where your contract triggers the sending of an IBC packet -/// through some other message (i.e. not through [`IbcMsg::SendPacket`]) and needs to know whether -/// or not the packet was successfully received on the other chain. -/// A prominent example is the [`IbcMsg::Transfer`] message. Without callbacks, you cannot know -/// whether the transfer was successful or not. -/// -/// Note that there are some prerequisites that need to be fulfilled to receive source chain callbacks: -/// - The contract must implement the `ibc_source_chain_callback` entrypoint. -/// - The module that sends the packet must be wrapped by an `IBCMiddleware` -/// (i.e. the source chain needs to support callbacks for the message you are sending). -/// - You have to add json-encoded [`IbcCallbackData`] to a specific field of the message. -/// For `IbcMsg::Transfer`, this is the `memo` field. -/// - The receiver of the callback must also be the sender of the message. -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] -pub enum IbcSourceChainCallback { - Acknowledgement(IbcPacketAckMsg), - Timeout(IbcPacketTimeoutMsg), - // TODO: should this be non-exhaustive? -} diff --git a/contracts/ibc-callbacks/src/msg.rs b/contracts/ibc-callbacks/src/msg.rs index 687a81e75e..cec0b1ea58 100644 --- a/contracts/ibc-callbacks/src/msg.rs +++ b/contracts/ibc-callbacks/src/msg.rs @@ -1,4 +1,5 @@ use cosmwasm_schema::{cw_serde, QueryResponses}; +use cosmwasm_std::Uint64; use crate::state::CallbackStats; @@ -16,4 +17,6 @@ pub struct ExecuteMsg { pub to_address: String, /// The channel to send the packet through pub channel_id: String, + /// The amount of seconds from now the transfer should timeout at + pub timeout_seconds: Uint64, } diff --git a/packages/std/src/exports.rs b/packages/std/src/exports.rs index 3d9e445c3a..a9527b54f2 100644 --- a/packages/std/src/exports.rs +++ b/packages/std/src/exports.rs @@ -16,7 +16,7 @@ use crate::deps::OwnedDeps; #[cfg(feature = "stargate")] use crate::ibc::{ IbcBasicResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcPacketAckMsg, - IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, + IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, IbcSourceChainCallbackMsg, }; use crate::ibc::{IbcChannelOpenMsg, IbcChannelOpenResponse}; use crate::imports::{ExternalApi, ExternalQuerier, ExternalStorage}; @@ -446,6 +446,31 @@ where Region::from_vec(v).to_heap_ptr() as u32 } +pub fn do_ibc_source_chain_callback( + contract_fn: &dyn Fn( + DepsMut, + Env, + IbcSourceChainCallbackMsg, + ) -> Result, E>, + env_ptr: u32, + msg_ptr: u32, +) -> u32 +where + Q: CustomQuery, + C: CustomMsg, + E: ToString, +{ + #[cfg(feature = "abort")] + install_panic_handler(); + let res = _do_ibc_source_callback( + contract_fn, + env_ptr as *mut Region, + msg_ptr as *mut Region, + ); + let v = to_json_vec(&res).unwrap(); + Region::from_vec(v).to_heap_ptr() as u32 +} + fn _do_instantiate( instantiate_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result, E>, env_ptr: *mut Region, @@ -700,6 +725,30 @@ where contract_fn(deps.as_mut(), env, msg).into() } +fn _do_ibc_source_chain_callback( + contract_fn: &dyn Fn( + DepsMut, + Env, + IbcSourceChainCallbackMsg, + ) -> Result, E>, + env_ptr: *mut Region, + msg_ptr: *mut Region, +) -> ContractResult> +where + Q: CustomQuery, + C: CustomMsg, + E: ToString, +{ + let env: Vec = unsafe { Region::from_heap_ptr(env_ptr).into_vec() }; + let msg: Vec = unsafe { Region::from_heap_ptr(msg_ptr).into_vec() }; + + let env: Env = try_into_contract_result!(from_json(env)); + let msg: IbcSourceChainCallbackMsg = try_into_contract_result!(from_json(msg)); + + let mut deps = make_dependencies(); + contract_fn(deps.as_mut(), env, msg).into() +} + /// Makes all bridges to external dependencies (i.e. Wasm imports) that are injected by the VM pub(crate) fn make_dependencies() -> OwnedDeps where diff --git a/packages/std/src/ibc.rs b/packages/std/src/ibc.rs index 29c3c3bf45..cec3b790d7 100644 --- a/packages/std/src/ibc.rs +++ b/packages/std/src/ibc.rs @@ -12,6 +12,9 @@ use crate::results::{Attribute, CosmosMsg, Empty, Event, SubMsg}; use crate::StdResult; use crate::{to_json_binary, Binary}; +mod callbacks; +pub use callbacks::*; + /// These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts /// (contracts that directly speak the IBC protocol via 6 entry points) #[non_exhaustive] diff --git a/packages/std/src/ibc/callbacks.rs b/packages/std/src/ibc/callbacks.rs new file mode 100644 index 0000000000..1a68c17558 --- /dev/null +++ b/packages/std/src/ibc/callbacks.rs @@ -0,0 +1,115 @@ +//! This module contains types for the IBC callbacks defined in +//! [ADR-8](https://github.com/cosmos/ibc-go/blob/main/docs/architecture/adr-008-app-caller-cbs.md). + +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +use crate::{Addr, IbcPacketAckMsg, IbcPacketTimeoutMsg, Uint64}; + +/// This is just a type representing the data that has to be sent with the IBC message to receive +/// callbacks. It should be serialized to JSON and sent with the IBC message. +/// The specific field to send it in can vary depending on the IBC message, +/// but is usually the `memo` field by convention. +/// +/// See [`IbcSourceChainCallback`] for more details. +/// +/// # Example +/// +/// ```rust +/// use cosmwasm_std::{ +/// to_json_string, Coin, IbcCallbackData, IbcMsg, IbcSrcCallback, IbcTimeout, Response, +/// Timestamp, +/// }; +/// +/// # use cosmwasm_std::testing::mock_env; +/// # let env = mock_env(); +/// +/// let transfer = IbcMsg::Transfer { +/// to_address: "cosmos1example".to_string(), +/// channel_id: "channel-0".to_string(), +/// amount: Coin::new(10u32, "ucoin"), +/// timeout: Timestamp::from_seconds(12345).into(), +/// memo: Some(to_json_string(&IbcCallbackData::source(IbcSrcCallback { +/// address: env.contract.address, +/// gas_limit: None, +/// })).unwrap()), +/// }; +/// +/// Response::new().add_message(transfer); +/// ``` +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +pub struct IbcCallbackData { + // using private fields to force use of the constructors + src_callback: Option, + dst_callback: Option, +} + +impl IbcCallbackData { + /// Use this if you want to execute callbacks on both the source and destination chain. + /// + /// In the first prototype, we only support receiving callbacks on the source chain. + pub fn both(src_callback: IbcSrcCallback, dst_callback: IbcDstCallback) -> Self { + IbcCallbackData { + src_callback: Some(src_callback), + dst_callback: Some(dst_callback), + } + } + + /// Use this if you want to execute callbacks on the source chain, but not the destination chain. + pub fn source(src_callback: IbcSrcCallback) -> Self { + IbcCallbackData { + src_callback: Some(src_callback), + dst_callback: None, + } + } + + /// Use this if you want to execute callbacks on the destination chain, but not the source chain. + /// + /// In the first prototype, we only support receiving callbacks on the source chain. + pub fn destination(dst_callback: IbcDstCallback) -> Self { + IbcCallbackData { + src_callback: None, + dst_callback: Some(dst_callback), + } + } +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +pub struct IbcSrcCallback { + /// The source chain address that should receive the callback. + /// You probably want to put `env.contract.address` here. + pub address: Addr, + /// Optional gas limit for the callback (in Cosmos SDK gas units) + #[serde(skip_serializing_if = "Option::is_none")] + pub gas_limit: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +pub struct IbcDstCallback { + /// The destination chain address that should receive the callback. + pub address: String, + /// Optional gas limit for the callback (in Cosmos SDK gas units) + #[serde(skip_serializing_if = "Option::is_none")] + pub gas_limit: Option, +} + +/// The type of IBC callback that is being called. +/// +/// IBC callbacks are needed for cases where your contract triggers the sending of an IBC packet +/// through some other message (i.e. not through [`IbcMsg::SendPacket`]) and needs to know whether +/// or not the packet was successfully received on the other chain. +/// A prominent example is the [`IbcMsg::Transfer`] message. Without callbacks, you cannot know +/// whether the transfer was successful or not. +/// +/// Note that there are some prerequisites that need to be fulfilled to receive source chain callbacks: +/// - The contract must implement the `ibc_source_chain_callback` entrypoint. +/// - The module that sends the packet must be wrapped by an `IBCMiddleware` +/// (i.e. the source chain needs to support callbacks for the message you are sending). +/// - You have to add json-encoded [`IbcCallbackData`] to a specific field of the message. +/// For `IbcMsg::Transfer`, this is the `memo` field. +/// - The receiver of the callback must also be the sender of the message. +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +pub enum IbcSourceChainCallbackMsg { + Acknowledgement(IbcPacketAckMsg), + Timeout(IbcPacketTimeoutMsg), +} diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index c668b28783..d779466c74 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -40,10 +40,10 @@ pub use crate::coins::Coins; pub use crate::deps::{Deps, DepsMut, OwnedDeps}; pub use crate::ibc::IbcChannelOpenResponse; pub use crate::ibc::{ - Ibc3ChannelOpenResponse, IbcAcknowledgement, IbcBasicResponse, IbcChannel, IbcChannelCloseMsg, - IbcChannelConnectMsg, IbcChannelOpenMsg, IbcEndpoint, IbcMsg, IbcOrder, IbcPacket, - IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, IbcTimeout, - IbcTimeoutBlock, + Ibc3ChannelOpenResponse, IbcAcknowledgement, IbcBasicResponse, IbcCallbackData, IbcChannel, + IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, IbcDstCallback, IbcEndpoint, + IbcMsg, IbcOrder, IbcPacket, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, + IbcReceiveResponse, IbcSourceChainCallbackMsg, IbcSrcCallback, IbcTimeout, IbcTimeoutBlock, }; #[cfg(feature = "iterator")] pub use crate::iterator::{Order, Record}; @@ -90,7 +90,10 @@ mod imports; mod memory; // Used by exports and imports only. This assumes pointers are 32 bit long, which makes it untestable on dev machines. #[cfg(target_arch = "wasm32")] -pub use crate::exports::{do_execute, do_instantiate, do_migrate, do_query, do_reply, do_sudo}; +pub use crate::exports::{ + do_execute, do_ibc_source_chain_callback, do_instantiate, do_migrate, do_query, do_reply, + do_sudo, +}; #[cfg(all(feature = "stargate", target_arch = "wasm32"))] pub use crate::exports::{ do_ibc_channel_close, do_ibc_channel_connect, do_ibc_channel_open, do_ibc_packet_ack, From 4ad16bb739bcefae05115aff6bc7a7cc1cafc8fb Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Wed, 14 Feb 2024 18:25:20 +0100 Subject: [PATCH 04/44] Fix imports --- contracts/ibc-callbacks/src/msg.rs | 4 +--- packages/std/src/exports.rs | 5 +++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/contracts/ibc-callbacks/src/msg.rs b/contracts/ibc-callbacks/src/msg.rs index cec0b1ea58..6c3e15f8fc 100644 --- a/contracts/ibc-callbacks/src/msg.rs +++ b/contracts/ibc-callbacks/src/msg.rs @@ -1,13 +1,11 @@ use cosmwasm_schema::{cw_serde, QueryResponses}; use cosmwasm_std::Uint64; -use crate::state::CallbackStats; - #[cw_serde] #[derive(QueryResponses)] pub enum QueryMsg { /// Returns stats about what callbacks have been received - #[returns(CallbackStats)] + #[returns(crate::state::CallbackStats)] CallbackStats {}, } diff --git a/packages/std/src/exports.rs b/packages/std/src/exports.rs index a9527b54f2..cb4085c8ad 100644 --- a/packages/std/src/exports.rs +++ b/packages/std/src/exports.rs @@ -13,10 +13,11 @@ use core::marker::PhantomData; use serde::de::DeserializeOwned; use crate::deps::OwnedDeps; +use crate::ibc::{IbcBasicResponse, IbcSourceChainCallbackMsg}; #[cfg(feature = "stargate")] use crate::ibc::{ - IbcBasicResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcPacketAckMsg, - IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, IbcSourceChainCallbackMsg, + IbcChannelCloseMsg, IbcChannelConnectMsg, IbcPacketAckMsg, IbcPacketReceiveMsg, + IbcPacketTimeoutMsg, IbcReceiveResponse, }; use crate::ibc::{IbcChannelOpenMsg, IbcChannelOpenResponse}; use crate::imports::{ExternalApi, ExternalQuerier, ExternalStorage}; From 578e6331bcf5d09c9e6409e0d0644af6667cf8dc Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Thu, 15 Feb 2024 14:25:41 +0100 Subject: [PATCH 05/44] Fix doctest --- packages/std/src/ibc/callbacks.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/std/src/ibc/callbacks.rs b/packages/std/src/ibc/callbacks.rs index 1a68c17558..01e2598cc7 100644 --- a/packages/std/src/ibc/callbacks.rs +++ b/packages/std/src/ibc/callbacks.rs @@ -24,7 +24,7 @@ use crate::{Addr, IbcPacketAckMsg, IbcPacketTimeoutMsg, Uint64}; /// # use cosmwasm_std::testing::mock_env; /// # let env = mock_env(); /// -/// let transfer = IbcMsg::Transfer { +/// let _transfer = IbcMsg::Transfer { /// to_address: "cosmos1example".to_string(), /// channel_id: "channel-0".to_string(), /// amount: Coin::new(10u32, "ucoin"), @@ -34,8 +34,6 @@ use crate::{Addr, IbcPacketAckMsg, IbcPacketTimeoutMsg, Uint64}; /// gas_limit: None, /// })).unwrap()), /// }; -/// -/// Response::new().add_message(transfer); /// ``` #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct IbcCallbackData { From bc0b4dc1ee883c851098180f2898ca0edad59b40 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 16 Feb 2024 13:27:23 +0100 Subject: [PATCH 06/44] Add ibc_callbacks wasm to testdata --- packages/vm/README.md | 12 ++++++++---- packages/vm/testdata/ibc_callbacks.wasm | Bin 0 -> 222490 bytes 2 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 packages/vm/testdata/ibc_callbacks.wasm diff --git a/packages/vm/README.md b/packages/vm/README.md index aa440a7960..7f21b8db19 100644 --- a/packages/vm/README.md +++ b/packages/vm/README.md @@ -42,10 +42,8 @@ compatibility list: There are demo files in `testdata/*.wasm`. Those are compiled and optimized versions of -[contracts/hackatom](https://github.com/CosmWasm/cosmwasm/tree/main/contracts/hackatom) -and -[contracts/staking](https://github.com/CosmWasm/cosmwasm/tree/main/contracts/staking) -run through [rust-optimizer](https://github.com/CosmWasm/rust-optimizer). +[contracts/\*](https://github.com/CosmWasm/cosmwasm/tree/main/contracts/) run +through [rust-optimizer](https://github.com/CosmWasm/rust-optimizer). To rebuild the test contracts, go to the repo root and do @@ -73,6 +71,12 @@ docker run --rm -v "$(pwd)":/code \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ cosmwasm/optimizer:0.15.0 ./contracts/empty \ && cp artifacts/empty.wasm packages/vm/testdata/empty.wasm + +docker run --rm -v "$(pwd)":/code \ + --mount type=volume,source="devcontract_cache_ibc_callback",target=/target \ + --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ + cosmwasm/optimizer:0.15.0 ./contracts/ibc-callbacks \ + && cp artifacts/ibc_callbacks.wasm packages/vm/testdata/ibc_callbacks.wasm ``` The `cyberpunk_rust170.wasm` for diff --git a/packages/vm/testdata/ibc_callbacks.wasm b/packages/vm/testdata/ibc_callbacks.wasm new file mode 100644 index 0000000000000000000000000000000000000000..1654a2047651dce68b7d8826d15b303c4aceb840 GIT binary patch literal 222490 zcmeFa54>IFS?9a{?7wI4eX`CCQJJ|^QSsVd>v+Gv z=Xu|?_dYo%Bq`4H^YN1QthLu#@4x5&^SsadzRC7?zAa6XB>fNR>TTKHz3E>4O}6EG z?LG~+$+lFlYCPphT^FuRyXvmtcgeOS+13hAs}Cud@c;NVw^sYTUeCRWSL=`YmF>M( z_xGyaPOOV754&SOt*iHXukO9~-X#0+Y+1hJ?RV9;zx5rv_awRQo4366rrkTX-;&hz ztHrPXWA|-)b|k5Ow(aHH-f`EC(Z}z+dHdUwEEawHj=T4G(cbo3ZrOd)UE6QJ?UwD7 zx9Vo>83o?)_SbLB8>$|?g zN7K3UT|0Ka`=*<3-G1BK>F*b_Kgnuot=4Y#+qHI@ru^VR>QQH&fLs&rOr8 z$%95SO{SCctg>2`tzxWqq(8~OdY&dTjn(xa{s-8=4l*KNCZyz?dqe)sl0@7SH}AA3lP zyT3!__NU8ldploz`*x~_0N;7rJKlcN6+E80=_Y7>`%OFEeoLNqZo28#9oz4?>8;z} zxg*coe+SgcwDW=V)xVg1I=%Az3%;pby?M)P52aWANcv;x?7AOKA4-2b{fYG9^aDWS zr_uxIPp2PDufFb@jn8IRUHdP$?%28O)wjSlx4-RqPo= zde!0d=h8jznos}FoB#DaciwvU&!_MHne?jNKbwBXx4-(4^wI1{_M7ReuR4}~D*a^o zJL#+cIQ?RJ)wREyKACr*;V&vSN&=B6WLWim3<)lNj-QtyZUFc!`ad76WJ%TU&;PBqs&#mnSCbvZ1#U= zPh_9V{$uuEvR}^rb2jzJ2fKfgJqPvgP4B%VDT`gh`r4#OXR~CGXPb+34)WPtlVMWf&M*9~44jWXRitZmF%dX^N8o#px~lcZCmWpZUwvtmUkSc?T~ zR%=q!c9ugvrk2`xEw!Syt89F;HC8K|{TXj=RBD)(MGt3ofbof=8K$cnswPLULK##Gx|)XP;n`P1FW&tbZean_6ax~w*A zZp!;b!i&P5CPi~o##riQ(y_0~V&~eV^C@_7ufsZ9n`E0az^nnMTYE{_DiT0Dq|}~a zUZniXUw6TfYuWnd3x;{Q_nqa%cMVd?2rpRytS>CGlJ-{di?YeaY=sb&mE5h;wMBOT zYF4h;*}uNXX0z@f)upwS8UXjktj0w>?qjT8$5$>TuuJwti@Xee}U&#=bxw5W{@r8YK{%#fRDD7gesEHl)q7FM)Z%3tu_457i zITD$xUQ*8w@SB0F4^}8J7X?Smr59qZ1+_)yve#m+4BB6pCpQSLEaB%$`n zNQZ=e5FoEhl1(&MhmOl1pCqC7*G@vKoP>;L0}VNnQy3hwy3jyl49t+rL|8Qp@wP&$ zIB5)(t6;8?EC;FM+$K?C2(FZX(ZG7q07886g2K~@L`vWb<0`imRc=H4;3~Hvq0$sF z=x*57#ZcKO+Mv>2w|QB##m`MCDxM`pdx6STv7#v&XutuXVAEnv|5A27b>>u3HBU>sO4F{YQ3AmFIVuDO1Fy|a`N9H;))g{ zK*6@8U|Zt~wpFyGV5b%;*r^Ex+j3$4)e5#7b`6^mw)GKg(c`T_L$KA|5EUO_TQ6FG z$X>U2Ngsf1!;ApI7RsG4XH=|c2)1>zgRCHS5LdH(%$(s>RZDIy6%B(eFATN|N>#9} zOOlM5r=UXDuMM`%axL41O*aPlb|JOy;z*SV; z6je9JsoLO*vA2+_YYX6N*4EF}qmjOO=kTAk#E=qg^gnK98BC4P*dUeHLf2!LV4Lye z@_}S&T^4Ls{$qNlK9DRLHch-OA`d}LYFxu-CK;X8TWSs7>z`*0^|DeeV98xe)iqdU z08^LsJ-AMT6zzW&jnH$M1*105BwjJfYu7OCC7lkfHVes08%>#9*Z=paiOXKr%{wM6 z`E#{+R!Yp|<>io(gj`GZOnB)GE!pZmihn4~SupI;Cg&{u+CnUlPo?9W6Z@+2dvx0D`=H5-U6kK~wK< zSlq{xDS_oMo4j$%gjZqrNj17bWx~htMH5~qQV)wvRLLdwkxH#!SgGHYu|I{RrIgE;ZOk4>&D78CEgD4t@H4|4-tNW%4x^`F!&( zd%W;-I*DUJb+h4mg|37&a5Rd0Bpz=3@I9DY{M>vGkK6o&?RYPTPeq%0cf&nJlQ(?v zuk`tr*Y1Nq+gq~lrqS2#yWi}#Epy*ZkC*Sef6K3Z@Vy`UzMrqncc`$*Ku!k&);-k!r;H>mA4qrhKb?Vt{a=CPlWebu{(%(8Quh8Eddc~G^p#|1xq)w1 z?CL)!*sO3+QaNol)aI~RwTgiw=q_j!3+1FnV@p-p8@;(d3(ck8T+upIZrFWgvV*_| z{j#3#EMEpa_8-fTjwwjS6ezMD0E|v1LcbAJsat0Qy+YJ8RM2i+kkzAz# zg|bXx-I}JOkQ@(}?A}S8TSXJ}dquFJ=~b(0B}C3bLuSRTpabJ0?=$kwdn_joC$e z>lXjYb_EnYCBL%jYpef@3I!fdv0?kano58BzapDUjuXI?iB;A-O3b6*PRqYfuH(_P zJrZ{3l4sIkQ}B|lwQJb8k_Y%Qm}fmi7~f?bg<7)Gn(jZU29H^TzrgKW@Mi|FJUuHm)W2$VNB_dr*F@Ko;18wUMq)!Fa>!)1HJRg|jPjj_ZL8+u~de zs6lP3It;e~`Xe+LZhhBulZm%1&r{6PngtPwFa8B8fga>SbFKXH`;f>TJ*0y?)R%;b zwtVrAKl-6Vzwp#Ay^wq>ab)@ch{~Kx+8KfVq(&N(ji|Q9WD|mPW03}^x6C^XwI+X| zA*P{|s~tt?likB$z_YtT1nWTi6$2W;sg>tmi|)(HrvYYGK9WVd z+(gsCY*Y56*{4%thVt1|q!)X?h9}sh&!*j#i`RTzj|j6FNr5~z1m;TyePh5G!|tob z_-{rSYGEA@HEV#mEB32hnRK}uao;(eE@84j267qt&UWhuQ#6SA1?FdmHChEH%Yjf& zL|Ig=Pjv}M@nirbr^IKSEy=*tnJs(kMf&znGT~h~Ei)!bRRqC0zCDuIzDU`I@F>K1^ox$>=K9~~q+c$$L z0Jyw+t^nU3)z=S0{Ng4t7ni=NB`$l2_8Htaa} z&_0zh`l)g5VTik?>uH|AKI)ix_2{K)I3j@$dTVpMB{M z9(yM6PTP5>J;^(hO-xNTAz)8UHXzQKTBQ2GIqf1B=S&683ApMM?cK-;iNPtxljTXn zG_J$QnFUznVwSvES)3!?j)q<-^?MF~TuE!Z#UVM|qI)lVG3q}Du9s{{2StFX)zi`s z0FAgRF4>eHhT#;UKd37+T?ex6@=h_d+L)OMwf#zp1LBBLCB~HAPC@-cZ)-@KhC4n1 z=;s@;uLHTAfxQWhUc6|d=X8pmRVy{~{reDmt^S&#-&^kD<79|Pwk{2kWg^fcMrs4~ z>WD${x*pnbmigVmdAc6U1~&P0G#m7~L?vSh#uG~b(oS(s~tyfhR;B8%kCk;4s(SSp*kYW>EEzaAB;$!grjVL~@y$Sl6X2kmB@$kuGy2gG$ zatA2T)kgwmlt^utNW_!xB%0GDxQys$$W7~{h~hpc3hN|l*QU-;yUWx$)NWH(G>Z|r zp!8+*`;0;^S@{CD%l!6vZY>aF)c%|Vb%FJMRS0#UoxGevUGX1iD z*OdvCsm_NqA}V}PS8Cg@>u^)PPuKG|X7}qlwK1F5wb+z@nOchFS0*p$3S^$w6_4~e zT``{ce|8;{*QV5DdPrSHb;p2h09koBlY1=z5Iao$>wxDbYU=h?PJGhp4+FwX%Xai! z!-npj%*-_~*qH9E=ok^8-UP*pf@~T$2F)8_UuoWA*;Y6co*gOnY)pFvRH%8YU=P$OLTTl-SBvHGBF&GHS(cBWWH?+``y%>dhXFhdgzY~NUw`{Gb|%kXmh zVlMffH0oO`6Z!%r(U;0vHC~2oOz*-r0L|D2TuGvOd+=Q@XGLA_l}&^>lW70-y-1uU zN|xBF&AY|d!g0RfHJVNOE)V*yT^Pi$AXRnI+&x?tV4TsalMbJF6q=YckdyR|m98l| zTYKHEQL>MxG9;VQjcIXCu_}mYsl{SdC8DL5ok$yfwAkJ-Ton@$iqQbiK#vhB=jsYn zpcvWoL&_R-_}ny_P_fvDodGY3b2p+|xRT3qOxOBG5{$SaA&z9-DRo5r*{Jx_I!_0e z)MHiQhPb0%$-;mOM8l{zAk}&oyC1D=q{WgwgX`%T!gk3|N(RLz1hBJmevAg+6UcgA zv?z%k3472q6T5=cNpjj8*aFT5HWxuStAbobi5T?S0eZ;UBZ3}DEq7g&e3JU>TcLy9 zJ=}}Bx$Uyo74J0@y{L&yvD_sx01Haqnm!g(#L=K4umnWw5tPWKe+#um9=KNO+F%;{ zZ43fTJH;{xrfCg#BsT_TW4x%AnG~$cJ5ntY_eOm|yaqR~60a`HMVc)UZIrB$cq_U3 zW#XYxuHNn3Bj6(w8VC_62D$U@@-GsR`h@fP*w~N(8wI+>;Lu=&H%xHQs

damRwH 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 N&3Ga z5gYhXez~O$(awznpvYb-CQ0B(;rI#0y@jnNSz=<_6PbHkLZ)R4AB;lRi}MNRa{D@f zBw1|XK~BWciVK9A2ttCZ<_Sc#@{bq|SVS^u+Y!QcO-6#GwAf)@t@otH&6QZG@ogiB z({ccgtWH%$HOnb)NobNT_5S}N1b#9t)}mf4-=DD%bxIv~@EQv_Bd@K?(MPXP5KZ}( z&k}DthxLM$!v|7$w7lr^2Pn=zNj7`tzQH2gjhkfyP?KBMU?uEd~7v9_4hdAdHI zGS$xYg_Hmr*Dt38)VO|C(^*{S6-42BzowYE5}1RC2s~s15=Cu(^kQ8JxD|SSAREl- zH-Wis}ZqKcE-W)>8wwmX39j|Hv= zhENWqWko-g1=?z9b4|0o1?SY6=*XCiHL^7nw6!%VHm^%elZ;D9O-W2=r?6qJV-_ZN z*Z8EKrf|RdfzUIB(G|~uIAz*=B}9Sr%Q`Q1sSisN2k?hgSuU(=3k&7Q5_AvKcq38OU;tBqwW&lVSA?fjQIN0nfvYI! z0LO@&MEd9gI#>>C%vLl@b|jbuWd^Lxlk9t(KiNu9F~qW=lE|;BBy!#A76=C<3St>p ze%p&kWEEOcBF~Nl@_L8yELlCQb@LHT2xQo$LH8IVZl4e{7jr6gJAi;JSz3w064=cN zd0ZKiE{_So@R_ZRZZZz!al_4Cya+X-8b_&@vIDz89T=+}%$Y&J2n21~ICH}BI)8IR9qifu51^C_QG*xS%T|#vah=oe7`AE1*r4Ag98|?C=Als|^czeYqu+Cqnnvh%lEjV9 zLEpOCw9V8oCA01veEJeE!y@6LNxX&$5S!8Ps(J(*#%BFPlQ+6KU- zv$bjg$%3x0{GkTpL{2)^6c+N?{#ulOX<;%Wh~fcJ<8m`XN4JiOPb!FCmK9@khNv(C zikb2@ZR&tCf~g9Txs>R)0)x9WwZI~zWgeEexQs#M;i`S%3m93pyH!g^oP={tBTR2! zc%*rc8SpeU|vM_P0)aGteby(;WCfN1kbK^de67SDGw-|NBWsLF zW+r^NxGM1llMJ{-fS2Ley$aOg9ygIaKb8|;HjAjBtscYzqJK|S$axKc-%6eKK(_`2$S$82dgh|fp+!t)c|4FBuCS! zJtGqI&WtowaR3k)b__@Q{*jT|%{SvnZONRX`!cC4=@;Sdq<&HU2}aL?R&Kz&p;_*2 z6Bu+%i#%Q#SJ=vJ>6w4aEEo;jvuGVoFus%NK4=!h(p1(?Tzw@ETJ;+p71aQQO&#z2{dgM6*E|=7~iUQdFuGM=Q2}nZW!=61B)< z8EUt#n}X!f3m+06^tkb8bq9jMv1(nDUGb7E2R=k{5OFB0F#(aZwnaqC0Id@}ja2F$ zc~qyI#(M^|l?6&^4*Bv(F3w#)$5;1AZhXxc~VN|ybr z#SetZfO-2s@@7HJJ58}t8`7)dcDbptHra#sG}koF3%@Li++y}x>V2kAGFhtZxmo60 z(n6OjS{6ds$XlIiuXl@D-peh}eGG#3vXA4JTQe^=LmD&3Z#OmbZ;#D3|@u}A%i3fdtR}LkX2MU zMu3in&McQG2|x*KSm0dao%7D-JNN?Gfef~+4nAh>B>dOv;0Y@^KFPRa-NZYs3RZ6V zT4doggyh2NSBpArt3?(7OX2(^tAzrr7WLMQiBnb4hpVv({8oiMq5%Da8voibABs)! zK{QU4@TuRKG4-|$o<}eBH+zK>JG1NijPRQ5JE-HkQtnc-j~nQ}Mxrv!g9O^tPD7xD zZ6BmLX|9Xt|@!;jw?e1S!$XkaH|7)ptbahP&%K1#U*m(!*Rv=f^`_y7MC_+>am{)pLeR z6COmb;0tj|mv~%;UuMTrZ0`gQ{8E8B==^21X*ZmKUt|>R<5!T*QT=YT#9XB$7E-jB zKZCsmzzDwwzapDjjRK3bvTzztVvc|IK?INt0Yvz0ZE!+oy z+OQEhiQ%WLtlsyTV3I-MAYXn$0yg+q5!^jh+1d>)&iq&aTG{S3S19bNI~+Q^L^A5$ zw^HIpiU-jEaBR_GawK45fsItazrU?|(MsVR-PVhYz(pq@Fe;3#Ddo zFX%euj++7OJF@=nETa*~JExEA-;rg0-`D+%_SN@S=>CPn`*phCF}$}4#N6`Y3?u75 z>+md)2+1j(iHQG(nP-ij&W*gDMIJ&#ZJ@s-$x(tOpHGuufl2n{;YO*w`}t%7-P&X7 zzwc`sX~wDGkS=Ov4r!v+WTSd58AZT76)Gqr#p;O0Dk?A`sLxXOcT z&Nj6i77T)X)N&T#`%%lW0A|;6jxzj7TF%~v#@kU+pMoowhq0*Xm?_deBQv)<7HwlzTnvx0&OH*^?!5 z+Xi+7@WSZ;j#VUYOB9k>3Xj~jv_w@0_g(byqnaj9>P?VG zVOIpw6tPSg#67SmBjYLWOL6y9*>=-E;5H;R@vjs#fr=H|73;HoNet@yUA1{_-^AY6 zs2e&+Mhbz$@Vep@!ksKlOZsJ2PBIfIqRbRdO>BjP(fe0yxy3MAqgkTef{}5+{@FwS)Cz+dXFcnt-p8?Yy=T zBx@o&cql}YdOHh7bOxN}+Y>TC^x}eL@56AxI*Aad-l;&qwSY<=%cPKIdd87PI{?r( zJS+g>&qv4_iM)&W^90rqpMdxc0a!%8Az*5WoJA&)UbjkSAjU3c;HaX_7Ei_vC;>Ov z+*OKOgBv-c@f0Ht#UrH{qw$r*QQ*=n+q4qZHT2)=Ioi8ntV|H(Qk3pq3!0D>(<_@7 zz#5fVi-L%-$Tebkp*}y!#`d}rics0{BIHi2pLT`JyM=qn#1Q@fxe5bow>W(PQ-v1>)Kh8>Sc`7&Kx(ci(?qTYBuZ10cJXznidbptC{xn;_gv)3(IH9<9LoWqXjwc zE@V86-gk=ulJ^}kig_g9!+r_)uz4lm1H`hxyqOBa1Js#-4Oktn$(3A^1dqT0Ehq#K z8lyF-Fd8IpBCksFOe#5|ArWH|e5dUcELZyoI>oILl{95u!@y@*;H&IF!YmOKuiFip zi2PPLq{{kiwd10&>W^tGGh&NYX`_AsyvKVK5Uh=gBHiX_%|zTFCnpg~Sn5=Glpm1C;eg`oa|A$>7TJ$)af|=>kf1*w-cJ|;+GE@!scwFau zJhbxj@Pd8e6dU8B^)1&@h)Bv(*$p>OThN&45&?)h3wN1q3zMo~m^~1S$FL^+BSo|3tYz^nrgZ^`>0zVv~ zx&;P4OPT2#TxPYX83Od#FuuF27+I!(n1OaHsZj;x(1*K?>;)J;|c!XVc8rLR*fvyI#W~dcj=Gee`{#uDW zs#&A(ik#y^c!6&Uli~whw9vvytPGj$kJFKWdg85^)0?)l59QZo9|dmS53N8=Ngl5A z?MpHdSB1A-q_(Nw+Jle`R1w2!c7y`^L-$7OZxQC$38rE6houIy;XSw4t7aBJh2P>n zc2u>^0qi&|tIhV6>4o-{jn$U+mD%fklmhjz{=8u@AQoN#HWHS{{be?jOajwT4Q?6~ zTi6a+>{XF^LJ}yTq*()Chq<-5s7%x){Ns-;@fIgj&f`O7%;~+rYw-g!Y;uPM_zKkQ zy*7QKITCH93N^GdJ6y8GQHwCMd`>=hco}SIXF-J8FBu&uGk|Q8y9rmv?&1l{RqEf2 z&bes%#5sS94Nkasor=Sfo=USSMFkg%Zi3+j<d2+-EAy>%%IJE;)fgYN(mu~@JrcV6Ls#`J}H6cD?IA2N@%j^A-V z;nDhmdXl|`k6))wS+D8Rj7eT7_UbuV8@~r>ouM4G z-5*>mTHuwxJ_5gt?~nQWh_W`^b->)SkW%cmngCP*dt)J$?j$0Gpn%6)#18kABecm0 z%a056ZEnQg`*{hWsr^WTqt%wnk3_tf?8a^Ly2|V1m3mr+i+WvO#`Y;m0{zRJj~+H8 z!ShZH^_-q0sOO+f`WFyCGVO%rHOL4MEkMt4(WeCiNGhu>_*uh!m}w(VCh0Yb7V_=# zU}%5I%%cge4nJWgXdDdB{^v>vUQYAFv)9;$bj_0-lG}Ywp4OB>a=_`$$$<`j4X#+g zd9Fbo;pWQp<`6ftwLhKL^3*Sa^x-b#rY-#9x~PW;VZyJWq1KOJpo3@esE)W}3GnFI zJZc2xkxq1Ql?F%zUxwsKhC3wBKnObDv1Akv&_d!2B>ldkx8o1c7ulLO=O`z|Ubc-*t7H-0LcsMK?eKEmOZGEFG|{T}E*xt-(GGPj1)w!69I{S`kZ?-J z9wbngI5p@uXr}WDwdf{(Fb%$nACw}xBCIia*hJB*nsVy1>lL(=4OqD) z-ptbL94RWJZZyCj)=9lCP;Z$+v`X8B2tb7J)#mz+1>yO)p?0=jsw?Yv5A$v|-O&i3 zw7fPQzI+gc{>yJ$Qog}&K}|@+<#HM}Vlhr!x~>RD5>tP5X#|9+*Csz}Kq_dAYdD)z zEebUNGADh6II1a6hWfrjLWi2Zz*+0~7E3$PI(w6CV3MP6tZtZ6UH7KC-i^aLlilE` z)MzI4E`AmCctrPDum@6}S?mpGA4I|IySAx(_2yl(FM1DItM%yB!=^RbZJ14qw3!?D zW=IvWaXe+Kw01(S%0m#==z(Oz3AYo>c`faIP3hjjXUDznuFiDU}B> znBUlsSds5nA49eednmJf+Wx?KEpMFH(tAySS=@#}3r9`vHV-qea1z9&B}if8+Ra{G zGg5{nq^?OHlqY03f)h1@7MOkyS~xolT40Ux-7qtfH9*!ROqo0v%#P)K;S5Gyi&{9_ zh+0^(!i&$`><^d!2UEAwQw-cq_LRRQiR$4YdTrMf4P*@WdHu6GlyuH z{$hdHl{M3q;=QWxF}b(6&y#DW&XXjra$N43viGWH0cS#vT1Wl4F(T#aZn=;htUKaEFwca7X!gOhWvS48et@RA>e7Ngv2YFC`jR z@V1>8qM!w(rrIO_sKxMRa!&C?PImMD14}tG!z?Zh0*rmMR%`EHsfFNYfA&-#P1bS@(Kwq|=?c(~Z~$?=Eb+ zj7Otf%_=J-VbYcDSeG2aRcyZiNM=h=NU_7JPe6dhGgy{XK)s1?a5G@<4>%6RK{ABj zm@gI+SE^GX+zdpnXv?jlnhTH)Ia!h779Ii2G=Z>$0upIO@nO-!l&-a-dDE>Twn?=f zn-Q4vm|itaF)$BjOvP2h!c&Nu3Jd0gwq&isXdsS*aO~|%8M@f3q>}nm?Nmum@mI5K zwJ$?vt;>9rpu6@Rn2$)PPpuq^!pR4gTnazR3XF0vS~%&ZjAIH^jE{@2hEekes19f zChwkHF+x@u_v$K~-L1Ax?3w715LBV_5G1)pp$<*L zf;R~OEE#37SZ@GzT1ho{s?|;H)!c3#@r!Htlzy3zC4NPu!@YNad!!2$WyVzmhQ$q? z!*yH8<8z3CDH6ewQx;k|^!iZr`WR^*h=L;P)mQ=2i;9X=*U!*0Yp+hBz{J|C!$AUc zCxw4&!poaHpQBWLszHAp&~r`KA`kqsTH|L%$Q|~W#>U>UNA)`&k4wgp`H1duk3Fnk ziV-ntW7l%ju=_3autjKZi5jCwMIIx}52TKp{jc{w78)>kw8xAWfT0ZE${cIQ7*hLS zPR52ZJV%d+Dt$UlC z@`Jt?hbh_P(vS<|%f3QM(OA;vG!xNX6511^Hzog}q}f-*Dv-aL22(}mDV~`+^YBF zq3_JQ#cU7*8LmOO=Ley3duIL&1h%L*o!~pw%Jpe@v)@)8}1bcup~%@bO6XW9kkC} zZ%RqQl7+UPHjkE3MT8G{rd}zVkmx>Unth0*On1md zCl8m*i^v6oTV><_U;#qI*5R%uESk_jt1f#bet|BT_yy2K0ApdDWw_#u#|pv7MXyVk zQ2^l_$>v2eO=VrTX`>#|t#8+ej}|71@cF~W#$wORy2`;)Jo8J{b{*3u~U%aPY*Kp52-%k=kwDNC#qj2 z<062N{5><;)+q$A!={6;h74Td8cb@i^~lxWyRmv%fIeN(Xsla}5ow(`A<-a?F^zn3 z!eH;PxZmk?AvcLkl$^aArJGunO8WwAHpevVkMAr7w@oSO=3={{+rn@mUkdnVl8)d8ZfdrmPa=>}v&B%Io`_`1Nn)BUBD*E&Ca(<{ z`7IyW4oy4ZP*>@fkfut{my{-p`*W@SfWBQYD;W1@TLVH7(1csA*&>uA&33puRl6%e zJm~&9gy$PnT5lmw%nT74CZ*2I^Yp}bPOE2_Zr0kmPXZRa_u2y+W^j`LqbFx)2o5o>O zR;L*bh}}mHx>dR*MlC*xv->}&;$Kw7zg$<$-hP{*0jFr&F=}?4*z;8F!BX}I%wDBS zo}aa29PGfe4Z43=d))bTyM-N) zW`{Gu0_$=m54ye!G4lTF(_Y?lur7 z@JO#wn69u{Zxy4fg;wh`jjdAJ?c~R2E0_3Yqe;>q{6wL86KOyJB7sUSKr1bWTN+ne zSlT%Oj2yZpeo7Vgi%w?Pv+bUKwovr9xzONCOv4Iy+td+k1w@#5WVERMF2fE-4xqpk zCnz|Qs5KLF_>1{BtyPISJh`v&1lg1)@(XzAjpg6uNn_0mcNxvkS=mPjAZTWHG zU0k{0@z&6O%~M#dZB|k4eB?u(*lx6%FFcNqOKKg}5p$&PT~$6ujHaQ$SxZ%}OgRja zv_WLrh-vAbdk<^jxeMD5-Q(J<)3yJ866Uvr2%=6k?qmFoIM0!KriHQw%=X3_Fq~%% z*x`Px0mFILfE``J8n6S&SObRhtO3rGhJtDD62Ghg!}&+dR%dI#aGo__IR9Y8dDZ|U z7DIHLXARhZSp$aiCnL_Y1`OxHeZ%?VhVzE|@I%WRk?WVWV59*o7-EbDUG`bywjiqK z-D5|TvJw!7;+n|g_6X&e86M~12J~U<ablT^Am{L2L#L3Ntff~szdicb)PR3dA?Aj+bk<&V7+_J(wLyy*AT)zZ% zo9%-jZL@vg?L4RFI6u$o7eA}nKyb904Wxfv@sOSqmHME56}75gB43 z>yoCqvOr(Uns-9?J1lU<^0E@OZHZZr>lgZgbqfcjLE|*PLV|t=SyLH|8kVTj^aPDO z!@R~%YcT89CcT^>-@`mV!g%J!Bahc&~K36Y;8T^^2t2{3ztD)JXy@PjR~;7FG&WlG{?25XnW& z4jU$A-gXbYncJqSS?s0XH)dda7#-7;7qcQ+m_{AKjDHvY#wN@Pp1^ic$6>T%Q zCff_|Bmjf+DM=pDma51R^b2?J=q$!MMQV8TK7j!O=&LHrvgLNS)Fh@tdPM!K3r*|5 zEMxtw+{@Q17{69wZDR@>Srb>Zwlx}Cg|)3&>8Q2MTtQ~}GGo@z0I49bjFFHwq6{B( zOPW2v7*?Cs>;VR`GPr5Y?P6vS`=*7A_6rCfrlaw9g9EW;tG%P)@}mcLxU7m=wC{>up}gUnsRgy9$+~-kXGL4VTdNILw<)A zOB2>bkZY@@I00h3Mhu{k2G#R;XSDo{k*lvxc$YwJ!aJhPYJ_)*2l%r znBLK0H>6?kO>-D9F`f*E!CQMW9Ex>b>2k!0R;hZ_y_a^f3f04V|7>RASvK{R#H6e2 zvK|tQ-JI+^7+ON*lQxr2WN3vVLhVGb`T@pryhs26TF1<2I0YLtgt4h^cFhftczKCP z-*V&WQDb!WMKYcqYenPf-K}b(@${I6tFc?Lq4BiXJN)O8syTP9F>AEhShS?lm|Ie5 zY}}GM)=sIjj!XcSQA1aE5<-8P&d?F2(>T?cVc$--AaeSw>g|f6OST@6j2Uha4-_ZoTfO$kuz8tu;POiR(q++HZ9T3iZ%N3F%jT0?8GI`18GmkcZ0 zo+QW`PHoTLSzMRBMSY`L!Jl!Nne^eh_{HJz;1C{$>W{9n+}XOEz_Dbd=yC)4g5nVR zPn3fGiCF42vTU;v)AcI1&O<{q2$=>f1Em|OZ|bABcKf+dxe^&2+M8*B=4!hF5xTrZ zD;8hp_io?!=%i)b+-y_@!90A4?FwXRr&>`1bW0<@wY8ZQ%&TLg7L2=*@ZRKIzi%07 zb7I#dZBFbOq%9J=NtAkMYo9E35%z7bZ7p7Rq_OxY&vy7!Z#_eno{8EIU{#({-7nFLreC9xr(Q3Gy|E!y{bfi_&B^7aFn9d2;5A$+ zYzpXf(ffNFR{Hq_bHvH$_-1qBLwJ{Sv@ck4zt<@+AnDwoeejfKyYd+ANsf zkTdlU-chpPgeJUI-Jo1}V|bI{^cIWCsN3r2EQG%RsA4%&1|SgsN&|(f=<sD4Y zc0g%b)FtciVlIxO-*E5Oma^V|^!-b3=QK6FfSsCigVs6{*3ynF-_n`kLYQ5JSl90hpQ0UIUOT)*oD*-lm#U0cfGuK0=mK0# zb0sDE?GR=03qIb?PvTqcYKm+4)o&H^8Qr4Mxq%J=Xom;YH6X9vr~vV(GUX=|hehgB zeY%&e8RLhJJyw<5txDSskKGLJg22d+vErNo$SU{1SHAk_nRoo=N5fkwU>QOd&VBa7 zZ$0whTR;2n-l}9F3Z-mzLqd|wr22!Pt)3w_T7sW~h)y^fCN|6-LyJ3Wc7qlprwV8> zGCB^$nhPyV^GGQ!C4$x1FABk|xul|pyBi%9`fS~HpXpS%QMj#z85M<4y$N|%LP_AF7daDk6{?>1UOi+u!4S=otuV6`D#hB@r`2(2V5lgaon@!NnCn8z${(1RD|W#U3<_RtSM`ET>h?>Z9l*t= zw`0>QsOB^h0ZGwyB><#otYTX7GDSzqmJ0soqt%xE*F^L?zCcgt07^bHT+mnM>PIEZ zP0Q5Cq6Oa>ebm~w7n`}^nQsOMx1xg23Sz>F#1Owy6dgZl+bNb>&^)#WvL@(KwdZ*5 ziWcs7TPaMfJVQobOi0yq3ZZ&G&Dx@7{_GMcje5yIhci~j(LL_H>+7rQYxJa(*FyVL z1y&8JFtkO3r3UcYURw~v)jlFid`&-F!omQA-GvO0dP}A#{FK#rw{P^_JQ+S%Gjm)j$sTp$bM-2o9 zpn7FF^6BlHL)QJ%!h7Kykv<5;2M_RQlpqXe^qabhRHu$1&BOXz!_>{}W>&RqVUZ+isBQ~Pj$c4R zh_D`N!wGlhj6?ziZICuB@Z1chjmEudI=JNZ7E%s!tI}#3l>1Fslh#efoVxN@rEr`V zxRYrQ>MYuwHS zs1f=U5d<}`pbBV=`=8Uujd$C0Ly+9tZMoM(hUtKfKx9Wl6%V&`0f9+2ZheVBJ@N~e z4%CCWPaNd54N#$9nmF^KPb1+laRfB;TtXe>NLMz6?XVPEYx@+!#C2#cLXgC}HsAS# z>S_-Yy33xWscpxpZJTJ+JyaH@lXV0Q6LxtI5Pmx!nOJCRZ&1eIR;M{1%w;HtcXNu1 zUCwCVAuG~1Qd%t^;Dt(B@U2U&nrNQ7Xe&upBCjZPvDZx2%)ISGL)Q83`OZ*g^I3;u zV#p&L#AhA8ZYxdT5m$DX4U=jF+x8O6@MnZvT9+l)8!IB%Dqb=Z|JhK-MM%Q7g-Ok- z&$n+Xd1#x8EUtm12MAkecfJu+sX5L4Nj0z|>cf+vIc4gsTI(H@W)#(cg^4nsT3gKc zOq^}T*l3SvF|x{5y0Zus3-Hqyx_c2S=wD|0*E|Qc1Z-RRzjiL$MJo*Uujv+9`mfEi z$Y6-9qCQQwxCtS({T9Ln+g)GI9}a~*zz>@S56n;b{A+%^4AZFs8AVNuW23gZz4%nE>KMk&+Xp;Z*M}Ebh4q=}9m87*WK+E#rx*@e zB>=Te0M}&C1x25qj_>i1aUD0zSKE>FsBv2)?plFqIC?(guZ1>I8nzpTPq6)?khMq*)P#=3jL!A5xF>K?xs*XF(2~C>a&!P<%?l{`C`z)dGfAfw3@gWK+h*%45l{|Nt?}a zFoV-joxQLU3AeKtj2|k5pM}=9MmR{p`C+%g55diqssTl_VAV{sH|l4Xvd|Cr|1!GN zZ=i^!ET;7XAI3{-4sNlfH47KVwhRm_a2>OfM;4yiIyT-`{ou*l67@KnNqTx6aO{4JBgr7=0UM3OEFE>Q&=+vgGVq^{L+q}wrpjJT>xba=7f zj$A2jHXToL(?Vs->8P9>x20?G&;eUgNui`Rf`P;FUzP4dP0~ib-xNxuEoDtZqr9$o zEibP1o&0!nrs7q8bN^*cBD9_KeW|_&O(Q!6z&{0XAWA;N)A+?abKai*GQU&%*UT4f{>$6#GHbV6ERj4s@gbH+k97bd^^YaPHRJ}PATld-h|QRts3^t zA$tWl<&O$ID(z7y$tOsRzh$51?7{>p|E-jrS|)`#Hz}-BC+DPC=4^%efdOZ!u)ewo z2QY3WTVk)kGy*O^b63(2RO0pcWZR1`H5DnSQ5Gb9^W}Fa z@k<_l?&wlx^0>0H;GU2YiqtIofTU*DOuTBd(4?PI9hL9zuT@VG8nLirsYW&sZ^{aCH)#mzDYy8y}^{e*yt1IhQo$*&&>Q__aueRzHjBpA; zt3M^dZYp$i#S)teZCy#hlCNe;0G$e@u0WtE#>5r4rF{;4lZ=egnYSY5CcT^h}UVO*F!KUi+g%|L9d9_)aimEFX2Hb6~u3Xs4?-kXSg-tx&y3pfp z8$Z&6`arBKx#$fJ2#3Mv$5DuQa<%JUFh`v*WKd!+PDd*WK~gnq|G#(Vw!+ zjdejYt=IGRdVc)1W?Qe<*y}apuQlU(z1Ci@9e?e!&eTmoj4P+w056Utes(*c>>VuufcN^V09XF&0_aY-8FyJ|?G|>=&`uSB$^* z$;!i(_WH{4*FIT!*kZ4@jKB8D%EMNBy>9l;i1GvhfLY@qTJOg0+i(#&SA>a`v;v@E65`K!>p=3Mhc9OGmWF2#iCnK zodIgj4fCaci07k#?F^>uZ8h~utdmn>&oYO>ny0lUr^e}l`Pyxg8m|&-<_OpESBW)G z!|TQ>OsshthB)>rvF2&G-Po(dnx`4h*ege+4lr@n+~}dNc||wCn(c7)TnyQgDkwoY zS0)F;kWDs6ZPgX?fn`-!$X!vMIre`ic?SO@uOHb2O)3t4}o1YiE&;{Q`-wPzf6 zew2PG5Kb=`8JOMM31%Y-zhZt~#wf}&a3oSK2o_0{XjuvRe)i?cp{!!qYS|4uwjd;s zat0RFbU56F^+G%jA>C1YZG4^92w&VNKR{e6jW5ztK`guxD>3=H4Z#~Z^Tzo#eBtY-QAb)oh^9Br6S^3eQR53OBMI7wu{X}I=L=s=jW2vPVSeV- z03Y$I=P#>~;?L6RCh*-I}^HC~eH$6l^YFCS{W zgrM2WHRSdhk${ewVJBvb9UrE>|N_55?t; z4RLv6EiP{~arrwlNH>#LZ5)c?lLT-Q27Cvf3M<7Ofw#!|jd;OQm(SN-22;bqGZELJ z;B(=e-q{+=LKg1SyZ2}v`Ephy-Y7$QQ)Lys zQR|K-q)msF$IRNk`6VJT~A2l}dd)mc^)UsUpFt?kc9>zmMb(GqJyT3KqM zWleD0q*vdn)}}h;EME=)qNlu)fmagR2Eld>K_?0;L$IAH*xKkt$9jRoLA{u=LBdOC z0#AUT*80UE*l9v=Q={T3t9WV%!D*{}S`gIJOM~E4>U*!z#I!X*!Uy%8pC^OhbgE=F zLQv-c&xV;Ag08==3_)hur=Zp7#jN#W)_MWRU>5?Jp$3YrP_iq4>H~=z&Nv@>kX2>o z6V`vl`Y$A}O_C<-6=nt-_9sPw9Etk@Xx(SA)uH6xU4!6}t08rC|`${KL6G}(Bp zTQUsIhl1b?1Xa2R>s8W_j)Ey;IngA-)176q8ScMkFUd#ENahFy=&>*7>%Oe6B*w2; z@}T&*d2LcvA5IS-8H^zPt2RI@))cuc`_l+ClBoqZd}0!ZXR!NeM76C;mP&mz`d}#U zJ@MzUorUTCCdkt~|DWam^0^|oxJ4{AKKfg=*35LWDI#&%+X2wlL-PsKKM4@H-ny@M zDzDfPCzvR_cA-ZDd4CopUD)iG+{)>`Pz`T+G(&$EwvRsI@mkPkVb}7451c)nyB}Rhte~8*jhqfFl0LwIkRRP%x}kHl^?zdlX@{%sdE?M-dKi8^2tGIcd+K z>y2+AICq@uvCSfEe=g<7WqxW)Z5w#bT&dcBZt z=)$DWh{oFp+w{*M!ZX!ceKr#h>jUYnQSn|Fw10*oFjLJ>`V3p!#)V$|OiZ|;2i*IS zgnx0R)(>E8)6@oTSiWpwy5uC*Ei+-Z+la!4Qx(K3U~g6Q0(?@@3yN?NzQ`M+sS`iH zTVET0?cxvdC@AdASBFADQ{8_-m{x8nm|%H|-&|*|kZ!e65wVEB3gYj|^)k)f)lvp! z+-__nAf_bW*4(|-MYSCmF&J*)Vg+Fj*VJ=`!}`S;dM{g|Jl0GH@5H?X$gg%#PdNJt zxpz3dht!X9-sW5>maNj1I;96PyWqL!ioo2D`^k!`HKuIlJI?$G$3B^=TEe)jDuyM* zP%pV}OLc{p&^OJ;^1eM1!9aX!0pNRNFzDAxA z=LmZuqZ|MIC>kRpo<4xW>6@yV6Jvy|){x0ejRq%35u@RBQcJnfommEGA&XqJ2DZCI zgxxxYdx?zhxR)41*)48^lECo$_@=6?Lyx zcT8<5qE7%P!JxG;SoR4dov_U0UN}fK*YXWP*P}H-((SXP`m_$}(-%zo6tZ3_9pCaw zu%#CbwX0~TT}7>SF&MlQgW{gSeAr|$nB}$0*;17U7q(7n+SX1-YiDI> zDJRn^Krx#@5q&QM7-j90Ss5(d6~ThVdeY3ydpkol_2TeaVc=_k%1WSIyAmjkV$EF~ zTA0XI11(I!jyRVFEokBjNVH)xv^G5xxOMqT0NHpk+#;;Ai^=<tH3Rsu1^J8 zTULY?Io>AW*0a2wr-@t7Hr(QblL@QwDgkBrG8L`s&sA$7fXFLts2%J_Q|Yyap- zFfB1iDUihEz8X1OW>E4vQdFBaDM~-+VJwdob9ql?7p0dJA(M%UU@yHTTtCJ-sF}&a zUX7<*CTluoB}V#3$z1%8kINYpul4iH}!`*KNj!OEFaSY zf)MM0;<*72%?30m1~fCJtox=%2;W+}jj z_oK%Srlq{uHngem9b(S}&1w%N2%|U;dkE_fwy_fIsUIRNn}I@Te?kI|Mv068B=^bg zJu8+!De@`4MR+6aq;o1Znxj+d*@LXk;Ejs+YgeV(ywGxAbE$4trzZI z%EHcY@Rw-h4{0RHlb+&EgADibiJRz8>f>(-kLrOwMtWik%Vrm%Huz7EA7yw6cTy#L zoYmEERM+>ZjRz=pOTFPOmneyFJVB(^c6{ucQ4j^UC4tj(50r$GXy38j!{;S%$NMBB zYp50^liN_cCF|r|nNP)SPOTAXPmP%#r-g`NxjzNXDQ)|q&>dA<2L@yE0_)k*g3)t7 z*@yr@Vd7><(2P(LHId~Y8?cFarG`Mruxc(9l+>#A2JW@T3EaT=;?d5geBsj2WT9h9 zIJIyu>MU=8JkTRacgUqg55IBY~4%#p}R-lJ87ftZkDA_3Rg zbC6UUu^9wEtv((#kl(n1ZDf=3kDZVXKznfb;O9tnlxR6t2T@IRVd#jEkS^T9A9Y80 zln+R!VHh+$0P*Ao!MX#M`zBxB*>)`{GfZ4e5+sytF^7hdi$4RhYz+^+3v@AyQhadc z=hK7xewHu#;Z*t}A#G_|%je@P6WrBKvn&9yJ2sSnMN3ruBkD@}sQ}v1nK(F)7zttL zaU@(OF!Sct0|y3E@+(t7`(H7-VS!`rSRz#P|HGYf|_02#l~>##p$tXF)2redmfwRd&0 zC}d_?*v1DLlkfWsWdv}QP}^ZN<1b&M6x&EX^}1kc;grKfR>b zMcdXX^rVX#FtmrbS$(P%BdVSs^ykjgav%$kEhy5j$?2ncWr zN`$jzWr>`W=D`nXamr|co(Ufi34G1^MrS!fJ@1bu415@Fbe1WpVgAuNKleVzp|LXc zM(5wli@XlWrknM^i@kB^+W%jZK*JA+5_7Xc%_aj4Fw~P>vlr6n-lMLm=CkvXpx1b_rkGQ`0j%7VjB8U1l@Uy<# zkC>=0^PXc*_aOlRDwjK!i$#qO3?BuujWaU)A^yN-k;z#8bp!+aPS|d2&!EB7DPqSm z^!G4NE8T&?gy&rO0R{ESfzz?dV_m`+fc79T7*Z-$ZCWhNi4{hi?sW!jvq3#=4MdBih0#L}Epm>3W_V1OnOworiDrW9DU$zODc>c%<|O00 zm?Ka&iMjBoZTZ1f0D9z>ZNnp$)3)Yv!jSzq_<<-V8Pt~7qr(+r%j<0Op5^s$^Zvo% z&DU>v9bSjbGbk|ElrNi%ihEPc>{2PJ3)&k%J`ugc{RC-#7^M94KcsMRVL>y7# zEu!Bf>DUii;~4d9qJv~1shMsGkes+oaD!Y*n`Gw+_2~x;G=Ek?&f%|`f_=;k+H1OO zTT(7d{+mL|l3YK5N1}WZJgqr2vx~HIKCR6z%IVAfGPBDZypXO+c(9J6PSJ78(V?Wn z;++;KEyGlLpsh5xGO2EvOn%1jahV$O5RXkAq!LMc3J{5TCosgIe(D(%mBzS&vWk$J zcAx{KX~+d?KB?JaO;CQJmH4A8Q#Ef(z>KqLQmD`7h?HA@KV*BfJz+Leef}#MIZC^; zgJ~UfHE6Aw$}{FFQ*g=((*z1=?$b0yfv=vXDDO?2CPPGt7EQ z_VI6qMc(};TjVExLriDcB46UMFY*bKd-#15%iPK1L>LUCpEf!8Yce&;W=!r5$U3-) zNmZ2er-oeIgn0x5w+w1Ir=>5}?Igl}#1t*k)&fK@42;*Z8B3xR1R~d*6+{Ye6cy3i zDZE+m+3zFU?$me{+qBb_yhPX{y$aSaW?`p4(XLDk7fWoE{^(AfMQNQIOf6>;WcFMh z_kyv5>=mLu+of(Q^%M}=lk_OtsVco`OxqNbFz!aAgbVeT!X&P3sylznwLT?)ClFB&#EGu(=UFKr!#BECC&|!Z4SZ$Zo$#lgN9pM+r7ZYJj-=0YA zmi2HV*LjLonfb~RZNBY?ipy>*wX^yNo{4esqdCzLDb~}^^^TeL)8bBKw_4v@<0eBB zIX9SKD&wJ@eMy9+lVvebybK#SPxXDG&%5^Z*I*PXWkA8Mj&lX$`SH?|1vQ(uYqyZ{ zw`%Roj$=z8-;LkAyBrij8Dy%0bAROyTeI-vC`?B=BPbp!aFq2o)jO1{fX)G-z$V3x zuW>u;8fCHgwbo0rnQ9I3x^&|n+l3*0oz^(|hRq@}Q{aX;PTIJPJ0uweUg0=(iG)0a zV5Q~HQDP{h^BHkxIepOkWjQ8ij>K~B+!9BpW_7lmRv7jW=b-nIR7)1kYaIY>;y1sI zrOU>k_gbaudfnyFyXAlw;_{~oSfk**@xTAkC-`VE6#&HIVx!5 z0(Nl!N=Zn)pRe38uoK+ek*t-~l9_EdWa9%^WZ4kyugDXoAwuDR(!kj2@c@5zs z*354(U7QbGYH;BYk3fzi<)GWhFsBa=r9P0hD3ImRkZfo66QxY(%2zd8YJky^;f)f> zXNjj~V&bV;;n#d&$)|9~7fRMdZDc0JE39`6QAwykrmj+!;Z~zR>WO;r7B$81qN5{7 z?s=$YLY;?74ZU1>r~sqqp(>PXO7*wG1)?reT^H14R-@k9X!OO-?5j>l0H~FTozU9s zDi@V6pV_#4&~$X5lY2&?DN0KP=sUnh(f6KR8VfE%Ybox21{+iO!pA=JuFfl{9xWoi z(<1LQ-^GN;DXZ121BwwHfNlY$P|%JelYw4Tg{T387pJ?l4ulVWa0z{;cM#*>%jRcA zW_&$$$>6A7dv8T5Tj30&YlVC3gN#@~I~dmP;*_OLO$F~r!=I1Chw0n!jhdtic^HmR zA;-Ilnjhv;5*3$+xHK`w#EF9~#ba>%4NtpDE=OHU20}=hUg&fBaSEfCN~=!mDhh_x zCsBY(4A9d=M_4!0xPR=)`YQ5og`Tvp5OtbC@oZ^Khh@8DK!^0pXb$3~fT$@X#%87> zY@2u_C38?Jz?0T%j;~6+7MOXyXtP8SPl+!0Xs~wz^!vFAjP0mez;1(e=a?P|P*cj) z<$#K5_#jb#thXOFb|u=cRlI}K$2eaad_L8}&2OOT{fLw3C$zxBo%q?+dfl%t*yH#3 z-a`v0POYD3N<~xO&Fs7+`@G%lfQt++-(5Urcd+BuVCKcyqjqO!oFSQ=<4yxPtKUai zdX{>SK0T_X2gYJ$iXFaOiYr{{avhw^7oRV*jQJ#Tg5w6X^F#+pGfjP#kqRPvlvd_8 zb+ucw70#CX7^q!7-dOElhGwba$JKOAccFNOR(Kl?C@8}Cy`i3&>Is>-t~jEJ zKzO#PH>A_V;N*Wv_7f0|>6fv@4k&%Cj0BL@adbc(jp%R<1-!AH5Q2KH4#&AVWOKD0 zoYKMOO_;!r=DTwnZGa6xo*mM#j%XO4kztKteok@_Btm?_9wy!^FD_;WaR%m?+=xbx zjrV#R8*1M0ur=hofz!(YpB)_x_B~t-O6Lu=)7k}t2h|^1pa&l<wq?o5YdNILX=R7UY)MX_%jZg8${;)4aN2oRLK)2hkZ__g zt`9{RozVEed;u5^0vLFKYjHWgDynaUe4Q4ps23f?1xJLFDKyKY!f16Q(WclDp}{rT zUu*6Ejcs{O_`V&Y;R5KRk)59_hcpT-TrV__C;mlJAKScBZPDhUe(y8rESa|3@aZFqo1Tk&B*EI6@uhuC z9#{lU9xWYQN}Di@-#Y@0}tCdextqAo7*Iyvw+}4c%;cPYY;;iF^bv zYKhxBTjJBg=#DRO4lCr+XZEKe;XdLsT#J0|p~x4P`1GjAH?8`SA{uoaN~1vmveD=Z z1lW3sTbbAiE%DA!?8mY=`|7ggK z4or!^m1D0F@m>aE$S$A&KZVIbFQA1N5&W*WsVVry<_=l_t<#pykhXXdQ{ZyOIO+u2 z(v9nviyl}tCusWj= z1~scyWk4sb?*8|Zrr`Ge zwi2ztg3Us$!+>zJOaW1}t-2hZ$DL#bB*uu(>ij}RhqYtXgt*Srm3FVVrxthPY)jnr zjzzRg;;peI(crPpx=1dAg^AE~dh_lQnKlurT9#eL43^8XR2>a3KL#w z@2H6OGa$s8y!KBk#L{~cVjl*Nk`Vi_kP%EvsnO%rgdKu2I7}CNo zOI>6gJg%lkg;-OiRup0pUQLKacr_u`^_Hd(yKLT{8KJe?RYG?J#|XH@*B*>3dCZ*g z(R?VjHu&0;m@|eV>uGDo`PvyGD1~r5f>NK(mzgt`QXk+j4c_*EfGnE!^)Y9hpg+k3 z@u4`MC#)wDUoXv^abKgZ`_gDe%^B~{-9Y#CGiQA6^iREG>J^jC8R;F2UR>>Im@^KE ziT*ce&WPjwW;bWRXGH$L`OO&loGqckp}9@WyjC@1)pOXLIvR8w~FWX`b56n=`lEyKaGjss^O0EPn9(YgGcsO&N%V_9! z&cLDT;tWUf!5q4Vv|;rj_2W?L$589}iJCKLW=^r?=Q7iNVyRTR{!K;?C+cG-Fm$8A z1LjpkjmUPZcca0BuFpjSIQ>))#rfY7=Y7$7H{=-0wINerhX(MDj;%nVCc}2B>y4m} z+rJ&q`e0}FeQa zN8oQavc$7#0lh)VT6SdF!r%YtpWXhIKl{rM{dM-eq-RA}LO)=3w6U%BEsRvv9j!|0 zg!a0RS48Lq+l1y>tBDxc!m;ou1g*SB#bsp$R9VbIG_?D-KrjKd=86f7OpYNWQnDc=2CG`rXRy*Pu7G9efXFuJhZVP#9!nDnC! zV*J0lX7|IR>|ASOMWqfUZbYdw6c+rFXF@HJrimO#@=o}jc__-4fvq?v514J*<4%?# z(=($0&UDR?8qPLm;&o$;M}Y%7v;V1~`pH#prihEi3QTv!)FOlDXo;G^f4^ydMDA*Z zzP4uXYUQTbwz#?sGCQ;HN$Q?}{R}bnO)D^UEU=NIvT3Ad#5efdf491Jah8ry&}8Xm zDBruku4wNVVD)}y7KR+12TzNmub;%x%j_ZyJ$&_dU{`if#6@{|tYi`^AFbk_n~R$m z1$zLHPlt;~uoxF7_a$6h{)XTcH$C*>172^VK5#>F{GUQFD*345S%2(~M;@fXSMggmy&$brl}<}qxb-E}Md zYT3A^n;^!T0Kd>F`7Zj{P|96yHJfhqEt17E#&O~MyST#sb>{N3HL^X8*o1C>ZS6Ry zy_<@Cv=D<c<* zsg>eQ+;1sKOW`&?gI0~Gfa1*v-!Rvve}Y0BrpV)odeI^R)_S7{2?@ldEAejWDjYA0 zT<+18sPzisP;{l~Nn#HQVr{55=0fw=A1-|rvIiRQBCto$DyL}ao}Z=aAq4*=wtXm z(|^f1i}JZ9C0IcS5ht~71uok*N2`|T)3bUKhC&LKvfiGfWIXH{C#nwbaf$n9+VVb3 zdmIsg>_b`wV~^1=>!e!{fZ0WBMD1l|NcDq!aDxL$H;@4#AF=>hvHM*^s&VkxjFQL~ zRlHTFbnpxk^?bN4j}0NsR}Ac%Fj``oZ9kUx*y$^yi+#38N~~1YXEb#(&It7Mn4RhB zG5C^xW6y>D=FVL@k2!8MV z_T8>Q=>|LP&*MdX3aZt2?e4Ny5m6>k<>9=wuKn*c@CMC3K+OXxETJ%XdJ z3q&Zs+9lw{L|x*|*BPUR;3c0h6HE$ro3x4UF66?)4w z3t8wv%xilS4?v<<@n95q0BSk(SOi7yT{ZAxP6RS66Gb71nD@ zT%@j7JSf;c>!Vld17&GOx0_JYk>5%+?Ob(DIIbqtbiA(V1*s+_e%heUtkfsejtMoL zehM`a%U3XS;TjFv>LeK*S3pMjt3~wagoFTB*6prTfjakzR#FMc4w(>Yu|j7mHUcNW`SMQRK9B5B5d zE_ce=W1}5itb@{Rw4#$GbQ1EIhqLcr%EG$d$6_Y>FY9)bZke<^{5Z5SY|yPB&s>Wh z%<qY;_8gCS> z;m&{s_jHC8O2W5wHII~gWk3++N9|-fL2hek zSzxlY`~UtU)gWDOFE)FlA}99d@AW2cyy^BK$xbaI(a5_uHfe^zIgz1*AENl>!zsR7 z_Yq-?2Hnd8Xi$>`tzm%S5q&7K*Zs2q(Fy(Lz0VZg#nx&C>PhsNYQ#D=Hbw0DHEVn8 z)?c<^qsiL$pA;kB9tPT3QG`#%+bgt{qX=J$w_6p3RD`$vo`1YWVNXT)^>}-g{60na z<9Pc#c{Gdgg?PJNu^mNt$M1XD-HIV8!k@<5=d&k_+b_r4JubJu`w#r%JqjQz!sp`c z3lvCFgr8jUx0@CIQG|Qq?ONZN@qu_dC(~3B{xIHd(aaa&Gxek7k=cASz$8k{F}VwOQrGV>j9rJph2OH2wXvC%DrK|XpFR2 zP8cIe@a3-zc|~UOcPuVKEDp>UkPmu6L#ZQ{>Nsrbs;6g)ynWj^UV39jS};}CjkU|Y z#a>{MPKBJ=zh+yOwOagd{J-X-j+UsPi;^r*ki{b=Th=!Aw)!UF9`~*9V7EA<&&ZCc z3`y&GXV|IYGGri0>2qqNvXM9bNcF#Z9>9$Bluc^}n9dL|7(tfz3Zz;#2g@E{nfnaR zANBb%@1FOw`|&()HK4fy99t2Nz6Z9=v^_&`1R|qwv@J`kgku`ZveEuno=@Kv%6=Kn z|MXJkDPYJa?FeXwI*x$@+?EQ?XJ@TU>TE@OHTgx&*FfN1f;OR6ge38}gzmv7TObCN zD!Di2agN#|7nsgE(EJMlW*JoXPjc2lu~+|A15|^qi9=-wJb*obs{3_G5|YP zPeRK~TauNGd3;5m@8w-(?1}al8knLadyczp%(~AGa_gyL@$t#;Y zsFbpU{cB#6Z*2TGa?^M|@zOsocvr^vEq>b@J6(hT1@Eq7%#sIS3souOIsQQH(gj>f zhy$5bE`3O^j(x1`*i>=XiJ#kdDmI|5__28JDn6D;)fw|@KAzLZV%w|vcvc^asjuc^ z9Vlije>ETD0TS+Nxybovh{JhcI!{1G11$ytOcTmZZx|0dciHjG>Z30kz&h4$ZhH&C z73iDr#BP<_o!igVxAP=NAn*KsJ1B*%U z9B@D#fWni-|8WjsSiH~96u{y7HM{$R+x~4>JaY0jEo4@YhwJMdpjos73Ha@a7Q%9L za?N6X;KkWG?l^<|RyJO7$FVqmE^6}=QbzeF%`$Z2EX~f{8qRvbl7e)dIC(y{E`9BT z!UT~S5CFQ+pF=JU9lD0l3?_s}kkR~L7n)P!Idw2CvHao*iA(`ct>oyrSn2z8wnJEJ zWMvVTggxf%BJqR%$t=KPsEh0%CvtZ2RQ7Ue1X_THoBa-?1Dwm<9OPx(v5nl0J2Jrd zs2N{#)UB}o)-ZK5yZi*KxT4|-8csLt1P!ozj1=&sN48>sA&)A#yCE{H$#C@4QWpB* zFh72V4aC}3o*nGrRg$WWSz2BtdMK|r#K3E;TKl?os)t$-bw^`>gNZ5Np@xAF;$r03 zNcXe|AG2lj4Y|Xb1^g6(znK@r&L9B&%J4+uQ_PSK*~$Mc1xo7fB6paN2YOd=u&dG) z40B9k5Q24^w!xSNb|L}9QSK%qG2)nVtw&zz-nDAq3)u@$-LZfVX|ehq@fc9n^T0Ff z)GwdX96u-|(g!@XoSc(JxXjDL7ZTt^uMR9qHc5o&&zqY4pzA z!8p*&?}@Z&LYQFUtqX+eI+YRfpyF?xN0D*MOvf!V)ACo=Rkc%9GABp~VwKgkwD*Mp zm9UZ|g#ahQE~p!3=xIf&;%cOg5>bXZHQzq?Bq$g@?94=$47IMhnHOdFH)192(7C0W zI$&QG>C1vI!Nd-cCql(Hh_31EMQEmdSlWl}u>KZS{o~oqRk1TG>oWcg3r6Dia!H4J zruVPeLQdAHc4unBe>qsxmgr;M6ImgPkTiC|$z(WS(@Kz%I4l@rEPF&S*1IO$R#8IV zOUZxc>$mx`>SZo^#=HNYZNOH)5at=L|NO9i2lFa`c`4xk;;??H-_Lme|DR#~A_>oU z{eM5KKgMTOlC5Chxy~bfk_Ic^<00hxy7cb9Snn=nK6YK|`WY_}c7@#xf9=hXq1hX@ zKs}xm2C(~^IVCUbg6Ut<;)N+r?Nb@Uf8c+c0N;xfu-FpOQr4v;Vi3*5U6QHDw8&jU zB$*G!H<~5Z+BXO#CXp;FQCFB+m=7jlHLI9U&6or@7jTK`h%<+Zi6P7nQPb=6Xu3Zn zW>9$oD%uuK#|KCs#t6_kot3Qw*G$YI!Leo?5XZ z!d7j4Va+)kMr4pljWQh05SgJgZ)c!2El1wrixEC5LC6c2iHUw2cF9^v4~v*5(b99{ z{oI*!g(+Z>4BNFS^ITrE>Qj?SIByv)$Bw5XF37sJ4>6_WN^02t6zq?PJmikBK{f_ALOI;p zaq2lcE=|1?aN@wwk4?5xstZ3vE6%76niD8WbM#`giSq5C4@dd-yJfI7#PG?9vUAQH zNXpg25!gxsu2F<(`QqQc|F1g0q>ET#G7RG5@8sR@iPfg*o*?x^H+jOnB2JowM46na zOe~rv{?ZWW)%M_-sPF%?`rcU-Wj(!Z4#m=DFN1+wsm9PutIViIJ$TlK)ug2x$Kq5$fVKX=Idt@oLEzW0#SA*n=@BrM{qKL_Hcw9>OKpz`%^qe&EkwN&$B!k-KTS zngZh`!drM*+rt4~%;X_(l7?SsZ`47BtP9o?O|@CPRg+I(=|y>wEu8!8hu?bS!MA?) z-&sK7!UJFV>Z51g@tYqFEST;lK2WFJ+a&I4uBK;EuR{(&E(-@gC857wivKzi50*Ka zvQQgHa{`viU_cx$Yz|VjbuC6JtwbP;rp?hR*LLkF6JPlsX<^)+Xt-2g(I?iF1VEUc zvW;jwQ&55;Fu_?5bUOWTQc}E`O6{Vi;7(B*yEtS;Xtk4vhHfcD>PTJkFBq2yp0BXV zuH@ylF~qt`V8dyc;$P)0h{XMtDL9lQ_A7Pfp;VJF%5`g%3}U}mfz z;2RW~jtp85Eq7xLBes?e@zZgLntTmxIM^CoXks#>DLO%4gJ*#XJ-|$7B?xB6(*W%g z!OT(0t5nb2;+i1Yth~^PiqXlPg+;3g-8HNc@U!qUj(Gk}4)*6f#BPzf9Z1{(-mAy~vvV=nLXV@EK zb6Fo?l$N2r%DUewhoB}CMcSxnc;qb);Be@@*FuW&@HySKxb4bwVh02;nS#)5GMHq* z=;&vbpcBFDfU@f7IjBbWv1`~{8;kz1w72L}I$)%-YHjJ7$432E{v*hYp;pc~xqy@B zydij79=x3ytI(Zg9lq7=0U0YqfHNaNfP)O!6+7da zF+_wGDA>UYr7({a!l2n*cm)<=e`|Q2;+Uskt zwf5c$w8J1!A(b`4G3KD=_QvM%v>Itn)#Oz%9v>*P- z`-Sh?$sFmP`Ze(2zJgi;d@t?WWb(OEpGq2tc?A*fx!bACKu?l=uFH(O6N|yTpfWa< zOp9;Yjk6HI$f{1g9)A%V$SXL5i`d-l1OlU|!6goe_G$csSL6GINHG3~8vj@_szh|n zF4a`+%%#1s@vWU*#H&4BH2l>QQMPY>`drb12`l7H%g4L3_rM*riS>JepYTWF?+)g$ zkV-B2yY@H+l?vjN<;ibWJwcHL7o%b4A~;p@owI~W?PJ~zj$3H~Uq(zC)JvU7pZu81 zNrUh9O&SyyD_cjBld&uMPvhrM|c{98StCP=at-~b1v8js5*Cks5CKabi zQipWba(D#s%eVih!^L2yoWI{u8v}be`+RU9BS6PykC&1vjiPai*`I2=M{{#PrPoiE zi=w?R(YTn9={X8q2Cdrn@I3MttQOzfpK+ioxY?^5(qi`SV;2o=8LD3--R9LWyh)M~ zJ5lS;jGa{8L1nFfDAK-;YU*46@fm1Kin9OoBgy7!_9r1Xa+3^Kb+SE|K5X27oIZCD zLrc}{)9l6A;2$pOa0gu_bkr=G6LeK#*F~zKgHCgdask*u&`AyD>~kQiYx8>6Wc7#v zxBx9wNc =pR}HpkzUE)t2zE_{m^qJ-HOoMgWBdu2M5xN_QJ|6h4=wd;TtK+qx;Helv3WO1y#@!?| z)JGU(9t%+s9-=C_oENI5Ma5fgZKmofM>Y-vXU3}Z&GG}{kgObN&Qb1QA$AUyT2L3v z3Q=2tdEIfCPJvdYEnsLT-ErKz1L7argg&h+=u^~c6Cd>vN7hqgbO31lm>oIoynv>4 zD8>uJpa|R@olJhZ3dYo`1OkSJ7YrUjhGXq>xP1EQr^h!&QeTU5AP)Es7S-;pgryCNr47xA$6&b{r|EciVrALL|YL+w#Wa7_%Lcy}V$R3P7Y~rw~w(a3Jikv3r_X z!cC}UR03%NPiunhz4lB5c?Y}ms;iygXK+DLovcstvAmHq?-ya{8$GRpMw_VWhvS!-&1hFcRIv zo!1W|xNE8#k2ef~xrX?Ff+kpypZe=jz>E#4Xd$Z!xp%VKcz%}Eq#8JZM^+a}R)eN2 zt4F<**V+a!yEDiA`WYCj&-~dYbNLIv?&f#f`_i&S%REQI7q0>!P@I zQDFxT1g>hy$Uq&TQ?c4^!C-ucW`=FKkyi#K*&d4sCC2#Xfn6~-H2XrQstl}Z_F2Ye z_UCA+Sau!^Om#PT;M4M7Q#psvqobDHg3v!z{=;=VtCJiwaQT;r`EVgC>N7UMRDFZC zgiH+q9G{oeVoCJ|PX^k}_#`nLGlrTP9*Z|mNJ2G2rh|~LT$o;+Y^kMv&Y4AV%j}P+ zwJB~nBWNOT4N-MQl*PkHONiojsVY0Wth3!fSC!F)w`c|s{(Qb%IJc{BiH@zq6w8Z> zr6D-(EKc^AT$+T4S)kA)EVLHJt0p0Y6K26!XAC=BCVkG2AsJ?b{s409ni%k$W(>6+ zzGSOd!OzgDf}aMzM5|d9m?DuhOUVB^Q4l#fp(vJbkta@~dA-1ZiES=%`n&m<+z31) zN3EkQ2GK1B&Lgc5tVsGveG<|^WQ6@dvSicI)(vMCB}YF=VhtD8(G!+o30Nvy^2mM4 zC|z!5rxq#;s>6nX>Z+4H-9@%Q8gf!>7-P64nfu;;D9q}5In1l}zG#NEy1~_d)6tcL zpKLzSOq$Tz;D!v&gUiGTddJny;BpxV1OZEy^lG(Nq%v`vb<9F7m1VT<`lM?+xudch zpo9@4vs+JUr?S5TlLyU29fbu{qB>OUT(>B&;I#gMm+kW!Z;NJvCAf&KGLVX9EAU`C zpSBMmz`foe$<%8^Nt%SU@8>T5D6Hgv{=d<>>`13?0Xpg1nt`67V>jGaq*t+8A`hin zp%iM^xbf_EBpP*UclL#{nTBU8WMWtE0-p1La;C}~lEvC= zF`ezTe{~XwfSFpI&}4|Df~CrjwoQ@lS|yQn#d_F`uY2oZ^C0ViGW431vov6fL%Z#> zFohg_tQLk0bH!<`Bb0PVvw8Z4QOA4kW4B?i>N}_w|ceZmH2e?jv~r8_`VAU2AyiZ z!H&l! zXm#NF4u!bLJ~Bq6a0GjvT}X2CI`s^~<8a2VXU^1_AvlM2=GCzlNza+1I@XFpR3nUt z;)7TV;8I@#-}bN5daL+WnPp_>^5Mtnie}8jGmuqiA!fv4WQ?6M$vhh63Ns$SJY9v9 z7+hE@YS(6y=b3m2=yNval7yH!en9|K^-G@5yic?TfwNoBQ$` zfBRw&dGkPi<8NQ=!`?iY-}u`Xd(@kU^BaHrVxRElk^IKrzS!g5JeJ@1+ZTJ%n@{C8 z{7QWipB)0wlmJck%gAU12O;u_0j`E*t!|& z0l}Qp55*TKvo+5E)^TWng@Kv4;&j*D+3(<`a6(hzN{x66`qTWZDy>4#0UV8fYTZ3! zsU>V^H>Tt2cV{2vZZo*)xb_1zRM-!^PT?t(@9Z;S#C1Qv6|o%S3v)FPktNkUbz!{} zOiNG-e;ST24U4WpdK{e#lQ6!kbA7nPI7l*@sAs>W?V;*s?n5odSkf{1-7D?*0$wQq1;kth2vR=8gcnbxAcS^(eM%>`tx8c8p0H#2MRo(HBK9})lPa!` z>Ncyoq#RQ@Vg(Xd?Fztnu=3%$`DAw4catEosV& z`77z!5s8X%aE)QnzWobPu_#C_9ZexFBd7>wqVRXbi~{k!a{XqWeIxY%4)we|u55*G zc;+r6*YL}(;mm&?qlMOix#o0R&)yABw2#r7Sf9aDHViWgmN8hkpQsRb_ijl8ZW~HI zyaK>}z*9zq6Oc-RxvfudRBv0=9 zjG%ubSD#PJz?J*CyiBGEqLwpWbh>>%edOvJPm?T=ph(pof%}=78=Ik+xS5Se+yjMyrg;scW?-8`vXv1d?SUgjH?%MbvaK!YzF3pz)bMS z8Qz_88b_Q4P__@ysn`Vx=_0Iny-n&Z+YkHVCDic|$o$UFa&r%VX7?k4+oTx8IT1y0 zfJ6c3N%lQjgz&@f9+LL*MORn?C;rbuVX&~Jg4%H*E3Q~6=$`suz|48JOwf^pLQ*EHeX4LevshCI zhasNXg6dIv^>g%U69{8OCU09*&rPwAd(e_KRCt?k0%^$36;1RGWP5u_uZiyW_M%=B zab}QAj6!lHeNsqt#lhASe@$p3Xs?7elYC2Q6HMKK5u}DskFu;>#c9a{UQAzodd@0r z`%5R$lQv@qrF^3&~ORDeED&#vSdcUN!+ zF%tadUWRCL|HH3JUT8q^9A19oX$~H*-L!Omv=&20bOaXmCTjZoQH5OcDjqQJy@nqM zc29pPq{828{IeI?P<(>j@X>P4&lT0H7G(sSBQ0p!;3tlKbBp%MSI-+8D&}*n!LrV6 zy{K>NY5*yl`RT<)XgBfr>;#bQ2a(%e^X%p#n9$b?lkKW`!DqC)r%@9i%`fr(_L7Zo z`F#^)h6KVqnVBs#AMpQS9z29d8beX6lms*9{`4GMR?R*dq@B=~$tQ?N$G_+S=&>q{ zwTa)y77bTaFT;c?uhVN#7*Ur}8%|0NcHCzO5B`lv+q?Am;ut<(>N(bY)#>>OzBsnaK|j;x7*Nq*Wy_=H z1WX(KU3_5Hh1&(WXI#+;tfLNOLJ`W)rY!6CS<* z5jIzeo^6{}O?{QiGx1+u>~E08Apj(!I}qr~!%NZgRGrKu7uJYXDg&GH$%K!0+IxN< z>Gt!Q%{$S*1tNqJ$9eUx{uKbUclLLe>3|(HmuVFMa>11vOTIaz_w@)5lo(Lw71hfj z5{XxFlx{;g;A_|I$b<)BKLRSW%Q1+DDWMJ|eu$1o?lito7In72eB1wEWE}?bWqUWu zXZ8qf&)#O`L1O97?5L|&1L}#oB-ApS&W9_|LE-)HG%bLwt5$f*jtOydj{Bg<$@7?ndg+KgtjY-#FH6UBT0j{OeDC zhBd{;%Qx5v+%XwKm|PBBhF`^#>iX@A`%127yABI;zADrgmvxjf<+QEiX|r`@Q8U)B zkTTkOmt)?bTOL;Nka%y)oYXoZrpk+flmTV{&eF&ckpQ0BhyNgxNIVh1$JUL9jhv{glFByEM#)5Fl#F%9n?Yrkk9Ehf1szmom5Iu#C6)0_tUHcxQW>d>xqtg_ zl2GdC&JMYg#b#@miB67qvI#Md7Sng0+IrpMd8e8;-3#K8>en^TyBA3@F}_eindDqF zb{rKHeN4w-+m+NutgqlCGJWl%5C`Q}%VaoEjPz;A9Gd5&!_~OAKf*$VW20vi0@~dnQ&iu&R5TRVd9)t(w z8V>jZ&oIdA=G$?eKnn|U7!5qvY@sLG4^nBYCFt*vM{avSCB_)71ilxBjrKMwAsPT{ zF6EJs)i=TSkNsgUDnPhQO`#SU@Cw5o4go70OM{_wH#5VcaWKb}Cu5A~0`frYoS~bXUE@AN01{>> zY4K^tGagNnhMlNk`M@%wNDYe)8NoaT|3B4_0r$J?%0$ z3{cV0aBIaqdEc|__KJIqKRnR+y_mhkX&dr)#*~W5PRx@CCs){EO&w=c9Hl-Q60+K} zA)2GP!rBMy&d-D1kybZH!;$u?W;mx-CXvstUnOYI611o=*YzxFNfjpl6eR#ID$Eb+ zX7S?c?=ky(_KT};;|CC~VS9eQldFq179Z3+2u}s4YBKrcE__9t1WM=Pn?2{Gxc`<@ z(&i#6pkyqO;y2Rn_>GBnKTo}SLEbamk34et3PSHqQ?^&)Y)m5l2p=qtG|%x)#7)h4 z3KY&X!(3k_hU=?}8BT)q=Ey={12yZw@=9m$c?+~WQxrdde{l)K77eL>Mw^SidW>=y z>95#8nfwX&q%}#C$ERr_sy<$)zu|S*3Kt0$GeQpPjpaxi^vnKk&;uok|2U}<5S^{Y z&DaR;HAE_tI5z9GwXM)E7Kk^&LEL=6tMB?2%CMsK78bf!`1+l11R%Qz=4p* zHx{6F0G{gr0ojrKT5GX+*0>4ugC4@T;=}{ti zLS{Gy`i|V|xqsl1pev61kc~X(1r7b9(v0vQ(_tr$%Ih5GcO?6p2%r0g1f zqUFR1eV<%^)H8*o7Tn;o^C|8V=TV&HI*Lo5wm)q|E*8})`NN9E>x>{)W0F0hpF7c} zi<$b?z8uXeat)I*$s*7R4I{#z#TmVN=~?wS5hC+g)6D=iglRC zJ5uK5MB^U)4)#}4vsAQNGrG*s0Q?$NGSUao&s{yR8C`9OJ=!D8NN^Do6to9kB=9!Y zmO#IhlmDe(o>}OVkA-Sjtg(i=Ze!k~wv6SJ9hUoL)TpP8&{2_&&NAxkFDEJ88CQgc zTt;2;A_4^E3TnRERPu}5JkE_ZrRZs@`kqrde z+lL5SIO;ZWIps~fWnpPZo+_DDoc3k(>}R#Kj774S%?GNaXYo7R?UUWVeKEelNkV)v z1bZpQJ1<+WVyy{_5jd=TU+lNNqc7-H`{YjrcnCmnNK&oC`>EuO^jn7s@L8VI`J@Nni5EJmlnLBCH3EmIfNnzsvq z;s@ysL^V|2?;gSGfGmHVAc3epVh>Xm+1a>IY)s2%0aGWCs^d5Wx-N8^!PTd@zv~J3@ z{O+Ea91=&R%VoIOJv-S-7fo?ya#7J<=F3|x%R-y$kMlNUCwZO|c#D)19DZaL-`c+@ z&rBxyMSbSl$@92QU$BI!JlndyC8*JC8D|P9^>y-9mSdzt~AUdL`cluhZsb|z?x zEmEXTt9%_R+oO^5%8a9))06bO8@~`|{@tBihM*U$*}_%BrL(S>9ZqupnA@FMUfvow zU^JsArzao7W-?{LKp1+U4CcA75*GG|JW zLQt%ERN`5gvqb7D{IeWAM?kvW(wPsOZF3erWn*J%ppN#V#V#uYSbBXkUO^~@!sD*+ z@ZiEY%c3x@eYeSE4M%qB-~tavEYff*Tsf@2WFKG*T}4#;XzU5xy$RP%TgP6#dg+N1 zSm;R$nGyb`KR!n$P5Ul>y3CMJA(ceR=DF_dj_a}6ihXgpX9+ZHLr79{6alEdd4|F& zA>5!h;4>_|h?GM~VH0nYVr)|+a+Ye3#2zmfK;pPPbmKN#X5tZWcj%1q`d}oEa$%^@ zqhmZ6qAf|w(?zG*!Cc{%X2kw~WyQ=_YzF>}-vhI7g0U5tojV51b%MD{1K)#j0hj{} zcYI$P_zS=s9dz@H1aoYbTmiFZfe15OEK3kCEtn?5@+**zb`zW7{qNu$qC&y#0BN#{ zu0nK`L7-4N1d#}|gEMyU?gwIUaN&J$=4jFZa5AS7aJ4sGO35fMLMJu_HlWX5q`S@t zdI*dhD2EJ5%W2Sck%tzxfNoG@5L6Xm&%)5iMhcB=goBY6$Zly9Q5d0-5=$SyCkF(t zY&%r_=$bHofXZiabMjH8*$olPT$v=sD_!S17v0TP3FtmO4Y;^ZJt?fEpYCsW!zxGCG$p1}&`uEre&0bu$>d<|bT zv1Krr9n;=at2cFj171WG@-goVIYcB{)4WKPc2xudi3mulL|cXtT&X9C4w#>Y$*#^l zx!Zm&nKtd8@k`>BqyGwiShTLU=w)%~Ze}U1%6ZO<5bwzVr__lR)1JAkrv153Yj1%M zUYmTCP5ZEM_%h}%?V}V5yEs!91e-j#O-(YA_R`~)FkIi>^$8^A3)*v?#QaD5xBGEd z1~gVdhjo54GNhogNj6xC4k<643u!Jq`Z20~ACEyfv7!_FEAsVS#Q+QKFr5)gkvK+p`k=e#q1q44UuuNqPxQu}#t-wn-YqHc1tYV$>N& zWrrjT6BSPw#N^^2H}*=GGy1#S$I(Q&h>2XSWuf)p!}Kp= zHSG(?vM#EUj}bs*(Wk6xLy7j8XD;Ui$%A$iE34)rN{A^&Y{Td}-kFG~ABl*%!6!eD z`oQZ(bL8Fyp>=|OLEzW}LNb_8SG8J=0w+GyKroz*XDmQUqAP6$7X66RI%+2&DNqnK zGAOY_7Eq@vq%v@$hL51Y8tezsGZ(rWj}b(wb^)zuDiYmW#nb>-+%Zo^V437q#U(E- zHrl&Ceh!fXPMN|#@P}MK%%2D$F(z9`7;Lg6ZC|lHZTd^os>@CU~<=530 zi9Y-`XIm_tc4U}wf+6ln>eKelPoATFvO~SS7!~P`>~^xG3WTG!hWRZs2dI5?N&X_g z;9=G7QAOej?@Io^y(`vh3?F!ASrEM|puzhMYH7@96MjDOen%q?B2w-$s>+F+8bGBC zCDX_>;Pb7T8L@HHFYjM7l%WbJAt?Rw-JMBQcK;Q@U)2p{LXa3jLPEr(-O&xQ=l?q; zHq>?}7Qy5wA4K5ZMiPMq&ojuV{h$E!vnZ=!hHixy9MMr5oiDoo=oVVt9%1U- zK>jtLXB@l&yHv)X1O29R+RNcVtcfPwo#2OIi3!osW;1pwJjbcHS5WG5%~lzfKSxf_ zzQ2;`Nm}BeW_?MDDAFp347>^I>-luFjro1SSD}SpG%G1(Uqx--KS6-1)fFo0S;B$ebTdo z>KOM?oT!+;22wDV-fH0c+9MTx2GZWs^FyGJClB;b;E(`-DlUmJhrwb))ojNd;Lm*U z4flh0x&O{T*Pe4l0mATM>kOA{Y?hWu$RKWL3J_?@Mc}dY{Ku7+fz>-c(T+|w@=kqd zATQK%<8R(ms@>lL?aw2ded#F~G%#<8k$nC3wuob=f5xngv&59qX3a1_Ff%=W zvU^88Y`@SAi!1^ZIGD$$$!M3Yn2)$80+WaXglFOCbRsb)`i1a>c$4rnv&}?5 zORfvgF450n04qCqG8CQ`Ou}=r9G5Z=U{3VI)@PD!NHByaqEQozDFeSt^$C)ot72Xz zlbJIbo1J#1KS+_cNJh^%Ejggvy3v;~qsdp|T(dhSyGm(X5l;c*AR6S>p)PrvjXvHW zut4i#TeGisQf%v_FhzkxZxXD>0*cEmyl8H4|ISl`H!hN0=-LTuj;27!Si5kWsbjMp zb|G%6-Y)zKTY^Ay-9)wV({v^T0$Y0nIGB~TVKwGf=rNo~d*M-QOHTa}k46Q;Vx+ez zgE?7^1wijV^Xj;hGzW~sOi@XQM?5C&MBD$abKj*$lFHk2cio>8&WpBjB%j6*nqvs@ z4daD{_z?p(Ar>O4q;BK?yE=l_G75Du2zjANw3*;cn{6vdVWh|U@=5Yzt@cl}CMo1Z z;_=Qra?B5@RZoz`9!{S_2D4_|u}3uO)UhxTRg-SUAzK>ImTJE89IFDK=Rwe$En-Rx-%Q)LEdyod1E(7|_n z;6~L0B+vc^ExNHlPvP}mjFPuewBRo#NnQ;`_KY(zVpzYz;fY5Fb?JW<|Bpv;>7Q{h zLWXJwMq`5qTP9@b`m2ka9&|u&uf00#QH}68$l9j#cAT+>+Yz+S-ckv!%yV_p@MLyf z^OBmCVoZV)!$r9}VKA1p1fvmdgQBnLvN>R#=T}$1q;C4=5A(Xw$?*fgwer-ZQ&=WK z+5TE!4XUApTX)CP*&lQtwC`KK_Z(&b{5s9UW zM}YxE{=O&CQOk?ItXe3WYndv}tY8dLVT|Af=muD5a5ds35QW@$dKN$VuwlH5F~9x@ zQWJXCOegW3V`#8hP0C~lRX!tke}SQc0=7s}GK>H}KpoP?_Nnrr@=jYm$Ue2eoHYpmvE!%M0o7EbE-J?O|w6N-=AM^ zoGShfuy9qdIEg&;r^`3ccC+($5drF1P?Df>xr&avcYaG)8cn)0=bYpy$}OL>r;EUX&_Wv z1jpsb*BE%) zqxwJ|3^@vyzpdimNo}>C#dNDP4C!1R{6%Itlf;}UP_tbiV-IajlWw$FON1oG{s|$n zrA31I)%w?e=hW>{9avv3QMTkxD@^ z!+n&C;jhBEWFa&{n&F$+inB6b-pRsO7BGs+L%cw5f z_d8e^^b8j038=fa39Cdm=Tc@I%0IAg;3WkL!b=GV7C9>@+H|eRM)9g z-mQY4D?vXg&~4;HD<35ij9%<`vIo7;e#THJXTRsMG#z|(`)8k867axSGn%-8&yXMeT`rU8u8E!LRRlx}+#+(R2)VN?=) zMdj8xa5R|g2+#u`vsq6X;W&)$pb=6L5+|CO;LT8aY_FdE zt13zHCkihWC+%nAGTwhWE+vz8;d_a^eV$ing)*It&c*D#Ig<1X@mt|A^8|s}FRDlC z*?nmn)tI{Q{a*OC8M*_?Da)yr7JO~kYVz)CwcCL-jQC1&m}ajQ=?rly2EWVWFw%0K z2!!r=DsO+5#iQQowZaFnJjK^D^qgaRHU(oLX<1_Z;ER>hDKsKh3$R>wy~4h|^(xlS z&fuI}J>L+5dL$C^Vj7odf`d`;kLAo4x7$U}$c&{v6FzeFDyLrPxHG_;5Z08>eAq?o z8nOSd3$wHWj2z19VTtG^O$`{(DuaT!xKUjTC`{-Eq}9|R8T3Tx1fNWPf3tcPGpnG^ za6Ect=2LhE%XUYugFQ@;V?`ET9hPWudazShN?i?elzHJhSdG@vO~)%l5+`N8^UaxlC(A!mE_l(iCFH%}ABW5%}2P6{RF z2h06S(nI}Vr@ig^`O#(v7f;ytfhv&H{cDbDSsVsOK*vhJQ)+=tm&(7fx$F&dR=Fn~ zHffG&-oR}xG&<2-)?7@PSi8Sn*C+ecOU*H61-SmPe$j_fC(9+~6F$iGrf=*LoOO9~ zNlb(kRO7WuDc};N6S?kG6$n|YDpvD@Kyv*MFCcl!KT?*PX{=9YAKD{qbDCD_Z#NuN z!jz`j=E!w$&ALDUcU;*cAV?!1ghaGUk+YVr{i$)qUt z&plYEZjPWJea=$v<}fEaNvHZUmP__o=1fNy1;7kI345jgKJ;pO09CCn*{5npqn?|* zBME{RoT9qtD+hx`{?a8(h0M}{&*?jmG2Jj-qJ z{Zb%eHQ~}_zU|sf{EWO$-rtot9Ys^FOY;6Q0HYv@OW0%eQIZw|}tyrI!pjjX_! zEvU)}O=JXe%?vXn#El@IaHLj3NVF{@VF(_#@E|tie00Yo&RDd%*$$v%2%1&mP?S#f zcEc&VD?AubusM5_DIGch5^#ZP=%XYPM)(KK*LR(#$v^-N@rLw_eMrCxH83uim|8BZ z-C#(4!hq&ye$hrL7$HAHZaM{_9Ohqs#;yiM%b;CVz&!aGP73x(fns>d{@T|qM#qIG zh!uq=*UHL5!NzuJ-Zlk$B%0m8pDEiw!>ZoGm+TeNY_h8Xk9y>Tf~yxU0xWLKM#Lv$P*-x7f0V}x(MT62jrFekSEq|5@9#TzJUiIL~~Uq#i0Gf$B{Je zP|}pHMhz#=L_T+MHTKpYZB|ET_w)=mHF{=vtS>zURxYNd}c8Xp@0Srj5(Y^-ckWK zj0T1cJp&eLfX`|K{G>U;i;Ei^)z)H!;Ig0xx>>^r&^>>;CD>NPz0Ss{b!M&1jodzH z3#}2g+3_*Yw;&c~HY~)l684O^g-?Zs!PM4qFk=~dL7xWAvtGlfj9#O5X5TwAfg9rv z>FkAs_Nx8RQ^k!z&R}B=y1hgD&cEzy`^cxV zVT3+IXSAQ&2FBFN4on#mZ)0kR$sgIYiZDQSY`h@*TN5 zRT7*Hm0DP-sRHOcLaahL3E>aey_`A*i# z4&Hb>T#H49oOIB;q@^bvKa-XkG)x>Y+r+W0gXHFz+*PqDq*hQts1?Bpj?g7&2YxnE zdJ-&yEfJ0 z_@9XF)>`YC2%@n_4u}#qy}S#nGoXoGchmlmli%HsTxJR#UL9I}gxN@sfQ`6EtE7}! z<0l2pSCCoi3y7C2P0RpeL0A%Lm4ZA0U%<>&j7o%Ka%oVTLL_~EKunAUGsqyc$^l3r zpf4F4agN0R#ExQ!b%RJ>KH7)tXcz7b3dGgnR8~ksi#@NT>Rv?FLB{WAht(!o()&=E z9Il`;Bhp->f-!R}1DQs*VJ$wB`@pDpPlZ9iOB4V88Iw8QEWd!hIs{>lhVTq#8r*oC zy&VH_=q9U5ryn+3ut#tygSDtHT<>Ni0#7tSK)~c)97vr=VMQ0ay1`}6o;!FUiXPr9 zT~@%1j@h{=u4`y9N}h_CaigRoXIe1%N>>d?u&W`0Dt85nvFsDy7>Loe^mKGn+U|8l z?Dz_2ooYj^!^}uaoslxSS;V$At8>|~X*o_XE&JHq1#L|EG3P=Y^B4sfB6!PS^Kf29 z4bn#lUfNK4j@8bfG<98(hWBfuqQ5Os(p~dA3wUJ1PLBzJ7@gfzaE^84QJFzQy%e#B zTylfJVO5mJk7LMzPsV&gk|C65d3dn@B)<|W+;4~`G#RUop$Wa#&fDp{K4@q0Onfkm z4XY@Q9a)~Wk9OkMC)C5LjsA(biuAXAsDBa&EgF7^PfQ-UtV&BlcO7t-Q522=Rf=GX6#X>*Rr#ll@QAcKV3w{(mnCB zeL<}h4<>e=<40@ZVuKwRHfd=fGZxlpJaH}}aX|C{`vN=HYjPml_<+qu1`JbhX6*<6 zqsAwaqgDm6bEF;}8Xnp_l>e)$vaEHr1jJ>iqqVe|ZBs2%WVtIv_6@>f(3&FIk}hmK ziWE$y8#iw|0Z4(I2N5cy{Q!E3ux~J@1^6GtzsQ~=Xs8W##$HU(bfalkGiV{ZhN{iU zr0R&A8P0u(%18qW`0lHd;*u3Om?br1;$3$jw}CD_Eiz|p zP1kS_u|aB#J!Qj|iJ|cGF3>fg!`}9RF5=Pzx+K$inOk$BK%fh24d$1nkXEpi*mS3e z4YI-cfm)V`u$!imu5=_(!L{4lk*C_dFppxLKt3q~F$^7voxru7Pc{+@zn7GlpsPAQ z3r@jGN@);j9n1R|Tb>6Z46Dd>6kznTdeT0mn-mC2l1lrkb(zMj>QqIYt$3u^2ZJm!n32E zC6O3+YL7NiJJQcv0b>onH2W37t?+_UX9h$J)dR5|;nJUvy; z*)o>-_x9gTBh6vbO1NK1e3l^4W&}v^9(9Be>`7co3K9>nY06S%Hc_d;E?M0&~&4eBFB|{ z$ilKnJnHx`tdc4T2Urq)(Wl6bR;5j!BA2C&X$SL75E#Q1ni$82PNsusAX4N;DMfB{ zJlHZ#OE)oE9ED5}9R+1c;H`<4U5Z@nUsOZ*ig{pdrl!atK)Vzf;hc^HGZMvBDw&M7GM%ZpACcW51torO^)N>~3esiYvZjvP(a8|&o=dRC@)qBn}M zM&|q!CgySbnP8c_wvPcQ3#GuS!JjdEk-lYG)BkD&Mb`pSUG;PlLGnR^)hi&$5v$Pi zQB)%Ip&h6Y9RTzRWe63t3e2~WSa&da8FgX_N)G)HejSl>ACOs|=aP)NR^95WmTV(>Zdw-yX`YEa*uy zlh}}W=Wh--%C-Lv9V$oVc=@Q_nv{dGJX#+uYyMQsT#oXVKi!~*%B@$k{} z7A_VC>F8k&o2=_-L{!7kXpk%$LWhpl*GbgaK!0>-G3|A<{#?gr)OIz8h)9jjb^iD@ldL7LbIXS(pyq3nUDgY|e*tzV|*w->IdmSy; zDN-Eard5cyN4gpM939X(!6W6wI;n59PBx{eMn-$Wga>}4vraF4N+ z#*P^}sM6zFysBUaZb>q+8x5+*O1Udp#{VVX%NBDr>(@DAjW z0xh9*c{II5QNcowV)o`LF`DzfD;5}ngyl)cmRvVJR*@|fPp3^=Me(hRinbNRaaifsT_ z+*d9x2=%G??=ovzOHw6P7l4QukBpuew6Gl+cVKb_N0OKDVZfxsjP9q&i5@BVIBB2; zdJXORo48c#K|St#Qh7Z??O?1fFsz+$b>NNGMan2nNY9{WMU>opJQKbOmJia9r<+ZYvy9(6gQ2L?)A-eLp~9`{4FB(tZBxQ5wdIz#FjW51$>!fmkXLoy&WQbHFq zR{V^>2DCfU4B+^PZoMa|L(i{f%k`d7q+9M;wLdR`AR#3XXC=WEc*RG@6qF-2yy=Yr z25@DK&$=bx;DYhwQo$aen$F7wyJJ5E2`t&2E+_eg+8UcVu7h` zW}t9yb;t@Y$;dshS5eg#5!PL??3hO*PnHgWC7~OTVG)FEt<9Ush#DY!I@rxeQ>%|l z1mrCEP0cr`$@K!Cw*cu$!Fd!wseVIwd4no+dm2X7JohrTqk?-iUJ#y_~iJ_4vMr;ML%Y84KN)M=X z1xNq>YVZ4V1!yGRTp_$S(Pm`XN6R!@x&=CaIdOviMo+&b_w*)$)zQ`zMbJU1_#+0sTb*d8(zK)%OraC_uQ(G2j7-T5#^_c1Ie2fAY=pJ-5e~qaNxs6 z&Vloob8{Rw0}o*cIZxx@pSk)e0ipJCoQGYtjf}be&Ls$oDCrL%Mj!XCYB@ z%Cv^I?Jt#h7+9HU*8`8*UvOTs-PjWxR#S}%c^7z0kig-xMl6Rl5>Lb^Nyj+rmF7Aw zOAM1uui%k77Dq)1yJQQUB+;JgXjx=~LY1|qLn4&Dp$(Iw|Q? zELN-bO0Q`DS)z?l-=QGU1UeN5^+`)bXM+}&ot46q6>DdCxz^bT31s-ixx#QBTjy9^ zh}N|(NEu8vzrrp=}FAxxq7_Mbh90GGPKt*sDNF@}Nc!VfjPX8su-r#z}~^=^in*SpQwqAry?AQa1@#@8;k%!r8TPDEm36Xq`+iOs2|u}f)+#KuZ| z$umXm@WgZ@zAwQP-$Nept!C0?M9}j@uQ1g+n=Opu7D=jJa|Vwp5x3#TEeRjon8!vD zsv=4?j;SQ<`r!dB!dz*Cr&Y)`d zHlaDCM+gd;Fh=a(W*&9K&}Wv>!4RM$?5KD}XP_85a#6rUOs{Gox%lXKCx)soNw|It z6XZtING^$24d2q|j)21~v1ymhgNc1~8<2o>zECEnxbft^VY%TlI~)i57QUx0457wV zO4cMCL5LeoJulHj>>Jx`#Bv_$ToOnM$d0Kt#0qKRvFBIZ zx)B+Pi0#}FsIKba7Fhha^~s8V03WVmMML|%NV0WTupM{HK%uHZ+;f2L+$ zZ++Xo|KsP1_Fa#i%iG=-$=408@)$&46rC9l)GuSLx{ooeW45tO(-&{a_$~QtWvWlL z*~KvVOr59~A-tBPCeG+QL&fT=j)H?(NmTZ|}nEMjw7 z13OUgM%%fFG6ipB3T6a3^dRO)sN$Z2k(xuyKbk}CLz$!vF9t?xOe6D1;Y4SVW9pt# zOUl`A3ngQqSDo{!quDSH!yN+nt2jbdfWNAJXPSU$+R#IR$W{)TFxs0JU><;QBeB(3 zHv>vv13va&;Z7oH62dk6hLwyQn1HuH3}!gV5}ZzL`s^UmXXzOe!8qge8FOBi!*=?^dH}-<-reNv-8{im`ubAl_ zX@BfT?q^|>V96zDo5PiJxk2muy=eD;gLjr?Md=>&z07H>Y|8&KQ7 ziA1zy_LP$!8k9pCqsn=adYO`Mbo3${Vuy}8dkd=^QIJ$i@*hh%F>8%{35gT=Q zcm75lt6!M^yH=*JqN|e)GbypY_eLhKZfb(L1Jp}X3B;l+RAsnH=oQ=Xd8iJPYyPn_ z8-C=f-C#-Mkd*ZHIk!6RizBSz%kWaT3jL_m3`TN}-oWk?wG4k6wQ#}SzCQ^uf$4et zq+ETyFnk#a>cUx}820wQE2JtA1^LC!6LDzL?5EAM%KDP#ST_adLrFMP>+1p-u1b2e8WLoFnE=ysF=Lm^LkRj#S)4-L!lp{gCbinSkX3|K|p{A z0!{zAOqWJ9(IHeA5W3K-A5#YT7KE#B*bQL8Z;Yu+x*XH8I+^`Su5(q}%J9HRmNc#5_JxoAJegX0`_RZLDM zYJmqsK7vOUPDO)!iSTP5`7`%!*0jAluJSIdo6P|=RIXDbc#Fwc= zl_#4Jed8jZY!U(E5mpLfxAK4!$Y@^GpjVuMr&#@NUge@u8~{HSloc zU`w!Sf%}>xf==@^ZBb$+EX(l=68M>#VgxV7QQZA-c-@b(QI)~905iMc3_7iXSY_?d zbwncsFUBxPV&Cv-|50|}cpQN&83RtOOY30t$xq=E#1raf$%uT>J^?b@|DG4mIo-bf z^ISi~pV+)E#7ryY{FL$rTjcrGG>s2qtSAF^M>8%R8M|JT&RxDFdE=l-M2Rs;GgsJTFKRn}cqUPhA&2 zM&%udqA&Xxm7DepwZJ7l@%Hg2!Pj>Cus>$)?EN_xzn$(v_ck;4_iSfkJV|j zo?oqcv6V$;9Anfz{FJ2cvXr!exiS=iegZUslp{&umbiW-Xx7Gy0KI8e&dF6yRT;VD zx(^;g+CrfE5ON~xaJn&4V+b3zeeL?%Uhf%t;xO=e2 zSMlK6(+DwPMD#;OL6uOG5Y?XX=y9sDw7-{Az#Sbt@{}vXA95y=>Avs5!b+UY7Hsd9 z4y%we`|D2?=VlJ9KUW^j^!2~>3-sg5ssBF_{zonZ|K~=`NuU%7j~x$!R_e0@SrkfP zoD@)s*&qb$pg9`~n!iVZVK1^QiNIrCq9(eMsmLfTXOC1pBQt!de5$W1Vh^BABExZT z!ze9hcgvq<)AJZ=yf3+AEN9XNIH7=;1t`)C@7TxV}>mzOwVW+}r~xG0Ms< zkqV3Np$uyE#ImT64x4W|cPpn(w@F%Q!!O)2>?I;RqKfB;frfGl7!_8)8MXx8np>$$ zr;S(4$7`#FpVK6X2Efk@`r(HyH-y3l)qD++dyj6N9WIP~Fx5Qd@|_lJ^9nTj(m7Ua zUl-80$`$z#Lv^fgYQ36h03dIeXxo@wZdDncRN)0*gl*efq|`J$o$MQcPLe5!b`Yef z!rWA%9OcI#M+mGef1Ya(KpWD-J!bC1mQrE^$J_Iz8%BD>=GXJIoPC^~F3R4x!VMuo zvey#W#F-o9UMPXFr#i6>0DP`EOmZL=_A#vbyG@tTTlWO5wx;@=h+aw$ak*;SS@HuFZijY%u`ujw0(0|ElqP z9LMfwdIOszPdFA+&`BIfrc84V#i?RoYY+Qh_gsJe7!~rS?*sO9F*kqrVr}Zv{5>V3zpXp@aIx-+o`Awiq z?!h6K*dU_M6rowCh^aix7_Ju#UmM{E-wuZLV#o+3Q#Pzffhj03yk)L&kf1>7c0g>P zoz8>B+0hb~n0a-uXt*%l=H#@zV`E}3_lAUv0&##Co|icJJfXzRz+$Ntq4$tfc{4ZQ zL0GZz3*r#l9$R6Gm~MX{&R*v-$R~n{iY(m$Gk%!UtTc_;RPFENRzwhG&F zEZ0U-&l-c179Q4}WAhhu%VUPAZvEs0o=BW+qvLav&(R7an0q66mcXNqQXZ`9v9whM zRG7w|8QEr(aYmLNp}V$ftd52Swwwvlsh9?6vKNyBCy5xW-qigKG`vO6&{=FV;Dl^b zy0WVIIBFet6((h+p+im{JNHLv^c~$uDqYN^nM-J$Ba6^FM;ArIs3MpDA7*7rt9a~c zSCa zY;FQ??bXd>UH3(Oo05-jRD6nAkL9I)_e0=pvJ^qJ(r&An(9M`f5PV&fh20BNA`A=s zVYdP#KcSxS4ri_3sb@5YJqrU9^}G*A8aKUmRY9jtL)CpBp{#(Jf&p_OlreH69CmF| zMPk6dtX3D;Ac(E5;{R~m3y!r+zN6QL29(?;5~7&>%SxYU)oZpYX|}3;Ys|fjK4i_t z2WTyHe-atI*f@1ZqvVX#WJhop*ZW!&r2?N!fKOwpE4HuY@JUQy; zq}kb(}#wg3QxpN$3hXNXWL&+dwtdt6rM?OKSSRB)P z{;S90m4SluzIr5H8J#-s)qCR=!t(rAj~2Ft{6>B6;iZ;p&-?y?C zh%(7O7cG=6Wj=SW#%$-8-K&EqVpOOg{H0-ZV#c5(7%@(>E}evYf!pMDKE#2~9E_9H zNb)-qVpw~ce5@P$o=zQq-P~(s74WF2eNVUI>5+X;4HlGV|3O>b+7h-YTMnf}>2Y*3 z5i$&_yMOrp;)MmrZ%c>O>GsFDze;5nJoWr?^b)V2T)x>k{lYRz7A+EianM=3CEA?| z|Npb|kW+;JK-=u+5E}dLbk?$6=I>V#_29H5<}~wp&Ht5xP7>oF_Zk`La4^BWrG1c~ zj8+qc7x@0KM;5a-PVtH?YwG08OY_dB!gkegbCd??vq2# z%`LRlH**O=2_7~~dD{;$Z*QNYf-2kj%2`fqH{U@;aR}U<3D_1E(%MC>t^kc0Sezj| z5X_^8^tSIj9jqpBBw<8kgrA#S?FZz$VY8PtoaU4YNciTVA5FZ1u|nU2-731Ws8r7l zCcZpeodu_{y|SoILahyPasUXC%{GqQDRPkvASMdz?ZrO1IGo-$-EANG z#TVSb`w#pK*F%n~(lPzxPfT{(k4=33(GPL?6G!ul*PUs9{PC^pc>YsA#`B&0_*HQD zzuVGn5CZD%??VP(**@XV17-W(AK>>_>e*u)oec7d_7^|Ro{uC?WxyUNcH76_a7&sm zwtw-1l)j?<^|$cz6IJ`kf5Pv-sPe~?yQ?)HrdlPjUX|odmF13ux+XQ!Ui0V69Sfc> zcYJ!j-0|u8a>u7%TJ8kxvCyh#l`2aiR@yD45InFhg;r%vgOpm8N!3y&Rf*G{BX-wS zk=?t6^8(JIBPJ(!-;~cUie9dTxn2}6CbV!dFS}rZSVjL%9vw#39Ap!5fvO#+9ZPY- z+dc55C%Ej#mK4x=^&Qs;?`f-|2evsxbH2kP0CtV)4 z+sLqK<=R&mdCR+C;5ba_6KnMo7-r>@uHZR*;{7L%AON^^_3TfzvfGm^;F8?x*`*G~B3 zzOFz<>5t1(kTfm;k(_AyYw)1ycC#}Pvm0_WMSDj$d4}zq`F#;@+`cDuOedSLn+St< z>%I&Sv-B=zF$nitj#~9Gk!Ua+L`bfv7w-{Q)`sVZ`l;<6WY9+jYY zTnALT$qXLyzaHm03RU|{SNx`BFys{uM!g3TGNvgh0OaZ~oGlG@*?so0VsEj@-|soE6ti3l z-1!^D-UZ%o`2O7Of9pc;w|u|%D<66xAUsxl$9^yvk|^;0e{s)qFH~YDO5AhTKY#PH zDdKkM2i3$j#(?;`@4gqhYi}nQ(w=DVF(zW<8cc=zyF-`oh$?>h0zA-z*X)NaPz1^E zGR%(^uVHV{13JK22EGSFuel&-5FnqvdN&p{fp@G&K3N|S8NU#cxBN!o9Fud>)!cFm z!gz@DAh$vh8e<22qQ40hLbhI65QeRIj)N_yqU(ihv5prcZvI|0T0>&d=#Y<7qnr~= z*Zq5eS^zNMa1Zl9Ghf!Gsl?OuCLvza6qt279+K)wMxu4A!qMBP%Z|{dd^->VF7s>Pm|BAqe_Vr zmH&SkW6zlAcp%bVjC^c~*){w$;rExMPC!yvW}d&z9S-!Es`5jYvzGnjV<~k59w~X6 ztRI}Rm@*hkJj19#GW9%ET-opKz{8R43_*2 zdK>|wU5DDbvM5t-fe&3#nI2a8p_9StRx$w;j*(}FMdPyQsy(M|G~&n8P{ax50gkQt z2JH^orwCb%wFdA#DPs(TRUEs%>4OI3fgk2{>OnnT?f6z0VRY-+Fb2=`fz1oOOnI3X z_%gC<4*Zg)4OA`&aOjDMLWmvuOY<&=-hp>1iFtL|(GX=<=+YI2D{ofl(onA{e~a)c zGW}0(N^+VUP5h|cXJE=IgOHK>iID5b-z=D1c;uF$O%}Mc;3g4)!KzpX%p|2PA_s)} za1$g`cybv$(9Mb04XZRglCNV59Wrzx%cSgkh_}C+ooNTlyXH(gymj)cWiOK1jqL)B z%u9@O9Q@nZ)|jhPenN;$^a}_k1~&@@FzPW%nk_D&vk9vM5D^%Mt`Oj^TOm+N6=48o z7@e%!yEd;7;Cf|+K)lH-1eR}%f=xQL^1)>%rq9%gY3c+)Ks$k!RT54w*opSszdYyC ziAnn)7xs#np0kxH6iJ`BTI&`0Nu4!8oxl z3Qcf&ZbVlR2A4Uprr2Py0qHNcQkov&dWFfBt}>j12)~W1ib&M+A&Gj-&QhYD2V*q@ z6Y@4-x@3$|Hd6Hlk*Wttp&6pKIDm#Aa%Aj9wWH0_OaCA8=<}y(d z1^8UICARRU(rosBSJCyFxeLKKMLw5A-L5Kj(vrP+#=L{Id2}wExMdS32JpjLiP%5@ z2_n1WUW}cfm5dEiFXAP74RWc~RejNH7g)!DR_DXrit;L&Y-L6R4BK(rt08E#vjM*W13$e%c$p&Ez+~8Zl zGX-I)rhMB6`=EH5Q2KA0^w& z44QcE91ynm7##R{=RD%y+2WJVg5r$Um5n4A$n`Na=#s}U9}U6#-8s~nN2pvG9yvtF z=lBuo6nx)C*`yZB_7h!;f4o7|j$E|IF`V#=0yXx(jznxM>;i#kUtj5Gx~<)VhpsI4 z!qPw_GQ!?J9p;GlUyS=N_V-^XC+3D^-SmoWh|Lrr{dtV#tQ}&M{hK%5Z+2$jE6lz8 z&isOuwF$^A223+Z7{cn&IE*L{W@T zhvhe&Np%Kb6kyzPfylkxbT+qEpx$2qsMZQ-1*ImUhH*RO0ev!2$7nU%u+e$Yk@!1K z2{z>bs57MIrGZ>N!F=tID_@K`-t-E{@)3dux>=zLw|MEV%@uzIBcP-8#ca*eIbmNJ zS6A@t<-EIEhufWRVw$hRm>p=^8o#NbLucC$@M89V$pk}YuFJajx0&+OUD>|c=BxTP zQ|o$-QtLWx`_@1FztK9%K3X5xI&?;dWg3x#)W|c|7)-4pU@l(H5S3X0=uAWbsJ*`3 zC@m&0Ygo=Amx5&DNI^2^+i<4wQD}nh$i<>Na*-J$S=?b(S4$N@@yOTCr!6KcOBW-( zgD9z#=6YGfmJ_P+Dd9Ju~#j!wV=(b3UWf2E-;L0 znk{}~V@+O#n#qfob%uwU!O9rSLBDDS8XZ72!Vqc(@6}eSxCBPkOln{uBPoB5#{o-B zwqlhcWprUjqYaAMQs@|B4K%=dd^)kL8<}C(ZOiyc_Ct)7+^d@7N2}fl&TD*%xu%}8 zGyiO`gn^Ig3Z^3$y=O*zg$px#X1L$O(XD#a8sTj|Af6Qu{kl`%oxkpsrz;18)#H{n}YS6@N%v{35oDhopOBm5I zKZXdXJDFgYAW9|c1aVn&1-2q?A{XF*wi8B4l(_(&SKr|_RMzKpm+0VP@-vfaE1gX? zi0O=a{~B?t{~f$=+A}||ufCz2@>FXe@&@XHr-b3;64|^oRwa@&^vW=v`RQ;unj>d@ z5AH}g9z~)p$`hK`c0^ZsMUIG`34$b6!DJ1{BX}}w2o}?u77npDcrTjib&K(Fj4Buv zMTM0}f03B(k$cx0JHv_(3AOma*6y51lyLz*(O}ghB-jC>Z-g2|u7V2IF9fPOpa<2N z)(WT_`#|0N%0Pvh^tJ2*wb|lHN6~>y3`;t*apPime1W)7zfYOPayO#e&`aPGl#}p) zOpx5kgqv`5G$oZ~oJTvp5j=+vC^>(~E7$sw#w6{5&Icw((()-S1W;#$@#~7>joc6Y zZ4TY;B?#~?U03P)_Bn^8GD0{W@(P&^nzj~GR#z&ZoE0#fOu_KnN#}q#Zl>%3FAdyA zV06L=-j-<1>=Oq}XP!sikh{&QEm&<^%A(7=Ow@4cInM5z?22?FFjMlFeUdZ`_D4^F zv7i28Q<+G@vjTg|mTka>HbDPW`r76xwN6uTRL_4$lw&^Jz@;cr@|oEIoWhOp9yJ@7 z{SnMtgHXfzPHLM3)LMFXqb<3BX`zrP#(t#P|ypbtLN%oadkaKJ( z2qa1s;TUChd|?uTqr2t9g9(FyO}8r2+)3aH9&WkNF(g`}oJ*c&MB-5%PQ&5ca0>X0 zyF+nGYpmZ6p%*KEm<7s2?GxXNu!+;dC9~V#*qgJwi@SIS9ky@tUCj5O!S+4<-TFJm zdF5R}cs04X-#lP(fr^ilBp7Tp{CrR=RBH)U4%cQ+yNPY&Of2NcH!~w!6&uTI(7HcM zitUmg04{2RSx_i9A4e|ZDApjjK4y@tO58fH5cV?DpN+_Ua^p>C08)&N(f3tnN%$dU zEe-0r9-^bhDL3l+?KmEF9Jx_rT@{;axlx-bH;UpWHbnt1Ny9>^ZLVZKjiSIX)BzLP zKJzI;W~0b_LYD+&&h?qJRR{EzZ39JxC79qHSb|rvRpqke1?oa{Qpsdd9l za==fH59?MjWvLA0JK1s=YL6YUECYh-4f{`(J8>x+duCxllR87n?bxt(5)Yl*hfw2b z#3rWQ7YW2}+&b5I)U&mX|4_{_aGIB}QMObV)s1nK@f(doS?+Mb_aU`S6g}iX>2`fkX*oGUVx!7s<>E7NxHtw$sF< zeaZ=Fjyz))mMO7}nfiC)+|$eosl)x5$p^|cYa8=41`J!Y{Uv-k?KVALNe7!VfXQ!5 zN&U7UM)Rq{nrq+X2NMs@?>Xs!ELvLSxa4j zw{{)B3&y1Ff9%tjawiz(F<7gUpf|?;dxeUz3b#l=a=IDw9CqqkHROMRh&TPIncwZN z0fD&&r}R>VYbG~QovcE#U> zguRtzkARk!YeoYUY-u=P#~4LS6fk)Tl7|X-UK(nY@bP-(y3A^@gNfF7WXCKaa32jRn^t2 zwwAHw-7a~RZK)S6tyX)%vMt*(#+$r=F-XK%5d3-flDk z7qrE;{3vFhns+5)Y0#^BeCh}DY{og6B>q5APUIpUSBk159~$Hrg*ee?tSd2=sND*2 z5|LnrII(9e#0hCk@R55ns<4)_5GUNV2nxkm;!QgWaiYR3#0d?@&>+ak)=q1!S7IqK zuvVZGLdEFEpGW}GnA7*0Y4q5E6%7^Uj!hh-2b&{BgaAdHl&4X|u4qN2tLObPa$q*{$E716S z04*|FUgV+tBridqq^gg30s2$cRMkl0##+Fvhd@T(cg9%S(W<*dI;xbq>qtgm+kgdZ1T8JG^dMjfMNDk7}RDRSfRke%pb zeUplWAxGngNm($4sU%S!EiK9FBYw7$`Y2SbriFn5SgAC)7!Zsmt6wmsH*BacZ)7CX8Adx>Vt`Dv8ZM9 zMWv`KYBH(pPZx(2eVZ^!)LED!$(t2)4OAihekqA%qO;daN3JIPHjNh)o zU}D(%6IQ{bQLNmr#t0>~oSsd`M>80)7zVMZ#bTU9A5bHq8`=G;k?l8%$yf|iSjrTU zHKFG)&52^a`2>Zm2k0$wEE`)4^~7Rm+?erLF*eVqBpt^D7Di&RRqXoN(5y5CH*D%+ zF?5UFjjMolj1Mt}1%2eBM-zbL%Ag}PYYfI>TT5DD1WYov_r;OCh8#V)ePf?jnnG(1 z-Rz;u*eq7jvuSk=YQ4FXezIzNhP4EE?}Um^(t|#|R7hy6htzbAcLv4Ss>Y0CDe%ds zg@>h@&S9m|I))G^<&p+5*KjbQC$%801T@MBf_s8s$Dmdy=mm!Mv)e$y0FN(}{la2g z?*&Y;;dfZLjH?GgS0}&)ptZrD@vGNL^Wj0D0lr){NwpH|fSN^!Iyoy@Bv8C^|o)AE^-&5+sq)e*yFrcxpS*3Utx7WBPreF!}y zU};@+bD6tW8)4JT*RdeX!Whw<6Hn3DDS$?Rs;o&HdF%vAI-Ae1eL|(dQ3_fSg93H} zqaaz@8`E8dVnJ+07Pxo+nr`3PB95nh7S|T}aA&f$H6B;P9idP-6$G;-wU!GFJ=a1DsU;i;1;VT- z#9UTSGJ)^}>WriAF3FT3xD{;rl2MAYO>?Z$ggm?)KGwm;jpM3?mok|I=}mT7c_Ye^ z%rHgr*7A__VPckEraGJt4dD7ItNrQu0K}jc!mevqZQ$yo&H*3+Njl*ElpHwi& zbrPVYcJM2-0O$n52VOtp!_`(Y(-deofKu0QXb=@iqaCwHa(Jm+EOw?O+mD%wW#1nrY^0cO{@3#EuVKkX_^=mm|OfTr! z>OaM7c0YD2TKaO>mNSdZCk?qZcHY6yS^<*G6eckRA`5FV38_-hR1AMSqbVdkV+!xs zX6U{O&45PZQsozxokkD&j%FxfE*e2Kktk(Nz2Wz0*ACQk3xN7PUT*KHG1tmoTq*rzGWHUr z(fZ(dxNNV;Si8_hzI&|vkK@W##_7pJQ%tvn0lZFSoAv`}AMUmGtR36eM)Bbprr*(iMC+30y#)6P;53`|iT0nB zbz}D*j`Mwm<9uHMZ*{L)y{2dFy7j#q&f0kPrp;TnZtL5=W9P1O&fTrXVRWYkhte1B z&17?W{-T0WEbZGrJaTa;+}hUO5$TL}EeX=+@;>3;3gkP}EEik4Y`IlR5G9A~bh$lV zUsZKYZJobu70zqoRC#?4K&BkRj zS6hV1^`_pk9CJ?lGx5U;fE_>6dKN<7mAI!hPS6do%fnUU@YTTASYVgKJ$QBsdj-2O zX|JZiau4bw8B6vBNkThLcGYS)Z1f^DT{Q`1f)%W+%ePRLY!hCFT#+y#9MHSMx-&Vovjip60*`A>Wd;~W7iwr^azW?M|zNyeR$CH0897S|MJ zNn=k{`rrV9aSFeOhJ;d)p1~niglIA}LmAOaxXUReLmSOnfXiy1hMee)nhYo#b%-w* zSa3lo>ohpFfSMIBbHh+l1wG3$pe7}4utx0HG8v_^(<&;QX+vnEPCluC(ub>}rxfU6 zsK?R~*iA}>r9*9^o+Q&G^-zK=F!ZaqUxQRtQ9-Un8-`|!Bn4&<%oWpQAjso< z+PR32(u?c>`Bb{=6kmd=MDx0T`>$!=3 zW?RvEC0m^1wC)-Kr&?nsBlTmnji9-Y_2&y(Dm|>3c7Z&}&(<~VyJV;7IrPRuLJCQO{6l=9SNlb8}3UW-3L*l5w=^oSO%!Beyg2JEP>;x3e>KIj0_ZR|P_ zNDJ!#>jAw0@-p@_bBuV48M|6CrU>tV#$=?Yb9pS6qK*a<|I@UNDZ&u&sh)#nn4!IY zlty!dpUIz7(Xba|bcRY;1&KCk7#sl*`oU&Znsq~%TP zZ0Fg5n^B(R7ax-ngfIDMIDVsr_mH=WDd9>h^m0f7$VD)(R^dejR$#}eD+0~mqpofn z?T0PemhP}#HHOyeg)D@?CvLv5WwM_>Usq`_`G4%~|LHjVA1r(uOkQ|0!0&Kjk=)6_ zvQ(JETq}Uy4?&mwOsC){^4Aweuu$GXJ_Y$`AESN4qH7UiVh)7i!B8zwojJn3-_-j3{}vfCU7x11ZC;7gNp| zF(t&rUpOELSE4-atvf6q2;)fb^ow{-K9UpW!+Oxi+hNX<^>mw6`xdI)A_;C`M48WP z%=+2@`ea6v^{?UHzV^u8*r^rLDRQFF>{t!kGu6-ZNvkF$Uy747=gk&|k=}r^>)>W9 zq!X2d+wt7iA7vHur(n*>nS}m6hICpxd>rAIQu&kniA1 zeo zogX8Kb%%*%-YiCdym<~n>7n(h)j-w2?xGT>~0HE&zk zv?1drTl!|)Tl0n#I8&{GHRsAg=m4P)a*xjn%8)%p^FXi_U`~^jf4w$r-R&r*qMP*M zS{htzlu0nDp`juy`$4VPPea*fjTb$(JU;Z850W`Bt44NXSVjkfr!xNKecgt3bSIPK zr!8f+===MI3VlNviyKUj$6y+Jy`twexSf&)@&{&^XImY(l24oyMq_k1rIC+T!q{~} zKD`s0!b-6A(3sHJ_W|tdYde+WDwBP>@%(AjPd<2icNxXBY1lzs#fhT!v-?a;mRVi-{p~;S0h|C_`r+W8?ww2l1Ttdy6+nj=*2bG($`BVm%-a={t-d z2EfW|@~$cO^u0(wj(oJ{inx*-pMieN2FwA>2Q&ee0Gek}@7R1nG0Z6NX3=3GG()!F zX(zUv+dZ4t!k|w>bL6XCRWeXs11CuU3&k&l)_JnDkE6GtZ}TQg@$IoBoT)mFHVYC8 zmVv4aEQ~E22vl;ZOfQ9|hItqyRj6rAG!*)E`KC3i)~;PNnvW@>l1s!6b9t9jU;C$%}A&axBO^6z@O(z**Lajj*@WU_a$hBv`4Uin9dN`%qEsGrDY>w zPcn}`m=r_Z&@@pEp9$C(LuoKSv_))NU>M>l);u!g@RS>S%qf*5T^d_bOEkdpK<{97 z5@=wDVyZVe=`yr?RHhLMQi@oXbVg>(jh0nOQ_rfl3>g(oV7aIvXp~wgn3hOZ&6@?O zV~{0KAxUvgYIKrC=PC(JOVUGB1D&R1ZaeI79}d~i@5};+S8VFY?kP6CfiBhR7M~y5{*ikZ%#oJtqIjJ>#2Tn3Ceq-M6~8cXXIdk$^p9j;VWc+INC(E#UJU z1AcBZjJo5fs~JG{6vwZ^eYXw20{4_>mFaQBjHZ~LTRqo25Bc2M3iXDcLd-*53AEu= z0JZhg`pd`qsMVyJ2eTVN4GWj{U(@%Gy3Ru#VOCf7^)KRN36b<9Fbm=85CP zN7T=X1CgncA9u*u3uh6c2jIkunVtydq=FMrgAtAGGm4FkyguBhgR75Rr9;qnu^Ceo zAR-9(@;CifVD6{U{>yCbA_+=Towsu*?rF#2__??zX~XfeaZmip@c`~=J#d`76~y2F zRrAAljQg7WLJsxb44`r5_^r4nZ<-xnX~S>9y*>Z!<8Ycsd-`4Da9ZE?bQ;e#0I!em z`8NCuxF^p%PbYkd4JS`0$rGNw689vJ?6?B_)9?}0nXF2I6%c~*Vm~_t`5fkn)JP_n zH=>T+Xe-SNc}6&X2=}x$xc*5TtU&iorO5Fg5MD$%8q-&CrF_4_6=Fl^;ku(XTu~|6 zdQg=}OFT{IBv$_d!iOkBX&;=E*({rx$ACqEZ^p*(`!eu|Y`z z(<3~-t*44Eq3#<&R+z2bW|WVhF7gJ^8a$B>2F?meDIzcRnPh1z0AtU>+E%>x?DtF; zwZeiyOm`|c&)Tz6u<$f6+1F8?_MGqIO6z`nU92!#^#;H1#toKH1Zqjfk%$Ecp5pGC-wuY;AOe5hv)@=$-i2%vg6z7-3EbRmv!13nA* zUI48JS~D2{tsyQivg2@)g*qS);PZPC?je!|Y|reE)^ZUrzKsY7!v7U6VnH6JNTWy# zb0>V;>fb&P34sRZ83AKQ>l?v(m1oOBe!+of#M27LWo`@vau&(Wbr;GtA^$u83!^f_R}(mSgf9Sx zb#&HgfUo0piVCL$0{w_rj-lLQswbzl&`}{YoHR~c;b}IxD+?pvay7thNi{)Y*w%?0 zHcy(G7Qw0n9hx(O5x~WO0|5K;OMu&DUmoQ@YuR@MH0`qQwB@RvH-d=#X7K{FZa{wv z`f)$N2{>)~@B|@}9PgbJawIHPw)%z5p!-b_CwXDV8*TUlNGJTX>mPNL2+yJJ4WJnZ z%mwg0V%sN(FuxS}>5ur9bYkA_PB6qg8~y|`kj>b?d()>1Rb@eIElDURxxtKv5G_P# zwXxNk(eMfk9pDKE+Wf*fsAD;x3czt%V|JWmvK^=&x0L)VLRy4K1uoo$ElBYe91U`H*k`d1JIf9)(M?M3>bj?|hKDa#cEm>89VQnHJgMG$8G%w`rv z#BL3Qvaq9T9Kjun_*sOhx6_PPufdhZB8V&5w!D3N&_3dKj&B7{dP-c^Gvt*fhj=s{ zj-=aK(~ZLOt9dkN22tYxaLH5F-Z><MU5p)xBb-WEsw78pin0WO7KWO_sl_k}d}U6B<||MhT0nD- zlFBtHEh`jE2Rq21Qw`;SqFj0a2mZsA{6B$QrTl?RW?we&880s=OSHaTh?4y~}J;OsP0^dlF!E{t~4-6yI!{~}3Vrkea*;4iWX{bkE3AWdn)xyOK798mC@6dVxj)fx5>v?eYyZL2?{ z4vM~b16SgUH?97)!B8PN&%B7tCpmV`u0+~e2wVzbV7m_Rs{o_}6ED&}@fYYGmdR!w zgVO#%k>o63(F|!c&lvg4Ch@pNTK{7wZx~-V;6bhYf+Hx6LO#a8_ z+Rt}UiaMc*W`~gsAzFMoDkn4`Zp{YUi_qx)f|^VZ_oGLavo@0^)5JVPgxaSm1Lw6i zD{YbU2VjAjhwj2P%gr}N^0<<$x)Y2>ytatz_F$az^8z03Pa~J zpT`v8o1j6x_yMlOx3A&q#dT~!Dq$5x8ZYxFt8Dd|W*J@tqpe+S zp|)^aYg=1eds|0aq^+|p+Sb(`Y7e)!wzsvnw|BHh+B@5$?Oh$Aj&Mh7M_WgGM@L7b zqq8I0(G>|r!jaZUTckbG5s5@PBhg4#X9zDqwsy94ws&@PMmjq?qn%yRP&6EEjkZPG zqaD#mv@;rwc6FhNU8uebq`Oe83y(%8)SSYYvKU9@1!aX2?&5v^-(Wc6XVT$mocXxj zj{Cm?+yVH|;(h*xPep&QrA^1glOD$NP6R#&IHH%Zu*_HplMNB0%^229p@nR~Da*W_ zR^+ay+vLq@xQ^1G_w-B(8}Xd@j;EXD&9u=lO~(Bw#9}rD{O$$QYY*W{veY_{r5FM_ zfx*kyq_|oU#94JXoh@Y%#SYa%5bi;l#V8~GfBqA?Z@uFCLRFjev48l4+?YR^{)FyV zsOVRxoUjnkYrCJ|l~ssNLSI*bDM&upak6bV-r+L!Y>p?!;YkY@&VxFAK07_IrXOO6 zoIfg4`AxBfS9q5yv^`MZqe0PyN|SkHwunUAzUESTv3&9 z6|N*Z?Ow@;PodVzez9Jf;5?&#qBu#KEKRMM;hgE2EzT1!l=n)HIv$sv zmR^!xmR_lT)%$bl7t(9u8_qYS-^y=G?<()hA4>n>_@h|8aOsLoo3H!ISN{6IH8efcYLO>O;zMd9{X&)VJ% zn>Hu4J>UM$^cilCuWI7tNLTE^ul@3$yq(wI@SxkbbVVwC-Hr8n|FiGDw>$p(KOOJe ze#f1G;KHUIci(gLtM@(d;5VLp`iHKn>Pa(WXZCEp|ABw_$9vpUr_Gta;>_Q^^WO32 zUyzl#^A|L=MPutXY~0efW9K=$_gpZL&{BJi;Y%;S`o4!AeeAhok35>wpSkIRIR~5$ zxy6xkh`~Vl&`d|TZiYP1JIlGmxkj#CTz<$kPo5_?dD^Qstv=Z4ZSZ-fEbZxXBs|_w z1AYQ~x>H;kmCtepWuM#YUa2gUtGy9N%sI_1SG%|LcDB{DxdR^G!3EpSTH;yUFm1t% ziIcsXP{Ep-scxTZy=S4fRJCfwV%Jiq&$ZPhI{gl3`I`8w^&VgO{tM>xRQX&rXT)5- zNV7b-{M}{AzUuW}-`bw(>pguny>4Im4{Loh9qW2K9km{xtIO>>7@6u`>X@-ptZS_~ zd}pduRsP}C8xu80LjH#99y+w{=ywlwxfjcOTnl__eNE0Y4n20Bc9z`bu3t$kaodNU zBR^m4z4x~V+v>!bu3Fi1@Jm<8d!027uiJm)z&dYnS@{n>!;_!1_Tq`v6RUT5rEO!Q^)aV-@Yv!*|Fit>i#EzWSvp+5X5;em z-!F5C@($#F4_I@jcx zv+3aW>X~Ru#8Zo`UU&JY^LYAz8O_htEbiYYpd&IzhlCLGrSGr zWO<4>)iKRIU7R7!ZcrRc94+`svXCPzwTcf&Uy~k^ANKr*^hf8PrH>rPz26ufx#rq? zL%Yto=1bSl`0urKXKnoBp8~-%_nhDV>m%2G`Gy<6_V|-eJ^#XwfAXuhesf%q8AEr* zmM-tzaQ=}mBk@~LKJ~&+e)iH^zrkc71IuOAeQ>x!jY7X*S2Jo=qyfArEX zUcY1IZMTQ6oBiKj`PuPJn|Gh*_SE?o2H$-zr*|$tb5+mvH}nmbUi|T~mw)+Bzy0XA zp!Cl<^tya#jc2;-sz3Pk+VaEB+1`WG9aBA`9F*H-w?lNh-1WXKbrak>+zxq$&+G6w z+ztslO|^_Kmb%2+NzP5~>F!-_$u+rpi@e&=0`XMus;iF4Gw1g!S^2{GJ@W@-$bKqx^Lw1;b}M%J+GeIqDqC z+)>XG=b_{EQ#`@?7Dr=UV_o@6@}b+NR!zF{W@pg36r482TYhFvvAX>8Y1Pj1acBAU z>VLc2(dj+7XJYvYPx+@#-;|{epDXHFiw~<7t7bWN%jbH_ho{W&HF!75<*Qu}-&Z|Z z4j+{dzP13LQ+1Z__aFSgEh>v$NWE4rKjWD0sH-`p47X%?KfN9RF+OF3d4945GMn~J zj_<)e?H{ABgqp97oob);Rfe`aQ+$h2ookNv#XVX+3z*qvt)5dY1Z$5qgi@zpk>w{2Li%JO5`iY z2O@tK-;9X9#?E;)Z+1Rht9Ava9PJ9tP}l!%*3peC+tn@aUwCxuX1#IS-A^CgCcLEf zX)hn`6JBfFF1+#Pjz@m2?t15~#&eIoee_&Kc=z1*#mjdKc^sv;K#7y^pSZp%G|4Y& z;8#f!<+E~6&yk2pNEPAoEI+r+>c@|F*l};3pJ>W~XPns#lsJQGw7N0Z?-?{9< z9xO{(2jVQrf$zZrcOrv0QEI>rjohH^5#0`-G)r8HvehWr1oEJYFa3(LTdHDIsY$3* zB7BC_h4%4UW{T@YSp;#>BW@KXceN)jO5Q4WuQVO>M6t70M2*fWah_L9$)XF5lBPimroKy zv%_)-xKnJx_psxw@K3`)QAf_Q>y}w5c(!b3&qtKc?mxl;1Ppj8>r&@tLXP)$s@i?!zMzZ z^ZUsJ6n`z=;uIX{rQGC@#lHc4LE7S2TNRcMh>^NQ=%>#S22HoP+%eB7dRE{^N7}vE zoWy0z{S|o+-m;EeQc>G7Jp7)$Q>}?pgB94xv+S^@z1%gHx;n)p|zJnH29qndLG@ zz@2pq1LgP4vzwV%Vx$*ycnbc7Hvu03=D~j30Dwx*>}Zl71f=_Z3v%UO0B-|+2l(y= G|NjFVwNqgL literal 0 HcmV?d00001 From ea64ce4d93ba2fc9586d237518e211927e577052 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 16 Feb 2024 13:10:08 +0100 Subject: [PATCH 07/44] Add callback entrypoint function to vm --- packages/vm/src/calls.rs | 49 +++++++++++++++++++++++++++++++++++++++- packages/vm/src/lib.rs | 3 ++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/packages/vm/src/calls.rs b/packages/vm/src/calls.rs index c56d738f5b..eedd0bccdf 100644 --- a/packages/vm/src/calls.rs +++ b/packages/vm/src/calls.rs @@ -1,7 +1,10 @@ use serde::de::DeserializeOwned; use wasmer::Value; -use cosmwasm_std::{ContractResult, CustomMsg, Env, MessageInfo, QueryResponse, Reply, Response}; +use cosmwasm_std::{ + ContractResult, CustomMsg, Env, IbcSourceChainCallbackMsg, MessageInfo, QueryResponse, Reply, + Response, +}; #[cfg(feature = "stargate")] use cosmwasm_std::{ Ibc3ChannelOpenResponse, IbcBasicResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, @@ -54,6 +57,8 @@ mod read_limits { /// Max length (in bytes) of the result data from a ibc_packet_timeout call. #[cfg(feature = "stargate")] pub const RESULT_IBC_PACKET_TIMEOUT: usize = 64 * MI; + /// Max length (in bytes) of the result data from a ibc_source_chain_callback call. + pub const RESULT_IBC_SOURCE_CHAIN_CALLBACK: usize = 64 * MI; } /// The limits for the JSON deserialization. @@ -93,6 +98,8 @@ mod deserialization_limits { /// Max length (in bytes) of the result data from a ibc_packet_timeout call. #[cfg(feature = "stargate")] pub const RESULT_IBC_PACKET_TIMEOUT: usize = 256 * KI; + /// Max length (in bytes) of the result data from a ibc_source_chain_callback call. + pub const RESULT_IBC_SOURCE_CHAIN_CALLBACK: usize = 256 * KI; } pub fn call_instantiate( @@ -327,6 +334,27 @@ where Ok(result) } +pub fn call_ibc_source_chain_callback( + instance: &mut Instance, + env: &Env, + msg: &IbcSourceChainCallbackMsg, +) -> VmResult>> +where + A: BackendApi + 'static, + S: Storage + 'static, + Q: Querier + 'static, + U: DeserializeOwned + CustomMsg, +{ + let env = to_vec(env)?; + let msg = to_vec(msg)?; + let data = call_ibc_source_chain_callback_raw(instance, &env, &msg)?; + let result = from_slice( + &data, + deserialization_limits::RESULT_IBC_SOURCE_CHAIN_CALLBACK, + )?; + Ok(result) +} + /// Calls Wasm export "instantiate" and returns raw data from the contract. /// The result is length limited to prevent abuse but otherwise unchecked. pub fn call_instantiate_raw( @@ -560,6 +588,25 @@ where ) } +pub fn call_ibc_source_chain_callback_raw( + instance: &mut Instance, + env: &[u8], + msg: &[u8], +) -> VmResult> +where + A: BackendApi + 'static, + S: Storage + 'static, + Q: Querier + 'static, +{ + instance.set_storage_readonly(false); + call_raw( + instance, + "ibc_source_chain_callback", + &[env, msg], + read_limits::RESULT_IBC_SOURCE_CHAIN_CALLBACK, + ) +} + /// Calls a function with the given arguments. /// The exported function must return exactly one result (an offset to the result Region). pub(crate) fn call_raw( diff --git a/packages/vm/src/lib.rs b/packages/vm/src/lib.rs index 7fe798e7ec..ede4815f09 100644 --- a/packages/vm/src/lib.rs +++ b/packages/vm/src/lib.rs @@ -27,7 +27,8 @@ pub use crate::cache::{ AnalysisReport, Cache, CacheOptions, Metrics, PerModuleMetrics, PinnedMetrics, Stats, }; pub use crate::calls::{ - call_execute, call_execute_raw, call_instantiate, call_instantiate_raw, call_migrate, + call_execute, call_execute_raw, call_ibc_source_chain_callback, + call_ibc_source_chain_callback_raw, call_instantiate, call_instantiate_raw, call_migrate, call_migrate_raw, call_query, call_query_raw, call_reply, call_reply_raw, call_sudo, call_sudo_raw, }; From a018d7e4a07c2dc3e1fff20aa3fa893157e71e3a Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Mon, 19 Feb 2024 13:04:00 +0100 Subject: [PATCH 08/44] Add source callback test --- packages/vm/src/calls.rs | 56 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/packages/vm/src/calls.rs b/packages/vm/src/calls.rs index eedd0bccdf..1718d62dc6 100644 --- a/packages/vm/src/calls.rs +++ b/packages/vm/src/calls.rs @@ -915,7 +915,8 @@ mod tests { use cosmwasm_std::{ Event, IbcAcknowledgement, IbcOrder, ReplyOn, SubMsgResponse, SubMsgResult, }; - static CONTRACT: &[u8] = include_bytes!("../testdata/ibc_reflect.wasm"); + const CONTRACT: &[u8] = include_bytes!("../testdata/ibc_reflect.wasm"); + const IBC_CALLBACKS: &[u8] = include_bytes!("../testdata/ibc_callbacks.wasm"); const IBC_VERSION: &str = "ibc-reflect-v1"; fn setup( instance: &mut Instance, @@ -1017,5 +1018,58 @@ mod tests { .unwrap() .unwrap(); } + #[test] + fn call_ibc_source_chain_callback_works() { + let mut instance = mock_instance(IBC_CALLBACKS, &[]); + + // init + let creator = instance.api().addr_make("creator"); + let info = mock_info(&creator, &[]); + call_instantiate::<_, _, _, Empty>(&mut instance, &mock_env(), &info, br#"{}"#) + .unwrap() + .unwrap(); + + /// Response type for the `callback_stats` query + #[derive(serde::Serialize, serde::Deserialize)] + struct CallbackStats { + pub ibc_ack_callbacks: Vec, + pub ibc_timeout_callbacks: Vec, + } + + // send ack callback + let ack = IbcAcknowledgement::new(br#"{}"#); + let msg = IbcSourceChainCallbackMsg::Acknowledgement( + mock_ibc_packet_ack(CHANNEL_ID, br#"{}"#, ack).unwrap(), + ); + call_ibc_source_chain_callback::<_, _, _, Empty>(&mut instance, &mock_env(), &msg) + .unwrap() + .unwrap(); + // query the CallbackStats + let stats: CallbackStats = serde_json::from_slice( + &call_query::<_, _, _>(&mut instance, &mock_env(), br#"{"callback_stats":{}}"#) + .unwrap() + .unwrap(), + ) + .unwrap(); + assert_eq!(1, stats.ibc_ack_callbacks.len()); + assert_eq!(0, stats.ibc_timeout_callbacks.len()); + + // send timeout callback + let msg = IbcSourceChainCallbackMsg::Timeout( + mock_ibc_packet_timeout(CHANNEL_ID, br#"{}"#).unwrap(), + ); + call_ibc_source_chain_callback::<_, _, _, Empty>(&mut instance, &mock_env(), &msg) + .unwrap() + .unwrap(); + // query the CallbackStats + let stats: CallbackStats = serde_json::from_slice( + &call_query::<_, _, _>(&mut instance, &mock_env(), br#"{"callback_stats":{}}"#) + .unwrap() + .unwrap(), + ) + .unwrap(); + assert_eq!(1, stats.ibc_ack_callbacks.len()); + assert_eq!(1, stats.ibc_timeout_callbacks.len()); + } } } From 62a088458e90302ffff8025b99395b70e11d8cd8 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Mon, 19 Feb 2024 13:22:50 +0100 Subject: [PATCH 09/44] Fix import --- packages/vm/src/calls.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/vm/src/calls.rs b/packages/vm/src/calls.rs index 1718d62dc6..b8fbd46720 100644 --- a/packages/vm/src/calls.rs +++ b/packages/vm/src/calls.rs @@ -2,14 +2,13 @@ use serde::de::DeserializeOwned; use wasmer::Value; use cosmwasm_std::{ - ContractResult, CustomMsg, Env, IbcSourceChainCallbackMsg, MessageInfo, QueryResponse, Reply, - Response, + ContractResult, CustomMsg, Env, IbcBasicResponse, IbcSourceChainCallbackMsg, MessageInfo, + QueryResponse, Reply, Response, }; #[cfg(feature = "stargate")] use cosmwasm_std::{ - Ibc3ChannelOpenResponse, IbcBasicResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, - IbcChannelOpenMsg, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, - IbcReceiveResponse, + Ibc3ChannelOpenResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, + IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, }; use crate::backend::{BackendApi, Querier, Storage}; From 387812eadeb48a3b8f4bffab23642bd1ec0b440e Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Wed, 21 Feb 2024 17:19:15 +0100 Subject: [PATCH 10/44] Omit src_callback and dst_callback of None --- packages/std/src/ibc/callbacks.rs | 43 +++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/packages/std/src/ibc/callbacks.rs b/packages/std/src/ibc/callbacks.rs index 01e2598cc7..0d8ca6382a 100644 --- a/packages/std/src/ibc/callbacks.rs +++ b/packages/std/src/ibc/callbacks.rs @@ -38,7 +38,9 @@ use crate::{Addr, IbcPacketAckMsg, IbcPacketTimeoutMsg, Uint64}; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct IbcCallbackData { // using private fields to force use of the constructors + #[serde(skip_serializing_if = "Option::is_none")] src_callback: Option, + #[serde(skip_serializing_if = "Option::is_none")] dst_callback: Option, } @@ -111,3 +113,44 @@ pub enum IbcSourceChainCallbackMsg { Acknowledgement(IbcPacketAckMsg), Timeout(IbcPacketTimeoutMsg), } + +#[cfg(test)] +mod tests { + use crate::to_json_string; + + use super::*; + + #[test] + fn ibc_callback_data_serialization() { + let mut data = IbcCallbackData::both( + IbcSrcCallback { + address: Addr::unchecked("src_address"), + gas_limit: Some(123u64.into()), + }, + IbcDstCallback { + address: "dst_address".to_string(), + gas_limit: Some(1234u64.into()), + }, + ); + + // both + let json = to_json_string(&data).unwrap(); + assert_eq!( + json, + r#"{"src_callback":{"address":"src_address","gas_limit":"123"},"dst_callback":{"address":"dst_address","gas_limit":"1234"}}"# + ); + + // dst only, without gas limit + let mut src = data.src_callback.take().unwrap(); + data.dst_callback.as_mut().unwrap().gas_limit = None; + let json = to_json_string(&data).unwrap(); + assert_eq!(json, r#"{"dst_callback":{"address":"dst_address"}}"#); + + // source only, without gas limit + src.gas_limit = None; + data.src_callback = Some(src); + data.dst_callback = None; + let json = to_json_string(&data).unwrap(); + assert_eq!(json, r#"{"src_callback":{"address":"src_address"}}"#); + } +} From 24f90b53f07aa38fd705c607d037426e49af8eab Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Thu, 22 Feb 2024 12:25:15 +0100 Subject: [PATCH 11/44] Update ibc-callbacks schema and add to circleci --- .circleci/config.yml | 28 ++++++++++++++++++ contracts/ibc-callbacks/Cargo.lock | 29 +++++++++---------- .../ibc-callbacks/schema/ibc-callbacks.json | 17 ++++++++++- .../ibc-callbacks/schema/raw/execute.json | 17 ++++++++++- 4 files changed, 74 insertions(+), 17 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a21a30f6a5..f38099bd54 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -77,6 +77,7 @@ workflows: - contract_empty # - contract_floaty # This contract needs nightly Rust to compile - contract_hackatom + - contract_ibc_callbacks - contract_ibc_reflect - contract_ibc_reflect_send - contract_queue @@ -653,6 +654,33 @@ jobs: - target/wasm32-unknown-unknown/release/deps key: cargocache-v2-contract_hackatom-rust:1.73-{{ checksum "Cargo.lock" }} + contract_ibc_callbacks: + docker: + - image: rust:1.70.0 + environment: + RUST_BACKTRACE: 1 + working_directory: ~/cosmwasm/contracts/ibc-callbacks + steps: + - checkout: + path: ~/cosmwasm + - run: + name: Version information + command: rustc --version; cargo --version; rustup --version + - restore_cache: + keys: + - cargocache-v2-contract_ibc_callbacks-rust:1.70.0-{{ checksum "Cargo.lock" }} + - check_contract + - save_cache: + paths: + - /usr/local/cargo/registry + - target/debug/.fingerprint + - target/debug/build + - target/debug/deps + - target/wasm32-unknown-unknown/release/.fingerprint + - target/wasm32-unknown-unknown/release/build + - target/wasm32-unknown-unknown/release/deps + key: cargocache-v2-contract_ibc_callbacks-rust:1.70.0-{{ checksum "Cargo.lock" }} + contract_ibc_reflect: docker: - image: rust:1.73 diff --git a/contracts/ibc-callbacks/Cargo.lock b/contracts/ibc-callbacks/Cargo.lock index 954bd7a9c6..1e2dc47adf 100644 --- a/contracts/ibc-callbacks/Cargo.lock +++ b/contracts/ibc-callbacks/Cargo.lock @@ -188,10 +188,9 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "2.0.0-beta.1" +version = "2.0.0-rc.1" dependencies = [ "digest 0.10.7", - "ecdsa", "ed25519-zebra", "k256", "rand_core 0.6.4", @@ -200,14 +199,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "2.0.0-beta.1" +version = "2.0.0-rc.1" dependencies = [ "syn 1.0.109", ] [[package]] name = "cosmwasm-schema" -version = "2.0.0-beta.1" +version = "2.0.0-rc.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -218,7 +217,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "2.0.0-beta.1" +version = "2.0.0-rc.1" dependencies = [ "proc-macro2", "quote", @@ -227,7 +226,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "2.0.0-beta.1" +version = "2.0.0-rc.1" dependencies = [ "base64", "bech32", @@ -247,7 +246,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "2.0.0-beta.1" +version = "2.0.0-rc.1" dependencies = [ "bech32", "bitflags", @@ -626,9 +625,9 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "elliptic-curve" -version = "0.13.5" +version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", "crypto-bigint", @@ -884,9 +883,9 @@ dependencies = [ [[package]] name = "k256" -version = "0.13.1" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" dependencies = [ "cfg-if", "ecdsa", @@ -1021,9 +1020,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" @@ -1996,6 +1995,6 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "zeroize" -version = "1.5.7" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/contracts/ibc-callbacks/schema/ibc-callbacks.json b/contracts/ibc-callbacks/schema/ibc-callbacks.json index 1b511c102b..2dce6a9daf 100644 --- a/contracts/ibc-callbacks/schema/ibc-callbacks.json +++ b/contracts/ibc-callbacks/schema/ibc-callbacks.json @@ -14,6 +14,7 @@ "type": "object", "required": [ "channel_id", + "timeout_seconds", "to_address" ], "properties": { @@ -21,12 +22,26 @@ "description": "The channel to send the packet through", "type": "string" }, + "timeout_seconds": { + "description": "The amount of seconds from now the transfer should timeout at", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, "to_address": { "description": "Address on the destination chain", "type": "string" } }, - "additionalProperties": false + "additionalProperties": false, + "definitions": { + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + } + } }, "query": { "$schema": "http://json-schema.org/draft-07/schema#", diff --git a/contracts/ibc-callbacks/schema/raw/execute.json b/contracts/ibc-callbacks/schema/raw/execute.json index 8fef4af7fa..518744082a 100644 --- a/contracts/ibc-callbacks/schema/raw/execute.json +++ b/contracts/ibc-callbacks/schema/raw/execute.json @@ -4,6 +4,7 @@ "type": "object", "required": [ "channel_id", + "timeout_seconds", "to_address" ], "properties": { @@ -11,10 +12,24 @@ "description": "The channel to send the packet through", "type": "string" }, + "timeout_seconds": { + "description": "The amount of seconds from now the transfer should timeout at", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, "to_address": { "description": "Address on the destination chain", "type": "string" } }, - "additionalProperties": false + "additionalProperties": false, + "definitions": { + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + } + } } From 7070a1a0a428c26435d7f4c244ad7684a86258cc Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Thu, 22 Feb 2024 16:30:28 +0100 Subject: [PATCH 12/44] Remove redundant clone --- contracts/ibc-callbacks/src/contract.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/ibc-callbacks/src/contract.rs b/contracts/ibc-callbacks/src/contract.rs index 53ac6ac8ff..eeddfaa9de 100644 --- a/contracts/ibc-callbacks/src/contract.rs +++ b/contracts/ibc-callbacks/src/contract.rs @@ -35,10 +35,10 @@ pub fn execute( timeout: IbcTimeout::with_timestamp( env.block.time.plus_seconds(msg.timeout_seconds.u64()), ), - channel_id: msg.channel_id.clone(), + channel_id: msg.channel_id, amount: coin.clone(), memo: Some(to_json_string(&IbcCallbackData::source(IbcSrcCallback { - address: env.contract.address.clone(), + address: env.contract.address, gas_limit: None, }))?), }, From 37ecc156124875662f0782031f59f7295a1db015 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 23 Feb 2024 16:33:23 +0100 Subject: [PATCH 13/44] Add integration test stub --- contracts/ibc-callbacks/tests/integration.rs | 30 ++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 contracts/ibc-callbacks/tests/integration.rs diff --git a/contracts/ibc-callbacks/tests/integration.rs b/contracts/ibc-callbacks/tests/integration.rs new file mode 100644 index 0000000000..7d7ebe9f4b --- /dev/null +++ b/contracts/ibc-callbacks/tests/integration.rs @@ -0,0 +1,30 @@ +//! This integration test tries to run and call the generated wasm. +//! It depends on a Wasm build being available, which you can create with `cargo wasm`. +//! Then running `cargo integration-test` will validate we can properly call into that generated Wasm. +//! +//! You can easily convert unit tests to integration tests. +//! 1. First copy them over verbatum, +//! 2. Then change +//! let mut deps = mock_dependencies(20, &[]); +//! to +//! let mut deps = mock_instance(WASM, &[]); +//! 3. If you access raw storage, where ever you see something like: +//! deps.storage.get(CONFIG_KEY).expect("no data stored"); +//! replace it with: +//! deps.with_storage(|store| { +//! let data = store.get(CONFIG_KEY).expect("no data stored"); +//! //... +//! }); +//! 4. Anywhere you see query(&deps, ...) you must replace it with query(&mut deps, ...) + +use cosmwasm_vm::testing::mock_instance; + +// This line will test the output of cargo wasm +static WASM: &[u8] = include_bytes!("../target/wasm32-unknown-unknown/release/ibc_callbacks.wasm"); +// You can uncomment this line instead to test productionified build from rust-optimizer +// static WASM: &[u8] = include_bytes!("../../artifacts/ibc_callbacks.wasm"); + +#[test] +fn validation_succeeds() { + mock_instance(WASM, &[]); +} From ebd684bffb8999014cf0b624ca84073bd5a31f4a Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 2 Apr 2024 17:44:37 +0200 Subject: [PATCH 14/44] Add ibc destination chain callback --- contracts/ibc-callbacks/src/contract.rs | 25 ++++++++++-- contracts/ibc-callbacks/src/state.rs | 6 +-- packages/std/src/exports.rs | 51 ++++++++++++++++++++++++- packages/std/src/ibc/callbacks.rs | 31 ++++++++++----- packages/std/src/lib.rs | 11 +++--- packages/vm/src/calls.rs | 48 ++++++++++++++++++++++- packages/vm/src/lib.rs | 3 +- 7 files changed, 150 insertions(+), 25 deletions(-) diff --git a/contracts/ibc-callbacks/src/contract.rs b/contracts/ibc-callbacks/src/contract.rs index eeddfaa9de..5822e49876 100644 --- a/contracts/ibc-callbacks/src/contract.rs +++ b/contracts/ibc-callbacks/src/contract.rs @@ -1,7 +1,8 @@ use cosmwasm_std::{ entry_point, to_json_binary, to_json_string, Binary, Deps, DepsMut, Empty, Env, - IbcBasicResponse, IbcCallbackData, IbcMsg, IbcSourceChainCallbackMsg, IbcSrcCallback, - IbcTimeout, MessageInfo, Response, StdError, StdResult, + IbcBasicResponse, IbcCallbackData, IbcDestinationChainCallbackMsg, IbcDstCallback, IbcMsg, + IbcPacketReceiveMsg, IbcSourceChainCallbackMsg, IbcSrcCallback, IbcTimeout, MessageInfo, + Response, StdError, StdResult, }; use crate::msg::{ExecuteMsg, QueryMsg}; @@ -73,11 +74,11 @@ pub fn ibc_source_chain_callback( match msg { IbcSourceChainCallbackMsg::Acknowledgement(ack) => { - // increment the counter + // save the ack counts.ibc_ack_callbacks.push(ack); } IbcSourceChainCallbackMsg::Timeout(timeout) => { - // increment the counter + // save the timeout counts.ibc_timeout_callbacks.push(timeout); } } @@ -86,3 +87,19 @@ pub fn ibc_source_chain_callback( Ok(IbcBasicResponse::new().add_attribute("action", "ibc_source_chain_callback")) } + +#[entry_point] +pub fn ibc_destination_chain_callback( + deps: DepsMut, + _env: Env, + msg: IbcDestinationChainCallbackMsg, +) -> StdResult { + let mut counts = load_stats(deps.storage)?; + + // save the receive + counts.ibc_receive_callback.push(msg); + + save_stats(deps.storage, &counts)?; + + Ok(IbcBasicResponse::new().add_attribute("action", "ibc_destination_chain_callback")) +} diff --git a/contracts/ibc-callbacks/src/state.rs b/contracts/ibc-callbacks/src/state.rs index 1ba645cb62..5ae360bdb5 100644 --- a/contracts/ibc-callbacks/src/state.rs +++ b/contracts/ibc-callbacks/src/state.rs @@ -2,8 +2,8 @@ use std::any::type_name; use cosmwasm_schema::cw_serde; use cosmwasm_std::{ - from_json, storage_keys::to_length_prefixed, to_json_vec, IbcPacketAckMsg, IbcPacketTimeoutMsg, - StdError, StdResult, Storage, + from_json, storage_keys::to_length_prefixed, to_json_vec, IbcPacketAckMsg, IbcPacketReceiveMsg, + IbcPacketTimeoutMsg, StdError, StdResult, Storage, }; use serde::{de::DeserializeOwned, Serialize}; @@ -15,7 +15,7 @@ pub const KEY_STATS: &[u8] = b"counts"; pub struct CallbackStats { pub ibc_ack_callbacks: Vec, pub ibc_timeout_callbacks: Vec, - // pub ibc_receive_callback: u32, + pub ibc_receive_callback: Vec, } pub fn load_stats(storage: &dyn Storage) -> StdResult { diff --git a/packages/std/src/exports.rs b/packages/std/src/exports.rs index cb4085c8ad..a1c4f42813 100644 --- a/packages/std/src/exports.rs +++ b/packages/std/src/exports.rs @@ -13,7 +13,7 @@ use core::marker::PhantomData; use serde::de::DeserializeOwned; use crate::deps::OwnedDeps; -use crate::ibc::{IbcBasicResponse, IbcSourceChainCallbackMsg}; +use crate::ibc::{IbcBasicResponse, IbcDestinationChainCallbackMsg, IbcSourceChainCallbackMsg}; #[cfg(feature = "stargate")] use crate::ibc::{ IbcChannelCloseMsg, IbcChannelConnectMsg, IbcPacketAckMsg, IbcPacketReceiveMsg, @@ -472,6 +472,31 @@ where Region::from_vec(v).to_heap_ptr() as u32 } +pub fn do_ibc_destination_chain_callback( + contract_fn: &dyn Fn( + DepsMut, + Env, + IbcDestinationChainCallbackMsg, + ) -> Result, E>, + env_ptr: u32, + msg_ptr: u32, +) -> u32 +where + Q: CustomQuery, + C: CustomMsg, + E: ToString, +{ + #[cfg(feature = "abort")] + install_panic_handler(); + let res = _do_ibc_destination_chain_callback( + contract_fn, + env_ptr as *mut Region, + msg_ptr as *mut Region, + ); + let v = to_json_vec(&res).unwrap(); + Region::from_vec(v).to_heap_ptr() as u32 +} + fn _do_instantiate( instantiate_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result, E>, env_ptr: *mut Region, @@ -750,6 +775,30 @@ where contract_fn(deps.as_mut(), env, msg).into() } +fn _do_ibc_destination_chain_callback( + contract_fn: &dyn Fn( + DepsMut, + Env, + IbcDestinationChainCallbackMsg, + ) -> Result, E>, + env_ptr: *mut Region, + msg_ptr: *mut Region, +) -> ContractResult> +where + Q: CustomQuery, + C: CustomMsg, + E: ToString, +{ + let env: Vec = unsafe { Region::from_heap_ptr(env_ptr).into_vec() }; + let msg: Vec = unsafe { Region::from_heap_ptr(msg_ptr).into_vec() }; + + let env: Env = try_into_contract_result!(from_json(env)); + let msg: IbcDestinationChainCallbackMsg = try_into_contract_result!(from_json(msg)); + + let mut deps = make_dependencies(); + contract_fn(deps.as_mut(), env, msg).into() +} + /// Makes all bridges to external dependencies (i.e. Wasm imports) that are injected by the VM pub(crate) fn make_dependencies() -> OwnedDeps where diff --git a/packages/std/src/ibc/callbacks.rs b/packages/std/src/ibc/callbacks.rs index 0d8ca6382a..6ed0e23014 100644 --- a/packages/std/src/ibc/callbacks.rs +++ b/packages/std/src/ibc/callbacks.rs @@ -4,7 +4,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use crate::{Addr, IbcPacketAckMsg, IbcPacketTimeoutMsg, Uint64}; +use crate::{Addr, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, Uint64}; /// This is just a type representing the data that has to be sent with the IBC message to receive /// callbacks. It should be serialized to JSON and sent with the IBC message. @@ -46,8 +46,6 @@ pub struct IbcCallbackData { impl IbcCallbackData { /// Use this if you want to execute callbacks on both the source and destination chain. - /// - /// In the first prototype, we only support receiving callbacks on the source chain. pub fn both(src_callback: IbcSrcCallback, dst_callback: IbcDstCallback) -> Self { IbcCallbackData { src_callback: Some(src_callback), @@ -64,8 +62,6 @@ impl IbcCallbackData { } /// Use this if you want to execute callbacks on the destination chain, but not the source chain. - /// - /// In the first prototype, we only support receiving callbacks on the source chain. pub fn destination(dst_callback: IbcDstCallback) -> Self { IbcCallbackData { src_callback: None, @@ -93,11 +89,11 @@ pub struct IbcDstCallback { pub gas_limit: Option, } -/// The type of IBC callback that is being called. +/// The type of IBC source chain callback that is being called. /// -/// IBC callbacks are needed for cases where your contract triggers the sending of an IBC packet -/// through some other message (i.e. not through [`IbcMsg::SendPacket`]) and needs to know whether -/// or not the packet was successfully received on the other chain. +/// IBC source chain callbacks are needed for cases where your contract triggers the sending of an +/// IBC packet through some other message (i.e. not through [`IbcMsg::SendPacket`]) and needs to +/// know whether or not the packet was successfully received on the other chain. /// A prominent example is the [`IbcMsg::Transfer`] message. Without callbacks, you cannot know /// whether the transfer was successful or not. /// @@ -114,6 +110,23 @@ pub enum IbcSourceChainCallbackMsg { Timeout(IbcPacketTimeoutMsg), } +/// The message type of the IBC destination chain callback. +/// This is just an alias for [`IbcPacketReceiveMsg`] to add some documentation. +/// +/// The IBC destination chain callback is needed for cases where someone triggers the sending of an +/// IBC packet through some other message (i.e. not through [`IbcMsg::SendPacket`]) and +/// your contract needs to know that it received this. +/// A prominent example is the [`IbcMsg::Transfer`] message. Without callbacks, you cannot know +/// that someone sent you IBC coins. +/// +/// Note that there are some prerequisites that need to be fulfilled to receive source chain callbacks: +/// - The contract must implement the `ibc_destination_chain_callback` entrypoint. +/// - The module that receives the packet must be wrapped by an `IBCMiddleware` +/// (i.e. the destination chain needs to support callbacks for the message you are being sent). +/// - You have to add json-encoded [`IbcCallbackData`] to a specific field of the message. +/// For `IbcMsg::Transfer`, this is the `memo` field. +pub type IbcDestinationChainCallbackMsg = IbcPacketReceiveMsg; + #[cfg(test)] mod tests { use crate::to_json_string; diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index d779466c74..d4e322776b 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -41,9 +41,10 @@ pub use crate::deps::{Deps, DepsMut, OwnedDeps}; pub use crate::ibc::IbcChannelOpenResponse; pub use crate::ibc::{ Ibc3ChannelOpenResponse, IbcAcknowledgement, IbcBasicResponse, IbcCallbackData, IbcChannel, - IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, IbcDstCallback, IbcEndpoint, - IbcMsg, IbcOrder, IbcPacket, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, - IbcReceiveResponse, IbcSourceChainCallbackMsg, IbcSrcCallback, IbcTimeout, IbcTimeoutBlock, + IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, IbcDestinationChainCallbackMsg, + IbcDstCallback, IbcEndpoint, IbcMsg, IbcOrder, IbcPacket, IbcPacketAckMsg, IbcPacketReceiveMsg, + IbcPacketTimeoutMsg, IbcReceiveResponse, IbcSourceChainCallbackMsg, IbcSrcCallback, IbcTimeout, + IbcTimeoutBlock, }; #[cfg(feature = "iterator")] pub use crate::iterator::{Order, Record}; @@ -91,8 +92,8 @@ mod memory; // Used by exports and imports only. This assumes pointers are 32 bi #[cfg(target_arch = "wasm32")] pub use crate::exports::{ - do_execute, do_ibc_source_chain_callback, do_instantiate, do_migrate, do_query, do_reply, - do_sudo, + do_execute, do_ibc_destination_chain_callback, do_ibc_source_chain_callback, do_instantiate, + do_migrate, do_query, do_reply, do_sudo, }; #[cfg(all(feature = "stargate", target_arch = "wasm32"))] pub use crate::exports::{ diff --git a/packages/vm/src/calls.rs b/packages/vm/src/calls.rs index b8fbd46720..2f21ccc130 100644 --- a/packages/vm/src/calls.rs +++ b/packages/vm/src/calls.rs @@ -2,8 +2,8 @@ use serde::de::DeserializeOwned; use wasmer::Value; use cosmwasm_std::{ - ContractResult, CustomMsg, Env, IbcBasicResponse, IbcSourceChainCallbackMsg, MessageInfo, - QueryResponse, Reply, Response, + ContractResult, CustomMsg, Env, IbcBasicResponse, IbcDestinationChainCallbackMsg, + IbcSourceChainCallbackMsg, MessageInfo, QueryResponse, Reply, Response, }; #[cfg(feature = "stargate")] use cosmwasm_std::{ @@ -58,6 +58,8 @@ mod read_limits { pub const RESULT_IBC_PACKET_TIMEOUT: usize = 64 * MI; /// Max length (in bytes) of the result data from a ibc_source_chain_callback call. pub const RESULT_IBC_SOURCE_CHAIN_CALLBACK: usize = 64 * MI; + /// Max length (in bytes) of the result data from a ibc_destination_chain_callback call. + pub const RESULT_IBC_DESTINATION_CHAIN_CALLBACK: usize = 64 * MI; } /// The limits for the JSON deserialization. @@ -99,6 +101,8 @@ mod deserialization_limits { pub const RESULT_IBC_PACKET_TIMEOUT: usize = 256 * KI; /// Max length (in bytes) of the result data from a ibc_source_chain_callback call. pub const RESULT_IBC_SOURCE_CHAIN_CALLBACK: usize = 256 * KI; + /// Max length (in bytes) of the result data from a ibc_destination_chain_callback call. + pub const RESULT_IBC_DESTINATION_CHAIN_CALLBACK: usize = 256 * KI; } pub fn call_instantiate( @@ -354,6 +358,27 @@ where Ok(result) } +pub fn call_ibc_destination_chain_callback( + instance: &mut Instance, + env: &Env, + msg: &IbcDestinationChainCallbackMsg, +) -> VmResult>> +where + A: BackendApi + 'static, + S: Storage + 'static, + Q: Querier + 'static, + U: DeserializeOwned + CustomMsg, +{ + let env = to_vec(env)?; + let msg = to_vec(msg)?; + let data = call_ibc_destination_chain_callback_raw(instance, &env, &msg)?; + let result = from_slice( + &data, + deserialization_limits::RESULT_IBC_DESTINATION_CHAIN_CALLBACK, + )?; + Ok(result) +} + /// Calls Wasm export "instantiate" and returns raw data from the contract. /// The result is length limited to prevent abuse but otherwise unchecked. pub fn call_instantiate_raw( @@ -606,6 +631,25 @@ where ) } +pub fn call_ibc_destination_chain_callback_raw( + instance: &mut Instance, + env: &[u8], + msg: &[u8], +) -> VmResult> +where + A: BackendApi + 'static, + S: Storage + 'static, + Q: Querier + 'static, +{ + instance.set_storage_readonly(false); + call_raw( + instance, + "ibc_destination_chain_callback", + &[env, msg], + read_limits::RESULT_IBC_DESTINATION_CHAIN_CALLBACK, + ) +} + /// Calls a function with the given arguments. /// The exported function must return exactly one result (an offset to the result Region). pub(crate) fn call_raw( diff --git a/packages/vm/src/lib.rs b/packages/vm/src/lib.rs index ede4815f09..27ccf20590 100644 --- a/packages/vm/src/lib.rs +++ b/packages/vm/src/lib.rs @@ -27,7 +27,8 @@ pub use crate::cache::{ AnalysisReport, Cache, CacheOptions, Metrics, PerModuleMetrics, PinnedMetrics, Stats, }; pub use crate::calls::{ - call_execute, call_execute_raw, call_ibc_source_chain_callback, + call_execute, call_execute_raw, call_ibc_destination_chain_callback, + call_ibc_destination_chain_callback_raw, call_ibc_source_chain_callback, call_ibc_source_chain_callback_raw, call_instantiate, call_instantiate_raw, call_migrate, call_migrate_raw, call_query, call_query_raw, call_reply, call_reply_raw, call_sudo, call_sudo_raw, From 1039bda2bba934fd0a3a2f6c726009e3a93beb7b Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 2 Apr 2024 17:47:55 +0200 Subject: [PATCH 15/44] Update ibc-callbacks lock file --- contracts/ibc-callbacks/Cargo.lock | 500 ++++++++++++++++------------- 1 file changed, 268 insertions(+), 232 deletions(-) diff --git a/contracts/ibc-callbacks/Cargo.lock b/contracts/ibc-callbacks/Cargo.lock index 1e2dc47adf..3d15fbc37e 100644 --- a/contracts/ibc-callbacks/Cargo.lock +++ b/contracts/ibc-callbacks/Cargo.lock @@ -23,11 +23,29 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.3", + "getrandom", "once_cell", "version_check", ] +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + [[package]] name = "arrayvec" version = "0.7.2" @@ -63,9 +81,9 @@ checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" -version = "0.21.2" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" [[package]] name = "base64ct" @@ -75,9 +93,9 @@ checksum = "dea908e7347a8c64e378c17e30ef880ad73e3b4498346b055c2c00ea342f3179" [[package]] name = "bech32" -version = "0.9.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" +checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" [[package]] name = "bitflags" @@ -86,13 +104,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] -name = "block-buffer" -version = "0.9.0" +name = "bitflags" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "block-buffer" @@ -105,9 +120,9 @@ dependencies = [ [[package]] name = "bnum" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56953345e39537a3e18bdaeba4cb0c58a78c1f61f361dc0fa7c5c7340ae87c5f" +checksum = "3e31ea183f6ee62ac8b8a8cf7feddd766317adfb13ff469de57ce033efd6a790" [[package]] name = "bumpalo" @@ -188,25 +203,29 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "2.0.0-rc.1" +version = "2.0.0" dependencies = [ - "digest 0.10.7", + "digest", + "ecdsa", "ed25519-zebra", "k256", - "rand_core 0.6.4", + "p256", + "rand_core", "thiserror", ] [[package]] name = "cosmwasm-derive" -version = "2.0.0-rc.1" +version = "2.0.0" dependencies = [ - "syn 1.0.109", + "proc-macro2", + "quote", + "syn 2.0.37", ] [[package]] name = "cosmwasm-schema" -version = "2.0.0-rc.1" +version = "2.0.0" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -217,16 +236,16 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "2.0.0-rc.1" +version = "2.0.0" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.37", ] [[package]] name = "cosmwasm-std" -version = "2.0.0-rc.1" +version = "2.0.0" dependencies = [ "base64", "bech32", @@ -239,18 +258,16 @@ dependencies = [ "schemars", "serde", "serde-json-wasm", - "sha2 0.10.3", + "sha2", "static_assertions", "thiserror", ] [[package]] name = "cosmwasm-vm" -version = "2.0.0-rc.1" +version = "2.0.0" dependencies = [ "bech32", - "bitflags", - "bytecheck", "bytes", "clru", "cosmwasm-crypto", @@ -261,27 +278,19 @@ dependencies = [ "schemars", "serde", "serde_json", - "sha2 0.10.3", + "sha2", "strum", "thiserror", + "tracing", "wasmer", "wasmer-middlewares", ] [[package]] name = "cpufeatures" -version = "0.1.5" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef" -dependencies = [ - "libc", -] - -[[package]] -name = "cpufeatures" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] @@ -339,8 +348,8 @@ checksum = "624b54323b06e675293939311943ba82d323bb340468ce1889be5da7932c8d73" dependencies = [ "cranelift-entity", "fxhash", - "hashbrown", - "indexmap", + "hashbrown 0.12.3", + "indexmap 1.9.3", "log", "smallvec", ] @@ -439,7 +448,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" dependencies = [ "generic-array", - "rand_core 0.6.4", + "rand_core", "subtle", "zeroize", ] @@ -456,17 +465,32 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "3.1.0" +version = "4.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "639891fde0dbea823fc3d798a0fdf9d2f9440a42d64a78ab3488b0ca025117b3" +checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "platforms", + "rustc_version", "subtle", "zeroize", ] +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + [[package]] name = "darling" version = "0.20.3" @@ -508,7 +532,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" dependencies = [ "cfg-if", - "hashbrown", + "hashbrown 0.12.3", "lock_api", "once_cell", "parking_lot_core", @@ -521,6 +545,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7ed52955ce76b1554f509074bb357d3fb8ac9b51288a65a3fd480d1dfba946" dependencies = [ "const-oid", + "pem-rfc7468", "zeroize", ] @@ -535,22 +560,13 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.2", + "block-buffer", "const-oid", "crypto-common", "subtle", @@ -568,7 +584,7 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "add9a102807b524ec050363f09e06f1504214b0e1c7797f64261c891022dce8b" dependencies = [ - "bitflags", + "bitflags 1.2.1", "byteorder", "lazy_static", "proc-macro-error", @@ -595,25 +611,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" dependencies = [ "der", - "digest 0.10.7", + "digest", "elliptic-curve", "rfc6979", "signature", "spki", ] +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "serde", + "signature", +] + [[package]] name = "ed25519-zebra" -version = "3.0.0" +version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403ef3e961ab98f0ba902771d29f842058578bb1ce7e3c59dad5a6a93e784c69" +checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9" dependencies = [ "curve25519-dalek", + "ed25519", + "hashbrown 0.14.3", "hex", - "rand_core 0.6.4", + "rand_core", "serde", - "sha2 0.9.5", - "thiserror", + "sha2", "zeroize", ] @@ -631,12 +659,13 @@ checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", "crypto-bigint", - "digest 0.10.7", + "digest", "ff", "generic-array", "group", + "pem-rfc7468", "pkcs8", - "rand_core 0.6.4", + "rand_core", "sec1", "subtle", "zeroize", @@ -683,6 +712,12 @@ dependencies = [ "syn 2.0.37", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "fallible-iterator" version = "0.2.0" @@ -695,24 +730,21 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "rand_core 0.6.4", + "rand_core", "subtle", ] [[package]] -name = "fnv" -version = "1.0.7" +name = "fiat-crypto" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +checksum = "c007b1ae3abe1cb6f85a16305acd418b7ca6343b953633fee2b76d8f108b830f" [[package]] -name = "form_urlencoded" -version = "1.1.0" +name = "fnv" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" -dependencies = [ - "percent-encoding", -] +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "forward_ref" @@ -740,17 +772,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.3" @@ -759,7 +780,7 @@ checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if", "libc", - "wasi 0.10.2+wasi-snapshot-preview1", + "wasi", ] [[package]] @@ -775,7 +796,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" dependencies = [ "fallible-iterator", - "indexmap", + "indexmap 1.9.3", "stable_deref_trait", ] @@ -786,7 +807,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -796,7 +817,17 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash", + "ahash 0.7.6", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash 0.8.11", + "allocator-api2", ] [[package]] @@ -826,7 +857,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.7", + "digest", ] [[package]] @@ -847,23 +878,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] -name = "idna" -version = "0.3.0" +name = "indexmap" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "autocfg", + "hashbrown 0.12.3", ] [[package]] name = "indexmap" -version = "1.9.3" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ - "autocfg", - "hashbrown", + "equivalent", + "hashbrown 0.14.3", ] [[package]] @@ -891,7 +922,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "once_cell", - "sha2 0.10.3", + "sha2", "signature", ] @@ -909,9 +940,9 @@ checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" [[package]] name = "libc" -version = "0.2.126" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "lock_api" @@ -1025,10 +1056,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] -name = "opaque-debug" -version = "0.3.0" +name = "p256" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] [[package]] name = "parking_lot_core" @@ -1044,16 +1081,19 @@ dependencies = [ ] [[package]] -name = "percent-encoding" -version = "2.3.0" +name = "pem-rfc7468" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] [[package]] name = "pin-project-lite" -version = "0.2.7" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pkcs8" @@ -1065,6 +1105,21 @@ dependencies = [ "spki", ] +[[package]] +name = "platforms" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -1091,9 +1146,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.67" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -1120,29 +1175,20 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.3", + "getrandom", ] [[package]] @@ -1176,7 +1222,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.2.1", ] [[package]] @@ -1197,7 +1243,7 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76e189c2369884dce920945e2ddf79b3dff49e071a167dd1817fa9c4c00d512e" dependencies = [ - "bitflags", + "bitflags 1.2.1", "libc", "mach", "winapi", @@ -1229,8 +1275,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21499ed91807f07ae081880aabb2ccc0235e9d88011867d984525e9a4c3cfa3e" dependencies = [ "bytecheck", - "hashbrown", - "indexmap", + "hashbrown 0.12.3", + "indexmap 1.9.3", "ptr_meta", "rend", "rkyv_derive", @@ -1254,6 +1300,15 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dead70b0b5e03e9c814bcb6b01e03e68f7c57a80aa48c72ec92152ab3e818d49" +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "rustversion" version = "1.0.14" @@ -1322,6 +1377,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c309e515543e67811222dbc9e3dd7e1056279b782e1dacffe4242b718734fb6" +[[package]] +name = "semver" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" + [[package]] name = "serde" version = "1.0.192" @@ -1384,19 +1445,6 @@ dependencies = [ "serde", ] -[[package]] -name = "sha2" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures 0.1.5", - "digest 0.9.0", - "opaque-debug", -] - [[package]] name = "sha2" version = "0.10.3" @@ -1404,8 +1452,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899bf02746a2c92bf1053d9327dadb252b01af1f81f90cdb902411f518bc7215" dependencies = [ "cfg-if", - "cpufeatures 0.2.2", - "digest 0.10.7", + "cpufeatures", + "digest", ] [[package]] @@ -1424,8 +1472,8 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" dependencies = [ - "digest 0.10.7", - "rand_core 0.6.4", + "digest", + "rand_core", ] [[package]] @@ -1470,18 +1518,18 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strum" -version = "0.25.0" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.25.3" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" dependencies = [ "heck", "proc-macro2", @@ -1544,28 +1592,12 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "tracing" -version = "0.1.26" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -1573,22 +1605,22 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.15" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.37", ] [[package]] name = "tracing-core" -version = "0.1.18" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9ff14f98b1a4b289c6248a023c1c2fa1491062964e9fed67ab29c4e4da4a052" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ - "lazy_static", + "once_cell", ] [[package]] @@ -1597,49 +1629,17 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" -[[package]] -name = "unicode-bidi" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" - [[package]] name = "unicode-ident" version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "url" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - [[package]] name = "version_check" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasi" @@ -1703,14 +1703,14 @@ checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "wasmer" -version = "4.2.5" +version = "4.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5467c7a23f9be04d5691590bea509dbea27e5ba5810d0020bef908456a495f33" +checksum = "5c15724dc25d1ee57962334aea8e41ade2675e5ea2ac6b8d42da6051b0face66" dependencies = [ "bytes", "cfg-if", "derivative", - "indexmap", + "indexmap 1.9.3", "js-sys", "more-asserts", "rustc-demangle", @@ -1719,6 +1719,7 @@ dependencies = [ "shared-buffer", "target-lexicon", "thiserror", + "tracing", "wasm-bindgen", "wasmer-compiler", "wasmer-compiler-cranelift", @@ -1731,9 +1732,9 @@ dependencies = [ [[package]] name = "wasmer-compiler" -version = "4.2.5" +version = "4.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "510ad01a668d774f3a103a7c219bbc0970be93e8f1b27e2fdb48d1f4ccd1deff" +checksum = "55a7f3b3a96f8d844c25e2c032af9572306dd63fa93dc17bcca4c5458ac569bd" dependencies = [ "backtrace", "bytes", @@ -1758,9 +1759,9 @@ dependencies = [ [[package]] name = "wasmer-compiler-cranelift" -version = "4.2.5" +version = "4.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54bf93078990d83960d798de3c5935bddaba771fc2fefb9ed6bab9c0bbdea5c1" +checksum = "102e2c5bacac69495c4025767e2fa26797ffb27f242dccb7cf57d9cefd944386" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -1777,9 +1778,9 @@ dependencies = [ [[package]] name = "wasmer-compiler-singlepass" -version = "4.2.5" +version = "4.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4d6359d66a8bcefac26d48fcb0f3f0882bdf122b52121a1ae21f918706e040" +checksum = "2071db9b993508dac72d12f7a9372e0c095fbdc173e0009c4b75886bed4a855e" dependencies = [ "byteorder", "dynasm", @@ -1796,9 +1797,9 @@ dependencies = [ [[package]] name = "wasmer-derive" -version = "4.2.5" +version = "4.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b374fd34d97b1c091d8675f9bc472df52dc6787d139d3762d42c7dc84813a9b" +checksum = "0ea737fa08f95d6abc4459f42a70a9833e8974b814e74971d77ef473814f4d4c" dependencies = [ "proc-macro-error", "proc-macro2", @@ -1808,9 +1809,9 @@ dependencies = [ [[package]] name = "wasmer-middlewares" -version = "4.2.5" +version = "4.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aab1347a1f81bf5929289db82b4f3966e9aecc4f874115110b6c0894ee8d9e77" +checksum = "0346ed39c185c1c5c1094e6c0271d798276a34f80e1e5576bcb2e32fa2e7f05a" dependencies = [ "wasmer", "wasmer-types", @@ -1819,14 +1820,14 @@ dependencies = [ [[package]] name = "wasmer-types" -version = "4.2.5" +version = "4.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0caf1c87937b52aba8e9f920a278e1beda282f7439612c0b48f51a58e7a87bab" +checksum = "b0689110e291b0f07fc665f2824e5ff81df120848e8a9acfbf1a9bf7990773f9" dependencies = [ "bytecheck", "enum-iterator", "enumset", - "indexmap", + "indexmap 1.9.3", "more-asserts", "rkyv", "target-lexicon", @@ -1835,9 +1836,9 @@ dependencies = [ [[package]] name = "wasmer-vm" -version = "4.2.5" +version = "4.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58315c25492bc72a33f47a7d7fb0869a0106fc0164ec051e349a9e1eddba9a01" +checksum = "4cd41f822a1ac4242d478754e8ceba2806a00ea5072803622e1fe91e8e28b2a1" dependencies = [ "backtrace", "cc", @@ -1848,7 +1849,7 @@ dependencies = [ "derivative", "enum-iterator", "fnv", - "indexmap", + "indexmap 1.9.3", "lazy_static", "libc", "mach", @@ -1863,12 +1864,13 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.95.0" +version = "0.121.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ea896273ea99b15132414be1da01ab0d8836415083298ecaffbe308eaac87a" +checksum = "9dbe55c8f9d0dbd25d9447a5a889ff90c0cc3feaa7395310d3d826b2c703eaab" dependencies = [ - "indexmap", - "url", + "bitflags 2.5.0", + "indexmap 2.2.6", + "semver", ] [[package]] @@ -1993,8 +1995,42 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + [[package]] name = "zeroize" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] From d131c1c43ed3ecf957c3abdddc09971e52d0685d Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 2 Apr 2024 18:02:25 +0200 Subject: [PATCH 16/44] Fix circleci contract_ibc_callbacks --- .circleci/config.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f38099bd54..ec1a0648b5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -656,7 +656,7 @@ jobs: contract_ibc_callbacks: docker: - - image: rust:1.70.0 + - image: rust:1.73 environment: RUST_BACKTRACE: 1 working_directory: ~/cosmwasm/contracts/ibc-callbacks @@ -668,8 +668,11 @@ jobs: command: rustc --version; cargo --version; rustup --version - restore_cache: keys: - - cargocache-v2-contract_ibc_callbacks-rust:1.70.0-{{ checksum "Cargo.lock" }} - - check_contract + - cargocache-v2-contract_ibc_callbacks-rust:1.73-{{ checksum "Cargo.lock" }} + # TODO: Enable this once 2.1 has been released to crates.io + - check_contract: + min_version: "2.1" + skip_cosmwasm_check: true - save_cache: paths: - /usr/local/cargo/registry @@ -679,7 +682,7 @@ jobs: - target/wasm32-unknown-unknown/release/.fingerprint - target/wasm32-unknown-unknown/release/build - target/wasm32-unknown-unknown/release/deps - key: cargocache-v2-contract_ibc_callbacks-rust:1.70.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-contract_ibc_callbacks-rust:1.73-{{ checksum "Cargo.lock" }} contract_ibc_reflect: docker: From eee39cb283320809162d40a7abc9ddbbfff9e22f Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Thu, 4 Apr 2024 13:40:30 +0200 Subject: [PATCH 17/44] Fix clippy lints --- contracts/ibc-callbacks/src/contract.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/ibc-callbacks/src/contract.rs b/contracts/ibc-callbacks/src/contract.rs index 5822e49876..26ab69f799 100644 --- a/contracts/ibc-callbacks/src/contract.rs +++ b/contracts/ibc-callbacks/src/contract.rs @@ -1,8 +1,8 @@ use cosmwasm_std::{ entry_point, to_json_binary, to_json_string, Binary, Deps, DepsMut, Empty, Env, - IbcBasicResponse, IbcCallbackData, IbcDestinationChainCallbackMsg, IbcDstCallback, IbcMsg, - IbcPacketReceiveMsg, IbcSourceChainCallbackMsg, IbcSrcCallback, IbcTimeout, MessageInfo, - Response, StdError, StdResult, + IbcBasicResponse, IbcCallbackData, IbcDestinationChainCallbackMsg, IbcMsg, + IbcSourceChainCallbackMsg, IbcSrcCallback, IbcTimeout, MessageInfo, Response, StdError, + StdResult, }; use crate::msg::{ExecuteMsg, QueryMsg}; From efa7d627d0a41493c980eb0c23f55b7b34cf273b Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Thu, 4 Apr 2024 13:57:06 +0200 Subject: [PATCH 18/44] Update ibc-callbacks schemas --- .../ibc-callbacks/schema/ibc-callbacks.json | 23 +++++++++++++++++++ .../raw/response_to_callback_stats.json | 23 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/contracts/ibc-callbacks/schema/ibc-callbacks.json b/contracts/ibc-callbacks/schema/ibc-callbacks.json index 2dce6a9daf..80ec9c3507 100644 --- a/contracts/ibc-callbacks/schema/ibc-callbacks.json +++ b/contracts/ibc-callbacks/schema/ibc-callbacks.json @@ -73,6 +73,7 @@ "type": "object", "required": [ "ibc_ack_callbacks", + "ibc_receive_callback", "ibc_timeout_callbacks" ], "properties": { @@ -82,6 +83,12 @@ "$ref": "#/definitions/IbcPacketAckMsg" } }, + "ibc_receive_callback": { + "type": "array", + "items": { + "$ref": "#/definitions/IbcPacketReceiveMsg" + } + }, "ibc_timeout_callbacks": { "type": "array", "items": { @@ -190,6 +197,22 @@ } } }, + "IbcPacketReceiveMsg": { + "description": "The message that is passed into `ibc_packet_receive`", + "type": "object", + "required": [ + "packet", + "relayer" + ], + "properties": { + "packet": { + "$ref": "#/definitions/IbcPacket" + }, + "relayer": { + "$ref": "#/definitions/Addr" + } + } + }, "IbcPacketTimeoutMsg": { "description": "The message that is passed into `ibc_packet_timeout`", "type": "object", diff --git a/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json index cceaa53af7..36b6e4bb89 100644 --- a/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json +++ b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json @@ -5,6 +5,7 @@ "type": "object", "required": [ "ibc_ack_callbacks", + "ibc_receive_callback", "ibc_timeout_callbacks" ], "properties": { @@ -14,6 +15,12 @@ "$ref": "#/definitions/IbcPacketAckMsg" } }, + "ibc_receive_callback": { + "type": "array", + "items": { + "$ref": "#/definitions/IbcPacketReceiveMsg" + } + }, "ibc_timeout_callbacks": { "type": "array", "items": { @@ -122,6 +129,22 @@ } } }, + "IbcPacketReceiveMsg": { + "description": "The message that is passed into `ibc_packet_receive`", + "type": "object", + "required": [ + "packet", + "relayer" + ], + "properties": { + "packet": { + "$ref": "#/definitions/IbcPacket" + }, + "relayer": { + "$ref": "#/definitions/Addr" + } + } + }, "IbcPacketTimeoutMsg": { "description": "The message that is passed into `ibc_packet_timeout`", "type": "object", From a052b4e7cb59946671bc0e92a02a739221feaf62 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Thu, 4 Apr 2024 15:05:22 +0200 Subject: [PATCH 19/44] Update ibc-callbacks --- contracts/ibc-callbacks/Cargo.lock | 12 ++++----- .../ibc-callbacks/schema/ibc-callbacks.json | 27 ++++++++++++------- .../ibc-callbacks/schema/raw/instantiate.json | 3 ++- .../raw/response_to_callback_stats.json | 24 +++++++++++------ 4 files changed, 42 insertions(+), 24 deletions(-) diff --git a/contracts/ibc-callbacks/Cargo.lock b/contracts/ibc-callbacks/Cargo.lock index 3d15fbc37e..f75dcfb5b5 100644 --- a/contracts/ibc-callbacks/Cargo.lock +++ b/contracts/ibc-callbacks/Cargo.lock @@ -203,7 +203,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "2.0.0" +version = "2.0.1" dependencies = [ "digest", "ecdsa", @@ -216,7 +216,7 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "2.0.0" +version = "2.0.1" dependencies = [ "proc-macro2", "quote", @@ -225,7 +225,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema" -version = "2.0.0" +version = "2.0.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -236,7 +236,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "2.0.0" +version = "2.0.1" dependencies = [ "proc-macro2", "quote", @@ -245,7 +245,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "2.0.0" +version = "2.0.1" dependencies = [ "base64", "bech32", @@ -265,7 +265,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "2.0.0" +version = "2.0.1" dependencies = [ "bech32", "bytes", diff --git a/contracts/ibc-callbacks/schema/ibc-callbacks.json b/contracts/ibc-callbacks/schema/ibc-callbacks.json index 80ec9c3507..b6aa482b76 100644 --- a/contracts/ibc-callbacks/schema/ibc-callbacks.json +++ b/contracts/ibc-callbacks/schema/ibc-callbacks.json @@ -6,7 +6,8 @@ "$schema": "http://json-schema.org/draft-07/schema#", "title": "InstantiateMsg", "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", - "type": "object" + "type": "object", + "additionalProperties": false }, "execute": { "$schema": "http://json-schema.org/draft-07/schema#", @@ -115,7 +116,8 @@ "data": { "$ref": "#/definitions/Binary" } - } + }, + "additionalProperties": false }, "IbcEndpoint": { "type": "object", @@ -130,7 +132,8 @@ "port_id": { "type": "string" } - } + }, + "additionalProperties": false }, "IbcPacket": { "type": "object", @@ -175,7 +178,8 @@ "timeout": { "$ref": "#/definitions/IbcTimeout" } - } + }, + "additionalProperties": false }, "IbcPacketAckMsg": { "description": "The message that is passed into `ibc_packet_ack`", @@ -195,7 +199,8 @@ "relayer": { "$ref": "#/definitions/Addr" } - } + }, + "additionalProperties": false }, "IbcPacketReceiveMsg": { "description": "The message that is passed into `ibc_packet_receive`", @@ -211,7 +216,8 @@ "relayer": { "$ref": "#/definitions/Addr" } - } + }, + "additionalProperties": false }, "IbcPacketTimeoutMsg": { "description": "The message that is passed into `ibc_packet_timeout`", @@ -227,7 +233,8 @@ "relayer": { "$ref": "#/definitions/Addr" } - } + }, + "additionalProperties": false }, "IbcTimeout": { "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.", @@ -253,7 +260,8 @@ } ] } - } + }, + "additionalProperties": false }, "IbcTimeoutBlock": { "description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)", @@ -275,7 +283,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, "Timestamp": { "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", diff --git a/contracts/ibc-callbacks/schema/raw/instantiate.json b/contracts/ibc-callbacks/schema/raw/instantiate.json index 5f6dfaf43c..d7966224ed 100644 --- a/contracts/ibc-callbacks/schema/raw/instantiate.json +++ b/contracts/ibc-callbacks/schema/raw/instantiate.json @@ -2,5 +2,6 @@ "$schema": "http://json-schema.org/draft-07/schema#", "title": "InstantiateMsg", "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", - "type": "object" + "type": "object", + "additionalProperties": false } diff --git a/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json index 36b6e4bb89..2438458b73 100644 --- a/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json +++ b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json @@ -47,7 +47,8 @@ "data": { "$ref": "#/definitions/Binary" } - } + }, + "additionalProperties": false }, "IbcEndpoint": { "type": "object", @@ -62,7 +63,8 @@ "port_id": { "type": "string" } - } + }, + "additionalProperties": false }, "IbcPacket": { "type": "object", @@ -107,7 +109,8 @@ "timeout": { "$ref": "#/definitions/IbcTimeout" } - } + }, + "additionalProperties": false }, "IbcPacketAckMsg": { "description": "The message that is passed into `ibc_packet_ack`", @@ -127,7 +130,8 @@ "relayer": { "$ref": "#/definitions/Addr" } - } + }, + "additionalProperties": false }, "IbcPacketReceiveMsg": { "description": "The message that is passed into `ibc_packet_receive`", @@ -143,7 +147,8 @@ "relayer": { "$ref": "#/definitions/Addr" } - } + }, + "additionalProperties": false }, "IbcPacketTimeoutMsg": { "description": "The message that is passed into `ibc_packet_timeout`", @@ -159,7 +164,8 @@ "relayer": { "$ref": "#/definitions/Addr" } - } + }, + "additionalProperties": false }, "IbcTimeout": { "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.", @@ -185,7 +191,8 @@ } ] } - } + }, + "additionalProperties": false }, "IbcTimeoutBlock": { "description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)", @@ -207,7 +214,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, "Timestamp": { "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", From ccd4bb80a608a9956f386fd9e525037685209559 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 5 Apr 2024 15:25:44 +0200 Subject: [PATCH 20/44] Fix destination callback --- contracts/ibc-callbacks/src/contract.rs | 2 +- contracts/ibc-callbacks/src/state.rs | 6 +++--- packages/std/src/ibc/callbacks.rs | 10 +++++++--- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/contracts/ibc-callbacks/src/contract.rs b/contracts/ibc-callbacks/src/contract.rs index 26ab69f799..f276f2c191 100644 --- a/contracts/ibc-callbacks/src/contract.rs +++ b/contracts/ibc-callbacks/src/contract.rs @@ -97,7 +97,7 @@ pub fn ibc_destination_chain_callback( let mut counts = load_stats(deps.storage)?; // save the receive - counts.ibc_receive_callback.push(msg); + counts.ibc_destination_callbacks.push(msg); save_stats(deps.storage, &counts)?; diff --git a/contracts/ibc-callbacks/src/state.rs b/contracts/ibc-callbacks/src/state.rs index 5ae360bdb5..0e0c60ae1d 100644 --- a/contracts/ibc-callbacks/src/state.rs +++ b/contracts/ibc-callbacks/src/state.rs @@ -2,8 +2,8 @@ use std::any::type_name; use cosmwasm_schema::cw_serde; use cosmwasm_std::{ - from_json, storage_keys::to_length_prefixed, to_json_vec, IbcPacketAckMsg, IbcPacketReceiveMsg, - IbcPacketTimeoutMsg, StdError, StdResult, Storage, + from_json, storage_keys::to_length_prefixed, to_json_vec, IbcDestinationChainCallbackMsg, + IbcPacketAckMsg, IbcPacketTimeoutMsg, StdError, StdResult, Storage, }; use serde::{de::DeserializeOwned, Serialize}; @@ -15,7 +15,7 @@ pub const KEY_STATS: &[u8] = b"counts"; pub struct CallbackStats { pub ibc_ack_callbacks: Vec, pub ibc_timeout_callbacks: Vec, - pub ibc_receive_callback: Vec, + pub ibc_destination_callbacks: Vec, } pub fn load_stats(storage: &dyn Storage) -> StdResult { diff --git a/packages/std/src/ibc/callbacks.rs b/packages/std/src/ibc/callbacks.rs index 6ed0e23014..df76c3ff58 100644 --- a/packages/std/src/ibc/callbacks.rs +++ b/packages/std/src/ibc/callbacks.rs @@ -4,7 +4,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use crate::{Addr, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, Uint64}; +use crate::{Addr, IbcAcknowledgement, IbcPacket, IbcPacketAckMsg, IbcPacketTimeoutMsg, Uint64}; /// This is just a type representing the data that has to be sent with the IBC message to receive /// callbacks. It should be serialized to JSON and sent with the IBC message. @@ -111,11 +111,11 @@ pub enum IbcSourceChainCallbackMsg { } /// The message type of the IBC destination chain callback. -/// This is just an alias for [`IbcPacketReceiveMsg`] to add some documentation. /// /// The IBC destination chain callback is needed for cases where someone triggers the sending of an /// IBC packet through some other message (i.e. not through [`IbcMsg::SendPacket`]) and /// your contract needs to know that it received this. +/// The callback is called after the packet was successfully acknowledged on the destination chain. /// A prominent example is the [`IbcMsg::Transfer`] message. Without callbacks, you cannot know /// that someone sent you IBC coins. /// @@ -125,7 +125,11 @@ pub enum IbcSourceChainCallbackMsg { /// (i.e. the destination chain needs to support callbacks for the message you are being sent). /// - You have to add json-encoded [`IbcCallbackData`] to a specific field of the message. /// For `IbcMsg::Transfer`, this is the `memo` field. -pub type IbcDestinationChainCallbackMsg = IbcPacketReceiveMsg; +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +pub struct IbcDestinationChainCallbackMsg { + pub packet: IbcPacket, + pub ack: IbcAcknowledgement, +} #[cfg(test)] mod tests { From 4dc36f2a18ca4bd4401a9b0580d4fe09717a9ffd Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 5 Apr 2024 15:57:04 +0200 Subject: [PATCH 21/44] Update schemas --- .../ibc-callbacks/schema/ibc-callbacks.json | 40 +++++++++---------- .../raw/response_to_callback_stats.json | 40 +++++++++---------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/contracts/ibc-callbacks/schema/ibc-callbacks.json b/contracts/ibc-callbacks/schema/ibc-callbacks.json index b6aa482b76..57edc232dc 100644 --- a/contracts/ibc-callbacks/schema/ibc-callbacks.json +++ b/contracts/ibc-callbacks/schema/ibc-callbacks.json @@ -74,7 +74,7 @@ "type": "object", "required": [ "ibc_ack_callbacks", - "ibc_receive_callback", + "ibc_destination_callbacks", "ibc_timeout_callbacks" ], "properties": { @@ -84,10 +84,10 @@ "$ref": "#/definitions/IbcPacketAckMsg" } }, - "ibc_receive_callback": { + "ibc_destination_callbacks": { "type": "array", "items": { - "$ref": "#/definitions/IbcPacketReceiveMsg" + "$ref": "#/definitions/IbcDestinationChainCallbackMsg" } }, "ibc_timeout_callbacks": { @@ -119,6 +119,23 @@ }, "additionalProperties": false }, + "IbcDestinationChainCallbackMsg": { + "description": "The message type of the IBC destination chain callback.\n\nThe IBC destination chain callback is needed for cases where someone triggers the sending of an IBC packet through some other message (i.e. not through [`IbcMsg::SendPacket`]) and your contract needs to know that it received this. The callback is called after the packet was successfully acknowledged on the destination chain. A prominent example is the [`IbcMsg::Transfer`] message. Without callbacks, you cannot know that someone sent you IBC coins.\n\nNote that there are some prerequisites that need to be fulfilled to receive source chain callbacks: - The contract must implement the `ibc_destination_chain_callback` entrypoint. - The module that receives the packet must be wrapped by an `IBCMiddleware` (i.e. the destination chain needs to support callbacks for the message you are being sent). - You have to add json-encoded [`IbcCallbackData`] to a specific field of the message. For `IbcMsg::Transfer`, this is the `memo` field.", + "type": "object", + "required": [ + "ack", + "packet" + ], + "properties": { + "ack": { + "$ref": "#/definitions/IbcAcknowledgement" + }, + "packet": { + "$ref": "#/definitions/IbcPacket" + } + }, + "additionalProperties": false + }, "IbcEndpoint": { "type": "object", "required": [ @@ -202,23 +219,6 @@ }, "additionalProperties": false }, - "IbcPacketReceiveMsg": { - "description": "The message that is passed into `ibc_packet_receive`", - "type": "object", - "required": [ - "packet", - "relayer" - ], - "properties": { - "packet": { - "$ref": "#/definitions/IbcPacket" - }, - "relayer": { - "$ref": "#/definitions/Addr" - } - }, - "additionalProperties": false - }, "IbcPacketTimeoutMsg": { "description": "The message that is passed into `ibc_packet_timeout`", "type": "object", diff --git a/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json index 2438458b73..1fa32554c4 100644 --- a/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json +++ b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json @@ -5,7 +5,7 @@ "type": "object", "required": [ "ibc_ack_callbacks", - "ibc_receive_callback", + "ibc_destination_callbacks", "ibc_timeout_callbacks" ], "properties": { @@ -15,10 +15,10 @@ "$ref": "#/definitions/IbcPacketAckMsg" } }, - "ibc_receive_callback": { + "ibc_destination_callbacks": { "type": "array", "items": { - "$ref": "#/definitions/IbcPacketReceiveMsg" + "$ref": "#/definitions/IbcDestinationChainCallbackMsg" } }, "ibc_timeout_callbacks": { @@ -50,6 +50,23 @@ }, "additionalProperties": false }, + "IbcDestinationChainCallbackMsg": { + "description": "The message type of the IBC destination chain callback.\n\nThe IBC destination chain callback is needed for cases where someone triggers the sending of an IBC packet through some other message (i.e. not through [`IbcMsg::SendPacket`]) and your contract needs to know that it received this. The callback is called after the packet was successfully acknowledged on the destination chain. A prominent example is the [`IbcMsg::Transfer`] message. Without callbacks, you cannot know that someone sent you IBC coins.\n\nNote that there are some prerequisites that need to be fulfilled to receive source chain callbacks: - The contract must implement the `ibc_destination_chain_callback` entrypoint. - The module that receives the packet must be wrapped by an `IBCMiddleware` (i.e. the destination chain needs to support callbacks for the message you are being sent). - You have to add json-encoded [`IbcCallbackData`] to a specific field of the message. For `IbcMsg::Transfer`, this is the `memo` field.", + "type": "object", + "required": [ + "ack", + "packet" + ], + "properties": { + "ack": { + "$ref": "#/definitions/IbcAcknowledgement" + }, + "packet": { + "$ref": "#/definitions/IbcPacket" + } + }, + "additionalProperties": false + }, "IbcEndpoint": { "type": "object", "required": [ @@ -133,23 +150,6 @@ }, "additionalProperties": false }, - "IbcPacketReceiveMsg": { - "description": "The message that is passed into `ibc_packet_receive`", - "type": "object", - "required": [ - "packet", - "relayer" - ], - "properties": { - "packet": { - "$ref": "#/definitions/IbcPacket" - }, - "relayer": { - "$ref": "#/definitions/Addr" - } - }, - "additionalProperties": false - }, "IbcPacketTimeoutMsg": { "description": "The message that is passed into `ibc_packet_timeout`", "type": "object", From 6cbe8541c74bd6b6ae33a938626788804891abd3 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Mon, 8 Apr 2024 10:20:31 +0200 Subject: [PATCH 22/44] Make callback type configurable for ibc-callbacks contract --- contracts/ibc-callbacks/src/contract.rs | 21 +++++++++++++++------ contracts/ibc-callbacks/src/msg.rs | 15 +++++++++++++++ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/contracts/ibc-callbacks/src/contract.rs b/contracts/ibc-callbacks/src/contract.rs index f276f2c191..bcf5335f19 100644 --- a/contracts/ibc-callbacks/src/contract.rs +++ b/contracts/ibc-callbacks/src/contract.rs @@ -1,11 +1,11 @@ use cosmwasm_std::{ entry_point, to_json_binary, to_json_string, Binary, Deps, DepsMut, Empty, Env, - IbcBasicResponse, IbcCallbackData, IbcDestinationChainCallbackMsg, IbcMsg, + IbcBasicResponse, IbcCallbackData, IbcDestinationChainCallbackMsg, IbcDstCallback, IbcMsg, IbcSourceChainCallbackMsg, IbcSrcCallback, IbcTimeout, MessageInfo, Response, StdError, StdResult, }; -use crate::msg::{ExecuteMsg, QueryMsg}; +use crate::msg::{CallbackType, ExecuteMsg, QueryMsg}; use crate::state::{load_stats, save_stats, CallbackStats}; #[entry_point] @@ -30,6 +30,14 @@ pub fn execute( info: MessageInfo, msg: ExecuteMsg, ) -> StdResult { + let src_callback = IbcSrcCallback { + address: env.contract.address, + gas_limit: None, + }; + let dst_callback = IbcDstCallback { + address: msg.to_address.clone(), + gas_limit: None, + }; let transfer_msg = match &*info.funds { [coin] if !coin.amount.is_zero() => IbcMsg::Transfer { to_address: msg.to_address, @@ -38,10 +46,11 @@ pub fn execute( ), channel_id: msg.channel_id, amount: coin.clone(), - memo: Some(to_json_string(&IbcCallbackData::source(IbcSrcCallback { - address: env.contract.address, - gas_limit: None, - }))?), + memo: Some(to_json_string(&match msg.callback_type { + CallbackType::Both => IbcCallbackData::both(src_callback, dst_callback), + CallbackType::Src => IbcCallbackData::source(src_callback), + CallbackType::Dst => IbcCallbackData::destination(dst_callback), + })?), }, _ => { return Err(StdError::generic_err( diff --git a/contracts/ibc-callbacks/src/msg.rs b/contracts/ibc-callbacks/src/msg.rs index 6c3e15f8fc..a08f92d22a 100644 --- a/contracts/ibc-callbacks/src/msg.rs +++ b/contracts/ibc-callbacks/src/msg.rs @@ -17,4 +17,19 @@ pub struct ExecuteMsg { pub channel_id: String, /// The amount of seconds from now the transfer should timeout at pub timeout_seconds: Uint64, + /// Who should receive callbacks for the message + #[serde(default)] + pub callback_type: CallbackType, +} + +#[cw_serde] +#[derive(Default)] +pub enum CallbackType { + /// Only this contract on the source chain should receive callbacks + Src, + /// Only the destination address should receive callbacks + Dst, + /// Both the source contract and the destination address should receive callbacks + #[default] + Both, } From 3942f43f8d1a0d67ef93a517c064a0440b404157 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Mon, 8 Apr 2024 13:47:05 +0200 Subject: [PATCH 23/44] Fix IbcCallbackData destination field name --- .../ibc-callbacks/schema/ibc-callbacks.json | 34 +++++++++++++++++++ .../ibc-callbacks/schema/raw/execute.json | 34 +++++++++++++++++++ packages/std/src/ibc/callbacks.rs | 20 +++++------ 3 files changed, 78 insertions(+), 10 deletions(-) diff --git a/contracts/ibc-callbacks/schema/ibc-callbacks.json b/contracts/ibc-callbacks/schema/ibc-callbacks.json index 57edc232dc..1b78d6f77f 100644 --- a/contracts/ibc-callbacks/schema/ibc-callbacks.json +++ b/contracts/ibc-callbacks/schema/ibc-callbacks.json @@ -19,6 +19,15 @@ "to_address" ], "properties": { + "callback_type": { + "description": "Who should receive callbacks for the message", + "default": "both", + "allOf": [ + { + "$ref": "#/definitions/CallbackType" + } + ] + }, "channel_id": { "description": "The channel to send the packet through", "type": "string" @@ -38,6 +47,31 @@ }, "additionalProperties": false, "definitions": { + "CallbackType": { + "oneOf": [ + { + "description": "Only this contract on the source chain should receive callbacks", + "type": "string", + "enum": [ + "src" + ] + }, + { + "description": "Only the destination address should receive callbacks", + "type": "string", + "enum": [ + "dst" + ] + }, + { + "description": "Both the source contract and the destination address should receive callbacks", + "type": "string", + "enum": [ + "both" + ] + } + ] + }, "Uint64": { "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", "type": "string" diff --git a/contracts/ibc-callbacks/schema/raw/execute.json b/contracts/ibc-callbacks/schema/raw/execute.json index 518744082a..4a45337822 100644 --- a/contracts/ibc-callbacks/schema/raw/execute.json +++ b/contracts/ibc-callbacks/schema/raw/execute.json @@ -8,6 +8,15 @@ "to_address" ], "properties": { + "callback_type": { + "description": "Who should receive callbacks for the message", + "default": "both", + "allOf": [ + { + "$ref": "#/definitions/CallbackType" + } + ] + }, "channel_id": { "description": "The channel to send the packet through", "type": "string" @@ -27,6 +36,31 @@ }, "additionalProperties": false, "definitions": { + "CallbackType": { + "oneOf": [ + { + "description": "Only this contract on the source chain should receive callbacks", + "type": "string", + "enum": [ + "src" + ] + }, + { + "description": "Only the destination address should receive callbacks", + "type": "string", + "enum": [ + "dst" + ] + }, + { + "description": "Both the source contract and the destination address should receive callbacks", + "type": "string", + "enum": [ + "both" + ] + } + ] + }, "Uint64": { "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", "type": "string" diff --git a/packages/std/src/ibc/callbacks.rs b/packages/std/src/ibc/callbacks.rs index df76c3ff58..281f75e48d 100644 --- a/packages/std/src/ibc/callbacks.rs +++ b/packages/std/src/ibc/callbacks.rs @@ -41,15 +41,15 @@ pub struct IbcCallbackData { #[serde(skip_serializing_if = "Option::is_none")] src_callback: Option, #[serde(skip_serializing_if = "Option::is_none")] - dst_callback: Option, + dest_callback: Option, } impl IbcCallbackData { /// Use this if you want to execute callbacks on both the source and destination chain. - pub fn both(src_callback: IbcSrcCallback, dst_callback: IbcDstCallback) -> Self { + pub fn both(src_callback: IbcSrcCallback, dest_callback: IbcDstCallback) -> Self { IbcCallbackData { src_callback: Some(src_callback), - dst_callback: Some(dst_callback), + dest_callback: Some(dest_callback), } } @@ -57,15 +57,15 @@ impl IbcCallbackData { pub fn source(src_callback: IbcSrcCallback) -> Self { IbcCallbackData { src_callback: Some(src_callback), - dst_callback: None, + dest_callback: None, } } /// Use this if you want to execute callbacks on the destination chain, but not the source chain. - pub fn destination(dst_callback: IbcDstCallback) -> Self { + pub fn destination(dest_callback: IbcDstCallback) -> Self { IbcCallbackData { src_callback: None, - dst_callback: Some(dst_callback), + dest_callback: Some(dest_callback), } } } @@ -154,19 +154,19 @@ mod tests { let json = to_json_string(&data).unwrap(); assert_eq!( json, - r#"{"src_callback":{"address":"src_address","gas_limit":"123"},"dst_callback":{"address":"dst_address","gas_limit":"1234"}}"# + r#"{"src_callback":{"address":"src_address","gas_limit":"123"},"dest_callback":{"address":"dst_address","gas_limit":"1234"}}"# ); // dst only, without gas limit let mut src = data.src_callback.take().unwrap(); - data.dst_callback.as_mut().unwrap().gas_limit = None; + data.dest_callback.as_mut().unwrap().gas_limit = None; let json = to_json_string(&data).unwrap(); - assert_eq!(json, r#"{"dst_callback":{"address":"dst_address"}}"#); + assert_eq!(json, r#"{"dest_callback":{"address":"dst_address"}}"#); // source only, without gas limit src.gas_limit = None; data.src_callback = Some(src); - data.dst_callback = None; + data.dest_callback = None; let json = to_json_string(&data).unwrap(); assert_eq!(json, r#"{"src_callback":{"address":"src_address"}}"#); } From f703a7434957e6f1d1d717a06e8b7deedd209d6f Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 16 Apr 2024 13:08:51 +0200 Subject: [PATCH 24/44] Apply review feedback --- contracts/ibc-callbacks/README.md | 2 +- packages/std/src/ibc/callbacks.rs | 4 +++- packages/vm/src/calls.rs | 8 ++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/contracts/ibc-callbacks/README.md b/contracts/ibc-callbacks/README.md index 50e6c3561b..e2435dc1dc 100644 --- a/contracts/ibc-callbacks/README.md +++ b/contracts/ibc-callbacks/README.md @@ -1,4 +1,4 @@ -# Ibc Reflect Contract +# IBC Callbacks Contract This is a simple contract to demonstrate [IBC Callbacks]. It sends an ICS-20 transfer message to a remote chain and writes to storage which callbacks were diff --git a/packages/std/src/ibc/callbacks.rs b/packages/std/src/ibc/callbacks.rs index 281f75e48d..6f42d8e118 100644 --- a/packages/std/src/ibc/callbacks.rs +++ b/packages/std/src/ibc/callbacks.rs @@ -73,7 +73,8 @@ impl IbcCallbackData { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct IbcSrcCallback { /// The source chain address that should receive the callback. - /// You probably want to put `env.contract.address` here. + /// For CosmWasm contracts, this *must* be `env.contract.address`. + /// Other addresses are not allowed and will effectively be ignored. pub address: Addr, /// Optional gas limit for the callback (in Cosmos SDK gas units) #[serde(skip_serializing_if = "Option::is_none")] @@ -105,6 +106,7 @@ pub struct IbcDstCallback { /// For `IbcMsg::Transfer`, this is the `memo` field. /// - The receiver of the callback must also be the sender of the message. #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[serde(rename_all = "snake_case")] pub enum IbcSourceChainCallbackMsg { Acknowledgement(IbcPacketAckMsg), Timeout(IbcPacketTimeoutMsg), diff --git a/packages/vm/src/calls.rs b/packages/vm/src/calls.rs index 2f21ccc130..2ef8abb80b 100644 --- a/packages/vm/src/calls.rs +++ b/packages/vm/src/calls.rs @@ -961,6 +961,7 @@ mod tests { const CONTRACT: &[u8] = include_bytes!("../testdata/ibc_reflect.wasm"); const IBC_CALLBACKS: &[u8] = include_bytes!("../testdata/ibc_callbacks.wasm"); const IBC_VERSION: &str = "ibc-reflect-v1"; + fn setup( instance: &mut Instance, channel_id: &str, @@ -1014,13 +1015,16 @@ mod tests { }; call_reply::<_, _, _, Empty>(instance, &mock_env(), &response).unwrap(); } + const CHANNEL_ID: &str = "channel-123"; const ACCOUNT: &str = "account-456"; + #[test] fn call_ibc_channel_open_and_connect_works() { let mut instance = mock_instance(CONTRACT, &[]); setup(&mut instance, CHANNEL_ID, ACCOUNT); } + #[test] fn call_ibc_channel_close_works() { let mut instance = mock_instance(CONTRACT, &[]); @@ -1032,6 +1036,7 @@ mod tests { .unwrap() .unwrap(); } + #[test] fn call_ibc_packet_ack_works() { let mut instance = mock_instance(CONTRACT, &[]); @@ -1042,6 +1047,7 @@ mod tests { .unwrap() .unwrap(); } + #[test] fn call_ibc_packet_timeout_works() { let mut instance = mock_instance(CONTRACT, &[]); @@ -1051,6 +1057,7 @@ mod tests { .unwrap() .unwrap(); } + #[test] fn call_ibc_packet_receive_works() { let mut instance = mock_instance(CONTRACT, &[]); @@ -1061,6 +1068,7 @@ mod tests { .unwrap() .unwrap(); } + #[test] fn call_ibc_source_chain_callback_works() { let mut instance = mock_instance(IBC_CALLBACKS, &[]); From 56a8fba59655c92a81d172b2191893b0ff3aff62 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 16 Apr 2024 13:37:47 +0200 Subject: [PATCH 25/44] Update ibc-callbacks lockfile --- contracts/ibc-callbacks/Cargo.lock | 149 ++++++++++++++--------------- 1 file changed, 71 insertions(+), 78 deletions(-) diff --git a/contracts/ibc-callbacks/Cargo.lock b/contracts/ibc-callbacks/Cargo.lock index f75dcfb5b5..5b9116d5a4 100644 --- a/contracts/ibc-callbacks/Cargo.lock +++ b/contracts/ibc-callbacks/Cargo.lock @@ -85,12 +85,6 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" -[[package]] -name = "base64ct" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea908e7347a8c64e378c17e30ef880ad73e3b4498346b055c2c00ea342f3179" - [[package]] name = "bech32" version = "0.11.0" @@ -201,10 +195,27 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "cosmwasm-core" +version = "2.0.1" +dependencies = [ + "base64", + "bnum", + "cosmwasm-crypto", + "derive_more", + "hex", + "schemars", + "serde", + "sha2", + "static_assertions", + "thiserror", +] + [[package]] name = "cosmwasm-crypto" version = "2.0.1" dependencies = [ + "derive_more", "digest", "ecdsa", "ed25519-zebra", @@ -220,7 +231,7 @@ version = "2.0.1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.58", ] [[package]] @@ -240,7 +251,7 @@ version = "2.0.1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.58", ] [[package]] @@ -249,17 +260,16 @@ version = "2.0.1" dependencies = [ "base64", "bech32", - "bnum", + "cosmwasm-core", "cosmwasm-crypto", "cosmwasm-derive", - "derivative", - "forward_ref", + "derive_more", "hex", + "rand_core", "schemars", "serde", "serde-json-wasm", "sha2", - "static_assertions", "thiserror", ] @@ -275,6 +285,7 @@ dependencies = [ "crc32fast", "derivative", "hex", + "rand_core", "schemars", "serde", "serde_json", @@ -488,7 +499,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.58", ] [[package]] @@ -511,7 +522,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.58", ] [[package]] @@ -522,7 +533,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.37", + "syn 2.0.58", ] [[package]] @@ -545,7 +556,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7ed52955ce76b1554f509074bb357d3fb8ac9b51288a65a3fd480d1dfba946" dependencies = [ "const-oid", - "pem-rfc7468", "zeroize", ] @@ -560,6 +570,27 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_more" +version = "1.0.0-beta.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7abbfc297053be59290e3152f8cbcd52c8642e0728b69ee187d991d4c1af08d" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0-beta.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bba3e9872d7c58ce7ef0fcf1844fcc3e23ef2a58377b50df35dd98e42a5726e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.58", + "unicode-xid", +] + [[package]] name = "digest" version = "0.10.7" @@ -615,7 +646,6 @@ dependencies = [ "elliptic-curve", "rfc6979", "signature", - "spki", ] [[package]] @@ -624,8 +654,6 @@ version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ - "pkcs8", - "serde", "signature", ] @@ -640,7 +668,6 @@ dependencies = [ "hashbrown 0.14.3", "hex", "rand_core", - "serde", "sha2", "zeroize", ] @@ -663,8 +690,6 @@ dependencies = [ "ff", "generic-array", "group", - "pem-rfc7468", - "pkcs8", "rand_core", "sec1", "subtle", @@ -709,7 +734,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.58", ] [[package]] @@ -746,12 +771,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "forward_ref" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e" - [[package]] name = "fxhash" version = "0.2.1" @@ -921,9 +940,7 @@ dependencies = [ "cfg-if", "ecdsa", "elliptic-curve", - "once_cell", "sha2", - "signature", ] [[package]] @@ -1080,31 +1097,12 @@ dependencies = [ "windows-targets", ] -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - [[package]] name = "pin-project-lite" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - [[package]] name = "platforms" version = "3.4.0" @@ -1323,9 +1321,9 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "schemars" -version = "0.8.12" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" +checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" dependencies = [ "dyn-clone", "schemars_derive", @@ -1335,9 +1333,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.12" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" +checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" dependencies = [ "proc-macro2", "quote", @@ -1366,7 +1364,6 @@ dependencies = [ "base16ct", "der", "generic-array", - "pkcs8", "subtle", "zeroize", ] @@ -1385,9 +1382,9 @@ checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" [[package]] name = "serde" -version = "1.0.192" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] @@ -1414,13 +1411,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.192" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.58", ] [[package]] @@ -1447,9 +1444,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.3" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899bf02746a2c92bf1053d9327dadb252b01af1f81f90cdb902411f518bc7215" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -1494,16 +1491,6 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" -[[package]] -name = "spki" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" -dependencies = [ - "base64ct", - "der", -] - [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -1535,7 +1522,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.37", + "syn 2.0.58", ] [[package]] @@ -1557,9 +1544,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.37" +version = "2.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" dependencies = [ "proc-macro2", "quote", @@ -1611,7 +1598,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.58", ] [[package]] @@ -1635,6 +1622,12 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + [[package]] name = "version_check" version = "0.9.4" @@ -2012,7 +2005,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.58", ] [[package]] @@ -2032,5 +2025,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.58", ] From e6471d86febfcb37a40c4df04c280c679ce688df Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 16 Apr 2024 14:02:48 +0200 Subject: [PATCH 26/44] Fix destination chain types --- .../ibc-callbacks/schema/ibc-callbacks.json | 27 ++++++++++++++++-- .../raw/response_to_callback_stats.json | 27 ++++++++++++++++-- packages/std/src/ibc/callbacks.rs | 22 ++++++++++++-- packages/std/src/lib.rs | 6 ++-- packages/vm/testdata/ibc_callbacks.wasm | Bin 222490 -> 233239 bytes 5 files changed, 72 insertions(+), 10 deletions(-) diff --git a/contracts/ibc-callbacks/schema/ibc-callbacks.json b/contracts/ibc-callbacks/schema/ibc-callbacks.json index 1b78d6f77f..1916115d15 100644 --- a/contracts/ibc-callbacks/schema/ibc-callbacks.json +++ b/contracts/ibc-callbacks/schema/ibc-callbacks.json @@ -154,7 +154,7 @@ "additionalProperties": false }, "IbcDestinationChainCallbackMsg": { - "description": "The message type of the IBC destination chain callback.\n\nThe IBC destination chain callback is needed for cases where someone triggers the sending of an IBC packet through some other message (i.e. not through [`IbcMsg::SendPacket`]) and your contract needs to know that it received this. The callback is called after the packet was successfully acknowledged on the destination chain. A prominent example is the [`IbcMsg::Transfer`] message. Without callbacks, you cannot know that someone sent you IBC coins.\n\nNote that there are some prerequisites that need to be fulfilled to receive source chain callbacks: - The contract must implement the `ibc_destination_chain_callback` entrypoint. - The module that receives the packet must be wrapped by an `IBCMiddleware` (i.e. the destination chain needs to support callbacks for the message you are being sent). - You have to add json-encoded [`IbcCallbackData`] to a specific field of the message. For `IbcMsg::Transfer`, this is the `memo` field.", + "description": "The message type of the IBC destination chain callback.\n\nThe IBC destination chain callback is needed for cases where someone triggers the sending of an IBC packet through some other message (i.e. not through [`IbcMsg::SendPacket`]) and your contract needs to know that it received this. A prominent example is the [`IbcMsg::Transfer`] message. Without callbacks, you cannot know that someone sent you IBC coins.\n\nThe callback is called after the packet was acknowledged on the destination chain, as follows: - If the acknowledgement is synchronous (i.e. returned immediately when the packet is received), the callback is called only if the acknowledgement was successful. - If the acknowledgement is asynchronous (i.e. written later using `WriteAcknowledgement`), the callback is called regardless of the success of the acknowledgement.\n\nNote that there are some prerequisites that need to be fulfilled to receive source chain callbacks: - The contract must implement the `ibc_destination_chain_callback` entrypoint. - The module that receives the packet must be wrapped by an `IBCMiddleware` (i.e. the destination chain needs to support callbacks for the message you are being sent). - You have to add json-encoded [`IbcCallbackData`] to a specific field of the message. For `IbcMsg::Transfer`, this is the `memo` field.", "type": "object", "required": [ "ack", @@ -162,7 +162,7 @@ ], "properties": { "ack": { - "$ref": "#/definitions/IbcAcknowledgement" + "$ref": "#/definitions/IbcFullAcknowledgement" }, "packet": { "$ref": "#/definitions/IbcPacket" @@ -186,6 +186,29 @@ }, "additionalProperties": false }, + "IbcFullAcknowledgement": { + "description": "The acknowledgement written by the module on the destination chain. It is different from the [`IbcAcknowledgement`] as it can be unsuccessful.", + "type": "object", + "required": [ + "data", + "success" + ], + "properties": { + "data": { + "description": "The acknowledgement data returned by the module.", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "success": { + "description": "Whether the acknowledgement was successful or not.", + "type": "boolean" + } + }, + "additionalProperties": false + }, "IbcPacket": { "type": "object", "required": [ diff --git a/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json index 1fa32554c4..e1ed218865 100644 --- a/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json +++ b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json @@ -51,7 +51,7 @@ "additionalProperties": false }, "IbcDestinationChainCallbackMsg": { - "description": "The message type of the IBC destination chain callback.\n\nThe IBC destination chain callback is needed for cases where someone triggers the sending of an IBC packet through some other message (i.e. not through [`IbcMsg::SendPacket`]) and your contract needs to know that it received this. The callback is called after the packet was successfully acknowledged on the destination chain. A prominent example is the [`IbcMsg::Transfer`] message. Without callbacks, you cannot know that someone sent you IBC coins.\n\nNote that there are some prerequisites that need to be fulfilled to receive source chain callbacks: - The contract must implement the `ibc_destination_chain_callback` entrypoint. - The module that receives the packet must be wrapped by an `IBCMiddleware` (i.e. the destination chain needs to support callbacks for the message you are being sent). - You have to add json-encoded [`IbcCallbackData`] to a specific field of the message. For `IbcMsg::Transfer`, this is the `memo` field.", + "description": "The message type of the IBC destination chain callback.\n\nThe IBC destination chain callback is needed for cases where someone triggers the sending of an IBC packet through some other message (i.e. not through [`IbcMsg::SendPacket`]) and your contract needs to know that it received this. A prominent example is the [`IbcMsg::Transfer`] message. Without callbacks, you cannot know that someone sent you IBC coins.\n\nThe callback is called after the packet was acknowledged on the destination chain, as follows: - If the acknowledgement is synchronous (i.e. returned immediately when the packet is received), the callback is called only if the acknowledgement was successful. - If the acknowledgement is asynchronous (i.e. written later using `WriteAcknowledgement`), the callback is called regardless of the success of the acknowledgement.\n\nNote that there are some prerequisites that need to be fulfilled to receive source chain callbacks: - The contract must implement the `ibc_destination_chain_callback` entrypoint. - The module that receives the packet must be wrapped by an `IBCMiddleware` (i.e. the destination chain needs to support callbacks for the message you are being sent). - You have to add json-encoded [`IbcCallbackData`] to a specific field of the message. For `IbcMsg::Transfer`, this is the `memo` field.", "type": "object", "required": [ "ack", @@ -59,7 +59,7 @@ ], "properties": { "ack": { - "$ref": "#/definitions/IbcAcknowledgement" + "$ref": "#/definitions/IbcFullAcknowledgement" }, "packet": { "$ref": "#/definitions/IbcPacket" @@ -83,6 +83,29 @@ }, "additionalProperties": false }, + "IbcFullAcknowledgement": { + "description": "The acknowledgement written by the module on the destination chain. It is different from the [`IbcAcknowledgement`] as it can be unsuccessful.", + "type": "object", + "required": [ + "data", + "success" + ], + "properties": { + "data": { + "description": "The acknowledgement data returned by the module.", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "success": { + "description": "Whether the acknowledgement was successful or not.", + "type": "boolean" + } + }, + "additionalProperties": false + }, "IbcPacket": { "type": "object", "required": [ diff --git a/packages/std/src/ibc/callbacks.rs b/packages/std/src/ibc/callbacks.rs index 6f42d8e118..52383b8d43 100644 --- a/packages/std/src/ibc/callbacks.rs +++ b/packages/std/src/ibc/callbacks.rs @@ -1,10 +1,11 @@ //! This module contains types for the IBC callbacks defined in //! [ADR-8](https://github.com/cosmos/ibc-go/blob/main/docs/architecture/adr-008-app-caller-cbs.md). +use cosmwasm_core::Binary; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use crate::{Addr, IbcAcknowledgement, IbcPacket, IbcPacketAckMsg, IbcPacketTimeoutMsg, Uint64}; +use crate::{Addr, IbcPacket, IbcPacketAckMsg, IbcPacketTimeoutMsg, Uint64}; /// This is just a type representing the data that has to be sent with the IBC message to receive /// callbacks. It should be serialized to JSON and sent with the IBC message. @@ -117,10 +118,15 @@ pub enum IbcSourceChainCallbackMsg { /// The IBC destination chain callback is needed for cases where someone triggers the sending of an /// IBC packet through some other message (i.e. not through [`IbcMsg::SendPacket`]) and /// your contract needs to know that it received this. -/// The callback is called after the packet was successfully acknowledged on the destination chain. /// A prominent example is the [`IbcMsg::Transfer`] message. Without callbacks, you cannot know /// that someone sent you IBC coins. /// +/// The callback is called after the packet was acknowledged on the destination chain, as follows: +/// - If the acknowledgement is synchronous (i.e. returned immediately when the packet is received), +/// the callback is called only if the acknowledgement was successful. +/// - If the acknowledgement is asynchronous (i.e. written later using `WriteAcknowledgement`), +/// the callback is called regardless of the success of the acknowledgement. +/// /// Note that there are some prerequisites that need to be fulfilled to receive source chain callbacks: /// - The contract must implement the `ibc_destination_chain_callback` entrypoint. /// - The module that receives the packet must be wrapped by an `IBCMiddleware` @@ -130,7 +136,17 @@ pub enum IbcSourceChainCallbackMsg { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct IbcDestinationChainCallbackMsg { pub packet: IbcPacket, - pub ack: IbcAcknowledgement, + pub ack: IbcFullAcknowledgement, +} + +/// The acknowledgement written by the module on the destination chain. +/// It is different from the [`IbcAcknowledgement`] as it can be unsuccessful. +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +pub struct IbcFullAcknowledgement { + /// The acknowledgement data returned by the module. + pub data: Binary, + /// Whether the acknowledgement was successful or not. + pub success: bool, } #[cfg(test)] diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index d4e322776b..7270e2e080 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -42,9 +42,9 @@ pub use crate::ibc::IbcChannelOpenResponse; pub use crate::ibc::{ Ibc3ChannelOpenResponse, IbcAcknowledgement, IbcBasicResponse, IbcCallbackData, IbcChannel, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, IbcDestinationChainCallbackMsg, - IbcDstCallback, IbcEndpoint, IbcMsg, IbcOrder, IbcPacket, IbcPacketAckMsg, IbcPacketReceiveMsg, - IbcPacketTimeoutMsg, IbcReceiveResponse, IbcSourceChainCallbackMsg, IbcSrcCallback, IbcTimeout, - IbcTimeoutBlock, + IbcDstCallback, IbcEndpoint, IbcFullAcknowledgement, IbcMsg, IbcOrder, IbcPacket, + IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, + IbcSourceChainCallbackMsg, IbcSrcCallback, IbcTimeout, IbcTimeoutBlock, }; #[cfg(feature = "iterator")] pub use crate::iterator::{Order, Record}; diff --git a/packages/vm/testdata/ibc_callbacks.wasm b/packages/vm/testdata/ibc_callbacks.wasm index 1654a2047651dce68b7d8826d15b303c4aceb840..66ef1bf4d00214ac5ca92966127df3bfeddb6ff0 100644 GIT binary patch delta 90629 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 A2><{9 delta 80576 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°JTvC*MB6 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 E0cUw3JOBUy From 366e87fb5a12de9e35d8c8c7135c7da2e5273659 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 16 Apr 2024 14:14:55 +0200 Subject: [PATCH 27/44] Fix link --- contracts/ibc-callbacks/schema/ibc-callbacks.json | 2 +- .../ibc-callbacks/schema/raw/response_to_callback_stats.json | 2 +- packages/std/src/ibc/callbacks.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/ibc-callbacks/schema/ibc-callbacks.json b/contracts/ibc-callbacks/schema/ibc-callbacks.json index 1916115d15..9955f8a82a 100644 --- a/contracts/ibc-callbacks/schema/ibc-callbacks.json +++ b/contracts/ibc-callbacks/schema/ibc-callbacks.json @@ -187,7 +187,7 @@ "additionalProperties": false }, "IbcFullAcknowledgement": { - "description": "The acknowledgement written by the module on the destination chain. It is different from the [`IbcAcknowledgement`] as it can be unsuccessful.", + "description": "The acknowledgement written by the module on the destination chain. It is different from the [`crate::IbcAcknowledgement`] as it can be unsuccessful.", "type": "object", "required": [ "data", diff --git a/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json index e1ed218865..a57f65fb7e 100644 --- a/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json +++ b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json @@ -84,7 +84,7 @@ "additionalProperties": false }, "IbcFullAcknowledgement": { - "description": "The acknowledgement written by the module on the destination chain. It is different from the [`IbcAcknowledgement`] as it can be unsuccessful.", + "description": "The acknowledgement written by the module on the destination chain. It is different from the [`crate::IbcAcknowledgement`] as it can be unsuccessful.", "type": "object", "required": [ "data", diff --git a/packages/std/src/ibc/callbacks.rs b/packages/std/src/ibc/callbacks.rs index 52383b8d43..1243e9a9d9 100644 --- a/packages/std/src/ibc/callbacks.rs +++ b/packages/std/src/ibc/callbacks.rs @@ -140,7 +140,7 @@ pub struct IbcDestinationChainCallbackMsg { } /// The acknowledgement written by the module on the destination chain. -/// It is different from the [`IbcAcknowledgement`] as it can be unsuccessful. +/// It is different from the [`crate::IbcAcknowledgement`] as it can be unsuccessful. #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct IbcFullAcknowledgement { /// The acknowledgement data returned by the module. From 6ce3476f0adf599e44f7073613ef77c182f2eeb1 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 16 Apr 2024 16:35:55 +0200 Subject: [PATCH 28/44] Update ibc-callbacks contract --- .../ibc-callbacks/schema/ibc-callbacks.json | 12 +++--------- .../ibc-callbacks/schema/raw/execute.json | 12 +++--------- contracts/ibc-callbacks/src/contract.rs | 2 +- contracts/ibc-callbacks/src/msg.rs | 3 +-- packages/vm/testdata/ibc_callbacks.wasm | Bin 233239 -> 233235 bytes 5 files changed, 8 insertions(+), 21 deletions(-) diff --git a/contracts/ibc-callbacks/schema/ibc-callbacks.json b/contracts/ibc-callbacks/schema/ibc-callbacks.json index 9955f8a82a..1107b88433 100644 --- a/contracts/ibc-callbacks/schema/ibc-callbacks.json +++ b/contracts/ibc-callbacks/schema/ibc-callbacks.json @@ -34,11 +34,9 @@ }, "timeout_seconds": { "description": "The amount of seconds from now the transfer should timeout at", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] + "type": "integer", + "format": "uint32", + "minimum": 0.0 }, "to_address": { "description": "Address on the destination chain", @@ -71,10 +69,6 @@ ] } ] - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" } } }, diff --git a/contracts/ibc-callbacks/schema/raw/execute.json b/contracts/ibc-callbacks/schema/raw/execute.json index 4a45337822..5c65aea3d4 100644 --- a/contracts/ibc-callbacks/schema/raw/execute.json +++ b/contracts/ibc-callbacks/schema/raw/execute.json @@ -23,11 +23,9 @@ }, "timeout_seconds": { "description": "The amount of seconds from now the transfer should timeout at", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] + "type": "integer", + "format": "uint32", + "minimum": 0.0 }, "to_address": { "description": "Address on the destination chain", @@ -60,10 +58,6 @@ ] } ] - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" } } } diff --git a/contracts/ibc-callbacks/src/contract.rs b/contracts/ibc-callbacks/src/contract.rs index bcf5335f19..a9d601ac24 100644 --- a/contracts/ibc-callbacks/src/contract.rs +++ b/contracts/ibc-callbacks/src/contract.rs @@ -42,7 +42,7 @@ pub fn execute( [coin] if !coin.amount.is_zero() => IbcMsg::Transfer { to_address: msg.to_address, timeout: IbcTimeout::with_timestamp( - env.block.time.plus_seconds(msg.timeout_seconds.u64()), + env.block.time.plus_seconds(msg.timeout_seconds as u64), ), channel_id: msg.channel_id, amount: coin.clone(), diff --git a/contracts/ibc-callbacks/src/msg.rs b/contracts/ibc-callbacks/src/msg.rs index a08f92d22a..bd45c60e9b 100644 --- a/contracts/ibc-callbacks/src/msg.rs +++ b/contracts/ibc-callbacks/src/msg.rs @@ -1,5 +1,4 @@ use cosmwasm_schema::{cw_serde, QueryResponses}; -use cosmwasm_std::Uint64; #[cw_serde] #[derive(QueryResponses)] @@ -16,7 +15,7 @@ pub struct ExecuteMsg { /// The channel to send the packet through pub channel_id: String, /// The amount of seconds from now the transfer should timeout at - pub timeout_seconds: Uint64, + pub timeout_seconds: u32, /// Who should receive callbacks for the message #[serde(default)] pub callback_type: CallbackType, diff --git a/packages/vm/testdata/ibc_callbacks.wasm b/packages/vm/testdata/ibc_callbacks.wasm index 66ef1bf4d00214ac5ca92966127df3bfeddb6ff0..48cb125bc41ece4525cf9d3e447807b913137d9a 100644 GIT binary patch delta 62013 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 z zy>vgtZK?sIw6rS`;5fqm`)MATd;C|eqJgG)(7*D(v6M(hzTsyc1cjA-t0}DVL28`1 zQl3Q_*xMj|q0o=$5?HOqdfQig+gVDED1#`r_Vc57?(hL7|7f?nocwo^ecjGX6UyxO z+q>T(&Unb#-kr+tucoH|<{s}PPxz4j{Tq_QWTQ?r;|K$J@uhY zC;5f-l#0&1yPlRtRU)^R*aaIXGl=EV4b~;J@F9wQUzJ;i8i@H~WoZQmK zdw?L={Pu1KNxyBNgorizJ%4HifuN5(xXU$Y4BM9v#QkQ>v@`POL4V3;qHtRBB=3KM z;^Vgk5Z_R0frB7iRb-BbhpQ7*0^Xz|`2FJKvm3Qhs zLph1MKk}k4HWkyyWCXgv;m^=Spzg(ID9d|C?4asrXn5KxJ>(&1i4H*vkJv;LVjQ;B zCGFURFIAoA!aq^Rm>~A}u|L6ujgrFh1chQAkrr1_$F^(3kzLO<;r5|{dYhm(6yPIS zDii*|!0CaK4>w`vYFHZx=kdes_Y7IlaYhc=&j}u7Vv8}w>2`SZ(Ue2$W1PDq!WSRDL&?uq(}>E0R-^k z&D5gwCxKxV2}1NNM)y(7}wBFDm!7`Nn9M*2g6?in>;uE-^r=bVw`6@hwvA49i^wdvSa1;t#lnCKi*1rMx2AjgX$^#Gd&PGzmto-;+*+i80L3a0S?UX zRA7GRPv3^Uspi*w<;!%+{1<2YVX=SBxB2Oph-Jr6?#q1ZcIujbjwlZu)3ejecwsN# z57vnMff)5yZl}&+ppo#`D1FF5UIJLSFlCT$p5n^|Rj≧;gdLPj5D&6OiCxAE?4*TQ)`lB>-;daUFGz&5 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 Gtp5erfkQk1 delta 62128 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 zƁ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 From 79598a94b902f991c32c8f85c8f17e19484c22c1 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Thu, 18 Apr 2024 15:58:44 +0200 Subject: [PATCH 29/44] Simplify doc comment Co-authored-by: srdtrk <59252793+srdtrk@users.noreply.github.com> --- packages/std/src/ibc/callbacks.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/std/src/ibc/callbacks.rs b/packages/std/src/ibc/callbacks.rs index 1243e9a9d9..57a8e3ba15 100644 --- a/packages/std/src/ibc/callbacks.rs +++ b/packages/std/src/ibc/callbacks.rs @@ -101,8 +101,7 @@ pub struct IbcDstCallback { /// /// Note that there are some prerequisites that need to be fulfilled to receive source chain callbacks: /// - The contract must implement the `ibc_source_chain_callback` entrypoint. -/// - The module that sends the packet must be wrapped by an `IBCMiddleware` -/// (i.e. the source chain needs to support callbacks for the message you are sending). +/// - The IBC application in the source chain must have support for the callbacks middleware. /// - You have to add json-encoded [`IbcCallbackData`] to a specific field of the message. /// For `IbcMsg::Transfer`, this is the `memo` field. /// - The receiver of the callback must also be the sender of the message. From f085538c0b7dd5f3f5d8eca0a09169dc953e507c Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Thu, 18 Apr 2024 16:00:56 +0200 Subject: [PATCH 30/44] Correct docs --- contracts/ibc-callbacks/schema/ibc-callbacks.json | 2 +- .../schema/raw/response_to_callback_stats.json | 2 +- packages/std/src/ibc/callbacks.rs | 15 +++++++-------- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/contracts/ibc-callbacks/schema/ibc-callbacks.json b/contracts/ibc-callbacks/schema/ibc-callbacks.json index 1107b88433..3d9f969cdb 100644 --- a/contracts/ibc-callbacks/schema/ibc-callbacks.json +++ b/contracts/ibc-callbacks/schema/ibc-callbacks.json @@ -148,7 +148,7 @@ "additionalProperties": false }, "IbcDestinationChainCallbackMsg": { - "description": "The message type of the IBC destination chain callback.\n\nThe IBC destination chain callback is needed for cases where someone triggers the sending of an IBC packet through some other message (i.e. not through [`IbcMsg::SendPacket`]) and your contract needs to know that it received this. A prominent example is the [`IbcMsg::Transfer`] message. Without callbacks, you cannot know that someone sent you IBC coins.\n\nThe callback is called after the packet was acknowledged on the destination chain, as follows: - If the acknowledgement is synchronous (i.e. returned immediately when the packet is received), the callback is called only if the acknowledgement was successful. - If the acknowledgement is asynchronous (i.e. written later using `WriteAcknowledgement`), the callback is called regardless of the success of the acknowledgement.\n\nNote that there are some prerequisites that need to be fulfilled to receive source chain callbacks: - The contract must implement the `ibc_destination_chain_callback` entrypoint. - The module that receives the packet must be wrapped by an `IBCMiddleware` (i.e. the destination chain needs to support callbacks for the message you are being sent). - You have to add json-encoded [`IbcCallbackData`] to a specific field of the message. For `IbcMsg::Transfer`, this is the `memo` field.", + "description": "The message type of the IBC destination chain callback.\n\nThe IBC destination chain callback is needed for cases where someone triggers the sending of an IBC packet through some other message (i.e. not through [`IbcMsg::SendPacket`]) and your contract needs to know that it received this. A prominent example is the [`IbcMsg::Transfer`] message. Without callbacks, you cannot know that someone sent you IBC coins.\n\nThe callback is called after the packet was acknowledged on the destination chain, as follows: - If the acknowledgement is synchronous (i.e. returned immediately when the packet is received), the callback is called only if the acknowledgement was successful. - If the acknowledgement is asynchronous (i.e. written later using `WriteAcknowledgement`), the callback is called regardless of the success of the acknowledgement.\n\nNote that there are some prerequisites that need to be fulfilled to receive source chain callbacks: - The contract must implement the `ibc_destination_chain_callback` entrypoint. - The IBC application in the destination chain must have support for the callbacks middleware. - You have to add serialized [`IbcCallbackRequest`] to a specific field of the message. For `IbcMsg::Transfer`, this is the `memo` field and it needs to be json-encoded.", "type": "object", "required": [ "ack", diff --git a/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json index a57f65fb7e..fd27793095 100644 --- a/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json +++ b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json @@ -51,7 +51,7 @@ "additionalProperties": false }, "IbcDestinationChainCallbackMsg": { - "description": "The message type of the IBC destination chain callback.\n\nThe IBC destination chain callback is needed for cases where someone triggers the sending of an IBC packet through some other message (i.e. not through [`IbcMsg::SendPacket`]) and your contract needs to know that it received this. A prominent example is the [`IbcMsg::Transfer`] message. Without callbacks, you cannot know that someone sent you IBC coins.\n\nThe callback is called after the packet was acknowledged on the destination chain, as follows: - If the acknowledgement is synchronous (i.e. returned immediately when the packet is received), the callback is called only if the acknowledgement was successful. - If the acknowledgement is asynchronous (i.e. written later using `WriteAcknowledgement`), the callback is called regardless of the success of the acknowledgement.\n\nNote that there are some prerequisites that need to be fulfilled to receive source chain callbacks: - The contract must implement the `ibc_destination_chain_callback` entrypoint. - The module that receives the packet must be wrapped by an `IBCMiddleware` (i.e. the destination chain needs to support callbacks for the message you are being sent). - You have to add json-encoded [`IbcCallbackData`] to a specific field of the message. For `IbcMsg::Transfer`, this is the `memo` field.", + "description": "The message type of the IBC destination chain callback.\n\nThe IBC destination chain callback is needed for cases where someone triggers the sending of an IBC packet through some other message (i.e. not through [`IbcMsg::SendPacket`]) and your contract needs to know that it received this. A prominent example is the [`IbcMsg::Transfer`] message. Without callbacks, you cannot know that someone sent you IBC coins.\n\nThe callback is called after the packet was acknowledged on the destination chain, as follows: - If the acknowledgement is synchronous (i.e. returned immediately when the packet is received), the callback is called only if the acknowledgement was successful. - If the acknowledgement is asynchronous (i.e. written later using `WriteAcknowledgement`), the callback is called regardless of the success of the acknowledgement.\n\nNote that there are some prerequisites that need to be fulfilled to receive source chain callbacks: - The contract must implement the `ibc_destination_chain_callback` entrypoint. - The IBC application in the destination chain must have support for the callbacks middleware. - You have to add serialized [`IbcCallbackRequest`] to a specific field of the message. For `IbcMsg::Transfer`, this is the `memo` field and it needs to be json-encoded.", "type": "object", "required": [ "ack", diff --git a/packages/std/src/ibc/callbacks.rs b/packages/std/src/ibc/callbacks.rs index 57a8e3ba15..be77ae3e3d 100644 --- a/packages/std/src/ibc/callbacks.rs +++ b/packages/std/src/ibc/callbacks.rs @@ -8,8 +8,8 @@ use serde::{Deserialize, Serialize}; use crate::{Addr, IbcPacket, IbcPacketAckMsg, IbcPacketTimeoutMsg, Uint64}; /// This is just a type representing the data that has to be sent with the IBC message to receive -/// callbacks. It should be serialized to JSON and sent with the IBC message. -/// The specific field to send it in can vary depending on the IBC message, +/// callbacks. It should be serialized and sent with the IBC message. +/// The specific field and format to send it in can vary depending on the IBC message, /// but is usually the `memo` field by convention. /// /// See [`IbcSourceChainCallback`] for more details. @@ -102,8 +102,8 @@ pub struct IbcDstCallback { /// Note that there are some prerequisites that need to be fulfilled to receive source chain callbacks: /// - The contract must implement the `ibc_source_chain_callback` entrypoint. /// - The IBC application in the source chain must have support for the callbacks middleware. -/// - You have to add json-encoded [`IbcCallbackData`] to a specific field of the message. -/// For `IbcMsg::Transfer`, this is the `memo` field. +/// - You have to add serialized [`IbcCallbackData`] to a specific field of the message. +/// For `IbcMsg::Transfer`, this is the `memo` field and it needs to be json-encoded. /// - The receiver of the callback must also be the sender of the message. #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] @@ -128,10 +128,9 @@ pub enum IbcSourceChainCallbackMsg { /// /// Note that there are some prerequisites that need to be fulfilled to receive source chain callbacks: /// - The contract must implement the `ibc_destination_chain_callback` entrypoint. -/// - The module that receives the packet must be wrapped by an `IBCMiddleware` -/// (i.e. the destination chain needs to support callbacks for the message you are being sent). -/// - You have to add json-encoded [`IbcCallbackData`] to a specific field of the message. -/// For `IbcMsg::Transfer`, this is the `memo` field. +/// - The IBC application in the destination chain must have support for the callbacks middleware. +/// - You have to add serialized [`IbcCallbackData`] to a specific field of the message. +/// For `IbcMsg::Transfer`, this is the `memo` field and it needs to be json-encoded. #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct IbcDestinationChainCallbackMsg { pub packet: IbcPacket, From 2f619f9c2ad5ba4b0cc6f4601a0daaf8a319154f Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Thu, 18 Apr 2024 16:01:31 +0200 Subject: [PATCH 31/44] Rename IbcCallbackData to IbcCallbackRequest --- contracts/ibc-callbacks/src/contract.rs | 8 ++++---- packages/std/src/ibc/callbacks.rs | 20 ++++++++++---------- packages/std/src/lib.rs | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/contracts/ibc-callbacks/src/contract.rs b/contracts/ibc-callbacks/src/contract.rs index a9d601ac24..ebaec8e827 100644 --- a/contracts/ibc-callbacks/src/contract.rs +++ b/contracts/ibc-callbacks/src/contract.rs @@ -1,6 +1,6 @@ use cosmwasm_std::{ entry_point, to_json_binary, to_json_string, Binary, Deps, DepsMut, Empty, Env, - IbcBasicResponse, IbcCallbackData, IbcDestinationChainCallbackMsg, IbcDstCallback, IbcMsg, + IbcBasicResponse, IbcCallbackRequest, IbcDestinationChainCallbackMsg, IbcDstCallback, IbcMsg, IbcSourceChainCallbackMsg, IbcSrcCallback, IbcTimeout, MessageInfo, Response, StdError, StdResult, }; @@ -47,9 +47,9 @@ pub fn execute( channel_id: msg.channel_id, amount: coin.clone(), memo: Some(to_json_string(&match msg.callback_type { - CallbackType::Both => IbcCallbackData::both(src_callback, dst_callback), - CallbackType::Src => IbcCallbackData::source(src_callback), - CallbackType::Dst => IbcCallbackData::destination(dst_callback), + CallbackType::Both => IbcCallbackRequest::both(src_callback, dst_callback), + CallbackType::Src => IbcCallbackRequest::source(src_callback), + CallbackType::Dst => IbcCallbackRequest::destination(dst_callback), })?), }, _ => { diff --git a/packages/std/src/ibc/callbacks.rs b/packages/std/src/ibc/callbacks.rs index be77ae3e3d..fa253bc5a9 100644 --- a/packages/std/src/ibc/callbacks.rs +++ b/packages/std/src/ibc/callbacks.rs @@ -18,7 +18,7 @@ use crate::{Addr, IbcPacket, IbcPacketAckMsg, IbcPacketTimeoutMsg, Uint64}; /// /// ```rust /// use cosmwasm_std::{ -/// to_json_string, Coin, IbcCallbackData, IbcMsg, IbcSrcCallback, IbcTimeout, Response, +/// to_json_string, Coin, IbcCallbackRequest, IbcMsg, IbcSrcCallback, IbcTimeout, Response, /// Timestamp, /// }; /// @@ -30,14 +30,14 @@ use crate::{Addr, IbcPacket, IbcPacketAckMsg, IbcPacketTimeoutMsg, Uint64}; /// channel_id: "channel-0".to_string(), /// amount: Coin::new(10u32, "ucoin"), /// timeout: Timestamp::from_seconds(12345).into(), -/// memo: Some(to_json_string(&IbcCallbackData::source(IbcSrcCallback { +/// memo: Some(to_json_string(&IbcCallbackRequest::source(IbcSrcCallback { /// address: env.contract.address, /// gas_limit: None, /// })).unwrap()), /// }; /// ``` #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] -pub struct IbcCallbackData { +pub struct IbcCallbackRequest { // using private fields to force use of the constructors #[serde(skip_serializing_if = "Option::is_none")] src_callback: Option, @@ -45,10 +45,10 @@ pub struct IbcCallbackData { dest_callback: Option, } -impl IbcCallbackData { +impl IbcCallbackRequest { /// Use this if you want to execute callbacks on both the source and destination chain. pub fn both(src_callback: IbcSrcCallback, dest_callback: IbcDstCallback) -> Self { - IbcCallbackData { + IbcCallbackRequest { src_callback: Some(src_callback), dest_callback: Some(dest_callback), } @@ -56,7 +56,7 @@ impl IbcCallbackData { /// Use this if you want to execute callbacks on the source chain, but not the destination chain. pub fn source(src_callback: IbcSrcCallback) -> Self { - IbcCallbackData { + IbcCallbackRequest { src_callback: Some(src_callback), dest_callback: None, } @@ -64,7 +64,7 @@ impl IbcCallbackData { /// Use this if you want to execute callbacks on the destination chain, but not the source chain. pub fn destination(dest_callback: IbcDstCallback) -> Self { - IbcCallbackData { + IbcCallbackRequest { src_callback: None, dest_callback: Some(dest_callback), } @@ -102,7 +102,7 @@ pub struct IbcDstCallback { /// Note that there are some prerequisites that need to be fulfilled to receive source chain callbacks: /// - The contract must implement the `ibc_source_chain_callback` entrypoint. /// - The IBC application in the source chain must have support for the callbacks middleware. -/// - You have to add serialized [`IbcCallbackData`] to a specific field of the message. +/// - You have to add serialized [`IbcCallbackRequest`] to a specific field of the message. /// For `IbcMsg::Transfer`, this is the `memo` field and it needs to be json-encoded. /// - The receiver of the callback must also be the sender of the message. #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] @@ -129,7 +129,7 @@ pub enum IbcSourceChainCallbackMsg { /// Note that there are some prerequisites that need to be fulfilled to receive source chain callbacks: /// - The contract must implement the `ibc_destination_chain_callback` entrypoint. /// - The IBC application in the destination chain must have support for the callbacks middleware. -/// - You have to add serialized [`IbcCallbackData`] to a specific field of the message. +/// - You have to add serialized [`IbcCallbackRequest`] to a specific field of the message. /// For `IbcMsg::Transfer`, this is the `memo` field and it needs to be json-encoded. #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct IbcDestinationChainCallbackMsg { @@ -155,7 +155,7 @@ mod tests { #[test] fn ibc_callback_data_serialization() { - let mut data = IbcCallbackData::both( + let mut data = IbcCallbackRequest::both( IbcSrcCallback { address: Addr::unchecked("src_address"), gas_limit: Some(123u64.into()), diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index 7270e2e080..e72f4889e4 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -40,7 +40,7 @@ pub use crate::coins::Coins; pub use crate::deps::{Deps, DepsMut, OwnedDeps}; pub use crate::ibc::IbcChannelOpenResponse; pub use crate::ibc::{ - Ibc3ChannelOpenResponse, IbcAcknowledgement, IbcBasicResponse, IbcCallbackData, IbcChannel, + Ibc3ChannelOpenResponse, IbcAcknowledgement, IbcBasicResponse, IbcCallbackRequest, IbcChannel, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, IbcDestinationChainCallbackMsg, IbcDstCallback, IbcEndpoint, IbcFullAcknowledgement, IbcMsg, IbcOrder, IbcPacket, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, From ff80f942f75a72a5264793181e45bd04888f254c Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Thu, 18 Apr 2024 17:05:00 +0200 Subject: [PATCH 32/44] Make source chain callbacks extendable --- contracts/ibc-callbacks/src/contract.rs | 25 +++++++++++++++++++------ packages/std/src/ibc/callbacks.rs | 12 +++++++++--- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/contracts/ibc-callbacks/src/contract.rs b/contracts/ibc-callbacks/src/contract.rs index ebaec8e827..950405b4d8 100644 --- a/contracts/ibc-callbacks/src/contract.rs +++ b/contracts/ibc-callbacks/src/contract.rs @@ -1,8 +1,8 @@ use cosmwasm_std::{ entry_point, to_json_binary, to_json_string, Binary, Deps, DepsMut, Empty, Env, IbcBasicResponse, IbcCallbackRequest, IbcDestinationChainCallbackMsg, IbcDstCallback, IbcMsg, - IbcSourceChainCallbackMsg, IbcSrcCallback, IbcTimeout, MessageInfo, Response, StdError, - StdResult, + IbcPacketAckMsg, IbcPacketTimeoutMsg, IbcSourceChainCallbackMsg, IbcSrcCallback, IbcTimeout, + MessageInfo, Response, StdError, StdResult, }; use crate::msg::{CallbackType, ExecuteMsg, QueryMsg}; @@ -82,13 +82,26 @@ pub fn ibc_source_chain_callback( let mut counts = load_stats(deps.storage)?; match msg { - IbcSourceChainCallbackMsg::Acknowledgement(ack) => { + IbcSourceChainCallbackMsg::Acknowledgement { + acknowledgement, + original_packet, + relayer, + .. + } => { // save the ack - counts.ibc_ack_callbacks.push(ack); + counts.ibc_ack_callbacks.push(IbcPacketAckMsg::new( + acknowledgement, + original_packet, + relayer, + )); } - IbcSourceChainCallbackMsg::Timeout(timeout) => { + IbcSourceChainCallbackMsg::Timeout { + packet, relayer, .. + } => { // save the timeout - counts.ibc_timeout_callbacks.push(timeout); + counts + .ibc_timeout_callbacks + .push(IbcPacketTimeoutMsg::new(packet, relayer)); } } diff --git a/packages/std/src/ibc/callbacks.rs b/packages/std/src/ibc/callbacks.rs index fa253bc5a9..f83c1c1216 100644 --- a/packages/std/src/ibc/callbacks.rs +++ b/packages/std/src/ibc/callbacks.rs @@ -5,7 +5,7 @@ use cosmwasm_core::Binary; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use crate::{Addr, IbcPacket, IbcPacketAckMsg, IbcPacketTimeoutMsg, Uint64}; +use crate::{Addr, IbcAcknowledgement, IbcPacket, Uint64}; /// This is just a type representing the data that has to be sent with the IBC message to receive /// callbacks. It should be serialized and sent with the IBC message. @@ -108,8 +108,14 @@ pub struct IbcDstCallback { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum IbcSourceChainCallbackMsg { - Acknowledgement(IbcPacketAckMsg), - Timeout(IbcPacketTimeoutMsg), + #[non_exhaustive] + Acknowledgement { + acknowledgement: IbcAcknowledgement, + original_packet: IbcPacket, + relayer: Addr, + }, + #[non_exhaustive] + Timeout { packet: IbcPacket, relayer: Addr }, } /// The message type of the IBC destination chain callback. From a37ab64d081e31272c7bb031cf828300612493bb Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 19 Apr 2024 09:57:15 +0200 Subject: [PATCH 33/44] Adjust source chain callback type --- .../ibc-callbacks/schema/ibc-callbacks.json | 78 +++++++++---------- .../raw/response_to_callback_stats.json | 78 +++++++++---------- contracts/ibc-callbacks/src/contract.rs | 25 ++---- contracts/ibc-callbacks/src/state.rs | 8 +- packages/std/src/ibc/callbacks.rs | 39 ++++++++-- packages/std/src/lib.rs | 11 +-- packages/vm/src/calls.rs | 22 ++++-- 7 files changed, 140 insertions(+), 121 deletions(-) diff --git a/contracts/ibc-callbacks/schema/ibc-callbacks.json b/contracts/ibc-callbacks/schema/ibc-callbacks.json index 3d9f969cdb..346aa4e9d9 100644 --- a/contracts/ibc-callbacks/schema/ibc-callbacks.json +++ b/contracts/ibc-callbacks/schema/ibc-callbacks.json @@ -109,7 +109,7 @@ "ibc_ack_callbacks": { "type": "array", "items": { - "$ref": "#/definitions/IbcPacketAckMsg" + "$ref": "#/definitions/IbcAckCallbackMsg" } }, "ibc_destination_callbacks": { @@ -121,7 +121,7 @@ "ibc_timeout_callbacks": { "type": "array", "items": { - "$ref": "#/definitions/IbcPacketTimeoutMsg" + "$ref": "#/definitions/IbcTimeoutCallbackMsg" } } }, @@ -135,6 +135,26 @@ "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", "type": "string" }, + "IbcAckCallbackMsg": { + "type": "object", + "required": [ + "acknowledgement", + "original_packet", + "relayer" + ], + "properties": { + "acknowledgement": { + "$ref": "#/definitions/IbcAcknowledgement" + }, + "original_packet": { + "$ref": "#/definitions/IbcPacket" + }, + "relayer": { + "$ref": "#/definitions/Addr" + } + }, + "additionalProperties": false + }, "IbcAcknowledgement": { "type": "object", "required": [ @@ -249,44 +269,6 @@ }, "additionalProperties": false }, - "IbcPacketAckMsg": { - "description": "The message that is passed into `ibc_packet_ack`", - "type": "object", - "required": [ - "acknowledgement", - "original_packet", - "relayer" - ], - "properties": { - "acknowledgement": { - "$ref": "#/definitions/IbcAcknowledgement" - }, - "original_packet": { - "$ref": "#/definitions/IbcPacket" - }, - "relayer": { - "$ref": "#/definitions/Addr" - } - }, - "additionalProperties": false - }, - "IbcPacketTimeoutMsg": { - "description": "The message that is passed into `ibc_packet_timeout`", - "type": "object", - "required": [ - "packet", - "relayer" - ], - "properties": { - "packet": { - "$ref": "#/definitions/IbcPacket" - }, - "relayer": { - "$ref": "#/definitions/Addr" - } - }, - "additionalProperties": false - }, "IbcTimeout": { "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.", "type": "object", @@ -337,6 +319,22 @@ }, "additionalProperties": false }, + "IbcTimeoutCallbackMsg": { + "type": "object", + "required": [ + "packet", + "relayer" + ], + "properties": { + "packet": { + "$ref": "#/definitions/IbcPacket" + }, + "relayer": { + "$ref": "#/definitions/Addr" + } + }, + "additionalProperties": false + }, "Timestamp": { "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", "allOf": [ diff --git a/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json index fd27793095..ec5ab4a057 100644 --- a/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json +++ b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json @@ -12,7 +12,7 @@ "ibc_ack_callbacks": { "type": "array", "items": { - "$ref": "#/definitions/IbcPacketAckMsg" + "$ref": "#/definitions/IbcAckCallbackMsg" } }, "ibc_destination_callbacks": { @@ -24,7 +24,7 @@ "ibc_timeout_callbacks": { "type": "array", "items": { - "$ref": "#/definitions/IbcPacketTimeoutMsg" + "$ref": "#/definitions/IbcTimeoutCallbackMsg" } } }, @@ -38,6 +38,26 @@ "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", "type": "string" }, + "IbcAckCallbackMsg": { + "type": "object", + "required": [ + "acknowledgement", + "original_packet", + "relayer" + ], + "properties": { + "acknowledgement": { + "$ref": "#/definitions/IbcAcknowledgement" + }, + "original_packet": { + "$ref": "#/definitions/IbcPacket" + }, + "relayer": { + "$ref": "#/definitions/Addr" + } + }, + "additionalProperties": false + }, "IbcAcknowledgement": { "type": "object", "required": [ @@ -152,44 +172,6 @@ }, "additionalProperties": false }, - "IbcPacketAckMsg": { - "description": "The message that is passed into `ibc_packet_ack`", - "type": "object", - "required": [ - "acknowledgement", - "original_packet", - "relayer" - ], - "properties": { - "acknowledgement": { - "$ref": "#/definitions/IbcAcknowledgement" - }, - "original_packet": { - "$ref": "#/definitions/IbcPacket" - }, - "relayer": { - "$ref": "#/definitions/Addr" - } - }, - "additionalProperties": false - }, - "IbcPacketTimeoutMsg": { - "description": "The message that is passed into `ibc_packet_timeout`", - "type": "object", - "required": [ - "packet", - "relayer" - ], - "properties": { - "packet": { - "$ref": "#/definitions/IbcPacket" - }, - "relayer": { - "$ref": "#/definitions/Addr" - } - }, - "additionalProperties": false - }, "IbcTimeout": { "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.", "type": "object", @@ -240,6 +222,22 @@ }, "additionalProperties": false }, + "IbcTimeoutCallbackMsg": { + "type": "object", + "required": [ + "packet", + "relayer" + ], + "properties": { + "packet": { + "$ref": "#/definitions/IbcPacket" + }, + "relayer": { + "$ref": "#/definitions/Addr" + } + }, + "additionalProperties": false + }, "Timestamp": { "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", "allOf": [ diff --git a/contracts/ibc-callbacks/src/contract.rs b/contracts/ibc-callbacks/src/contract.rs index 950405b4d8..ebaec8e827 100644 --- a/contracts/ibc-callbacks/src/contract.rs +++ b/contracts/ibc-callbacks/src/contract.rs @@ -1,8 +1,8 @@ use cosmwasm_std::{ entry_point, to_json_binary, to_json_string, Binary, Deps, DepsMut, Empty, Env, IbcBasicResponse, IbcCallbackRequest, IbcDestinationChainCallbackMsg, IbcDstCallback, IbcMsg, - IbcPacketAckMsg, IbcPacketTimeoutMsg, IbcSourceChainCallbackMsg, IbcSrcCallback, IbcTimeout, - MessageInfo, Response, StdError, StdResult, + IbcSourceChainCallbackMsg, IbcSrcCallback, IbcTimeout, MessageInfo, Response, StdError, + StdResult, }; use crate::msg::{CallbackType, ExecuteMsg, QueryMsg}; @@ -82,26 +82,13 @@ pub fn ibc_source_chain_callback( let mut counts = load_stats(deps.storage)?; match msg { - IbcSourceChainCallbackMsg::Acknowledgement { - acknowledgement, - original_packet, - relayer, - .. - } => { + IbcSourceChainCallbackMsg::Acknowledgement(ack) => { // save the ack - counts.ibc_ack_callbacks.push(IbcPacketAckMsg::new( - acknowledgement, - original_packet, - relayer, - )); + counts.ibc_ack_callbacks.push(ack); } - IbcSourceChainCallbackMsg::Timeout { - packet, relayer, .. - } => { + IbcSourceChainCallbackMsg::Timeout(timeout) => { // save the timeout - counts - .ibc_timeout_callbacks - .push(IbcPacketTimeoutMsg::new(packet, relayer)); + counts.ibc_timeout_callbacks.push(timeout); } } diff --git a/contracts/ibc-callbacks/src/state.rs b/contracts/ibc-callbacks/src/state.rs index 0e0c60ae1d..88cc3b1a9e 100644 --- a/contracts/ibc-callbacks/src/state.rs +++ b/contracts/ibc-callbacks/src/state.rs @@ -2,8 +2,8 @@ use std::any::type_name; use cosmwasm_schema::cw_serde; use cosmwasm_std::{ - from_json, storage_keys::to_length_prefixed, to_json_vec, IbcDestinationChainCallbackMsg, - IbcPacketAckMsg, IbcPacketTimeoutMsg, StdError, StdResult, Storage, + from_json, storage_keys::to_length_prefixed, to_json_vec, IbcAckCallbackMsg, + IbcDestinationChainCallbackMsg, IbcTimeoutCallbackMsg, StdError, StdResult, Storage, }; use serde::{de::DeserializeOwned, Serialize}; @@ -13,8 +13,8 @@ pub const KEY_STATS: &[u8] = b"counts"; #[cw_serde] #[derive(Default)] pub struct CallbackStats { - pub ibc_ack_callbacks: Vec, - pub ibc_timeout_callbacks: Vec, + pub ibc_ack_callbacks: Vec, + pub ibc_timeout_callbacks: Vec, pub ibc_destination_callbacks: Vec, } diff --git a/packages/std/src/ibc/callbacks.rs b/packages/std/src/ibc/callbacks.rs index f83c1c1216..9506578572 100644 --- a/packages/std/src/ibc/callbacks.rs +++ b/packages/std/src/ibc/callbacks.rs @@ -108,14 +108,43 @@ pub struct IbcDstCallback { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum IbcSourceChainCallbackMsg { - #[non_exhaustive] - Acknowledgement { + Acknowledgement(IbcAckCallbackMsg), + Timeout(IbcTimeoutCallbackMsg), +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[non_exhaustive] +pub struct IbcAckCallbackMsg { + acknowledgement: IbcAcknowledgement, + original_packet: IbcPacket, + relayer: Addr, +} + +impl IbcAckCallbackMsg { + pub fn new( acknowledgement: IbcAcknowledgement, original_packet: IbcPacket, relayer: Addr, - }, - #[non_exhaustive] - Timeout { packet: IbcPacket, relayer: Addr }, + ) -> Self { + Self { + acknowledgement, + original_packet, + relayer, + } + } +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[non_exhaustive] +pub struct IbcTimeoutCallbackMsg { + packet: IbcPacket, + relayer: Addr, +} + +impl IbcTimeoutCallbackMsg { + pub fn new(packet: IbcPacket, relayer: Addr) -> Self { + Self { packet, relayer } + } } /// The message type of the IBC destination chain callback. diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index e72f4889e4..5bd2bd184c 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -40,11 +40,12 @@ pub use crate::coins::Coins; pub use crate::deps::{Deps, DepsMut, OwnedDeps}; pub use crate::ibc::IbcChannelOpenResponse; pub use crate::ibc::{ - Ibc3ChannelOpenResponse, IbcAcknowledgement, IbcBasicResponse, IbcCallbackRequest, IbcChannel, - IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, IbcDestinationChainCallbackMsg, - IbcDstCallback, IbcEndpoint, IbcFullAcknowledgement, IbcMsg, IbcOrder, IbcPacket, - IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, - IbcSourceChainCallbackMsg, IbcSrcCallback, IbcTimeout, IbcTimeoutBlock, + Ibc3ChannelOpenResponse, IbcAckCallbackMsg, IbcAcknowledgement, IbcBasicResponse, + IbcCallbackRequest, IbcChannel, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, + IbcDestinationChainCallbackMsg, IbcDstCallback, IbcEndpoint, IbcFullAcknowledgement, IbcMsg, + IbcOrder, IbcPacket, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, + IbcReceiveResponse, IbcSourceChainCallbackMsg, IbcSrcCallback, IbcTimeout, IbcTimeoutBlock, + IbcTimeoutCallbackMsg, }; #[cfg(feature = "iterator")] pub use crate::iterator::{Order, Record}; diff --git a/packages/vm/src/calls.rs b/packages/vm/src/calls.rs index 2ef8abb80b..5491e89905 100644 --- a/packages/vm/src/calls.rs +++ b/packages/vm/src/calls.rs @@ -956,7 +956,8 @@ mod tests { mock_ibc_packet_ack, mock_ibc_packet_recv, mock_wasmd_attr, }; use cosmwasm_std::{ - Event, IbcAcknowledgement, IbcOrder, ReplyOn, SubMsgResponse, SubMsgResult, + Event, IbcAckCallbackMsg, IbcAcknowledgement, IbcOrder, IbcTimeoutCallbackMsg, ReplyOn, + SubMsgResponse, SubMsgResult, }; const CONTRACT: &[u8] = include_bytes!("../testdata/ibc_reflect.wasm"); const IBC_CALLBACKS: &[u8] = include_bytes!("../testdata/ibc_callbacks.wasm"); @@ -1088,10 +1089,13 @@ mod tests { } // send ack callback - let ack = IbcAcknowledgement::new(br#"{}"#); - let msg = IbcSourceChainCallbackMsg::Acknowledgement( - mock_ibc_packet_ack(CHANNEL_ID, br#"{}"#, ack).unwrap(), - ); + let ack = mock_ibc_packet_ack(CHANNEL_ID, br#"{}"#, IbcAcknowledgement::new(br#"{}"#)) + .unwrap(); + let msg = IbcSourceChainCallbackMsg::Acknowledgement(IbcAckCallbackMsg::new( + ack.acknowledgement, + ack.original_packet, + ack.relayer, + )); call_ibc_source_chain_callback::<_, _, _, Empty>(&mut instance, &mock_env(), &msg) .unwrap() .unwrap(); @@ -1106,9 +1110,11 @@ mod tests { assert_eq!(0, stats.ibc_timeout_callbacks.len()); // send timeout callback - let msg = IbcSourceChainCallbackMsg::Timeout( - mock_ibc_packet_timeout(CHANNEL_ID, br#"{}"#).unwrap(), - ); + let timeout = mock_ibc_packet_timeout(CHANNEL_ID, br#"{}"#).unwrap(); + let msg = IbcSourceChainCallbackMsg::Timeout(IbcTimeoutCallbackMsg::new( + timeout.packet, + timeout.relayer, + )); call_ibc_source_chain_callback::<_, _, _, Empty>(&mut instance, &mock_env(), &msg) .unwrap() .unwrap(); From 57d5174df0bfde3db292c67f7d1bf38bbcdda80a Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Mon, 29 Apr 2024 13:53:16 +0200 Subject: [PATCH 34/44] Fix doc links --- contracts/ibc-callbacks/schema/ibc-callbacks.json | 2 +- .../schema/raw/response_to_callback_stats.json | 2 +- packages/std/src/ibc/callbacks.rs | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/contracts/ibc-callbacks/schema/ibc-callbacks.json b/contracts/ibc-callbacks/schema/ibc-callbacks.json index 346aa4e9d9..80a3d7ae83 100644 --- a/contracts/ibc-callbacks/schema/ibc-callbacks.json +++ b/contracts/ibc-callbacks/schema/ibc-callbacks.json @@ -168,7 +168,7 @@ "additionalProperties": false }, "IbcDestinationChainCallbackMsg": { - "description": "The message type of the IBC destination chain callback.\n\nThe IBC destination chain callback is needed for cases where someone triggers the sending of an IBC packet through some other message (i.e. not through [`IbcMsg::SendPacket`]) and your contract needs to know that it received this. A prominent example is the [`IbcMsg::Transfer`] message. Without callbacks, you cannot know that someone sent you IBC coins.\n\nThe callback is called after the packet was acknowledged on the destination chain, as follows: - If the acknowledgement is synchronous (i.e. returned immediately when the packet is received), the callback is called only if the acknowledgement was successful. - If the acknowledgement is asynchronous (i.e. written later using `WriteAcknowledgement`), the callback is called regardless of the success of the acknowledgement.\n\nNote that there are some prerequisites that need to be fulfilled to receive source chain callbacks: - The contract must implement the `ibc_destination_chain_callback` entrypoint. - The IBC application in the destination chain must have support for the callbacks middleware. - You have to add serialized [`IbcCallbackRequest`] to a specific field of the message. For `IbcMsg::Transfer`, this is the `memo` field and it needs to be json-encoded.", + "description": "The message type of the IBC destination chain callback.\n\nThe IBC destination chain callback is needed for cases where someone triggers the sending of an IBC packet through some other message (i.e. not through [`crate::IbcMsg::SendPacket`]) and your contract needs to know that it received this. A prominent example is the [`crate::IbcMsg::Transfer`] message. Without callbacks, you cannot know that someone sent you IBC coins.\n\nThe callback is called after the packet was acknowledged on the destination chain, as follows: - If the acknowledgement is synchronous (i.e. returned immediately when the packet is received), the callback is called only if the acknowledgement was successful. - If the acknowledgement is asynchronous (i.e. written later using `WriteAcknowledgement`), the callback is called regardless of the success of the acknowledgement.\n\nNote that there are some prerequisites that need to be fulfilled to receive source chain callbacks: - The contract must implement the `ibc_destination_chain_callback` entrypoint. - The IBC application in the destination chain must have support for the callbacks middleware. - You have to add serialized [`IbcCallbackRequest`] to a specific field of the message. For `IbcMsg::Transfer`, this is the `memo` field and it needs to be json-encoded.", "type": "object", "required": [ "ack", diff --git a/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json index ec5ab4a057..20b5c0b728 100644 --- a/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json +++ b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json @@ -71,7 +71,7 @@ "additionalProperties": false }, "IbcDestinationChainCallbackMsg": { - "description": "The message type of the IBC destination chain callback.\n\nThe IBC destination chain callback is needed for cases where someone triggers the sending of an IBC packet through some other message (i.e. not through [`IbcMsg::SendPacket`]) and your contract needs to know that it received this. A prominent example is the [`IbcMsg::Transfer`] message. Without callbacks, you cannot know that someone sent you IBC coins.\n\nThe callback is called after the packet was acknowledged on the destination chain, as follows: - If the acknowledgement is synchronous (i.e. returned immediately when the packet is received), the callback is called only if the acknowledgement was successful. - If the acknowledgement is asynchronous (i.e. written later using `WriteAcknowledgement`), the callback is called regardless of the success of the acknowledgement.\n\nNote that there are some prerequisites that need to be fulfilled to receive source chain callbacks: - The contract must implement the `ibc_destination_chain_callback` entrypoint. - The IBC application in the destination chain must have support for the callbacks middleware. - You have to add serialized [`IbcCallbackRequest`] to a specific field of the message. For `IbcMsg::Transfer`, this is the `memo` field and it needs to be json-encoded.", + "description": "The message type of the IBC destination chain callback.\n\nThe IBC destination chain callback is needed for cases where someone triggers the sending of an IBC packet through some other message (i.e. not through [`crate::IbcMsg::SendPacket`]) and your contract needs to know that it received this. A prominent example is the [`crate::IbcMsg::Transfer`] message. Without callbacks, you cannot know that someone sent you IBC coins.\n\nThe callback is called after the packet was acknowledged on the destination chain, as follows: - If the acknowledgement is synchronous (i.e. returned immediately when the packet is received), the callback is called only if the acknowledgement was successful. - If the acknowledgement is asynchronous (i.e. written later using `WriteAcknowledgement`), the callback is called regardless of the success of the acknowledgement.\n\nNote that there are some prerequisites that need to be fulfilled to receive source chain callbacks: - The contract must implement the `ibc_destination_chain_callback` entrypoint. - The IBC application in the destination chain must have support for the callbacks middleware. - You have to add serialized [`IbcCallbackRequest`] to a specific field of the message. For `IbcMsg::Transfer`, this is the `memo` field and it needs to be json-encoded.", "type": "object", "required": [ "ack", diff --git a/packages/std/src/ibc/callbacks.rs b/packages/std/src/ibc/callbacks.rs index 9506578572..c8ab73f565 100644 --- a/packages/std/src/ibc/callbacks.rs +++ b/packages/std/src/ibc/callbacks.rs @@ -12,7 +12,7 @@ use crate::{Addr, IbcAcknowledgement, IbcPacket, Uint64}; /// The specific field and format to send it in can vary depending on the IBC message, /// but is usually the `memo` field by convention. /// -/// See [`IbcSourceChainCallback`] for more details. +/// See [`IbcSourceChainCallbackMsg`] and [`IbcDestinationChainCallbackMsg`] for more details. /// /// # Example /// @@ -94,9 +94,9 @@ pub struct IbcDstCallback { /// The type of IBC source chain callback that is being called. /// /// IBC source chain callbacks are needed for cases where your contract triggers the sending of an -/// IBC packet through some other message (i.e. not through [`IbcMsg::SendPacket`]) and needs to +/// IBC packet through some other message (i.e. not through [`crate::IbcMsg::SendPacket`]) and needs to /// know whether or not the packet was successfully received on the other chain. -/// A prominent example is the [`IbcMsg::Transfer`] message. Without callbacks, you cannot know +/// A prominent example is the [`crate::IbcMsg::Transfer`] message. Without callbacks, you cannot know /// whether the transfer was successful or not. /// /// Note that there are some prerequisites that need to be fulfilled to receive source chain callbacks: @@ -150,9 +150,9 @@ impl IbcTimeoutCallbackMsg { /// The message type of the IBC destination chain callback. /// /// The IBC destination chain callback is needed for cases where someone triggers the sending of an -/// IBC packet through some other message (i.e. not through [`IbcMsg::SendPacket`]) and +/// IBC packet through some other message (i.e. not through [`crate::IbcMsg::SendPacket`]) and /// your contract needs to know that it received this. -/// A prominent example is the [`IbcMsg::Transfer`] message. Without callbacks, you cannot know +/// A prominent example is the [`crate::IbcMsg::Transfer`] message. Without callbacks, you cannot know /// that someone sent you IBC coins. /// /// The callback is called after the packet was acknowledged on the destination chain, as follows: From 0abe2a431c47eaf13e738cc7a0bdb31246226b56 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 10 May 2024 15:11:33 +0200 Subject: [PATCH 35/44] Rename ibc callbacks entrypoints and types --- .../ibc-callbacks/schema/ibc-callbacks.json | 6 +- .../raw/response_to_callback_stats.json | 6 +- contracts/ibc-callbacks/src/contract.rs | 21 +++---- contracts/ibc-callbacks/src/state.rs | 4 +- packages/std/src/exports.rs | 32 ++++------ packages/std/src/ibc/callbacks.rs | 22 +++---- packages/std/src/lib.rs | 8 +-- packages/vm/src/calls.rs | 61 +++++++++---------- packages/vm/src/lib.rs | 9 ++- 9 files changed, 78 insertions(+), 91 deletions(-) diff --git a/contracts/ibc-callbacks/schema/ibc-callbacks.json b/contracts/ibc-callbacks/schema/ibc-callbacks.json index 80a3d7ae83..aa78db7a89 100644 --- a/contracts/ibc-callbacks/schema/ibc-callbacks.json +++ b/contracts/ibc-callbacks/schema/ibc-callbacks.json @@ -115,7 +115,7 @@ "ibc_destination_callbacks": { "type": "array", "items": { - "$ref": "#/definitions/IbcDestinationChainCallbackMsg" + "$ref": "#/definitions/IbcDestinationCallbackMsg" } }, "ibc_timeout_callbacks": { @@ -167,8 +167,8 @@ }, "additionalProperties": false }, - "IbcDestinationChainCallbackMsg": { - "description": "The message type of the IBC destination chain callback.\n\nThe IBC destination chain callback is needed for cases where someone triggers the sending of an IBC packet through some other message (i.e. not through [`crate::IbcMsg::SendPacket`]) and your contract needs to know that it received this. A prominent example is the [`crate::IbcMsg::Transfer`] message. Without callbacks, you cannot know that someone sent you IBC coins.\n\nThe callback is called after the packet was acknowledged on the destination chain, as follows: - If the acknowledgement is synchronous (i.e. returned immediately when the packet is received), the callback is called only if the acknowledgement was successful. - If the acknowledgement is asynchronous (i.e. written later using `WriteAcknowledgement`), the callback is called regardless of the success of the acknowledgement.\n\nNote that there are some prerequisites that need to be fulfilled to receive source chain callbacks: - The contract must implement the `ibc_destination_chain_callback` entrypoint. - The IBC application in the destination chain must have support for the callbacks middleware. - You have to add serialized [`IbcCallbackRequest`] to a specific field of the message. For `IbcMsg::Transfer`, this is the `memo` field and it needs to be json-encoded.", + "IbcDestinationCallbackMsg": { + "description": "The message type of the IBC destination callback.\n\nThe IBC destination callback is needed for cases where someone triggers the sending of an IBC packet through some other message (i.e. not through [`crate::IbcMsg::SendPacket`]) and your contract needs to know that it received this. A prominent example is the [`crate::IbcMsg::Transfer`] message. Without callbacks, you cannot know that someone sent you IBC coins.\n\nThe callback is called after the packet was acknowledged on the destination chain, as follows: - If the acknowledgement is synchronous (i.e. returned immediately when the packet is received), the callback is called only if the acknowledgement was successful. - If the acknowledgement is asynchronous (i.e. written later using `WriteAcknowledgement`), the callback is called regardless of the success of the acknowledgement.\n\nNote that there are some prerequisites that need to be fulfilled to receive source callbacks: - The contract must implement the `ibc_destination_callback` entrypoint. - The IBC application in the destination chain must have support for the callbacks middleware. - You have to add serialized [`IbcCallbackRequest`] to a specific field of the message. For `IbcMsg::Transfer`, this is the `memo` field and it needs to be json-encoded.", "type": "object", "required": [ "ack", diff --git a/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json index 20b5c0b728..975fe76533 100644 --- a/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json +++ b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json @@ -18,7 +18,7 @@ "ibc_destination_callbacks": { "type": "array", "items": { - "$ref": "#/definitions/IbcDestinationChainCallbackMsg" + "$ref": "#/definitions/IbcDestinationCallbackMsg" } }, "ibc_timeout_callbacks": { @@ -70,8 +70,8 @@ }, "additionalProperties": false }, - "IbcDestinationChainCallbackMsg": { - "description": "The message type of the IBC destination chain callback.\n\nThe IBC destination chain callback is needed for cases where someone triggers the sending of an IBC packet through some other message (i.e. not through [`crate::IbcMsg::SendPacket`]) and your contract needs to know that it received this. A prominent example is the [`crate::IbcMsg::Transfer`] message. Without callbacks, you cannot know that someone sent you IBC coins.\n\nThe callback is called after the packet was acknowledged on the destination chain, as follows: - If the acknowledgement is synchronous (i.e. returned immediately when the packet is received), the callback is called only if the acknowledgement was successful. - If the acknowledgement is asynchronous (i.e. written later using `WriteAcknowledgement`), the callback is called regardless of the success of the acknowledgement.\n\nNote that there are some prerequisites that need to be fulfilled to receive source chain callbacks: - The contract must implement the `ibc_destination_chain_callback` entrypoint. - The IBC application in the destination chain must have support for the callbacks middleware. - You have to add serialized [`IbcCallbackRequest`] to a specific field of the message. For `IbcMsg::Transfer`, this is the `memo` field and it needs to be json-encoded.", + "IbcDestinationCallbackMsg": { + "description": "The message type of the IBC destination callback.\n\nThe IBC destination callback is needed for cases where someone triggers the sending of an IBC packet through some other message (i.e. not through [`crate::IbcMsg::SendPacket`]) and your contract needs to know that it received this. A prominent example is the [`crate::IbcMsg::Transfer`] message. Without callbacks, you cannot know that someone sent you IBC coins.\n\nThe callback is called after the packet was acknowledged on the destination chain, as follows: - If the acknowledgement is synchronous (i.e. returned immediately when the packet is received), the callback is called only if the acknowledgement was successful. - If the acknowledgement is asynchronous (i.e. written later using `WriteAcknowledgement`), the callback is called regardless of the success of the acknowledgement.\n\nNote that there are some prerequisites that need to be fulfilled to receive source callbacks: - The contract must implement the `ibc_destination_callback` entrypoint. - The IBC application in the destination chain must have support for the callbacks middleware. - You have to add serialized [`IbcCallbackRequest`] to a specific field of the message. For `IbcMsg::Transfer`, this is the `memo` field and it needs to be json-encoded.", "type": "object", "required": [ "ack", diff --git a/contracts/ibc-callbacks/src/contract.rs b/contracts/ibc-callbacks/src/contract.rs index ebaec8e827..108fe990f4 100644 --- a/contracts/ibc-callbacks/src/contract.rs +++ b/contracts/ibc-callbacks/src/contract.rs @@ -1,8 +1,7 @@ use cosmwasm_std::{ entry_point, to_json_binary, to_json_string, Binary, Deps, DepsMut, Empty, Env, - IbcBasicResponse, IbcCallbackRequest, IbcDestinationChainCallbackMsg, IbcDstCallback, IbcMsg, - IbcSourceChainCallbackMsg, IbcSrcCallback, IbcTimeout, MessageInfo, Response, StdError, - StdResult, + IbcBasicResponse, IbcCallbackRequest, IbcDestinationCallbackMsg, IbcDstCallback, IbcMsg, + IbcSourceCallbackMsg, IbcSrcCallback, IbcTimeout, MessageInfo, Response, StdError, StdResult, }; use crate::msg::{CallbackType, ExecuteMsg, QueryMsg}; @@ -74,19 +73,19 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { /// This is the entrypoint that is called by the source chain when a callbacks-enabled IBC message /// is acknowledged or times out. #[entry_point] -pub fn ibc_source_chain_callback( +pub fn ibc_source_callback( deps: DepsMut, _env: Env, - msg: IbcSourceChainCallbackMsg, + msg: IbcSourceCallbackMsg, ) -> StdResult { let mut counts = load_stats(deps.storage)?; match msg { - IbcSourceChainCallbackMsg::Acknowledgement(ack) => { + IbcSourceCallbackMsg::Acknowledgement(ack) => { // save the ack counts.ibc_ack_callbacks.push(ack); } - IbcSourceChainCallbackMsg::Timeout(timeout) => { + IbcSourceCallbackMsg::Timeout(timeout) => { // save the timeout counts.ibc_timeout_callbacks.push(timeout); } @@ -94,14 +93,14 @@ pub fn ibc_source_chain_callback( save_stats(deps.storage, &counts)?; - Ok(IbcBasicResponse::new().add_attribute("action", "ibc_source_chain_callback")) + Ok(IbcBasicResponse::new().add_attribute("action", "ibc_source_callback")) } #[entry_point] -pub fn ibc_destination_chain_callback( +pub fn ibc_destination_callback( deps: DepsMut, _env: Env, - msg: IbcDestinationChainCallbackMsg, + msg: IbcDestinationCallbackMsg, ) -> StdResult { let mut counts = load_stats(deps.storage)?; @@ -110,5 +109,5 @@ pub fn ibc_destination_chain_callback( save_stats(deps.storage, &counts)?; - Ok(IbcBasicResponse::new().add_attribute("action", "ibc_destination_chain_callback")) + Ok(IbcBasicResponse::new().add_attribute("action", "ibc_destination_callback")) } diff --git a/contracts/ibc-callbacks/src/state.rs b/contracts/ibc-callbacks/src/state.rs index 88cc3b1a9e..ece4fb1ac9 100644 --- a/contracts/ibc-callbacks/src/state.rs +++ b/contracts/ibc-callbacks/src/state.rs @@ -3,7 +3,7 @@ use std::any::type_name; use cosmwasm_schema::cw_serde; use cosmwasm_std::{ from_json, storage_keys::to_length_prefixed, to_json_vec, IbcAckCallbackMsg, - IbcDestinationChainCallbackMsg, IbcTimeoutCallbackMsg, StdError, StdResult, Storage, + IbcDestinationCallbackMsg, IbcTimeoutCallbackMsg, StdError, StdResult, Storage, }; use serde::{de::DeserializeOwned, Serialize}; @@ -15,7 +15,7 @@ pub const KEY_STATS: &[u8] = b"counts"; pub struct CallbackStats { pub ibc_ack_callbacks: Vec, pub ibc_timeout_callbacks: Vec, - pub ibc_destination_callbacks: Vec, + pub ibc_destination_callbacks: Vec, } pub fn load_stats(storage: &dyn Storage) -> StdResult { diff --git a/packages/std/src/exports.rs b/packages/std/src/exports.rs index a1c4f42813..66fac9c961 100644 --- a/packages/std/src/exports.rs +++ b/packages/std/src/exports.rs @@ -13,7 +13,7 @@ use core::marker::PhantomData; use serde::de::DeserializeOwned; use crate::deps::OwnedDeps; -use crate::ibc::{IbcBasicResponse, IbcDestinationChainCallbackMsg, IbcSourceChainCallbackMsg}; +use crate::ibc::{IbcBasicResponse, IbcDestinationCallbackMsg, IbcSourceCallbackMsg}; #[cfg(feature = "stargate")] use crate::ibc::{ IbcChannelCloseMsg, IbcChannelConnectMsg, IbcPacketAckMsg, IbcPacketReceiveMsg, @@ -447,12 +447,8 @@ where Region::from_vec(v).to_heap_ptr() as u32 } -pub fn do_ibc_source_chain_callback( - contract_fn: &dyn Fn( - DepsMut, - Env, - IbcSourceChainCallbackMsg, - ) -> Result, E>, +pub fn do_ibc_source_callback( + contract_fn: &dyn Fn(DepsMut, Env, IbcSourceCallbackMsg) -> Result, E>, env_ptr: u32, msg_ptr: u32, ) -> u32 @@ -472,11 +468,11 @@ where Region::from_vec(v).to_heap_ptr() as u32 } -pub fn do_ibc_destination_chain_callback( +pub fn do_ibc_destination_callback( contract_fn: &dyn Fn( DepsMut, Env, - IbcDestinationChainCallbackMsg, + IbcDestinationCallbackMsg, ) -> Result, E>, env_ptr: u32, msg_ptr: u32, @@ -488,7 +484,7 @@ where { #[cfg(feature = "abort")] install_panic_handler(); - let res = _do_ibc_destination_chain_callback( + let res = _do_ibc_destination_callback( contract_fn, env_ptr as *mut Region, msg_ptr as *mut Region, @@ -751,12 +747,8 @@ where contract_fn(deps.as_mut(), env, msg).into() } -fn _do_ibc_source_chain_callback( - contract_fn: &dyn Fn( - DepsMut, - Env, - IbcSourceChainCallbackMsg, - ) -> Result, E>, +fn _do_ibc_source_callback( + contract_fn: &dyn Fn(DepsMut, Env, IbcSourceCallbackMsg) -> Result, E>, env_ptr: *mut Region, msg_ptr: *mut Region, ) -> ContractResult> @@ -769,17 +761,17 @@ where let msg: Vec = unsafe { Region::from_heap_ptr(msg_ptr).into_vec() }; let env: Env = try_into_contract_result!(from_json(env)); - let msg: IbcSourceChainCallbackMsg = try_into_contract_result!(from_json(msg)); + let msg: IbcSourceCallbackMsg = try_into_contract_result!(from_json(msg)); let mut deps = make_dependencies(); contract_fn(deps.as_mut(), env, msg).into() } -fn _do_ibc_destination_chain_callback( +fn _do_ibc_destination_callback( contract_fn: &dyn Fn( DepsMut, Env, - IbcDestinationChainCallbackMsg, + IbcDestinationCallbackMsg, ) -> Result, E>, env_ptr: *mut Region, msg_ptr: *mut Region, @@ -793,7 +785,7 @@ where let msg: Vec = unsafe { Region::from_heap_ptr(msg_ptr).into_vec() }; let env: Env = try_into_contract_result!(from_json(env)); - let msg: IbcDestinationChainCallbackMsg = try_into_contract_result!(from_json(msg)); + let msg: IbcDestinationCallbackMsg = try_into_contract_result!(from_json(msg)); let mut deps = make_dependencies(); contract_fn(deps.as_mut(), env, msg).into() diff --git a/packages/std/src/ibc/callbacks.rs b/packages/std/src/ibc/callbacks.rs index c8ab73f565..b4d08a788f 100644 --- a/packages/std/src/ibc/callbacks.rs +++ b/packages/std/src/ibc/callbacks.rs @@ -12,7 +12,7 @@ use crate::{Addr, IbcAcknowledgement, IbcPacket, Uint64}; /// The specific field and format to send it in can vary depending on the IBC message, /// but is usually the `memo` field by convention. /// -/// See [`IbcSourceChainCallbackMsg`] and [`IbcDestinationChainCallbackMsg`] for more details. +/// See [`IbcSourceCallbackMsg`] and [`IbcDestinationCallbackMsg`] for more details. /// /// # Example /// @@ -91,23 +91,23 @@ pub struct IbcDstCallback { pub gas_limit: Option, } -/// The type of IBC source chain callback that is being called. +/// The type of IBC source callback that is being called. /// -/// IBC source chain callbacks are needed for cases where your contract triggers the sending of an +/// IBC source callbacks are needed for cases where your contract triggers the sending of an /// IBC packet through some other message (i.e. not through [`crate::IbcMsg::SendPacket`]) and needs to /// know whether or not the packet was successfully received on the other chain. /// A prominent example is the [`crate::IbcMsg::Transfer`] message. Without callbacks, you cannot know /// whether the transfer was successful or not. /// -/// Note that there are some prerequisites that need to be fulfilled to receive source chain callbacks: -/// - The contract must implement the `ibc_source_chain_callback` entrypoint. +/// Note that there are some prerequisites that need to be fulfilled to receive source callbacks: +/// - The contract must implement the `ibc_source_callback` entrypoint. /// - The IBC application in the source chain must have support for the callbacks middleware. /// - You have to add serialized [`IbcCallbackRequest`] to a specific field of the message. /// For `IbcMsg::Transfer`, this is the `memo` field and it needs to be json-encoded. /// - The receiver of the callback must also be the sender of the message. #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] -pub enum IbcSourceChainCallbackMsg { +pub enum IbcSourceCallbackMsg { Acknowledgement(IbcAckCallbackMsg), Timeout(IbcTimeoutCallbackMsg), } @@ -147,9 +147,9 @@ impl IbcTimeoutCallbackMsg { } } -/// The message type of the IBC destination chain callback. +/// The message type of the IBC destination callback. /// -/// The IBC destination chain callback is needed for cases where someone triggers the sending of an +/// The IBC destination callback is needed for cases where someone triggers the sending of an /// IBC packet through some other message (i.e. not through [`crate::IbcMsg::SendPacket`]) and /// your contract needs to know that it received this. /// A prominent example is the [`crate::IbcMsg::Transfer`] message. Without callbacks, you cannot know @@ -161,13 +161,13 @@ impl IbcTimeoutCallbackMsg { /// - If the acknowledgement is asynchronous (i.e. written later using `WriteAcknowledgement`), /// the callback is called regardless of the success of the acknowledgement. /// -/// Note that there are some prerequisites that need to be fulfilled to receive source chain callbacks: -/// - The contract must implement the `ibc_destination_chain_callback` entrypoint. +/// Note that there are some prerequisites that need to be fulfilled to receive source callbacks: +/// - The contract must implement the `ibc_destination_callback` entrypoint. /// - The IBC application in the destination chain must have support for the callbacks middleware. /// - You have to add serialized [`IbcCallbackRequest`] to a specific field of the message. /// For `IbcMsg::Transfer`, this is the `memo` field and it needs to be json-encoded. #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] -pub struct IbcDestinationChainCallbackMsg { +pub struct IbcDestinationCallbackMsg { pub packet: IbcPacket, pub ack: IbcFullAcknowledgement, } diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index 5bd2bd184c..6c6f4809be 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -42,9 +42,9 @@ pub use crate::ibc::IbcChannelOpenResponse; pub use crate::ibc::{ Ibc3ChannelOpenResponse, IbcAckCallbackMsg, IbcAcknowledgement, IbcBasicResponse, IbcCallbackRequest, IbcChannel, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, - IbcDestinationChainCallbackMsg, IbcDstCallback, IbcEndpoint, IbcFullAcknowledgement, IbcMsg, + IbcDestinationCallbackMsg, IbcDstCallback, IbcEndpoint, IbcFullAcknowledgement, IbcMsg, IbcOrder, IbcPacket, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, - IbcReceiveResponse, IbcSourceChainCallbackMsg, IbcSrcCallback, IbcTimeout, IbcTimeoutBlock, + IbcReceiveResponse, IbcSourceCallbackMsg, IbcSrcCallback, IbcTimeout, IbcTimeoutBlock, IbcTimeoutCallbackMsg, }; #[cfg(feature = "iterator")] @@ -93,8 +93,8 @@ mod memory; // Used by exports and imports only. This assumes pointers are 32 bi #[cfg(target_arch = "wasm32")] pub use crate::exports::{ - do_execute, do_ibc_destination_chain_callback, do_ibc_source_chain_callback, do_instantiate, - do_migrate, do_query, do_reply, do_sudo, + do_execute, do_ibc_destination_callback, do_ibc_source_callback, do_instantiate, do_migrate, + do_query, do_reply, do_sudo, }; #[cfg(all(feature = "stargate", target_arch = "wasm32"))] pub use crate::exports::{ diff --git a/packages/vm/src/calls.rs b/packages/vm/src/calls.rs index 5491e89905..dde9e634a1 100644 --- a/packages/vm/src/calls.rs +++ b/packages/vm/src/calls.rs @@ -2,8 +2,8 @@ use serde::de::DeserializeOwned; use wasmer::Value; use cosmwasm_std::{ - ContractResult, CustomMsg, Env, IbcBasicResponse, IbcDestinationChainCallbackMsg, - IbcSourceChainCallbackMsg, MessageInfo, QueryResponse, Reply, Response, + ContractResult, CustomMsg, Env, IbcBasicResponse, IbcDestinationCallbackMsg, + IbcSourceCallbackMsg, MessageInfo, QueryResponse, Reply, Response, }; #[cfg(feature = "stargate")] use cosmwasm_std::{ @@ -56,10 +56,10 @@ mod read_limits { /// Max length (in bytes) of the result data from a ibc_packet_timeout call. #[cfg(feature = "stargate")] pub const RESULT_IBC_PACKET_TIMEOUT: usize = 64 * MI; - /// Max length (in bytes) of the result data from a ibc_source_chain_callback call. - pub const RESULT_IBC_SOURCE_CHAIN_CALLBACK: usize = 64 * MI; - /// Max length (in bytes) of the result data from a ibc_destination_chain_callback call. - pub const RESULT_IBC_DESTINATION_CHAIN_CALLBACK: usize = 64 * MI; + /// Max length (in bytes) of the result data from a ibc_source_callback call. + pub const RESULT_IBC_SOURCE_CALLBACK: usize = 64 * MI; + /// Max length (in bytes) of the result data from a ibc_destination_callback call. + pub const RESULT_IBC_DESTINATION_CALLBACK: usize = 64 * MI; } /// The limits for the JSON deserialization. @@ -99,10 +99,10 @@ mod deserialization_limits { /// Max length (in bytes) of the result data from a ibc_packet_timeout call. #[cfg(feature = "stargate")] pub const RESULT_IBC_PACKET_TIMEOUT: usize = 256 * KI; - /// Max length (in bytes) of the result data from a ibc_source_chain_callback call. - pub const RESULT_IBC_SOURCE_CHAIN_CALLBACK: usize = 256 * KI; - /// Max length (in bytes) of the result data from a ibc_destination_chain_callback call. - pub const RESULT_IBC_DESTINATION_CHAIN_CALLBACK: usize = 256 * KI; + /// Max length (in bytes) of the result data from a ibc_source_callback call. + pub const RESULT_IBC_SOURCE_CALLBACK: usize = 256 * KI; + /// Max length (in bytes) of the result data from a ibc_destination_callback call. + pub const RESULT_IBC_DESTINATION_CALLBACK: usize = 256 * KI; } pub fn call_instantiate( @@ -337,10 +337,10 @@ where Ok(result) } -pub fn call_ibc_source_chain_callback( +pub fn call_ibc_source_callback( instance: &mut Instance, env: &Env, - msg: &IbcSourceChainCallbackMsg, + msg: &IbcSourceCallbackMsg, ) -> VmResult>> where A: BackendApi + 'static, @@ -350,18 +350,15 @@ where { let env = to_vec(env)?; let msg = to_vec(msg)?; - let data = call_ibc_source_chain_callback_raw(instance, &env, &msg)?; - let result = from_slice( - &data, - deserialization_limits::RESULT_IBC_SOURCE_CHAIN_CALLBACK, - )?; + let data = call_ibc_source_callback_raw(instance, &env, &msg)?; + let result = from_slice(&data, deserialization_limits::RESULT_IBC_SOURCE_CALLBACK)?; Ok(result) } -pub fn call_ibc_destination_chain_callback( +pub fn call_ibc_destination_callback( instance: &mut Instance, env: &Env, - msg: &IbcDestinationChainCallbackMsg, + msg: &IbcDestinationCallbackMsg, ) -> VmResult>> where A: BackendApi + 'static, @@ -371,10 +368,10 @@ where { let env = to_vec(env)?; let msg = to_vec(msg)?; - let data = call_ibc_destination_chain_callback_raw(instance, &env, &msg)?; + let data = call_ibc_destination_callback_raw(instance, &env, &msg)?; let result = from_slice( &data, - deserialization_limits::RESULT_IBC_DESTINATION_CHAIN_CALLBACK, + deserialization_limits::RESULT_IBC_DESTINATION_CALLBACK, )?; Ok(result) } @@ -612,7 +609,7 @@ where ) } -pub fn call_ibc_source_chain_callback_raw( +pub fn call_ibc_source_callback_raw( instance: &mut Instance, env: &[u8], msg: &[u8], @@ -625,13 +622,13 @@ where instance.set_storage_readonly(false); call_raw( instance, - "ibc_source_chain_callback", + "ibc_source_callback", &[env, msg], - read_limits::RESULT_IBC_SOURCE_CHAIN_CALLBACK, + read_limits::RESULT_IBC_SOURCE_CALLBACK, ) } -pub fn call_ibc_destination_chain_callback_raw( +pub fn call_ibc_destination_callback_raw( instance: &mut Instance, env: &[u8], msg: &[u8], @@ -644,9 +641,9 @@ where instance.set_storage_readonly(false); call_raw( instance, - "ibc_destination_chain_callback", + "ibc_destination_callback", &[env, msg], - read_limits::RESULT_IBC_DESTINATION_CHAIN_CALLBACK, + read_limits::RESULT_IBC_DESTINATION_CALLBACK, ) } @@ -1071,7 +1068,7 @@ mod tests { } #[test] - fn call_ibc_source_chain_callback_works() { + fn call_ibc_source_callback_works() { let mut instance = mock_instance(IBC_CALLBACKS, &[]); // init @@ -1091,12 +1088,12 @@ mod tests { // send ack callback let ack = mock_ibc_packet_ack(CHANNEL_ID, br#"{}"#, IbcAcknowledgement::new(br#"{}"#)) .unwrap(); - let msg = IbcSourceChainCallbackMsg::Acknowledgement(IbcAckCallbackMsg::new( + let msg = IbcSourceCallbackMsg::Acknowledgement(IbcAckCallbackMsg::new( ack.acknowledgement, ack.original_packet, ack.relayer, )); - call_ibc_source_chain_callback::<_, _, _, Empty>(&mut instance, &mock_env(), &msg) + call_ibc_source_callback::<_, _, _, Empty>(&mut instance, &mock_env(), &msg) .unwrap() .unwrap(); // query the CallbackStats @@ -1111,11 +1108,11 @@ mod tests { // send timeout callback let timeout = mock_ibc_packet_timeout(CHANNEL_ID, br#"{}"#).unwrap(); - let msg = IbcSourceChainCallbackMsg::Timeout(IbcTimeoutCallbackMsg::new( + let msg = IbcSourceCallbackMsg::Timeout(IbcTimeoutCallbackMsg::new( timeout.packet, timeout.relayer, )); - call_ibc_source_chain_callback::<_, _, _, Empty>(&mut instance, &mock_env(), &msg) + call_ibc_source_callback::<_, _, _, Empty>(&mut instance, &mock_env(), &msg) .unwrap() .unwrap(); // query the CallbackStats diff --git a/packages/vm/src/lib.rs b/packages/vm/src/lib.rs index 27ccf20590..699c03735f 100644 --- a/packages/vm/src/lib.rs +++ b/packages/vm/src/lib.rs @@ -27,11 +27,10 @@ pub use crate::cache::{ AnalysisReport, Cache, CacheOptions, Metrics, PerModuleMetrics, PinnedMetrics, Stats, }; pub use crate::calls::{ - call_execute, call_execute_raw, call_ibc_destination_chain_callback, - call_ibc_destination_chain_callback_raw, call_ibc_source_chain_callback, - call_ibc_source_chain_callback_raw, call_instantiate, call_instantiate_raw, call_migrate, - call_migrate_raw, call_query, call_query_raw, call_reply, call_reply_raw, call_sudo, - call_sudo_raw, + call_execute, call_execute_raw, call_ibc_destination_callback, + call_ibc_destination_callback_raw, call_ibc_source_callback, call_ibc_source_callback_raw, + call_instantiate, call_instantiate_raw, call_migrate, call_migrate_raw, call_query, + call_query_raw, call_reply, call_reply_raw, call_sudo, call_sudo_raw, }; #[cfg(feature = "stargate")] pub use crate::calls::{ From c8216e735a55a94cf339dfcbcaa4ad2dd267667a Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 10 May 2024 15:13:48 +0200 Subject: [PATCH 36/44] Reduce nesting --- contracts/ibc-callbacks/src/contract.rs | 30 +++++++++++++------------ 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/contracts/ibc-callbacks/src/contract.rs b/contracts/ibc-callbacks/src/contract.rs index 108fe990f4..94dab3586e 100644 --- a/contracts/ibc-callbacks/src/contract.rs +++ b/contracts/ibc-callbacks/src/contract.rs @@ -37,20 +37,8 @@ pub fn execute( address: msg.to_address.clone(), gas_limit: None, }; - let transfer_msg = match &*info.funds { - [coin] if !coin.amount.is_zero() => IbcMsg::Transfer { - to_address: msg.to_address, - timeout: IbcTimeout::with_timestamp( - env.block.time.plus_seconds(msg.timeout_seconds as u64), - ), - channel_id: msg.channel_id, - amount: coin.clone(), - memo: Some(to_json_string(&match msg.callback_type { - CallbackType::Both => IbcCallbackRequest::both(src_callback, dst_callback), - CallbackType::Src => IbcCallbackRequest::source(src_callback), - CallbackType::Dst => IbcCallbackRequest::destination(dst_callback), - })?), - }, + let coin = match &*info.funds { + [coin] if !coin.amount.is_zero() => coin, _ => { return Err(StdError::generic_err( "Must send exactly one denom to trigger ics-20 transfer", @@ -58,6 +46,20 @@ pub fn execute( } }; + let transfer_msg = IbcMsg::Transfer { + to_address: msg.to_address, + timeout: IbcTimeout::with_timestamp( + env.block.time.plus_seconds(msg.timeout_seconds as u64), + ), + channel_id: msg.channel_id, + amount: coin.clone(), + memo: Some(to_json_string(&match msg.callback_type { + CallbackType::Both => IbcCallbackRequest::both(src_callback, dst_callback), + CallbackType::Src => IbcCallbackRequest::source(src_callback), + CallbackType::Dst => IbcCallbackRequest::destination(dst_callback), + })?), + }; + Ok(Response::new() .add_message(transfer_msg) .add_attribute("action", "execute")) From 9f049b26cb80c647710a6dd6cc0699ba96732601 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 10 May 2024 15:16:56 +0200 Subject: [PATCH 37/44] Remove IbcFullAcknowledgement --- .../ibc-callbacks/schema/ibc-callbacks.json | 25 +------------------ .../raw/response_to_callback_stats.json | 25 +------------------ packages/std/src/ibc/callbacks.rs | 13 +--------- packages/std/src/lib.rs | 7 +++--- 4 files changed, 6 insertions(+), 64 deletions(-) diff --git a/contracts/ibc-callbacks/schema/ibc-callbacks.json b/contracts/ibc-callbacks/schema/ibc-callbacks.json index aa78db7a89..67c36744aa 100644 --- a/contracts/ibc-callbacks/schema/ibc-callbacks.json +++ b/contracts/ibc-callbacks/schema/ibc-callbacks.json @@ -176,7 +176,7 @@ ], "properties": { "ack": { - "$ref": "#/definitions/IbcFullAcknowledgement" + "$ref": "#/definitions/IbcAcknowledgement" }, "packet": { "$ref": "#/definitions/IbcPacket" @@ -200,29 +200,6 @@ }, "additionalProperties": false }, - "IbcFullAcknowledgement": { - "description": "The acknowledgement written by the module on the destination chain. It is different from the [`crate::IbcAcknowledgement`] as it can be unsuccessful.", - "type": "object", - "required": [ - "data", - "success" - ], - "properties": { - "data": { - "description": "The acknowledgement data returned by the module.", - "allOf": [ - { - "$ref": "#/definitions/Binary" - } - ] - }, - "success": { - "description": "Whether the acknowledgement was successful or not.", - "type": "boolean" - } - }, - "additionalProperties": false - }, "IbcPacket": { "type": "object", "required": [ diff --git a/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json index 975fe76533..572b916219 100644 --- a/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json +++ b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json @@ -79,7 +79,7 @@ ], "properties": { "ack": { - "$ref": "#/definitions/IbcFullAcknowledgement" + "$ref": "#/definitions/IbcAcknowledgement" }, "packet": { "$ref": "#/definitions/IbcPacket" @@ -103,29 +103,6 @@ }, "additionalProperties": false }, - "IbcFullAcknowledgement": { - "description": "The acknowledgement written by the module on the destination chain. It is different from the [`crate::IbcAcknowledgement`] as it can be unsuccessful.", - "type": "object", - "required": [ - "data", - "success" - ], - "properties": { - "data": { - "description": "The acknowledgement data returned by the module.", - "allOf": [ - { - "$ref": "#/definitions/Binary" - } - ] - }, - "success": { - "description": "Whether the acknowledgement was successful or not.", - "type": "boolean" - } - }, - "additionalProperties": false - }, "IbcPacket": { "type": "object", "required": [ diff --git a/packages/std/src/ibc/callbacks.rs b/packages/std/src/ibc/callbacks.rs index b4d08a788f..001b1734aa 100644 --- a/packages/std/src/ibc/callbacks.rs +++ b/packages/std/src/ibc/callbacks.rs @@ -1,7 +1,6 @@ //! This module contains types for the IBC callbacks defined in //! [ADR-8](https://github.com/cosmos/ibc-go/blob/main/docs/architecture/adr-008-app-caller-cbs.md). -use cosmwasm_core::Binary; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -169,17 +168,7 @@ impl IbcTimeoutCallbackMsg { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct IbcDestinationCallbackMsg { pub packet: IbcPacket, - pub ack: IbcFullAcknowledgement, -} - -/// The acknowledgement written by the module on the destination chain. -/// It is different from the [`crate::IbcAcknowledgement`] as it can be unsuccessful. -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] -pub struct IbcFullAcknowledgement { - /// The acknowledgement data returned by the module. - pub data: Binary, - /// Whether the acknowledgement was successful or not. - pub success: bool, + pub ack: IbcAcknowledgement, } #[cfg(test)] diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index 6c6f4809be..d83774e750 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -42,10 +42,9 @@ pub use crate::ibc::IbcChannelOpenResponse; pub use crate::ibc::{ Ibc3ChannelOpenResponse, IbcAckCallbackMsg, IbcAcknowledgement, IbcBasicResponse, IbcCallbackRequest, IbcChannel, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, - IbcDestinationCallbackMsg, IbcDstCallback, IbcEndpoint, IbcFullAcknowledgement, IbcMsg, - IbcOrder, IbcPacket, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, - IbcReceiveResponse, IbcSourceCallbackMsg, IbcSrcCallback, IbcTimeout, IbcTimeoutBlock, - IbcTimeoutCallbackMsg, + IbcDestinationCallbackMsg, IbcDstCallback, IbcEndpoint, IbcMsg, IbcOrder, IbcPacket, + IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, + IbcSourceCallbackMsg, IbcSrcCallback, IbcTimeout, IbcTimeoutBlock, IbcTimeoutCallbackMsg, }; #[cfg(feature = "iterator")] pub use crate::iterator::{Order, Record}; From 64fa6c32532111263818df192af822b8f2f9d0ee Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 10 May 2024 15:24:27 +0200 Subject: [PATCH 38/44] Use enum for ibc-callbacks ExecuteMsg --- .../ibc-callbacks/schema/ibc-callbacks.json | 73 +++++++++++-------- .../ibc-callbacks/schema/raw/execute.json | 73 +++++++++++-------- contracts/ibc-callbacks/src/contract.rs | 37 ++++++++-- contracts/ibc-callbacks/src/msg.rs | 22 +++--- 4 files changed, 128 insertions(+), 77 deletions(-) diff --git a/contracts/ibc-callbacks/schema/ibc-callbacks.json b/contracts/ibc-callbacks/schema/ibc-callbacks.json index 67c36744aa..a7456b2272 100644 --- a/contracts/ibc-callbacks/schema/ibc-callbacks.json +++ b/contracts/ibc-callbacks/schema/ibc-callbacks.json @@ -12,38 +12,51 @@ "execute": { "$schema": "http://json-schema.org/draft-07/schema#", "title": "ExecuteMsg", - "type": "object", - "required": [ - "channel_id", - "timeout_seconds", - "to_address" - ], - "properties": { - "callback_type": { - "description": "Who should receive callbacks for the message", - "default": "both", - "allOf": [ - { - "$ref": "#/definitions/CallbackType" + "oneOf": [ + { + "type": "object", + "required": [ + "transfer" + ], + "properties": { + "transfer": { + "type": "object", + "required": [ + "channel_id", + "timeout_seconds", + "to_address" + ], + "properties": { + "callback_type": { + "description": "Who should receive callbacks for the message", + "default": "both", + "allOf": [ + { + "$ref": "#/definitions/CallbackType" + } + ] + }, + "channel_id": { + "description": "The channel to send the packet through", + "type": "string" + }, + "timeout_seconds": { + "description": "The amount of seconds from now the transfer should timeout at", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "to_address": { + "description": "Address on the destination chain", + "type": "string" + } + }, + "additionalProperties": false } - ] - }, - "channel_id": { - "description": "The channel to send the packet through", - "type": "string" - }, - "timeout_seconds": { - "description": "The amount of seconds from now the transfer should timeout at", - "type": "integer", - "format": "uint32", - "minimum": 0.0 - }, - "to_address": { - "description": "Address on the destination chain", - "type": "string" + }, + "additionalProperties": false } - }, - "additionalProperties": false, + ], "definitions": { "CallbackType": { "oneOf": [ diff --git a/contracts/ibc-callbacks/schema/raw/execute.json b/contracts/ibc-callbacks/schema/raw/execute.json index 5c65aea3d4..e5bed95bb4 100644 --- a/contracts/ibc-callbacks/schema/raw/execute.json +++ b/contracts/ibc-callbacks/schema/raw/execute.json @@ -1,38 +1,51 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "title": "ExecuteMsg", - "type": "object", - "required": [ - "channel_id", - "timeout_seconds", - "to_address" - ], - "properties": { - "callback_type": { - "description": "Who should receive callbacks for the message", - "default": "both", - "allOf": [ - { - "$ref": "#/definitions/CallbackType" + "oneOf": [ + { + "type": "object", + "required": [ + "transfer" + ], + "properties": { + "transfer": { + "type": "object", + "required": [ + "channel_id", + "timeout_seconds", + "to_address" + ], + "properties": { + "callback_type": { + "description": "Who should receive callbacks for the message", + "default": "both", + "allOf": [ + { + "$ref": "#/definitions/CallbackType" + } + ] + }, + "channel_id": { + "description": "The channel to send the packet through", + "type": "string" + }, + "timeout_seconds": { + "description": "The amount of seconds from now the transfer should timeout at", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "to_address": { + "description": "Address on the destination chain", + "type": "string" + } + }, + "additionalProperties": false } - ] - }, - "channel_id": { - "description": "The channel to send the packet through", - "type": "string" - }, - "timeout_seconds": { - "description": "The amount of seconds from now the transfer should timeout at", - "type": "integer", - "format": "uint32", - "minimum": 0.0 - }, - "to_address": { - "description": "Address on the destination chain", - "type": "string" + }, + "additionalProperties": false } - }, - "additionalProperties": false, + ], "definitions": { "CallbackType": { "oneOf": [ diff --git a/contracts/ibc-callbacks/src/contract.rs b/contracts/ibc-callbacks/src/contract.rs index 94dab3586e..a0f4223de5 100644 --- a/contracts/ibc-callbacks/src/contract.rs +++ b/contracts/ibc-callbacks/src/contract.rs @@ -28,13 +28,38 @@ pub fn execute( env: Env, info: MessageInfo, msg: ExecuteMsg, +) -> StdResult { + match msg { + ExecuteMsg::Transfer { + to_address, + channel_id, + timeout_seconds, + callback_type, + } => execute_transfer( + env, + info, + to_address, + channel_id, + timeout_seconds, + callback_type, + ), + } +} + +fn execute_transfer( + env: Env, + info: MessageInfo, + to_address: String, + channel_id: String, + timeout_seconds: u32, + callback_type: CallbackType, ) -> StdResult { let src_callback = IbcSrcCallback { address: env.contract.address, gas_limit: None, }; let dst_callback = IbcDstCallback { - address: msg.to_address.clone(), + address: to_address.clone(), gas_limit: None, }; let coin = match &*info.funds { @@ -47,13 +72,11 @@ pub fn execute( }; let transfer_msg = IbcMsg::Transfer { - to_address: msg.to_address, - timeout: IbcTimeout::with_timestamp( - env.block.time.plus_seconds(msg.timeout_seconds as u64), - ), - channel_id: msg.channel_id, + to_address, + timeout: IbcTimeout::with_timestamp(env.block.time.plus_seconds(timeout_seconds as u64)), + channel_id, amount: coin.clone(), - memo: Some(to_json_string(&match msg.callback_type { + memo: Some(to_json_string(&match callback_type { CallbackType::Both => IbcCallbackRequest::both(src_callback, dst_callback), CallbackType::Src => IbcCallbackRequest::source(src_callback), CallbackType::Dst => IbcCallbackRequest::destination(dst_callback), diff --git a/contracts/ibc-callbacks/src/msg.rs b/contracts/ibc-callbacks/src/msg.rs index bd45c60e9b..d5cdb38f96 100644 --- a/contracts/ibc-callbacks/src/msg.rs +++ b/contracts/ibc-callbacks/src/msg.rs @@ -9,16 +9,18 @@ pub enum QueryMsg { } #[cw_serde] -pub struct ExecuteMsg { - /// Address on the destination chain - pub to_address: String, - /// The channel to send the packet through - pub channel_id: String, - /// The amount of seconds from now the transfer should timeout at - pub timeout_seconds: u32, - /// Who should receive callbacks for the message - #[serde(default)] - pub callback_type: CallbackType, +pub enum ExecuteMsg { + Transfer { + /// Address on the destination chain + to_address: String, + /// The channel to send the packet through + channel_id: String, + /// The amount of seconds from now the transfer should timeout at + timeout_seconds: u32, + /// Who should receive callbacks for the message + #[serde(default)] + callback_type: CallbackType, + }, } #[cw_serde] From ee75e9588fbe43517fcffc7575ec8cce7e0f2cbc Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 10 May 2024 15:27:47 +0200 Subject: [PATCH 39/44] Update packages/vm/README.md Co-authored-by: Simon Warta <2603011+webmaster128@users.noreply.github.com> --- packages/vm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vm/README.md b/packages/vm/README.md index 7f21b8db19..3dbcff7e51 100644 --- a/packages/vm/README.md +++ b/packages/vm/README.md @@ -43,7 +43,7 @@ compatibility list: There are demo files in `testdata/*.wasm`. Those are compiled and optimized versions of [contracts/\*](https://github.com/CosmWasm/cosmwasm/tree/main/contracts/) run -through [rust-optimizer](https://github.com/CosmWasm/rust-optimizer). +through [cosmwasm/optimizer](https://github.com/CosmWasm/optimizer). To rebuild the test contracts, go to the repo root and do From 2426bb9986e3854abd20bec1b03229930f66beb1 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 10 May 2024 15:58:25 +0200 Subject: [PATCH 40/44] Update ibc_callbacks.wasm for tests --- packages/vm/testdata/ibc_callbacks.wasm | Bin 233235 -> 231737 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/packages/vm/testdata/ibc_callbacks.wasm b/packages/vm/testdata/ibc_callbacks.wasm index 48cb125bc41ece4525cf9d3e447807b913137d9a..63519505aa2d7742653caa375a12758dbccb45f8 100644 GIT binary patch delta 64025 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 #fsi5Otf6$Z)ABK*qMXBr+DqGx~VH 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 delta 67507 zcmce93!IhH`v3c^eVIKoduI03OwG04y_;%AO&2nyi{?!?gc6RsLS!P9IF8#M$`L}m zX@yh>p@^aoCf6wB2qDDjD1;oh-2dO_S?{~|o*JC<`~Uv``g~@+d%f%Wtmk>wv!2U( zAH5;pou9vKI|aT}pSzz?ja#fby8YF_NSN?17!JDA)VIlB7Ot^!la|wX8`7-Jlovj0 z+*xN&`J1wG&zN}5)Ugw%o-uanIBQJSxbw%IaxR|6h9;joZpz=RlS|Jy`IM8+Is4ox zr;I!4l<{NFn0V4DW6wPEvlDd%vz zeeiNXuygWJ^%e~-Ek9^P*?|WSf0+heO4F%F&&y~U{hh9$8FVFGMcukzO*82lx|W8F zI&}YU)WDI49M*XPp3fYJ$8*k_IC=b}DV?vUrL=+`pw17{a(b8^p@(Q04S9~9rAKMt zz%}$FHPMg<)#LO9eM$pgp$)W}{*k05^aQ;|&(OeC^eWv)_tQ#xOueKwQs;qh(i`+T zZK2LP=qnmH@Abt;$*QUG#JJ z!qC(7gS&tDV7k+NV1AW*fB1Gf+#QwGFT4b699!z%kaZ;;uH$V~D(8gAD^g`>jZ@WN z2V*aio#jLt?2w&Rt*R3ERjsW>0mka4T*?LI^pUP*OZGyoE{B!IJVdw9sM@fR?crU*|CPjZg&sLTS@o0Dt}-4 zYI&dh`zgHSx+W|3w!5R?z>=SoO^)4QM+RAg{_)|x?|gpui&uPS#eQ-RiM2H^>nGUZ z-Ctf5yMcak3kutWUsvd9ncJnX6YX*jFYGCGY66xWz6cHf%WA;inbZ(_-Myu-BZ{mk zY)4PJTMGB8zgR`M)H>GZY(&X-n$^E3b0Gz;Ti zxBT)}*AU&aymir8M0dHD7TcKJ?ZrLY?YtCaB6e1+fZH3HN2t32BM3Ns8k}A3SH*E! zxV&|n2f5aBZ9Cw{Cv6=A<-zXRrO|@BD2lN}?64iQL$TZ3t4gn>ZEk7V?fAR8Y)qbk z8z6>7{M@Z6uSj~6u*@W!`UzE5L9UY;`M_oa2Y%eAD3Ek+x^<0JYguIu#e=F|)jMH_ zV&f7a03hT98=Td%o2>4Z)z7ljQEI3zESi(xA} z5c|P>r~HuugO2Fa0UTmW+yxag4Wgc&dV{628>+0_?-QzHGQeoHEHELVsw}+N&Px}Y zPdvW#e_PdB;~koef#B&3=O=3@9;w!fCUW?}&T(i$BB!qvwR7B;E6bCb(AE}d>qb1* zTBpWykh2Lns#=XnWTOj5#q*Ukcr=;@8VpkL&d7}NYM{z7@i4bLIo=vIzfleGc1Twt zZI5&@(iqa&frfY?(nUyZq<12X+r`Sc2L%$yxDROu)3W>3CvDxPLt^gphZiSX1De_K z{AfuoI%&LQay;M!qAJ&J9jtd^$Zwl#XUAk3j7vOT9@8j{3CTzva2`sBncNa#Co#-a zL&h)Gu)H=-Yc$b@$#HE)?crvgPB5OIbgX!el&G~1G}ZG>6|dKYihI2ky;iFwDjwi; zvEuHl)gl$gl2@yRDiLwopldq_@J6IQAQ}WLmHY>m1SaGMNhwPPd&gxUm2m7wm6s$8 zAP@!egq=ClkQ?A!3#iFZz$yf=3M$!BGeIZa3|e8J1)H~ls*cLVn8QQzK-x?t=&iK@ zG^l<`A}7g!%MYpmg|ONJ#&`|`Cfb^zW@bN6W{+8hoi;=BFlA>+00`tPQ4Q6~s#8E% zTh#y@z15;XG?Z(19;6Ou9CdbqcX*=&Rt!?T1Cufvj@wC~Pyo!-j)5hEarFl8Qg%$9 z76RBc0d$MzMuD9uX9gCdeMUiN7d6=JkdYcjd#Txo@!0KZ6q?&9V_&P{MZ8k$RlJzf z4Juy6>Bgjrx8a9PD&CgU%_`oJ(=94q!s%8OFXeQ*ig)64hl-bRx>Lo=F`&5^P$V^M z9&Mm^U=~9oFe4DJ;gZt>@d{2G1M$jeZmu1bok20S06r%IK;F8y1fUe;vw&X$dF%&1 z5!8EVY{hf2Vp-8_Ay)@nfvF&$bKIiC<7XD(DJR$2-~zqk&MG9aRbWg$UG-rEH{78= z<2UbP7;m3M#3QyIUOx)`Sn(`D*s%1~6Zjv%TknO6=ecWsE~lhhSW`5DXPC>AWeR5u zj|zQTlD}m;%Fg*t{+ekXR zKQcjwz*<1i0gs?P$mZIiDG9-@M1XmX6~Y>Wgk_cAv;Aw zJoGHV%|)ugd8ZLm2*v=^csLm?NVk_@U@Zy6TX{e$;1od1;uJuWZonk%R&{C_Q)59L z*eBAgIGqo>#jhg#$rM z2b3V#RO)L~6_a*# zZv(@;zE%bdu{2Sx;mnei?!dsA<*h(4*N)kR-byozmE}%xOS1^v02ot2Jb+CrD-i^0 z3EKFpFPw5oAemZh07MoWV3oxVF;1aUYOw>}VxxT-XehPV(OmT5EjP<9rXz2;(UBdm zvB0%wp$j|iWHpHBrSYrQN&+%Mqgb6N(0e<;cFt{4;6A^OyihdURrGo>OQLEQWsa zAn<`t@+PR9M(j?qzwN$5oX>)gt;~KHOYN85)?nbmTc@`(04^w+3{0{s0J2Jvc8l>; zBu{Pe)JC34@l+yD@qxZN73T+V6b8NgK=ib@UW-)Id*64&j12L2V3>|=CKiv zGe8zeySz>{;lVDeQ>!`cRHs&PT3V-8a9RRd=d>dhgVVNH3{Kksn4DJCsfC;t*D2;l zc2S+0i_}>!1HoRNLd=4G*5~}@OS~!Y2q3BK$~v`yD^}FuD2lYEcVH8zU@BWU1)go? zG_Ou==QP^a+QBI%w3B+PXDM35pvaI)3}^$B1WqabmL2Qhp|(goSzPJoBn!=uastdX zl`~xi4M8Y1=y06^$jqWLQnG-U2sx4S;`jjqSMh4*u0Sh6vJPPHC5E(l;KC(AFoMRp zf_^B8+RO)p|H_7D7YqRsL!z591tgaxtDTJlfI|(5EM}v27E?yHoyDgBbPJ&sd_{y- zp&kgWS)f5a%$Us~J9aZ*B!mpI8j8v(ZX{G5u=!+^6-&xV5hNIm10ZHzpa<{Ct{zl9 zJ%eLN;`=_KkIS~#JK`c z4j2SD8j!<6r$7vnY~<~!B15E6%;J3cDBBzoB8Dvae8FNv4sQv~WFdFcfTK*uNNlWbBd7W4A>dbzEYQU%u@2w^M0j^LOCzGI_2+b3o+ex?O}LcH zc{EyR0o4d}s$og2w8%MFAh3Enpm)&%Klisy5> ziul}C4Z_8mAzems>~`4GiO+FB7wih0E~0og(j+L?@c((l=v)oTjpt#3=E_L`ti)#` zA`=Tu`-H&~K4WsK2#<3Hd0ZaI_AEcMP!NztSnhZDv6IaCX11=~Fs@ z`Gh$w1u@J4hC*;4b%*bDAkA}c*y|WdxL@^Y>jt_Eq@&yex?GCC&vkjC)X1$(lnC&S z4+iG!1oXJOTe|+mbi}F>9AMmEyS739#kDg{_9kS9P;P1M2xR|Q+r?z_i7kX-_3U<3 z8=SORTn{r>jyN~4{wh26qx;&|74D1h?Czt6 zm;ujKX22jdXr*`@U>&tqJy_8YKE~Brj`M{mZ$jqqBg1m$c|xfBK=(=v`sMCN#s%^? zk%hb?S}!J32WKUaV2?x|CU`)PYjdTP-2hyf?{4mKFzQzK^d{Vd3Fl$LC-po%vWuq( zy@UJJ=nD7Ko>lGqjLd1}*oFSIy6#;=^OhgAcQuOrdG@65A z`Kfh#5#}@Ui;Cs<^}dp#ybBc%!7c@v$F1M5cP(echCmxt#=|Z*lraQgDqvX;s^0U! z3G;{KRobnf*+NXAhuF~}Sm!BIaQ3sK=(5*< zQJBx)2YkC17iWR2K)Ni$lj)oVvY6yyoREG{>CXKJ_G`B1uwt+oog(92s9}tHc?%9I zMh}RS4O3#_HpYkU+e*z!OYW`i=xqn6wdB@r@9I9gt*x4VgZtjL9yHv|-(F5@^>vGA zsF#;J9A`;JJSMrN+s|`r2bZe(q~ooqlRI(n@w7m{dJ}bx0R92=x4`{vu!H`bA*D<- zMvY6cTXnX%9BM*K1+ zgUfW(zb>R4H#nku?yT$g;G?zCIUsP6s2P{%j5w|1?#qqWvmv8-^gaXJ5hU%#4`E)~ z_mB;SJ7Jf%bJ0MXLkA%Hh(kRZUW?MXpy8_z9bWnC3`4_)cZp&p=uE#7nIRDN&OXrpVdZ#!=P=#MYt+Wbv2QG*Xe&4W#5V3t zBcmAGT_cZdzdK|xMqq+bIOk$=Wuv;H)FHk0fRU$k1g4?F@q(LLvgx?-=cZ4?xy-+AtnM@+!`y^buy zpoSbd&`jMQ)T|?i(pTx@9LrFSJM%>DZpVq&pv(m)*(KnI*iE6z9fBPM$R#I~LQLtQlTK)#9uXE2!Y4LC z9u5A2Dq=Ug-Nw|Snd8T_$KQ*_RN(JTV>;1Xw@LE9ko^3yoZn?^M|#Q~HTFb2FB{u| z`B={ggi=90FdHx`mriynd@~PBV4jHvN=xV~QQ!yn#FKB#S!%2^1nbN%CzqkMl2Zni zG+oL1Ej2qoo$1&5{KJI-FIg!mA`X8qaM0TswYfbhn5E6K-d+_NZ zDS-(9E>I{zDakA-7u;s$>4z18xbVt|P^lMX<9RiQkM9jqXdHh`iIIwCc~TLJal*jo zyI+kz(kvV{fGn_#QD+om45yzl%j9BD31DQZfl2)Eh76G=fRSC4dBBx6hf^lzzwKj>K%cFt4?dQCK(%V1Ir8%zIm>q!&@9v4peBz2&S! z=-=)qXN{om+`5SuVGzqFcBW6=cPE}f+m;VGyO8kXFOzI^aQ>tYcs*~@!5sw=Sy;w| zMC_Yw(4Bcckbf4jX5EcWo@(IC@-t`5oP0PM_+YX(Nd`Z(({7t7gCch`AA=^@9W$kE ziT?vo9~K8n=djqr8~b%r2GHH^%Tr1)nvbXS!r$_9Ui9l$xhI~}##K{KL?2_PP6KrQ zHT58{k{;*sN}YJ_=t^(#nBA*7wTYroOkqnCESTrMa&8-p!eR99Z<{^f5+qR*v& zdkjDrf5C@X=7TOA1yIbpa3FFvU)T@NB^UKUnNb&QEn?or*1qf^kPun(g0q-=;KeN3 zetvPkjzX%?zk~bbv24nkIdkUO#EZ_HE;iRa8DD;ILN2B9=^nAGrOASE=-nU=#M22ChdkBYfG^%0Tfy~ z=r@`c4+bEH^GTIuy%CLlWHsy{{0ws7doZiXAcX^o*l?7hrV_rG*7?R2MII*b;& z>nLECb+xQ&+=yNS!&|6jKAGukOX$!G7t$)KuN|8q}*-*F`P z@$%>Qa3py3?-|=r3)_lYaz#7e#iaig)n!W_W@$BwU2xTX{8VIP|8b%XvG?3du+^+` z=U=f8z32Ypimuppe!JpGQS<%R+s6m2#dWziJ7D??`2Ati zmp%dwPJ*k4FuRP-QDK4;J4D79a0+9EW|Zk#Fptff(`41a)PdSTP@=O0zcJyyR+2L! z4bGx;0dBr9JvV8d{N~l3%{#Y$W4u>TPc<+^%o2oRi@gQdV;MYnL)eBzo*hPHVG>z( zB$$M5WCopy)d>uVGu>jY?192mmk4ko%aH|69`i^Mb{2sMca8TjRhq?M-p06)CAh$9 zkX@eo5=g+-C-j>15Q7PK7F>PM6Woa+kUiKS%6(>YB7FwHhM~{m*D!wL7q0>oe;6wF znw^OPaD&En1KG$0J58ELScU_FYlDswGTscU3-W0%EY z2HLQg*kE^xHRQ;S|> z3-O)>b!=vS#}H|pb*w=uu*0!^`Sni1p(XS6J9v#zL4D4U3A2#|53xE^I08m-QtS_x z(bZ~!2AiQ68t95W8=PgSuKsw4i_`Ve7C#p8cyVX@P;4ZqUc%0de$)_$uNjDpDQW_r z$#7xqUE&^|# zrD+}%cJdmM&SRMwU{VjKe>0OR{$FKM25DrMFzl(lYz;y!U>5uzrZC82;BOd<<{?S};6V4WmMk z?TAKAB}up$(LpjaS~*>{AWz3%gT|C)>?p zW+$xB-^Rt*@@J?HSEq&q46fcj?qR#xs0>g4^W7tZrOWQo^8Sw*W$Yfj|MTRM*aw*C z07pB_Y!#^M6C?Hq;=pL5@BD&;A&x<9WYqq>9v*^KUrYF8-V!5fm9Q^BPNmUkor2 z(@+qmR!>Y5IYfkmu_CLdx89Tl119AQFdKNSi~uA487)f(&DU3?1I%_c=?$c+k|MlA z#>^ZKCOyFk^8)gVEI{1M3j-Hc2xnDsPpdXZi3pa<`RKBglekn$&rVvC_2U=3ei^N? zsNdiV>+(LmfbodzZU(H-FET_iu%JJ%P-atTIwV#7AqE}&NNPwyc51%`zYUJ@sRrfH zCgcfeG~hQH+^x}IW~0tGTi>`Z3^yq@mf|1@y5VgVBUFDZc4jQvmh_?lg>ls2{Sr3V z^ft-5LD?))nb;+a&=dwE#-5VHdkTw9P{}mgPR59R7+Q@`s%|VV&&D`wRIoQDY?)zO zz+m(eZEz>Po|P2u!ao$7TOL1@9?IFlCnXPAjr)q=XK!_?XplwLZ1Fu947=+(%aS5# zrbJYRYKsyoZ?i^1EuER<>8F5CPiUzm)>$%BO z`9v_%lr3V;_lGkRI&GQUJh=mt0CLEIT1d{5v~bp7b@?8n@4}P*v*EJ|2!-7E>!oJA zJ^b-Xo9qSPL)wQ(OKf9|sb$Uw!fg0lkpYsHjt4%knJ%Y_wP6E&_qGjX#~C=+dt>3* zv2EU|$Y_%BuZSUR0|SA2vPkeAF(_%443x-{EC2;1n)K4B+{jI9CAjD?MA*b{oy_7nX)A;>DHe^<)}$eBd_foYo&^t}df`pfZ~5`J6;qz+8HXQ4r98F#lH1!7Eq3SJ z@c?QMUDQYEYu(00)#|2em*2Z+3>DseO)5?XTT_E`k6V7%7m-J2^3H+qox;11h)hQj z{J7U0^Ke`D{YN71%)6)19qw;;JCPabSA*S|i{FVn!4<=(IPsq0=y2sdM`3XJ_nsfw z#4iHU;z0N1dwUQ!H`pC?-zVm2`J^RX$jjWabZO+>^auvJ8}IKFak;B38O30C=mYK5 z&DXfMtQhI$Eh~V+{I&;&@{^i=rQ2@V@sWGEaIRPQ`DN|tVfW)@W9Tt=*n`JN=_5_a z3U}p-Uhdh;vfcUz!?ead`k@me&u4a|mZv&ezq}ylWoZ{;d>?nzgY_=5(AwtZhetN? zi>TM(1uMKtC!yb;R-6#onjX$6X51C-hYw#<_<;u$tTp`4;XUY1dTJl{?tAhg+s*WS zn75}L%YS_&K#^xSKZ1U;S2fT&cj~H>>GkDr;V%}X?_;MGevkLwrk2M$#!v2pk2M_l z1NR?@-7TaWbe6#!fb%_PD$WEi@H2nq%q-3X{`#4hGfGC0nd?5dqOUvu@jUdlxh3QQ`fNqdX-{m{n+xxc99&uF!;)nE{3D!q}b5+ddtmVR!S$!p$ZYa+Y#t zsM*9qzB78}#6r$PUP*W2GY0`rAAP1XlwPU*$o=S<*I_?+Z?9))b+4T^YBYc6xI zd~P)8>b>Xwnhh-w77wvLEa-v1VkpDy zV68O*A%N-LpK~8uw=a0c&UI~D?ENZ=cwoEDed6We94y)Navyi#E3?6tHokIv#Ai!x zpI1j=MpwOB2R^js)dbqyioboAXKg4Uups-j?&JjlDrW`u#Zc@;_r!mc6x@crk9ASZ zArYPFUj7dT`G$Xd1`w})eK`H-hBgks-vc(*MYhjs;zCcjmu>`*+`jLYy9?gVZ_AvG z4{~7iEK-3D;|WbY`*ysN-&r{I#RkCv7$o8qvV<4A_8Yy?&Czch7?Cy*De3<9Rwc43 zH-V+SQHQ7EH*Gir@!kfxiamn(3@PnPuhsm_=6$@aLZ2tS*$YZ`ulVs&9D8%RJhn3Y z;QVTJs_X`M7$N0gFiV#+hw}uC(9-l&PC1^Fi4rviOO5&o=?WX9HruDd+#-fj@>cg6 zRDdeeJBFKHEBs!&N*gi(l>X|iE;8>5XkDPyM9x!hwPVv5ch_>!_-OC-U>PN>*=9I0 zMsxDty-OY+VHfoZ3JC2qL@+k@`c17XxLtGdVvlFmGVp?-F?MKa+SDB*-MOiYSTkB! zcxknyAr4S*$Yj`4Q}_siHc-Nx3wCQ>qHc1R5F$yzdeJAZlofOMk&RL8%8AT`I9SKs zk?)573;}bvFN1*Ymv5J}*+ywRWR&+1vGScR<54oVmC4~=4Ty4cCm_q&>Z1*^$H@3C zr>h4yWL0}vef%t^7e9Hq&t_Dv2LPA7(-r_+`_4W>9TXdiC4pFOW=o!e7v)OcWrvME z@3y0%?gQ@@fhm;CSbbc)!>0y|CRC?;l!#kuZoM zbd?E1Dg59sY?$Ts6xVt_=Q4M=@Po79?gpU_ON%VV`0qYA-z!S&h%at|%#$wN(uiTH z4=a4nfwl{~UzBSz8aPI1Qu$ zf@1d*gedzKM#z_NVsX#f`cd<6_v`;PyLrax9}l6e?$VDBayxv|7M9q4pRi^Aq)&#X z+$`9IciAWGX7T(d(^GC1>;Q7)r*N`!=YQ&%;aTg%4j^xQI?8vIjWE{=IQO!4ASd>t zK4c43xJQ3h#9kmc#xYfgQ*YhI&ln-*e8#@9Pkwd~{$}sEQ2y2|zkkPI!ppBeKOS9< z{GxqcGh4TN(HC!d{zO4o)YB2{K0thc1Blj3nW-@T#oDC1*mLooOJHLAqtj7@~q%7(|@eD}bA&oz+Z z(yj^xIDybw>uW3}}VoS4~9w#WBvslpqj7bMdI93rg1?jg={BlPEuwJ}tJPOUsBIY=?_k&a5hRz* zrlx@NEF(A^ZuH|3s?B^K;=MAMe*etvbaG@n#4d=#N9x);s0^Hk*Aog>u*}q(BrG=E?YmG{`a1oSwLUxFoX%R#sm zbTl9d*`xK?D2?iU1>Z3sjw0zh2AIBgzhi)vd1H)y7f)l|vp?zVj{LdMTqM961fNEZ zX9Zx|t%oCb&8gFi%J;4jV4pDz3T=%7QNe~W8IIcKx&XdTfUgTce6@p^&o~0K<$3`G zXv_5ih|6~1HyLjW!wCi5{o%vXqZP&61^%ox!gdQ9@Y=F3yRT@_D{~LaKB< z`|q=RNjwLG%98i&$}iUrimlG!}|M;8lV>tXp0W(R~udNk`XzwvxeL`%&M%VTE} zoNfFC@54*Tio#lJzf`1r03Kqh9tgrWX@t;6#Qkt&*@?}zBp$f8w(wnyq{1=KRAx8^ zU#Ahk^mDj}Y7bv{q1XsfYjI?|M6Koq+)?ey+;O!9$yAU$qT6xnLP)R|%3=n!yb}zT z$oD+sV2!;Bp%uU_M7FahZLMX?v`|4}aBG2jwP=LfnKAFv0TJ*Zj&7D4i69 z<}rt)K&@5kBec};`s5`;9Ep$6n2jJbz{_!tDTGGgw?Sw)Q3=ypXoE1$yUj*?F8Iz-%t3Idy6_r?7y`3PiE~+$2Ke@={T!QWagb zwoAQnwB~W}U?71TMYE}$%RD0oWGAEYXN(Q|4~HgEt*9eIOSUvN7)dZT39bH};qx|w zBH~&JsmMpE=CROr7)S+ua=Cc-1QVguNIm++NMVHl6n%WcU<99pVS+XILzR$B1l;jV zS^F(+eb_MYh@d{63x+&N=vbm8Q;fpnUg(G;bH_9Pg8;-5z6Y|T5u<#VmGA(toWh~8 zoPyvOh}^&d+>J-Utp#~_7!uT$3Voab;Y&F)nnzTR$Jh|G$Pv}7j>jWMR5t?UY?}k9 z!S?L97eS4{=4JdM;YCn)@FJ)Y_`HbotGo#6j$Q`_+|DUtAGdOvTbEQ@_yGXj%qgHLG1Um86ty=ZAjL?Cn8&sJ9^>a&YUuK@ zSwiCuAfRo3Sr8z}kGw2c4_+1tz%;P8S?jFR3Dee zAV+a=+$#hQK2w{cc{Hz$$MQiqkrd&`Mj|N5BY@uBkJjd4%I=Z^2X5#~#%*8vrMS7TT%PfKUxH-k}u1GA7C%$(lV7GOW8G*TN zQvtaC#XF`sptRiv+$V+UKrOpClO45@SB=0AyO?%V^RK=C*mat22K&+ zT8;)LhWrR}jtv&34=NC*j|G!UEjVtzpLHW-nVccmm!{+q_`eDEW$8m)33yktahD7N zOzp6Q@mHfU!y@Mf3`d$B;Ei8y`Tzz(0frG647^zY@1q)k(`@iQTMNOFL^K-Qe+X?M zTHeRJ3^r?sSm+rW4#S!;4+VvpGFd=wfSwG4ist3;H6r17Ik$uD$``q^jf@@P{h9T2 zq9#X0Y?TmSopz0U*vg3FZ|?T4j|tL#$?rkGSw3)OIJn<{hXZzXkr@>(2H>sL5H+H` z!FmMN=dyT#lLrq`LV6GjYMCQ2h&XGAFc)^|Z;?9zNMKHoQS27EQ#l7Z$!!e0qd-Aq zLiTx&;cMA4mXnzTwhviOmS8~_el$O@Tl{2z?Oyc#Rxj9oi{~Dj+)RA^8t8@ioKyqW z92X>CPv$}^IAX{>R*0;Ud#n)FFJ!Zf_?{|Y02%UHOosjz;h4br3+37XpqF<&z+46s z@)5Ek3~3heM(89>m_PP6pLD!1e`7l}?1{tt3o@7lkFzl&%zw2X=3gL}BJT;NFo_kw9=6g9Nve zaP&X6+!07{x5;oM*k}hM!M+L&AR`w?|7X=5F46zsy&U}yn&9YvFy*dDu;W!D`Cp6v zPvYh~?`9Xioy zoemO@2k&NwoDQ)ix?3StaMWBtTz{bz(MJ{15qk#l2An4NE)gHY0uCG{Ss$WbEfl@Z z_CmUyBWVK8T)conRnKWf2yD_HwIYeB!waB0$1Rt)rcrxy2mqo3OaL7YLV$u2ms_XU zKgydxL~&1aN&)Ekt*OW0X7%{2Zya?~wfK+{PSug)zjs8(j={VSVWzrO5mh5(x?d6X z?d3ISW8^qod_z%iaDS{g8bO(jfPEIkvFd!Ar_Al1B083}SOF8tccacPrY@Ll-(o-C zmMuUpD5ie8u#Dm>e=4Rh(dd<`EpBUp*?&*VB4g1$9XG z#pf)U6ASLVU^^=4c+(gAAaP$uR8luopH}Jj1=bA!&R_XSB^^ZQpjUe;;0^}c^p=`8 zM_0ya5+-$RoTi{ZO3>)4suZ z?(!xJDgpSN;de=c^CW)Pn7|qF%zY&DH|*>8Xa2q`{R8n~4Y8MW=W2Q-J&R}!!IZ1_ zs-d!U=5Z$TZ#C4T+4$PaGQe}c0U&I}AZ#Td+>2=nBAnh@Lw}{4_3?WF>ch0&3%51T z)$O{-uVcEc8v-T_aCb)T3rN3n zr2#ZmZ>Y?xB!XarL72Q1*x-F#X&jhkVJ!_8OBHPXF?5Sll|H=|!{4SqsHMuPe=}jP zWj9S2!e;RgSf#=2_Kseoo~0M*x1UcT<$hdPJw zJ2qSgd(i%U_t32coL#CRp$un*aYnI*El_K9WyK;a#SEEhxT4P27xgf=L&%jAobeeh zy#PY>>PcdYK}+a23^qFfIhc{|NqjxTqdkQihxVosl@OBA-Y(*c3i&QTQ%A-So2w`8 zP17@`!Oh7uqCAZ*G+gh!4?W)Yr7OJE#Cu*%Z{ya%Uev$cmaCgYQ3I7NT%(qxeyzZ- z8CS17u@`fVlk~)WX;`J_anM)moPU5mt}l&E&b7~9Et6v>gB)Qv_G{= zrY`fXRx?zhy`xxPYGejs3<=AVu>%e~>+uG$)(P_S_>Qa@5aVVD0x#riYXJ}_7)tmJ z^j01D_cFe=7U>FBPa=O6AHTs+&|WgY8&C|zYOM{Fuz3M+s$&;k;9HzYeXDsa$0N*% zoZA|Yo6Tb!kDJV61$VKLPZmfUDW1S9)+)#vU6cT$!zr9%!XO|uSWsCzRuaq;U9%n@ z(pM02544OJlS~!vW&T9Prx@*JHK#ZV(>OEeTF(LjGB-+jSRim0p3~Zi zfld8l4K2qY6W&Yc(}MUJ=XHlQB9dfV2AU9agjgfs!HsLVxIl(ALTZQ!CcrvY5EiTv zfXZy#Xvpa-4$wzBlXXr=L0!0+bXZ=tg03-TR>O}hCuc%_*a`$xfY_*%bXIr{4GP83 zb%>Qd!IUEd-*CZZH3;ZI=R-d9u(24kW5{y@&Q8wE<4hcgkcrb5&oFIk+oM+pr!c?U zBwL;XWytUyE2Kwmx}bS~EZP?|?~O(KVCqg_(WznvS!NLd@F|eop-;*WlL`c_ELgF8 z=oyh4P)f=Lu7I6~{j*c|dJFc?#1(ae86vDAmCF9WZF5pEi;-%MfsT^Ey&9|qUvJln z)j&;4mhrut6mmQvnP;?*}jC<&De<_QprfUyGwz1Xz_gzDa zo6)uOoCK19!*SPO0o-*P({&;1eB0$A=*C01TFwW4;i^~YQSfYVY^bT;3=whL?s*{H z81NXT=Nu4vNJu z2UrK!CU3lnVC*<9h7sqa+XlZk8xlrE6Y>=yF4n7p4@;!W4b3ZJ#kjP!+lxZsehie| zUKGI023!|ID$6h&;0PXwFzYCufQQTiWsE)toH@HG>0L=vtBqJ!^JIj4ig~upd4Ho!%z|il-fCxX6wMsEf%(27FDA|z=R5iKz#I| zic@*9XyCw%oHp<+VdXWrJU}AVh7*XL50sF$aYa72i!J95k;5R8k09CXc){cHfb7A>=Aic9!4X#8C$U=4Jn#uQ z#c#6BuI?%A4L&T!rYn+~FKvnXRzycH$HIF^Y2Gi;8HN5= z;JBM?#{8XSGqc|RiEzd|X*iHhSXY`BjA&q}1QZE4MFqHwYzVhZ(TM2#8eN z3gm}RD3~o~2@5>95)3n-PNQY^;E_QQGJOb_JQDW!LEC@l^E%S`0S*Xda}3t8yEQM+ zkEU}zubr%G46(SokHGY7Iu=HbA;Dsk8bLks^A%(JEkO>00 za~ogog*{m|r5ZEBulRV-9i!oI`2?J=@e{r>W~g%FkUO67Ng$kf_!?gieQodLjuQ`e z$+>*cfF+wBaZs|0m)fzVgY3UgXMH*XuH`=RfP;(qHvlwgOA!`#137t~k`eZifU^Sx z!S+#Zs!?*bA_g#(1tkbxpl3garKpXdnw<>NjgTJFnuYcFmDVggi(fOY_O%W>(2j(b zVZeBVd4oILibt46_;Cv!;da1}$<26%9fY6xu*nC%S!ufE^Hl<8JyvV`wCrp^m4GuH zZ#-bFMTU1`f)QmCFHfi5ICvt32gwRfaZmg*PCNDv;FA6T`wj3V`*sqhn1%cR2Eq42 z^O|y7O-T8$h4X?HFTf>N3!&4uM5hnjg2>pTVP70hJA#dh4ugpb8Vqa|xXoD3aXV2g zJNAIG;p=@wJjTgLs9Uj~c#+Qz`&p0?bX6jEH*XYZ>@1~tz9Y;)j}cxNnz4HYuhqBEc$W56V; zFG_T_tB(NK`0|oL@^uktn$6`?%hoVvA|~8f@(4d69-Jq)1=+FXESnK@d`Yy2rDF>V z4(+h`5n2K0`JJ(_Wt;VZwj5&6;N+n-|<$t$1fyym+-)${K?RtqdZx zPI*FR*IE^jQ~N>~=CN3eqH6(NCjVzS1#@UZ%EMWPl+g=ggrdQ=`R6jy9~?&g`xZFj zB4#n_OMUo!Nqt-=-h_gC*2m;b{gETd8Nif*-`wpYPSNc`q+AV}*FR}izciA{6^8Qh zNIGj+4w{AP5wAWGpTy(X0nqGD|9gpsy1dd(D&smfQsRm%{s9zmT!<&Hzj1%=*0MAXR%9U4uO3*y^4$GO5IfP;} zgvQhmxWpEH=@Hbrl9xePJesIMbsj7Du8eiPe((sudP^p(Lk-TqrfK^~I^=*ftULZs zVXf~wk}CHG&a@0#)-k3)y9Z>G{}aga)OnZTn-Xx6_l9{7j4~~K@5*X3M zCU&H&%@-O4d&DB(&kW@}UepNGzxVG=mQ#xcv9ht`K8%@-3RjJ=cAfiMhwV@xgx(My zZ}EyiyI|0Vxhp>JnA+VfRyP98GBQ{p$&!z^|66PYhW0$2!6-Og0R^oCY)}$VF(L~P z*q{rKhP@9~%cChS;dt1`G5b<5HC`l{K3KjF3n$J1oIoliJvDha@i$ zfSbSu6HF+FrY52`1cO7$B@J>4ndr=T2jo7o`2FyKPGD-hN`ceJ9tfU~9Skxv%G9X} zJZ9^|j-j?yRdxq(x}t{I;k=><8blR5MEH=C&7PU?#?n{elL*Q5w;~B6=G_sBc6bi+ zDoVSIMeuIvliDeH9wQm}#11ZJB7pwCA2wJI-1IUquo~-96s~7X=5vL}b;D2< z0KvOqy)AAhn|}oASRpgJy&= z{MbdgY(DjYgZ(f&XEI8eFeu2btX@N66c$-VE2gyL3x4|D??balDyr!V@)u36ej=&RvhjTS;k_CJ{Vgu4-m_QM3jx>@N3|4 z^^jub(>S4&9TQ%Y{*VD@xWWU`abDa&@PCM&KnEq|>zys?66!NG6Tl*G=>p7RAm*nT z6rW$x{L3?K`K9^bv8g4^gi%Z+#iaE+nh8W6_<97 zHZCRj_!u1U1aC@Ewyiwz=P^pBEFp?*TF zzbJJ@oscwIAsm)5m)WVEl)(c1KyMtIjT&H?9JBW<5LnD`Vvh0Ru!nnbi8~pFq`p=izNm;Q^MbE~J zy$iPN-OSiHn(t=D{<2azp_Js$>aWyQnuLF|%kDvq6H=a&6(usF>8Bh4w zw(fccb*2~e5oget;$aw^+)V^>OuLV~cm}P)wF5lzJ)A*w12tvCxzLc9cZ9gcVz)*PKQ0`qS^8CC*EuCjz^^)8|d38%jJn zk%kSKES$+?qV2P(Iw=$@7m%5~3!Qk5SIU9fh-Izxx5TBp-N@-T8}o3ZU*8lV|`Pt?x$S zJD_Ib!!CGO_+OEcMvvCnlQHXgy6a>*jsCLIolH<;;IkN%OGWy=DHO#WA7X1HF* zr&2BU6o9;b2*;RJtNvKq6Q@#FeZyobUb$c@h1jR^&U2|sHW?O=OyE#Co{X5F}i($Vh!d1HLh2%qa^qH@oGv*UrT%oaPy?X%f*JH9f2GcQz4dqSnBG7=-j!+w z1>#k<8pIJU8D;{5O)Im`hY#8i9(C2AfQj>gS`<|og(2_an2)G;5e#qcAzBF@2XddnJ5X1frD0Od+=v0{0jV4DM~kw0w()a$u;)*zKS^Vce^kPAh?X zA5N!>=?Hz&<=78?(0{ue{>dH^-O5PR?)Q*r^xtXTfT2JNdE zC3UM19$L*q1`n1_bz?(O&6uhaviUvf?ZWpW9XI({OdZmyCMGex-+7oFQp)&j+ zH9p+dI{Oo&q>OFXl~dd%mN$(U8HfQQYe&@^I*Y%m4;%ge&4*;^gICuWOgz@he; zEn;xo@IRU0MIqsA(jBjbYU&5v4Z-Bkf^G{_f0qgwc{nCT4qfVW!n~Qf*_Td8uluJ~Q;OhcG9OKBj zh2QdxFte_sHf3A5rnxajjN#AFI!uj}IJ!uxT zRoj$yS_jH2ci!B@bACcWQc+Nju*8`g;boxMM7?Gf?G;{eQ~m zS+9@0o(8mj0>%u5IY2=pH;sjyo%+t}sh*zDA776+jh(vd4b-cHAMeC^!y?!Tkzixy zBnoepD6Zxlr>EUOaeQk`c#PrV7Ic5|{h{^fAHsyipBbBu;W}IJ$DA_}Pk^wgcW$7b z#hLe&0j_8qagf?}F_CTBaS>UF?E*mL&hcWROYIMs%nS>6mGjX6PvTi<*cUE=MM;>lHu(Ktg5opp^Tq-ry2GgQsaWIQ_-C{cIGySf4zb68s@g04K=m0ZXi#vRN4h zD)JUH(8aS62Qc$KHbz#X*%_EC2lgqb0iD^%jxE=PH&WZm)%UhoWGk{!WXO%wxqh-p zItjU}36c%ZMnXY3n`eW>%mx&}aXyU2n2M<8vD%aMk{hW<>lP5gZS35W8uhuFYJffm z&!OQZJWhC|K%xcVh*@Bv0d>dx-JrbX7C&Pav#+?b*)QRLL@@x) zHSBJ>BF|fdWed25e)n#w+5L-+AZd052U8BSQ1yfEu$YdooQn$V%n6(F`WQD{o`V)8o2d)&H@hjeVY$BUdPu*LUVwxw!w!&)jME?PWUi*3i=ak_ z;U21vEP&Goc9S3UH89k-@#a1IPJfy>;b20~+(R8Q_`P_gfJ4AJEY+mp_u2PS`_>*C zu*~Nq4Kwd|FLl9Plyb`k^jdln3br>4lKnOegY^7141-jbE_{@VJr=n~A&*6FxtEG! z{va?{GmPMUG^jIrLzJ~#ge^C^0MxR}3zLWXMF#et^|IhTD(mg{V){r3uZJilYsCp< zFtK^=4wIetQHL-F!(nixOQ_wU8yA@s#xYp-g_zA3!#Z>C@|M#dS!#&61FYQ|6>nEl zPQU#)$ZX*f3UgK@NQ3H6xB2QOCI7$rw)y3kI@ zr|+ar{AxgoR>==v%x!x6mTl}8Thz}gcyFAVs zjIPjaaDp?5k#1AV0dnO}&Vru>cVF2t%V=+?ENtLfZ(J^bA=UBS0x+S;2x2b~eu%1r z=fg^yDxZ`Y?rVd@H%B=#cwVf{MLhCKrcay`19^9U97_s3#5jK>XyZy3CV8$aW1)^2!fMn3Wp zI;!IH42YKqcVTfF9HRv5`t&2%`Zw$E9)ZZcP4`(zJ$`T0tIen{UrC8L#>#9fHQ+sX zsB9+x(T?M-&F}0upx?^_|4VCgkhd)DXWi4{vdl#`Z}4U#+}d)X9a2c2_&C`E_!RQ{ ztB0Xa3sR8Lsvaj`oC(>wF6{6kuoAuTQNVAU{`OJo7?g~5k4eVB$EeC=oNh8^Jch%f zU{sC%`7tUSWyW8P_WY9$U$X7|?2Vt#xV;(%rJXjrBEw8)k2*8W(FfB>9D~V({rw2+ z6+c7xY4q}fqihE<%6WDv$v{+0_0RUq_8joM{4~|tm@OCbQ82YJ;X_1neyv$e18}1= zhTEedk!2UbpfN|EyBfRP3IkBcG)D%wm7j*FJ&P=jkV&q)jL`=P5eQyq^WTGT#yL%TsdyN1G5sx<6OwdJ6@w9x?v6B+spc-e^8$?UK7mbJeGlT_|q_c*?Iaw zyw~fWM!;tF>o{qguP=F;hDE#zQ}xSF(_1iIp1Bd%44kdEJVTd7=3|bv)^??PzJXd- zJqtUK)+f9{Rr;}KDL?;gzFPq?i%=8tAm4nJ&crZs-lSvotccuIPd)NKC|VK-z?BJ5jsa^EAawdM%1_&XVV4(z~9|oHRb?tb4v7me&(rzzK7n zPQE~WO3t^@(v|??FA##q>bzB6Bd@-ITQqLg^=oMmW;Jas^=M~iwG2mST;K_HTCMe< z;>c3LKCNF{3!Zeg4!uaYl0tWRk#MoJp7El;R_qVLYxU)evR09o=mKvM@q!J;*S;jf ze&?mkVY9)w^*S09Y2@``_0I|GsBMY=OTjBAj*C4Zwct1g*>UDN>Qn5!J&&*aG|L!{ z$uicp#{)4>=4mesCUE;J4;j4lr2xS76pl1e;ewCgBKu_2}#~I96ix)m-!1Rp;5d$tJwicfrLXGz} z_~ft(MLFm6*964NU&{osM-EebO8A+NrvD8kcol>ap45kLg!(^|9H#2>Hw3BodV}^h zbg(x_fQ13Mz=sER>l;1^jE{Qv7z4fLlD_RJYNKbrNqx{;J2m4YA=HZX^N@l9!k7z!iZ53k~)~fqkpq#{Cf& z>M!4h1^#>;e}^vg`47vH58F)mCb)iaGc;}dI0y@Wq@-yaM)ZhYu2O%fcMcQAEj5aTT zIbub_U4W{ti zhHWWE>g}CBY{O}6o^H3D&O))7+o{Sdn%P@#)vLGDfn9w$6c-@*2O^*d&UX>$^vmoB z$I|iVuYnKqbxoXv?bQnfB^;4?Ne2b;$w-0?v7u0)tphjO&ZOHs;vby2B1SGZ$GfxEL+Vt2?N~Q#iuX~ZZq!3YLyU=YI-j;pC7IDYz3MA-8=iU?o4gIbc$ z-MiH>+Ne1@afsTcOLkHRB>i{NdC4XzU+pCL4guwSk_n>*bA9F%{T3m1W3WCKd-QnMqp!f99f78)f z70!+oIOwcedEdX`XVtD*9+N|}3|;>XeOTTs3uXRF;UpWZBJrRe{w>A(;QV=*xe>b7 z0=I?^0xtLPwij(33sf+c@YSKnIVeE2WWD*T{l{6a?- zrG4+A<#A>{ERBBk3mph9BGK)veZdhr5L>Gc{uRs+8q;6tw5pwGiar0~TPFBr;|c1r zUEBj}g3kgR^hHmol9jD~qwmA$E+?#xp#AlS5oPN~f1?t8Q&?S9o}%tX!#vpt4#I0> zW$*r3Y8_XMsLIp~9+4UJim1QPZF*)z0V4Pw*Is%IsVsbYLfu9G(#Pefu2nPFH;MZT zu5R3{a@$yJn6nc6ho9J#@GqtF^HfK@AxCA=&w5jissT2rT-CK~_KQ5bh;60g`0xx( z+t~$DM$vS?|>QWQuSAu2bP?OkuDjL@Ds4A{}_794Lq)1tl^wLr*x?NP2lx_L_ z_apiJ_TTMdPCi~QeChWFsaHf*0tE0@RHlsRrv22+wYqpO{&9`M+n3j{)mZBw~Xvu^nDxypS~f!E^k1HQlp=@v;XJUyoLgaQ@UKjkYYvHn-! z$O_;fSou;sJL1m3URMncw73&uPwEp3)TIBU+|B}3(t6MCKG)?jH9oIdM|xIF6}5em z?cBZ(74{I;OUJ%8w(!XG$C~)(6Z-v_nozk4s4Uvm6pl%t;5-z92JEy#Ro`~)N>t#_ zY&up93J=6Rt&*2d6spl6#KKleHhT!9;vi=N6ZB!N6h|UWY^BPOT-iz;faK*?svmz5 zDmOm`(Wh3nZLR8vp4W#Kss3TZ3G}QYby_*j;UJPo9Q;x!hR>_=QBQ2Qg~e*`^i&Qm zR^8RpFE4Z4eiqYNe@- z8a~Kp49pp0y=JppEq88hvK3>ZeBW<-6Kfvj08&cDQ$6!`{~*)!Af5B zWD`Qhta!0=rT5gv?RizP9#f(^Lya_}L|xEt9o{tbw5&wQpxy3!REhFbiJ)J?uUwIO74l!{Yf-r(Rk@w?&dP$UREcLx)iw-s zNg396onB{>Pfe0tE}7LP8D^5xOmca-x(5}yS4fdVO>&k=W}4(ale}b-PfQZ2RQK4a z5gB;kEAZH@g7_9Z!z1LZ)2~%ZvpY>v&`y4JGs*uc?n}U{Dw6%rsm>lkPDmgd%T3q< zNeFuoS#sDkAOZq{EJ6rj3nVN7HzWZ;K}6w!G%7++9B{;u8PMPmXM%u&#u3yRQNyMY zQNj=vM@A6due#5<_Xcrh-h2P=`@?tBdv$kpb#--hcb&o7nW>$XP3dn^j8%1) z9aT|!$vm)ZqW)*>br7f3%WVB<_OBYifU{p-xZG7BagSB z)Cec)F;%pzVN052MmQ*{)Y+bBMJX9hwkj3n2WrRl5l*2qtthLXQ>fg{;|bxX)**0U zK|BBsADQuuEGJ_LP^QNu4A?oK@iC({JqP{~ftzUf{s@Hn>LgOt^CloFoEoBmFg=Y9Z$7-^8>_SyLPVzAB=nc$%ehP99$G; z)n|Z_C@%Wg8|VfLDfTgR2v>jjk(a&tb@*%WM_v875KUrHgmdr_${K2LpQQTsa))sM zc`5Sews?>{RsL5h4UK*5Ba~!faX*)_ttXm=y)^ssY# z-P8Nq|DvbOpsDlq^p*CM5>&&Z^_o21p3>YoxkC?NqYl&}wn`=Yjc%n*9M*vn7@e~^ zP-AvicA%C?{;iD!=feBUfFkg@fCY0MP%VPH)4j_>2@Vgv`RF~ zy%!RsXDT;xIVP!+((DcJ*=_9u98oD(cP3AE6_>{+XdrXgXW4&=A-xMoMX-q0+;Giu zsMGOZatkFH=tI1JcBb}V7j3&xn;V?=2^JxA#=PVaRr~{{a8t&nh6|2>jM*FE#^aXmcs2IEz)MXzi~RWgP;bTTaoE zw@@_9e)O$kxB>~d{J)yxZd5IQ7X?||vZb6a0%hU+yP`Ox;-Ya*wJ&p-NV}XJ-X4a` zD7Fu9;3NLS-N#D85vt$T=NRR>b$`nFxZQC6UEQquP!Kh?s<}+~^+k(s+-262_?5lD zWkc*A*}-L*e~B&DsUS;Zr^}ah(TCnfQEUgiMV&67eqKD0$=hYt!T14qoJ-cTpZ*m9 zzbx+%u1h5^aKR8Cm0%lpu>w(gr1^V#eiY`Av|ILNUALDwS$((9Tefad-coq@GrJny zuXE7`zG^{Wl^k^)fe8?{e5@yRq>YDUMNi6T@ZurlatMDn{MKP<_QK-1_A27RGjLlL zw`Zduda-nbOSATWU6n)6Q-Yk?i<;X9xOl7&T~!=*u&=sW!!S?tMw5Vgb)g!YI@8_= zbpgJ#P$iG_qO_a}?EX2V_<(62*RY zcY1tpd@`k$6GIq~QU~j4$w5$&Y5N)hn(%J~h8UV!E*t%SYEz^a)0)M|v@Gfy4aGqd zEwO>WV^K8h-Ev75weu>oh4Hf5kdL?2b4TOVp^9+P+Xp{^~D z6IL~Qh3(;uJa~7FY}$`fW3QCpMMt1j z<_PMG7b6&8mC1?yC=qR6*pCtd4nfy0pYBI(5Op+kpsJmKlZ0r@EHkKotS@;#RDic zNGny!b`Buh{fhJzAP1GaA=}+bvD5Jygm_a$UAgeN%@Z>NTM({Nk14^VM7#TDZPi?>}c%QX zpavMLK?~I%bkGB(vD;Yv;=~_>sX%BOXWU=q!x0AiJqi~0R%HULF8;vqoF9_k? zofRX)|7}iVQehJ_q9{3#?RsDU*pi#DE~{@r;Vq2Eg#7`Jo)LgFXAW$cT$(a4B$ z)Xf0+>gaA6KA5@|U*!6(HG|L#1KiC9D}#R_;V%W7fyEdyys$!V`Gu9qkA@VPApHN1 zNE-ZmDoMTxgh_a$h2FY!1t#m@#Cg^AKO>j4y5thzBNvP?L)0UzsYRZ@of3;(n%7?) zxG@zl5$IdAXfG4Njc5pKqFsY3Fb;#U2X~&oVeJ5m^nd;)Y;ZFbXH!wWd}IhEr8}Jk zi}>|&CQg9`h~=34>k#S??i5KfG2l@{snIR4fN2iG{cgnqlMPr|K>=pz)}weF#If}f z>S2R%27o*wAGG9782@J1$bz91+wn_0e`EsUKj;uYQ{lPcF(OO=Nca~t|F@wuvMKrt zTZ6jeFbAkTs8@Ss_Atr_QZE6I$VJ0w5a!4`!>Dn?%VtqhFt-}NK!KTo33f$Z9!3QX z^eaKbeI*!xN%p`Ul-8({XC0G1-?&#(z=I`NzHtX7rtm8~%*{m}anBqyo;QF3CYh|o zc*BNgV)|Qtppo^%K?m*}G;rYxIQz+*hT*Z*Ol7eA7|j#F=TD}!0+S~oOMq&1WHP2H z))A2nGj+^eJ(#75NhXpxr}`!g%JMwJZF8#{_LCGsJOaaoyaCn{@?`S)_CuQ0a(zHF z1Op5=z}U^^BpXH6KLOTb6wTqbB@;RVj$J8_4yTx6#e0$s=B&uCmPh8-A(&3Kev9ag z<020^xPWSs>t$yd4C8}%MG-oPFRs*Sg%XMkAAbvW8Fx|;b2<%HP98yV;CBy>pv>Nj z|Dz(<6?4zT0`!8}T`<;d)mr)e2Vd<#o+SGKfYou^b?rC zxx8Zq9ig5eMxM)MflI!z{fi-1a|JUn90My$M^X@&>$Z`w>EInib*)SD6g5PHfjwNT z${&L77=pH(=a+#PVT_wQ#{Be?(|~K3Wd?G+3nvG^WSu->>aHIes|rQJmbczXQ9$mP zJ1O(7#mLRHn=H^!%_-f#P&M<)rCP=hMfE#N737B`njd)}o9lTw!)YN-drAWE9`c(z zX@sX506gIsisUex{V1*1QulT1-J>Wj)nPrn)?oG}8EPhg{e%nvJ)=yBB6?n+YvqyY+!#E3T)PG%OM7T{2p&rYZ5b3#cQ!td3l|(BKAveP{@v3Z8RHHg+V)Vqg~} zZ1PO63lJ@4T317%c@!o>0BD>?n_CNN))eoc1&A^jv0f^LfgAK4CcjjjAlqccA~`!> z;Kv_4+qiEWg)^byx{MwkcfG;LAe{*f%>%!`5uu@7x*rOy+&7o0fOBXOAQ+88--0xj zocvmzcKA<{al21I0ul^faUHB;I~$DQH<;i8oIyqe2+oCw90AwyLpf}`qPyASDI-%2 z4tUE&ZrrtIOxORK>W_fvArkbun+iRb*k6M`T#Q}2+6k0wM&P2XxSL|4m$UzhlfW(# z%n1||yi_O1$O%*cb>y506d$yk<95i^NRKXOKSwb5LmViVN0AV8g#8D~PE5ewwsmS_@_AB3+$((Gix2928UGy zXQjXVK^@mZYz`Sc9)O(*$t4#jn4&W)AM?FR(j z>shoraoL1~?QnNFXcBcx(ek9}$dk#!w;TrKv(*6HoijkQ%jHXxsAUwa|NB5;ZeNk7 zCsEUQZHNL)0Tvl}O1aJ#GA@^rZ&mgN)F#U&Cc=qLxnpl*3P7c_NFp3kN9fg3($kFQiAK+sK=p}R=tQ+G!Jy?D@U|755}T-MVhYZR(3hyGxVyCRv}!X8DjOJ^srF8;2**Ei z-&M0=(<+_L8#`ZraX5MfnbDj_r_wErSaFo#ss>q?$`>|H$gieS7EU)(rcp}xS%3kE z9y6eq89R+SBYyQX8a&jAZ;W^fhvcdZAK=9!3$EyN^|xpeD<1K>fh!O!WbzL25+|@p zr;`R=^L>Xv1^&Q}S^9KH;Z<_Lbezu|lJ`%igw|iNaRF!)aeX}kTN60-KvcL}9fFP4 zVe}T5W~J2L>C`8v{3O8a#&^ppGqw^`fG^0pTF}!RYyfH-HiO!Po`dYk*NaZbhi1@C z%`Ym7VHupyG*~7JWEn3YDaJOH-7ULXo}58VY3XP3+6>%{zaUrV(>$~>U?ydUo~i}x zAnP2h{rw#=a>h(3f@E3AOd3l;71e0btMYUKHHI-lBgu0q%c5^tdF z8owB5KvD3DHwOE{aC@sPnNLOL8u`O~7>HUUixyBx&|~KqPT5Zj=nk`iu2$r&QXVa)Ci3kED7`V*35Frv0Ec0%R0xlH zDB6Gz3>=ZxLd@D)*-k_LH2x7p6(%@|PjGNd;o_~OXQDyOiw2=_kWDyNPaMmK4 z&B2q4l%hGTn3B_%E1>=jf;jGN5I)|+d}Kd!2PlcTTUEC12IK<3`r7^vH zx8giOum+7oIQ@Vg(uMnm*#lIwfnbQ)e3-5-*`b%{!cO_oQo371WaWGJWuTIsa@I0R z80rO#BeLqVJxI)j2UxF}O+aG0wA|MPOZ8_ zRuM|y2APEg34HMmmtnY7CE&yse^Ua@=j{#aDX~tfTl4`ltPiC51U0_FwbXZH`zL7P ze{!!C_g@ob?$j-A!z!{k=Tt}^Xl^~>75EFYsbdblW)ElWr3^7|(HJ}dL#T!TL zksq$3-9bCKmNR9mo}?aZsqdZjG#TPShE!4l><}g)G(*zRxR1PWc~i#s?yFUd{6JD> zlbR*GQ{glGotKy*E%?xpi=1VbY_);Lr@w-laJ>{KnfTz7VZT|*U(2z7S2y;9$5iag za_0tW*mpT7P7w>?FT(Us{>(UOoO$f{WN z_fJu>52sC@rXCY3kfw3!cJm`Q##V|#NJ#Z;7XsuiQ{PDl0P^wuR3DO<+SL0f2v0y4 zuIVW_Wv@R?YpMCEwfmeaMuzRl2C}Xh`F2wFTr8OUxf(oS`&t%0OAQH8Gmc!5N*gh=>WCPTH)sJi)}l|Mp@i>w@r3*Sxw`zt41Uf2wc zq3Q*=?S>_|sYt3-p;Wi1!=m^Ex5ktYWe77q;6Mu-BcHxr&j2iosx zWf>1DPR{I0j5j{QMpoRQ0i)ny!i5-jECX$xR1ED-&J)B>&mg|~rTaR;=ZC0_Zz!NR z))bu!#1rU8JTPLYrn*Z3gI<6=elzjd-)V=rDKm%*nT|{820=4HjbFju& z5bvwpWS|Ji-+9p~8*iglz5l^stjvr$wW|TvVa5d{oCT$^1%lVHNvH_qA{3Axy@llB zZPc{sdA|4H)+6loHF`W4CM>tfl1hq^N4HTzm~Y(W58LR@_-Y0Op#eD|*4X@p5shIp z*ORwXt1x$9L9m|ps9CJg#%??T{B{95NNhZ@qLj&Zw$rHMgX)GA7>QxQ%LHP7r@TDa z_TQBk4BW7jIURdO!*0z!=;KVg3g$I|E7N+@c~P=oxrCJ%RxnNL0Jsr!8E@&c9~M~9 zVZ0-OFv3HCe6sXK3X1mSW6T4rb+GL97qJS0f1mv=rG}_YF$+}6Ltq(#^PQ7fd#DjM!K3zocSJZV`vxRJq+0$u*lo}$mY2@RSO17UT`t?Qmll}d zJ#eGTQs1DjP3(gk{+Vnzqy9`Ew=Dr3>6H)1j95AF4FhismV3km*|i$v=nC5G&k4%rXP>DxMqs0`!P+3-;HGm5RWLouaVLRCkJQ zmV@_Gw!Ph(og!Qms0H>#zl8c~fps}LV`l}oQ*m|q@qQ|C2Si{4jGImuJycJd63$9PB8lbuVQ5K1O*zPl7XNP#akcK+9Dr(mlDH1*Gz_CUp)wR z>SH=G=`Fl-+ad?PMH3qM)unD3ppw0BQBRjPxH!Fy=MEd?-EULl7$>_LNM1rA_H2=l zzYW^FEbl$!TcNq!`-keR&_Q~I4oc*X$>_s03dS$;595J|Z#6NsSYYZrZycuB_$^pe zyj(WKzQWy7lqAm|rX~I;yzd=_!jN|;C~?5nGrL6sIt(=j2cC zQnEjeT2)f34nOOGaTaZ!4;VD8@4?>15Hx~q7H3oPnS8L4+Wu9i=A4erSnk#E-o- zyXYT*$$~DH^CaV&8$82fxLP+oTBYyv&Q+vG^HXxaX8APe zwl;8GgV?^wFB;^(C}8V@GHB2X6j9GRdcppjzCY$3KDB*4=y1Eq4Pg7N0qg!s;}d-x z6Fmh!95Ia-7g_Ibls(9Q6=1Jnk!dP%lF~WGgNzrR08w@1Iqpdiz7+W<;s9B~SQ%x~m_ zr)Ydj-zJNj!UB_8Z2887Zz9WUry%!kf~X8J7un?L)6}u0ce}@AXV|anMyolBT{Z6n zxK;B{Q`xIg%M7^ssPrq&0$X{8I>$jF0nDf=g?Zw` zzl{3|6|Rw8zoOv{oC+05VUA;yTlUOXxP@n~lFyx`Rw=%zqNl9}$jE`v?76Ls_v_F8i9M7W2Y~$*a~yARL+&M^j5U61UG{9kh>pQK2<7 z9^MXP#RcV&wTf?fEmn&yE1M0Q*H*}pOiOqZ;$1UOPn4K;1;YnrpsJObEi<|-w^5k6q%li#H^*m%Anchpe(=5IZT^9A14 zZ->V^O!iTZ2n8Z=zpzTh$!j(L!AqW-LUvyS&G3eQ&3THUjnB$$=c!YZD?hj=Mdixp z=$x1S15Mji_TzanP45#GGy`@IWY7gl?dU=S&62$ix$RECelu9fWq&Ofe;1?RzOsb% zZJB$4hWN}5LrJ79CxJ8=v1~T!FBh;&dRYw~!aMj-B1Q(+QiFeSGEs?c{mYYy;kDGd z^=c^8@xJcjk8q$zvP(JqPaV<+9EiXJqAj)5IsD>ft$in){G6(#Wmt-)d`lVmM{vNy z=Sl&|AenmX!@7-wRO?3*N)jjp^&yhJz;0LntK9BAh}FoXNWhIK)e&;dRmzs3-&6e% zT+F~+#{s~E?`UA`o-1fL>lH9>h;L=6G*bB+UE#+vzep@=_C4+6L!r|b=@S#@WqbcY z&Aae1U`up|dw@c?9c))^)K|RGl|zmf?{JjClP;`+u)dSgKhorus}+9O3cGtwp{%gi zlz>DT?0$k#6xkEsk(axFq(%YXVFi|1m++eG?2pvDk=FnUNVo*A-_Qd#fYS34js3N> z-(8|c4SlvvSm9+muW~-QMDG*MUSGUS@0p*;d#*sm@tJ)73iW|=<_diQ=bfLaphY=^ zc)pkO3)@zEobK>&kGqO%k^GI11Rz0)?&WgXRT|l7C(dSWfZE!tlx2p#$(#WA+5hBC zBC}t~I-n6q?QYa(y2cx8J93Wgi;YmRA=ky$Q?d1&SowQX#Kif^gsIdRC-uowqIFa` zs>v{nn+@O(@2>4X$v9Jt{Qp{e$3#qK#h1}G*WL}dv}e8H;Fv-rNBB-~ z@X1)&UWleh86w1BoSr``M7y9`b;Ki&3b87#d^v_7&0eh5FlE{ zJ^eU>DfTz)Y$kif8n~|zQg;Q2E`FG-4{qZdll6fj#t&tDG=zIn*9{FbDBSJ5E*1tU z5bHN232Cg3$G%uE23=(%x@XD(dFnNDf4h|LF z%wzK5P|=Q7U6rqeiZ(#WsZcSo-4T!_<{VCAkNu3yWT^Bez>34MqNH2{ujtlO>wNX&R+MeWS!}2(8wkSEEFKgf2&MfwGhaqMnJHC0(LL z>yVEC3)A)uX8SR)_W?GGcQVo9EHX@u5pBI0%ASf5^#iadZ;ulT>K(>S5GX!EVP5&L zY#T2!Y3)^cB16OxUd;|m5YcjVycpiZKO64t9R!*~J>mM{`Qh~mqRVx~TA7E-?oALw zO>geA!5i^69Yrm(dcqskLW%~@Alw$fpzrboo zEOLA+kr_1Nc?$s2#7DDn@_DB0NK=9PN@rxcM~rN?^AX^csR(yl)IC6!i3IMtR3icA z+_rec1nbhn$b@46l?k^2%d8|Z%Iva(qxs<*mkk8*u*Ai6;t)PSZ%X*mCNB!%U{l-( z(9ym}O;^Ektt)+KtZOGTINV#0##!w6!QOe=3Vi5rf5; zb)5bhqa_GcZ{<)0huBE63aK<)cD4^FNSubxli446Lv_<4ylL{aRFNBV5xkxmxJ~)> zg<%rZ71c654YXA)??}TOsFn-U#8Y9_fCqsP^I6*IA{M(E*)3hPxh}quT$~PceR>5Lp*`=iRJAvyCN_1DFdF>1~`U`U+ch$azID1x4HlHLc{Zcv>?0Mn3<0|oOp$5 z7THy@MJF*HGiFIA(HhQgJBd~h8jf}n(RdL1WhZg}4XlhIWpQWG2nO6XbQWxv*6f05 z@MUL_Xgmu5MjeOEY-7-na`(+5qoIx&F@08E;ryb(^QO+`9P;GNqD8L(^JmVqbMp%d@0po5d1~IQyn>>6 z^K*0a=FKyVa>Ftr4a4XMHyCdAq}+aa^NOYy5^*u?^pUyemuG(_uuQWh5c?A^e)* z=Z1Hfb;AeUaG7a~D6?Kc-h#Zjh57ww%`Uo6w(28pj~X9r8EJsZ%z1g<_#7u5!?hUhy`pD{z(D0(1qIt5szi8f|2>lXB`Wac+HNxe0{l$O)_A*`0hPvVR z1H{xer@}SjF2H3}TyxyWdX`ZS;Y7GhXvxyPMO>qp2-)XWvB+F5_uVR*h1N#s(%0nI zw*sG5eT~3tG9p{F4(;p&`^%o$A~tX`f|d`h9Tp<&L#tu9VHb~X*u~!#`E9ls6xA)# zGLpGv_;HK7$-x6fYWzY(Cveb7?gl>-WVf<41I6&T;bKV9^P*@z24cuh~!bydBO`xtN_wdGL18JH95`G8phh6j5{yx^2K= z*<^?q9(r4hg>4@P?;9cpwb_m!KiPk%Xq{fv z&@vjKbU(NrxHsV!h+kp8VQfVl3LDcfIvlsB?5UyR7179uw~VO>x5lp_7|||J>cycv z;7!bUxp0KIBkU-$G(oZvFOQ87bCW|7^eFJ;Vtl#b74UOkLSXb`q-ZKOCRpREmeCj$m&p8aSeZ7+N5+YaCc6>a3bCGo!XnQUOxVe28hXJ0 zs^y2{MDs8s*;2DME_wZU(R5fEg0V=AgUh2b1k7v7%))!Rd%zqJ7lycg(-%yioadQz zpXYvXw(g#3h-a963k#5Y9+Z}xm>2CtZ+O!6#Dn(dhY!oFWfDP&4sdX0=oOM zd}adra7gZ*0E#@@LKE-E0$wnDKvHD%L@_VEw54T)qncat3i9So&((DxyjyOb2<%kK z{cvKdP|->JKF9A%{LbQct~ow=FjMrAy>mpO)uNSUj77N)`0-Hdwe8Uyu_0#%lI9?a z=LO@<4c`raJHK!a{1JZPJovecn}0g|%zfQ(PxzURcgTk(iARcex3-LX5uAh{BhC#! z3qMaHH@pIVuEq^>tFeFZhDX59J#f>9!Oy*N!?(cS)-TM>06YT9R_2Q0;_?*BVE(*b z#~W^V1HuFF^ABhFg(dvlE;s$@>%tqa3vaqEyjh1Qc>z3vh)(#q06E;!FT5OnTm$l^ zb2!y6oCSZPU$_tajHq&XZZhPl#%<;3JkfUi^0u1AOSp`;Qn=t_Mz%BArx(ngU*wsY zS1`3`8WV3h(wS|!=`(ZY6?x{}H)~SiOivZkSZMIVk|*;ZD2JrVOL=1bO~X?yV+@kN z4ADc{4`Hs#btifX=Xxgk!bgxE#OdQu{X)5SBz%QGyaGlC1yk@j#? z(ljS2Mb*e@c+#<*cH*j#mltd17asKwYX{=Ek4!pQsFJJFY0lrAB9GNx^AaBI6!;lu z`vDWKjL*jgrHAaBkIv7Q59EVEZk2oCkkvti~Te ziP?S`R>IHY>K5QIPnW)aanHiv1;4a5DZP5MYMbTeUBYpG`If@ZQKTpg^n$pcOMk3oJ{Fq(2 z;py;mw_C`)^F*#WMK&uEEAvt_F{ANof#03@rQkOlKaT5-Uw8a&cf#%A_QS6$egp9v zgCFPPUpjs^e$|*xW1YB8aBsoyE*UvrJQTXEyOxm0$!F$^-l1m^WVC>X%!l|gS`Jwt z#>VfyS+kI5;j)NO0+$DNaoPR_;vq9EwI@U)gsq-(=)F*PE|!J&iqiPotslIHP4e*FxfM`U~=BQo*Kk+tNtjz0I<+{wq7HWW$Z#oby;%ILa`#~wWa%v z@J{mdLdfT}3q`QJ1Run4>p{`VF6v_`YU%^V#LK;ZIK?mA1ohUGmEicv}5 z08BWNe}Jo|e_!kh5N-|^IgK{*!h<3;djx_!S0=$_+MfcK+usH*BeB9>=3BaV6B#j^JoiCuwFd$K{O2oJ@N z-92*cQYay;fqF;N8ByHkaq}NAtbt|KOGQFJ)L2l)V*EDYcL2X{WaJ7F8$AML7UH)Y LzqR Date: Tue, 21 May 2024 12:11:24 +0200 Subject: [PATCH 41/44] Add changelog entries --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01c5b3fcb5..0c31c742fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,8 +41,13 @@ and this project adheres to `bls12_381_pairing_equality`, `bls12_381_hash_to_g1`, and `bls12_381_hash_to_g2` to enable BLS12-381 curve operations, such as verifying pairing equalities ([#2106]) +- cosmwasm-std: Add IBC Callbacks support, including two new entrypoints + `ibc_source_callback` and `ibc_destination_callback`, as well as the + `IbcCallbackRequest` type. ([#2025]) +- cosmwasm-vm: Add support for the two new IBC Callbacks entrypoints. ([#2025]) [#1983]: https://github.com/CosmWasm/cosmwasm/pull/1983 +[#2025]: https://github.com/CosmWasm/cosmwasm/pull/2025 [#2057]: https://github.com/CosmWasm/cosmwasm/pull/2057 [#2058]: https://github.com/CosmWasm/cosmwasm/pull/2058 [#2068]: https://github.com/CosmWasm/cosmwasm/pull/2068 From 31d8cf319832e6711636fa404103c379cabfeff9 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 21 May 2024 12:50:24 +0200 Subject: [PATCH 42/44] Improve docs --- packages/std/src/ibc/callbacks.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/std/src/ibc/callbacks.rs b/packages/std/src/ibc/callbacks.rs index 001b1734aa..86b59bcc0b 100644 --- a/packages/std/src/ibc/callbacks.rs +++ b/packages/std/src/ibc/callbacks.rs @@ -154,13 +154,16 @@ impl IbcTimeoutCallbackMsg { /// A prominent example is the [`crate::IbcMsg::Transfer`] message. Without callbacks, you cannot know /// that someone sent you IBC coins. /// +/// It is important to validate that the packet and acknowledgement are what you expect them to be. +/// For example for a transfer message, the receiver is not necessarily the contract itself. +/// /// The callback is called after the packet was acknowledged on the destination chain, as follows: /// - If the acknowledgement is synchronous (i.e. returned immediately when the packet is received), /// the callback is called only if the acknowledgement was successful. /// - If the acknowledgement is asynchronous (i.e. written later using `WriteAcknowledgement`), /// the callback is called regardless of the success of the acknowledgement. /// -/// Note that there are some prerequisites that need to be fulfilled to receive source callbacks: +/// Note that there are some prerequisites that need to be fulfilled to receive destination callbacks: /// - The contract must implement the `ibc_destination_callback` entrypoint. /// - The IBC application in the destination chain must have support for the callbacks middleware. /// - You have to add serialized [`IbcCallbackRequest`] to a specific field of the message. From 4423fdcf2735381705cc42d90e7c565b3f817e83 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 21 May 2024 17:47:04 +0200 Subject: [PATCH 43/44] Update schemas --- contracts/ibc-callbacks/schema/ibc-callbacks.json | 2 +- .../ibc-callbacks/schema/raw/response_to_callback_stats.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/ibc-callbacks/schema/ibc-callbacks.json b/contracts/ibc-callbacks/schema/ibc-callbacks.json index a7456b2272..eb38638e78 100644 --- a/contracts/ibc-callbacks/schema/ibc-callbacks.json +++ b/contracts/ibc-callbacks/schema/ibc-callbacks.json @@ -181,7 +181,7 @@ "additionalProperties": false }, "IbcDestinationCallbackMsg": { - "description": "The message type of the IBC destination callback.\n\nThe IBC destination callback is needed for cases where someone triggers the sending of an IBC packet through some other message (i.e. not through [`crate::IbcMsg::SendPacket`]) and your contract needs to know that it received this. A prominent example is the [`crate::IbcMsg::Transfer`] message. Without callbacks, you cannot know that someone sent you IBC coins.\n\nThe callback is called after the packet was acknowledged on the destination chain, as follows: - If the acknowledgement is synchronous (i.e. returned immediately when the packet is received), the callback is called only if the acknowledgement was successful. - If the acknowledgement is asynchronous (i.e. written later using `WriteAcknowledgement`), the callback is called regardless of the success of the acknowledgement.\n\nNote that there are some prerequisites that need to be fulfilled to receive source callbacks: - The contract must implement the `ibc_destination_callback` entrypoint. - The IBC application in the destination chain must have support for the callbacks middleware. - You have to add serialized [`IbcCallbackRequest`] to a specific field of the message. For `IbcMsg::Transfer`, this is the `memo` field and it needs to be json-encoded.", + "description": "The message type of the IBC destination callback.\n\nThe IBC destination callback is needed for cases where someone triggers the sending of an IBC packet through some other message (i.e. not through [`crate::IbcMsg::SendPacket`]) and your contract needs to know that it received this. A prominent example is the [`crate::IbcMsg::Transfer`] message. Without callbacks, you cannot know that someone sent you IBC coins.\n\nIt is important to validate that the packet and acknowledgement are what you expect them to be. For example for a transfer message, the receiver is not necessarily the contract itself.\n\nThe callback is called after the packet was acknowledged on the destination chain, as follows: - If the acknowledgement is synchronous (i.e. returned immediately when the packet is received), the callback is called only if the acknowledgement was successful. - If the acknowledgement is asynchronous (i.e. written later using `WriteAcknowledgement`), the callback is called regardless of the success of the acknowledgement.\n\nNote that there are some prerequisites that need to be fulfilled to receive destination callbacks: - The contract must implement the `ibc_destination_callback` entrypoint. - The IBC application in the destination chain must have support for the callbacks middleware. - You have to add serialized [`IbcCallbackRequest`] to a specific field of the message. For `IbcMsg::Transfer`, this is the `memo` field and it needs to be json-encoded.", "type": "object", "required": [ "ack", diff --git a/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json index 572b916219..02e8342828 100644 --- a/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json +++ b/contracts/ibc-callbacks/schema/raw/response_to_callback_stats.json @@ -71,7 +71,7 @@ "additionalProperties": false }, "IbcDestinationCallbackMsg": { - "description": "The message type of the IBC destination callback.\n\nThe IBC destination callback is needed for cases where someone triggers the sending of an IBC packet through some other message (i.e. not through [`crate::IbcMsg::SendPacket`]) and your contract needs to know that it received this. A prominent example is the [`crate::IbcMsg::Transfer`] message. Without callbacks, you cannot know that someone sent you IBC coins.\n\nThe callback is called after the packet was acknowledged on the destination chain, as follows: - If the acknowledgement is synchronous (i.e. returned immediately when the packet is received), the callback is called only if the acknowledgement was successful. - If the acknowledgement is asynchronous (i.e. written later using `WriteAcknowledgement`), the callback is called regardless of the success of the acknowledgement.\n\nNote that there are some prerequisites that need to be fulfilled to receive source callbacks: - The contract must implement the `ibc_destination_callback` entrypoint. - The IBC application in the destination chain must have support for the callbacks middleware. - You have to add serialized [`IbcCallbackRequest`] to a specific field of the message. For `IbcMsg::Transfer`, this is the `memo` field and it needs to be json-encoded.", + "description": "The message type of the IBC destination callback.\n\nThe IBC destination callback is needed for cases where someone triggers the sending of an IBC packet through some other message (i.e. not through [`crate::IbcMsg::SendPacket`]) and your contract needs to know that it received this. A prominent example is the [`crate::IbcMsg::Transfer`] message. Without callbacks, you cannot know that someone sent you IBC coins.\n\nIt is important to validate that the packet and acknowledgement are what you expect them to be. For example for a transfer message, the receiver is not necessarily the contract itself.\n\nThe callback is called after the packet was acknowledged on the destination chain, as follows: - If the acknowledgement is synchronous (i.e. returned immediately when the packet is received), the callback is called only if the acknowledgement was successful. - If the acknowledgement is asynchronous (i.e. written later using `WriteAcknowledgement`), the callback is called regardless of the success of the acknowledgement.\n\nNote that there are some prerequisites that need to be fulfilled to receive destination callbacks: - The contract must implement the `ibc_destination_callback` entrypoint. - The IBC application in the destination chain must have support for the callbacks middleware. - You have to add serialized [`IbcCallbackRequest`] to a specific field of the message. For `IbcMsg::Transfer`, this is the `memo` field and it needs to be json-encoded.", "type": "object", "required": [ "ack", From 9a3573c2d45c5e1bd49619d6f5cf0a318da275ac Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 21 May 2024 18:20:40 +0200 Subject: [PATCH 44/44] Fix ibc-callbacks lock file --- contracts/ibc-callbacks/Cargo.lock | 817 +++++++++++++++++++---------- 1 file changed, 528 insertions(+), 289 deletions(-) diff --git a/contracts/ibc-callbacks/Cargo.lock b/contracts/ibc-callbacks/Cargo.lock index 5b9116d5a4..e7176f96b1 100644 --- a/contracts/ibc-callbacks/Cargo.lock +++ b/contracts/ibc-callbacks/Cargo.lock @@ -4,11 +4,11 @@ version = 3 [[package]] name = "addr2line" -version = "0.15.2" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7a2e47a1fbe209ee101dd6d61285226744c6c8d3c21c8dc878ba6cb9f467f3a" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ - "gimli 0.24.0", + "gimli 0.28.1", ] [[package]] @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ "getrandom", "once_cell", @@ -42,27 +42,148 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "ark-bls12-381" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools", + "num-traits", + "rayon", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest", + "itertools", + "num-bigint", + "num-traits", + "paste", + "rayon", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", + "rayon", +] [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.60" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7815ea54e4d821e791162e078acbebfd6d8c8939cd559c9335dceb1c8ca7282" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", @@ -81,9 +202,9 @@ checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bech32" @@ -93,9 +214,9 @@ checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" @@ -103,11 +224,23 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "block-buffer" -version = "0.10.2" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] @@ -120,15 +253,15 @@ checksum = "3e31ea183f6ee62ac8b8a8cf7feddd766317adfb13ff469de57ce033efd6a790" [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytecheck" -version = "0.6.10" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13fe11640a23eb24562225322cd3e452b93a3d4091d62fab69c70542fcd17d1f" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" dependencies = [ "bytecheck_derive", "ptr_meta", @@ -137,9 +270,9 @@ dependencies = [ [[package]] name = "bytecheck_derive" -version = "0.6.10" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31225543cb46f81a7e224762764f4a6a0f097b1db0b175f69e8065efaa42de5" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" dependencies = [ "proc-macro2", "quote", @@ -148,21 +281,21 @@ dependencies = [ [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.4.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.69" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" +checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" [[package]] name = "cfg-if" @@ -172,27 +305,27 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clru" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8191fa7302e03607ff0e237d4246cc043ff5b3cb9409d995172ba3bea16b807" +checksum = "cbd0f76e066e64fdc5631e3bb46381254deab9ef1158292f27c8c57e3bf3fe59" [[package]] name = "const-oid" -version = "0.9.4" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "795bc6e66a8e340f075fcf6227e417a2dc976b92b91f3cdc778bb858778b6747" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "corosensei" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9847f90f32a50b0dcbd68bc23ff242798b13080b97b0569f6ed96a45ce4cf2cd" +checksum = "80128832c58ea9cbd041d2a759ec449224487b2c1e400453d99d244eead87a8e" dependencies = [ "autocfg", "cfg-if", "libc", "scopeguard", - "windows-sys", + "windows-sys 0.33.0", ] [[package]] @@ -215,13 +348,21 @@ dependencies = [ name = "cosmwasm-crypto" version = "2.0.1" dependencies = [ + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-serialize", + "cfg-if", "derive_more", "digest", "ecdsa", "ed25519-zebra", "k256", + "num-traits", "p256", "rand_core", + "rayon", + "sha2", "thiserror", ] @@ -231,7 +372,7 @@ version = "2.0.1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.65", ] [[package]] @@ -251,7 +392,7 @@ version = "2.0.1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.65", ] [[package]] @@ -329,7 +470,7 @@ dependencies = [ "cranelift-egraph", "cranelift-entity", "cranelift-isle", - "gimli 0.26.1", + "gimli 0.26.2", "log", "regalloc2", "smallvec", @@ -391,72 +532,52 @@ checksum = "393bc73c451830ff8dbb3a07f61843d6cb41a084f9996319917c0b291ed785bb" [[package]] name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", - "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.1" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.5" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "cfg-if", "crossbeam-utils", - "lazy_static", - "memoffset 0.6.4", - "scopeguard", ] [[package]] name = "crossbeam-queue" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.8" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" -dependencies = [ - "cfg-if", - "lazy_static", -] +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crypto-bigint" -version = "0.5.2" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", "rand_core", @@ -499,14 +620,14 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.65", ] [[package]] name = "darling" -version = "0.20.3" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" dependencies = [ "darling_core", "darling_macro", @@ -514,36 +635,36 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.3" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.65", ] [[package]] name = "darling_macro" -version = "0.20.3" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" dependencies = [ "darling_core", "quote", - "syn 2.0.58", + "syn 2.0.65", ] [[package]] name = "dashmap" -version = "5.4.0" +version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "hashbrown 0.12.3", + "hashbrown 0.14.5", "lock_api", "once_cell", "parking_lot_core", @@ -551,9 +672,9 @@ dependencies = [ [[package]] name = "der" -version = "0.7.7" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7ed52955ce76b1554f509074bb357d3fb8ac9b51288a65a3fd480d1dfba946" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "zeroize", @@ -587,7 +708,7 @@ checksum = "2bba3e9872d7c58ce7ef0fcf1844fcc3e23ef2a58377b50df35dd98e42a5726e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.65", "unicode-xid", ] @@ -605,9 +726,9 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.4" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "dynasm" @@ -615,7 +736,7 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "add9a102807b524ec050363f09e06f1504214b0e1c7797f64261c891022dce8b" dependencies = [ - "bitflags 1.2.1", + "bitflags 1.3.2", "byteorder", "lazy_static", "proc-macro-error", @@ -632,14 +753,14 @@ checksum = "64fba5a42bd76a17cad4bfa00de168ee1cbfa06a5e8ce992ae880218c05641a9" dependencies = [ "byteorder", "dynasm", - "memmap2 0.5.0", + "memmap2 0.5.10", ] [[package]] name = "ecdsa" -version = "0.16.8" +version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der", "digest", @@ -665,7 +786,7 @@ checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9" dependencies = [ "curve25519-dalek", "ed25519", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "hex", "rand_core", "sha2", @@ -674,9 +795,9 @@ dependencies = [ [[package]] name = "either" -version = "1.6.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" [[package]] name = "elliptic-curve" @@ -718,9 +839,9 @@ dependencies = [ [[package]] name = "enumset" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e875f1719c16de097dee81ed675e2d9bb63096823ed3f0ca827b7dea3028bbbb" +checksum = "226c0da7462c13fb57e5cc9e0dc8f0635e7d27f276a3a7fd30054647f669007d" dependencies = [ "enumset_derive", ] @@ -734,7 +855,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.65", ] [[package]] @@ -761,9 +882,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.7" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c007b1ae3abe1cb6f85a16305acd418b7ca6343b953633fee2b76d8f108b830f" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "fnv" @@ -771,6 +892,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "fxhash" version = "0.2.1" @@ -793,9 +920,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.3" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -804,21 +931,21 @@ dependencies = [ [[package]] name = "gimli" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189" - -[[package]] -name = "gimli" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" dependencies = [ "fallible-iterator", "indexmap 1.9.3", "stable_deref_trait", ] +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + [[package]] name = "group" version = "0.13.0" @@ -836,14 +963,23 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.6", + "ahash 0.7.8", ] [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.11", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash 0.8.11", "allocator-api2", @@ -855,15 +991,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hex" version = "0.4.3" @@ -913,20 +1040,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.14.5", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", ] [[package]] name = "itoa" -version = "0.4.7" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.61" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -951,21 +1087,21 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "leb128" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -973,12 +1109,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.14" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" -dependencies = [ - "cfg-if", -] +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "mach" @@ -989,17 +1122,26 @@ dependencies = [ "libc", ] +[[package]] +name = "mach2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" +dependencies = [ + "libc", +] + [[package]] name = "memchr" -version = "2.4.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "memmap2" -version = "0.5.0" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4647a11b578fead29cdbb34d4adef8dd3dc35b876c9c6d5240d83f205abfe96e" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" dependencies = [ "libc", ] @@ -1015,53 +1157,61 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.6.4" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ "autocfg", ] [[package]] -name = "memoffset" -version = "0.9.0" +name = "miniz_oxide" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" dependencies = [ - "autocfg", + "adler", ] [[package]] -name = "miniz_oxide" -version = "0.4.4" +name = "more-asserts" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389" + +[[package]] +name = "num-bigint" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" dependencies = [ - "adler", - "autocfg", + "num-integer", + "num-traits", ] [[package]] -name = "more-asserts" -version = "0.2.1" +name = "num-integer" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0debeb9fcf88823ea64d64e4a815ab1643f33127d995978e099942ce38f25238" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] [[package]] -name = "num_cpus" -version = "1.13.0" +name = "num-traits" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ - "hermit-abi", - "libc", + "autocfg", ] [[package]] name = "object" -version = "0.25.3" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38f2be3697a57b4060074ff41b44c16870d916ad7877c17696e063257482bc7" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "memchr", ] @@ -1086,9 +1236,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", @@ -1097,6 +1247,12 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -1109,6 +1265,12 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + [[package]] name = "primeorder" version = "0.13.6" @@ -1144,9 +1306,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" dependencies = [ "unicode-ident", ] @@ -1173,13 +1335,39 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + [[package]] name = "rand_core" version = "0.6.4" @@ -1191,36 +1379,31 @@ dependencies = [ [[package]] name = "rayon" -version = "1.5.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ - "autocfg", - "crossbeam-deque", "either", "rayon-core", ] [[package]] name = "rayon-core" -version = "1.9.1" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "lazy_static", - "num_cpus", ] [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" dependencies = [ - "bitflags 1.2.1", + "bitflags 2.5.0", ] [[package]] @@ -1237,21 +1420,21 @@ dependencies = [ [[package]] name = "region" -version = "3.0.0" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76e189c2369884dce920945e2ddf79b3dff49e071a167dd1817fa9c4c00d512e" +checksum = "e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7" dependencies = [ - "bitflags 1.2.1", + "bitflags 1.3.2", "libc", - "mach", - "winapi", + "mach2", + "windows-sys 0.52.0", ] [[package]] name = "rend" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581008d2099240d37fb08d77ad713bcaec2c4d89d50b5b21a8bb1996bbab68ab" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" dependencies = [ "bytecheck", ] @@ -1268,24 +1451,28 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.7.41" +version = "0.7.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21499ed91807f07ae081880aabb2ccc0235e9d88011867d984525e9a4c3cfa3e" +checksum = "5cba464629b3394fc4dbc6f940ff8f5b4ff5c7aef40f29166fd4ad12acbc99c0" dependencies = [ + "bitvec", "bytecheck", + "bytes", "hashbrown 0.12.3", "indexmap 1.9.3", "ptr_meta", "rend", "rkyv_derive", "seahash", + "tinyvec", + "uuid", ] [[package]] name = "rkyv_derive" -version = "0.7.41" +version = "0.7.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1c672430eb41556291981f45ca900a0239ad007242d1cb4b4167af842db666" +checksum = "a7dddfff8de25e6f62b9d64e6e432bf1c6736c57d20323e15ee10435fbda7c65" dependencies = [ "proc-macro2", "quote", @@ -1294,9 +1481,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.20" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dead70b0b5e03e9c814bcb6b01e03e68f7c57a80aa48c72ec92152ab3e818d49" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc_version" @@ -1309,21 +1496,21 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "ryu" -version = "1.0.5" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "schemars" -version = "0.8.16" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" +checksum = "b0218ceea14babe24a4a5836f86ade86c1effbc198164e619194cb5069187e29" dependencies = [ "dyn-clone", "schemars_derive", @@ -1333,21 +1520,21 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.16" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" +checksum = "3ed5a1ccce8ff962e31a165d41f6e2a2dd1245099dc4d594f5574a86cd90f4d3" dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 1.0.109", + "syn 2.0.65", ] [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "seahash" @@ -1370,21 +1557,21 @@ dependencies = [ [[package]] name = "self_cell" -version = "1.0.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c309e515543e67811222dbc9e3dd7e1056279b782e1dacffe4242b718734fb6" +checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a" [[package]] name = "semver" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.202" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" dependencies = [ "serde_derive", ] @@ -1411,31 +1598,31 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.202" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.65", ] [[package]] name = "serde_derive_internals" -version = "0.26.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.65", ] [[package]] name = "serde_json" -version = "1.0.64" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", @@ -1465,9 +1652,9 @@ dependencies = [ [[package]] name = "signature" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest", "rand_core", @@ -1481,15 +1668,15 @@ checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" [[package]] name = "slice-group-by" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" +checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" [[package]] name = "smallvec" -version = "1.6.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "stable_deref_trait" @@ -1522,14 +1709,14 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.58", + "syn 2.0.65", ] [[package]] name = "subtle" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" @@ -1544,41 +1731,62 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.58" +version = "2.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "target-lexicon" -version = "0.12.7" +version = "0.12.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd1ba337640d60c3e96bc6f0638a939b9c9a7f2c316a1598c279828b3d1dc8c5" +checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.65", ] +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tracing" version = "0.1.40" @@ -1598,7 +1806,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.65", ] [[package]] @@ -1612,15 +1820,15 @@ dependencies = [ [[package]] name = "typenum" -version = "1.15.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-xid" @@ -1628,6 +1836,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "uuid" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" + [[package]] name = "version_check" version = "0.9.4" @@ -1636,15 +1850,15 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1652,24 +1866,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.65", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1677,22 +1891,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.65", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wasmer" @@ -1736,7 +1950,7 @@ dependencies = [ "enumset", "lazy_static", "leb128", - "memmap2 0.5.0", + "memmap2 0.5.10", "more-asserts", "region", "rkyv", @@ -1759,7 +1973,7 @@ dependencies = [ "cranelift-codegen", "cranelift-entity", "cranelift-frontend", - "gimli 0.26.1", + "gimli 0.26.2", "more-asserts", "rayon", "smallvec", @@ -1779,7 +1993,7 @@ dependencies = [ "dynasm", "dynasmrt", "enumset", - "gimli 0.26.1", + "gimli 0.26.2", "lazy_static", "more-asserts", "rayon", @@ -1846,7 +2060,7 @@ dependencies = [ "lazy_static", "libc", "mach", - "memoffset 0.9.0", + "memoffset", "more-asserts", "region", "scopeguard", @@ -1901,26 +2115,36 @@ dependencies = [ "windows_x86_64_msvc 0.33.0", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ "windows_aarch64_gnullvm", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", "windows_x86_64_gnullvm", - "windows_x86_64_msvc 0.48.0", + "windows_x86_64_msvc 0.52.5", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -1930,9 +2154,9 @@ checksum = "cd761fd3eb9ab8cc1ed81e56e567f02dd82c4c837e48ac3b2181b9ffc5060807" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -1942,9 +2166,15 @@ checksum = "cab0cf703a96bab2dc0c02c0fa748491294bf9b7feb27e1f4f96340f208ada0e" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -1954,9 +2184,9 @@ checksum = "8cfdbe89cc9ad7ce618ba34abc34bbb6c36d99e96cae2245b7943cd75ee773d0" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -1966,15 +2196,15 @@ checksum = "b4dd9b0c0e9ece7bb22e84d70d01b71c6d6248b81a3c60d11869451b4cb24784" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -1984,28 +2214,37 @@ checksum = "ff1e4aa646495048ec7f3ffddc411e1d829c026a2ec62b39da15c1055e406eaa" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.65", ] [[package]] @@ -2025,5 +2264,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.65", ]