From ddb7b35b00ae07775c0eeead4861d365a24d6a00 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Fri, 29 Nov 2024 14:12:28 +0000 Subject: [PATCH 01/31] Add PFM related deps Co-authored-by: Jacob Turner --- Cargo.lock | 108 ++++++--- Cargo.toml | 12 +- crates/ibc/Cargo.toml | 2 + crates/ibc/src/context/common.rs | 9 +- crates/ibc/src/context/nft_transfer_mod.rs | 6 +- crates/ibc/src/context/transfer_mod.rs | 6 +- crates/ibc/src/context/validation.rs | 12 +- crates/ibc/src/lib.rs | 17 +- crates/tests/Cargo.toml | 2 + wasm/Cargo.lock | 124 ++++++++--- wasm_for_tests/Cargo.lock | 244 ++++++++++++++++++--- 11 files changed, 419 insertions(+), 123 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7ecc06cc14..cc17140f7f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1892,6 +1892,16 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +[[package]] +name = "dur" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce5b6c91b5e394b75cd96c36393fc938496c030220207a0ccf34d6cd313d3b49" +dependencies = [ + "nom", + "rust_decimal", +] + [[package]] name = "duration-str" version = "0.10.0" @@ -3340,7 +3350,7 @@ dependencies = [ [[package]] name = "ibc" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-apps", "ibc-clients", @@ -3353,7 +3363,7 @@ dependencies = [ [[package]] name = "ibc-app-nft-transfer" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-app-nft-transfer-types", "ibc-core", @@ -3363,7 +3373,7 @@ dependencies = [ [[package]] name = "ibc-app-nft-transfer-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "arbitrary", "base64 0.22.1", @@ -3385,7 +3395,7 @@ dependencies = [ [[package]] name = "ibc-app-transfer" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-app-transfer-types", "ibc-core", @@ -3395,7 +3405,7 @@ dependencies = [ [[package]] name = "ibc-app-transfer-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "arbitrary", "borsh", @@ -3414,7 +3424,7 @@ dependencies = [ [[package]] name = "ibc-apps" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-app-nft-transfer", "ibc-app-transfer", @@ -3423,7 +3433,7 @@ dependencies = [ [[package]] name = "ibc-client-tendermint" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "derive_more", "ibc-client-tendermint-types", @@ -3440,7 +3450,7 @@ dependencies = [ [[package]] name = "ibc-client-tendermint-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "displaydoc", "ibc-core-client-types", @@ -3457,7 +3467,7 @@ dependencies = [ [[package]] name = "ibc-client-wasm-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "base64 0.22.1", "displaydoc", @@ -3471,7 +3481,7 @@ dependencies = [ [[package]] name = "ibc-clients" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-client-tendermint", "ibc-client-wasm-types", @@ -3480,7 +3490,7 @@ dependencies = [ [[package]] name = "ibc-core" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-core-channel", "ibc-core-client", @@ -3496,7 +3506,7 @@ dependencies = [ [[package]] name = "ibc-core-channel" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-core-channel-types", "ibc-core-client", @@ -3511,7 +3521,7 @@ dependencies = [ [[package]] name = "ibc-core-channel-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "arbitrary", "borsh", @@ -3535,7 +3545,7 @@ dependencies = [ [[package]] name = "ibc-core-client" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-core-client-context", "ibc-core-client-types", @@ -3548,7 +3558,7 @@ dependencies = [ [[package]] name = "ibc-core-client-context" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "derive_more", "displaydoc", @@ -3564,7 +3574,7 @@ dependencies = [ [[package]] name = "ibc-core-client-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "arbitrary", "borsh", @@ -3585,7 +3595,7 @@ dependencies = [ [[package]] name = "ibc-core-commitment-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "arbitrary", "borsh", @@ -3605,7 +3615,7 @@ dependencies = [ [[package]] name = "ibc-core-connection" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-client-wasm-types", "ibc-core-client", @@ -3619,7 +3629,7 @@ dependencies = [ [[package]] name = "ibc-core-connection-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "arbitrary", "borsh", @@ -3641,7 +3651,7 @@ dependencies = [ [[package]] name = "ibc-core-handler" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-core-channel", "ibc-core-client", @@ -3656,7 +3666,7 @@ dependencies = [ [[package]] name = "ibc-core-handler-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "arbitrary", "borsh", @@ -3681,7 +3691,7 @@ dependencies = [ [[package]] name = "ibc-core-host" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "derive_more", "displaydoc", @@ -3699,7 +3709,7 @@ dependencies = [ [[package]] name = "ibc-core-host-cosmos" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "derive_more", "displaydoc", @@ -3722,7 +3732,7 @@ dependencies = [ [[package]] name = "ibc-core-host-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "arbitrary", "borsh", @@ -3738,7 +3748,7 @@ dependencies = [ [[package]] name = "ibc-core-router" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "derive_more", "displaydoc", @@ -3752,7 +3762,7 @@ dependencies = [ [[package]] name = "ibc-core-router-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "borsh", "derive_more", @@ -3771,17 +3781,36 @@ dependencies = [ [[package]] name = "ibc-derive" version = "0.8.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "proc-macro2", "quote", "syn 2.0.96", ] +[[package]] +name = "ibc-middleware-packet-forward" +version = "0.6.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.6.0#ca824cfbe550c529d30bf27a97026dd0a058cfdf" +dependencies = [ + "borsh", + "dur", + "either", + "ibc-app-transfer-types", + "ibc-core-channel", + "ibc-core-channel-types", + "ibc-core-host-types", + "ibc-core-router", + "ibc-core-router-types", + "ibc-primitives", + "serde", + "serde_json", +] + [[package]] name = "ibc-primitives" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "arbitrary", "borsh", @@ -3822,7 +3851,7 @@ dependencies = [ [[package]] name = "ibc-query" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "displaydoc", "ibc", @@ -3833,7 +3862,7 @@ dependencies = [ [[package]] name = "ibc-testkit" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "basecoin-store", "derive_more", @@ -5162,8 +5191,10 @@ dependencies = [ "assert_matches", "borsh", "data-encoding", + "dur", "ibc", "ibc-derive", + "ibc-middleware-packet-forward", "ibc-testkit", "ics23", "konst", @@ -5593,12 +5624,14 @@ dependencies = [ "concat-idents", "data-encoding", "derivative", + "dur", "escargot", "expectrl", "eyre", "flate2", "fs_extra", "hyper 0.14.27", + "ibc-middleware-packet-forward", "ibc-testkit", "ics23", "itertools 0.12.1", @@ -7284,12 +7317,18 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.35.0" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1790d1c4c0ca81211399e0e0af16333276f375209e71a37b67698a373db5b47a" +checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" dependencies = [ "arrayvec", + "borsh", + "bytes", "num-traits", + "rand", + "rkyv", + "serde", + "serde_json", ] [[package]] @@ -7679,11 +7718,12 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] diff --git a/Cargo.toml b/Cargo.toml index 6ac30ef46a..91e66c9baf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -99,6 +99,7 @@ derivation-path = "0.2.0" derivative = "2.2.0" directories = "4.0.1" drain_filter_polyfill = "0.1.3" +dur = "0.5.3" duration-str = "0.10.0" ed25519-consensus = "2.1.0" either = "1.12.0" @@ -117,10 +118,11 @@ flume = "0.11.1" fs_extra = "1.2.0" futures = "0.3" git2 = { version = "0.18.1", default-features = false } -# branch yuji/derive-arbitrary -ibc = { git = "https://github.com/heliaxdev/cosmos-ibc-rs", rev = "38bd2a32f35117d4d9165a3c68c64ccd87ad56dd", features = ["serde"] } -ibc-derive = { git = "https://github.com/heliaxdev/cosmos-ibc-rs", rev = "38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" } -ibc-testkit = { git = "https://github.com/heliaxdev/cosmos-ibc-rs", rev = "38bd2a32f35117d4d9165a3c68c64ccd87ad56dd", default-features = false } +# branch tiago/optional-ack +ibc = { git = "https://github.com/heliaxdev/cosmos-ibc-rs", rev = "aa229566e6bb688cc2626dab276c3849abc0c583", features = ["serde"] } +ibc-derive = { git = "https://github.com/heliaxdev/cosmos-ibc-rs", rev = "aa229566e6bb688cc2626dab276c3849abc0c583" } +ibc-middleware-packet-forward = { git = "https://github.com/heliaxdev/ibc-middleware", tag = "pfm/v0.6.0", features = ["borsh"] } +ibc-testkit = { git = "https://github.com/heliaxdev/cosmos-ibc-rs", rev = "aa229566e6bb688cc2626dab276c3849abc0c583", default-features = false } ics23 = "0.12.0" usize-set = { version = "0.10.3", features = ["serialize-borsh", "serialize-serde"] } indexmap = { package = "nam-indexmap", version = "2.7.1-nam.0", features = ["borsh-schema", "serde"] } @@ -168,7 +170,7 @@ rpassword = "5.0.1" rustversion = "1.0" serde = {version = "1.0.125", features = ["derive"]} serde_bytes = "0.11.5" -serde_json = "1.0.62" +serde_json = "1.0.133" serde_tuple = "0.5.0" sha2 = "0.9.3" sha2-const = "0.1.2" diff --git a/crates/ibc/Cargo.toml b/crates/ibc/Cargo.toml index 39f0c77965..f520e810c3 100644 --- a/crates/ibc/Cargo.toml +++ b/crates/ibc/Cargo.toml @@ -40,10 +40,12 @@ namada_vp = { path = "../vp" } arbitrary = { workspace = true, optional = true } borsh.workspace = true data-encoding.workspace = true +dur.workspace = true konst.workspace = true linkme = {workspace = true, optional = true} ibc.workspace = true ibc-derive.workspace = true +ibc-middleware-packet-forward.workspace = true ibc-testkit = {workspace = true, optional = true} ics23.workspace = true masp_primitives.workspace = true diff --git a/crates/ibc/src/context/common.rs b/crates/ibc/src/context/common.rs index 7f920d8cb3..35233fd70e 100644 --- a/crates/ibc/src/context/common.rs +++ b/crates/ibc/src/context/common.rs @@ -576,14 +576,11 @@ pub trait IbcCommonContext: IbcStorageContext { port_id: &PortId, channel_id: &ChannelId, sequence: Sequence, - ) -> Result { + ) -> Result> { let key = storage::ack_key(port_id, channel_id, sequence); match self.storage().read_bytes(&key)? { - Some(value) => Ok(value.into()), - None => { - Err(PacketError::PacketAcknowledgementNotFound { sequence } - .into()) - } + Some(value) => Ok(Some(value.into())), + None => Ok(None), } } diff --git a/crates/ibc/src/context/nft_transfer_mod.rs b/crates/ibc/src/context/nft_transfer_mod.rs index 420d80362e..b8450468ce 100644 --- a/crates/ibc/src/context/nft_transfer_mod.rs +++ b/crates/ibc/src/context/nft_transfer_mod.rs @@ -261,7 +261,7 @@ where &mut self, packet: &Packet, _relayer: &Signer, - ) -> (ModuleExtras, Acknowledgement) { + ) -> (ModuleExtras, Option) { on_recv_packet_execute(&mut self.ctx, packet) } @@ -482,10 +482,10 @@ pub mod testing { &mut self, _packet: &Packet, _relayer: &Signer, - ) -> (ModuleExtras, Acknowledgement) { + ) -> (ModuleExtras, Option) { ( ModuleExtras::empty(), - AcknowledgementStatus::success(ack_success_b64()).into(), + Some(AcknowledgementStatus::success(ack_success_b64()).into()), ) } diff --git a/crates/ibc/src/context/transfer_mod.rs b/crates/ibc/src/context/transfer_mod.rs index 9a1075e280..a30826514d 100644 --- a/crates/ibc/src/context/transfer_mod.rs +++ b/crates/ibc/src/context/transfer_mod.rs @@ -276,7 +276,7 @@ where &mut self, packet: &Packet, _relayer: &Signer, - ) -> (ModuleExtras, Acknowledgement) { + ) -> (ModuleExtras, Option) { on_recv_packet_execute(&mut self.ctx, packet) } @@ -497,10 +497,10 @@ pub mod testing { &mut self, _packet: &Packet, _relayer: &Signer, - ) -> (ModuleExtras, Acknowledgement) { + ) -> (ModuleExtras, Option) { ( ModuleExtras::empty(), - AcknowledgementStatus::success(ack_success_b64()).into(), + Some(AcknowledgementStatus::success(ack_success_b64()).into()), ) } diff --git a/crates/ibc/src/context/validation.rs b/crates/ibc/src/context/validation.rs index 0f00feefcf..7173a14a82 100644 --- a/crates/ibc/src/context/validation.rs +++ b/crates/ibc/src/context/validation.rs @@ -5,6 +5,7 @@ use ibc::core::channel::types::channel::ChannelEnd; use ibc::core::channel::types::commitment::{ AcknowledgementCommitment, PacketCommitment, }; +use ibc::core::channel::types::error::PacketError; use ibc::core::channel::types::packet::Receipt; use ibc::core::client::context::{ ClientValidationContext, ExtClientValidationContext, @@ -253,11 +254,18 @@ where &self, path: &AckPath, ) -> Result { - self.inner.borrow().packet_ack( + let maybe_ack = self.inner.borrow().packet_ack( &path.port_id, &path.channel_id, path.sequence, - ) + )?; + + maybe_ack.ok_or_else(|| { + PacketError::PacketAcknowledgementNotFound { + sequence: path.sequence, + } + .into() + }) } fn channel_counter(&self) -> Result { diff --git a/crates/ibc/src/lib.rs b/crates/ibc/src/lib.rs index 9fa49d58aa..bd5aafc814 100644 --- a/crates/ibc/src/lib.rs +++ b/crates/ibc/src/lib.rs @@ -143,6 +143,8 @@ pub enum Error { ChainId(IdentifierError), #[error("Verifier insertion error: {0}")] Verifier(StorageError), + #[error("Storage read/write error: {0}")] + Storage(StorageError), #[error("IBC error: {0}")] Other(String), } @@ -690,7 +692,9 @@ where // Extract MASP tx from the memo in the packet if needed let masp_tx = match &*envelope { MsgEnvelope::Packet(PacketMsg::Recv(msg)) - if self.is_receiving_success(msg)? => + if self + .is_receiving_success(msg)? + .is_some_and(|ack_succ| ack_succ) => { extract_masp_tx_from_packet(&msg.packet) } @@ -713,8 +717,8 @@ where pub fn is_receiving_success( &self, msg: &IbcMsgRecvPacket, - ) -> Result { - let packet_ack = self + ) -> Result, Error> { + let Some(packet_ack) = self .ctx .inner .borrow() @@ -723,11 +727,14 @@ where &msg.packet.chan_id_on_b, msg.packet.seq_on_a, ) - .map_err(|e| Error::Context(Box::new(e)))?; + .map_err(|e| Error::Context(Box::new(e)))? + else { + return Ok(None); + }; let success_ack_commitment = compute_ack_commitment( &AcknowledgementStatus::success(ack_success_b64()).into(), ); - Ok(packet_ack == success_ack_commitment) + Ok(Some(packet_ack == success_ack_commitment)) } /// Validate according to the message in IBC VP diff --git a/crates/tests/Cargo.toml b/crates/tests/Cargo.toml index add26e1621..9ce5aca59e 100644 --- a/crates/tests/Cargo.toml +++ b/crates/tests/Cargo.toml @@ -38,7 +38,9 @@ namada_vm = {path = "../vm", features = ["testing"]} concat-idents.workspace = true derivative.workspace = true +dur.workspace = true hyper = {version = "0.14.20", features = ["full"]} +ibc-middleware-packet-forward.workspace = true ibc-testkit.workspace = true ics23.workspace = true itertools.workspace = true diff --git a/wasm/Cargo.lock b/wasm/Cargo.lock index 09c312fe38..8fd208707f 100644 --- a/wasm/Cargo.lock +++ b/wasm/Cargo.lock @@ -1394,6 +1394,16 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +[[package]] +name = "dur" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce5b6c91b5e394b75cd96c36393fc938496c030220207a0ccf34d6cd313d3b49" +dependencies = [ + "nom", + "rust_decimal", +] + [[package]] name = "duration-str" version = "0.10.0" @@ -2636,7 +2646,7 @@ dependencies = [ [[package]] name = "ibc" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-apps", "ibc-clients", @@ -2649,7 +2659,7 @@ dependencies = [ [[package]] name = "ibc-app-nft-transfer" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-app-nft-transfer-types", "ibc-core", @@ -2659,7 +2669,7 @@ dependencies = [ [[package]] name = "ibc-app-nft-transfer-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "base64 0.22.1", "borsh", @@ -2680,7 +2690,7 @@ dependencies = [ [[package]] name = "ibc-app-transfer" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-app-transfer-types", "ibc-core", @@ -2690,7 +2700,7 @@ dependencies = [ [[package]] name = "ibc-app-transfer-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "borsh", "derive_more", @@ -2708,7 +2718,7 @@ dependencies = [ [[package]] name = "ibc-apps" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-app-nft-transfer", "ibc-app-transfer", @@ -2717,7 +2727,7 @@ dependencies = [ [[package]] name = "ibc-client-tendermint" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "derive_more", "ibc-client-tendermint-types", @@ -2734,7 +2744,7 @@ dependencies = [ [[package]] name = "ibc-client-tendermint-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "displaydoc", "ibc-core-client-types", @@ -2751,7 +2761,7 @@ dependencies = [ [[package]] name = "ibc-client-wasm-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "base64 0.22.1", "displaydoc", @@ -2765,7 +2775,7 @@ dependencies = [ [[package]] name = "ibc-clients" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-client-tendermint", "ibc-client-wasm-types", @@ -2774,7 +2784,7 @@ dependencies = [ [[package]] name = "ibc-core" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-core-channel", "ibc-core-client", @@ -2790,7 +2800,7 @@ dependencies = [ [[package]] name = "ibc-core-channel" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-core-channel-types", "ibc-core-client", @@ -2805,7 +2815,7 @@ dependencies = [ [[package]] name = "ibc-core-channel-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "borsh", "derive_more", @@ -2828,7 +2838,7 @@ dependencies = [ [[package]] name = "ibc-core-client" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-core-client-context", "ibc-core-client-types", @@ -2841,7 +2851,7 @@ dependencies = [ [[package]] name = "ibc-core-client-context" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "derive_more", "displaydoc", @@ -2857,7 +2867,7 @@ dependencies = [ [[package]] name = "ibc-core-client-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "borsh", "derive_more", @@ -2877,7 +2887,7 @@ dependencies = [ [[package]] name = "ibc-core-commitment-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "borsh", "derive_more", @@ -2896,7 +2906,7 @@ dependencies = [ [[package]] name = "ibc-core-connection" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-client-wasm-types", "ibc-core-client", @@ -2910,7 +2920,7 @@ dependencies = [ [[package]] name = "ibc-core-connection-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "borsh", "derive_more", @@ -2931,7 +2941,7 @@ dependencies = [ [[package]] name = "ibc-core-handler" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-core-channel", "ibc-core-client", @@ -2946,7 +2956,7 @@ dependencies = [ [[package]] name = "ibc-core-handler-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "borsh", "derive_more", @@ -2970,7 +2980,7 @@ dependencies = [ [[package]] name = "ibc-core-host" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "derive_more", "displaydoc", @@ -2988,7 +2998,7 @@ dependencies = [ [[package]] name = "ibc-core-host-cosmos" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "derive_more", "displaydoc", @@ -3011,7 +3021,7 @@ dependencies = [ [[package]] name = "ibc-core-host-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "borsh", "derive_more", @@ -3026,7 +3036,7 @@ dependencies = [ [[package]] name = "ibc-core-router" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "derive_more", "displaydoc", @@ -3040,7 +3050,7 @@ dependencies = [ [[package]] name = "ibc-core-router-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "borsh", "derive_more", @@ -3059,17 +3069,36 @@ dependencies = [ [[package]] name = "ibc-derive" version = "0.8.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "proc-macro2", "quote", "syn 2.0.96", ] +[[package]] +name = "ibc-middleware-packet-forward" +version = "0.6.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.6.0#ca824cfbe550c529d30bf27a97026dd0a058cfdf" +dependencies = [ + "borsh", + "dur", + "either", + "ibc-app-transfer-types", + "ibc-core-channel", + "ibc-core-channel-types", + "ibc-core-host-types", + "ibc-core-router", + "ibc-core-router-types", + "ibc-primitives", + "serde", + "serde_json", +] + [[package]] name = "ibc-primitives" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "borsh", "derive_more", @@ -3109,7 +3138,7 @@ dependencies = [ [[package]] name = "ibc-query" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "displaydoc", "ibc", @@ -3120,7 +3149,7 @@ dependencies = [ [[package]] name = "ibc-testkit" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "basecoin-store", "derive_more", @@ -3648,6 +3677,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.1" @@ -3953,8 +3988,10 @@ version = "0.46.1" dependencies = [ "borsh", "data-encoding", + "dur", "ibc", "ibc-derive", + "ibc-middleware-packet-forward", "ibc-testkit", "ics23", "konst", @@ -4238,7 +4275,9 @@ version = "0.46.1" dependencies = [ "concat-idents", "derivative", + "dur", "hyper 0.14.27", + "ibc-middleware-packet-forward", "ibc-testkit", "ics23", "itertools 0.12.1", @@ -4508,6 +4547,16 @@ dependencies = [ "tempfile", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "nonempty" version = "0.7.0" @@ -5591,12 +5640,18 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.35.0" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1790d1c4c0ca81211399e0e0af16333276f375209e71a37b67698a373db5b47a" +checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" dependencies = [ "arrayvec", + "borsh", + "bytes", "num-traits", + "rand", + "rkyv", + "serde", + "serde_json", ] [[package]] @@ -5959,11 +6014,12 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] diff --git a/wasm_for_tests/Cargo.lock b/wasm_for_tests/Cargo.lock index 6093c82920..590a861424 100644 --- a/wasm_for_tests/Cargo.lock +++ b/wasm_for_tests/Cargo.lock @@ -23,6 +23,17 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "1.1.2" @@ -378,6 +389,28 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "byteorder" version = "1.5.0" @@ -734,6 +767,16 @@ dependencies = [ "litrs", ] +[[package]] +name = "dur" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce5b6c91b5e394b75cd96c36393fc938496c030220207a0ccf34d6cd313d3b49" +dependencies = [ + "nom", + "rust_decimal", +] + [[package]] name = "dyn-clone" version = "1.0.16" @@ -1135,6 +1178,15 @@ dependencies = [ "byteorder", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + [[package]] name = "hashbrown" version = "0.14.3" @@ -1228,7 +1280,7 @@ dependencies = [ [[package]] name = "ibc" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-apps", "ibc-clients", @@ -1241,7 +1293,7 @@ dependencies = [ [[package]] name = "ibc-app-nft-transfer" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-app-nft-transfer-types", "ibc-core", @@ -1251,7 +1303,7 @@ dependencies = [ [[package]] name = "ibc-app-nft-transfer-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "base64 0.22.1", "borsh", @@ -1272,7 +1324,7 @@ dependencies = [ [[package]] name = "ibc-app-transfer" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-app-transfer-types", "ibc-core", @@ -1282,7 +1334,7 @@ dependencies = [ [[package]] name = "ibc-app-transfer-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "borsh", "derive_more", @@ -1300,7 +1352,7 @@ dependencies = [ [[package]] name = "ibc-apps" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-app-nft-transfer", "ibc-app-transfer", @@ -1309,7 +1361,7 @@ dependencies = [ [[package]] name = "ibc-client-tendermint" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "derive_more", "ibc-client-tendermint-types", @@ -1326,7 +1378,7 @@ dependencies = [ [[package]] name = "ibc-client-tendermint-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "displaydoc", "ibc-core-client-types", @@ -1343,7 +1395,7 @@ dependencies = [ [[package]] name = "ibc-client-wasm-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "base64 0.22.1", "displaydoc", @@ -1357,7 +1409,7 @@ dependencies = [ [[package]] name = "ibc-clients" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-client-tendermint", "ibc-client-wasm-types", @@ -1366,7 +1418,7 @@ dependencies = [ [[package]] name = "ibc-core" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-core-channel", "ibc-core-client", @@ -1382,7 +1434,7 @@ dependencies = [ [[package]] name = "ibc-core-channel" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-core-channel-types", "ibc-core-client", @@ -1397,7 +1449,7 @@ dependencies = [ [[package]] name = "ibc-core-channel-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "borsh", "derive_more", @@ -1420,7 +1472,7 @@ dependencies = [ [[package]] name = "ibc-core-client" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-core-client-context", "ibc-core-client-types", @@ -1433,7 +1485,7 @@ dependencies = [ [[package]] name = "ibc-core-client-context" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "derive_more", "displaydoc", @@ -1449,7 +1501,7 @@ dependencies = [ [[package]] name = "ibc-core-client-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "borsh", "derive_more", @@ -1469,7 +1521,7 @@ dependencies = [ [[package]] name = "ibc-core-commitment-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "borsh", "derive_more", @@ -1488,7 +1540,7 @@ dependencies = [ [[package]] name = "ibc-core-connection" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-client-wasm-types", "ibc-core-client", @@ -1502,7 +1554,7 @@ dependencies = [ [[package]] name = "ibc-core-connection-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "borsh", "derive_more", @@ -1523,7 +1575,7 @@ dependencies = [ [[package]] name = "ibc-core-handler" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "ibc-core-channel", "ibc-core-client", @@ -1538,7 +1590,7 @@ dependencies = [ [[package]] name = "ibc-core-handler-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "borsh", "derive_more", @@ -1562,7 +1614,7 @@ dependencies = [ [[package]] name = "ibc-core-host" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "derive_more", "displaydoc", @@ -1580,7 +1632,7 @@ dependencies = [ [[package]] name = "ibc-core-host-cosmos" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "derive_more", "displaydoc", @@ -1603,7 +1655,7 @@ dependencies = [ [[package]] name = "ibc-core-host-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "borsh", "derive_more", @@ -1618,7 +1670,7 @@ dependencies = [ [[package]] name = "ibc-core-router" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "derive_more", "displaydoc", @@ -1632,7 +1684,7 @@ dependencies = [ [[package]] name = "ibc-core-router-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "borsh", "derive_more", @@ -1651,17 +1703,36 @@ dependencies = [ [[package]] name = "ibc-derive" version = "0.8.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "proc-macro2", "quote", "syn 2.0.96", ] +[[package]] +name = "ibc-middleware-packet-forward" +version = "0.6.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.6.0#ca824cfbe550c529d30bf27a97026dd0a058cfdf" +dependencies = [ + "borsh", + "dur", + "either", + "ibc-app-transfer-types", + "ibc-core-channel", + "ibc-core-channel-types", + "ibc-core-host-types", + "ibc-core-router", + "ibc-core-router-types", + "ibc-primitives", + "serde", + "serde_json", +] + [[package]] name = "ibc-primitives" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38bd2a32f35117d4d9165a3c68c64ccd87ad56dd#38bd2a32f35117d4d9165a3c68c64ccd87ad56dd" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" dependencies = [ "borsh", "derive_more", @@ -2068,6 +2139,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "multimap" version = "0.8.3" @@ -2283,8 +2360,10 @@ version = "0.46.1" dependencies = [ "borsh", "data-encoding", + "dur", "ibc", "ibc-derive", + "ibc-middleware-packet-forward", "ics23", "konst", "masp_primitives", @@ -2620,6 +2699,16 @@ dependencies = [ "sha2 0.9.9", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "nonempty" version = "0.7.0" @@ -3087,7 +3176,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac" dependencies = [ "anyhow", - "itertools 0.12.1", + "itertools 0.13.0", "proc-macro2", "quote", "syn 2.0.96", @@ -3111,6 +3200,26 @@ dependencies = [ "prost 0.13.2", ] +[[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.36" @@ -3225,6 +3334,15 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + [[package]] name = "rfc6979" version = "0.4.0" @@ -3244,6 +3362,35 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "rkyv" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "rlp" version = "0.5.2" @@ -3266,6 +3413,22 @@ dependencies = [ "svgbobdoc", ] +[[package]] +name = "rust_decimal" +version = "1.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" +dependencies = [ + "arrayvec", + "borsh", + "bytes", + "num-traits", + "rand", + "rkyv", + "serde", + "serde_json", +] + [[package]] name = "rustc-hex" version = "2.1.0" @@ -3369,6 +3532,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[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" @@ -3459,11 +3628,12 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -3539,6 +3709,12 @@ dependencies = [ "rand_core", ] +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "slab" version = "0.4.9" @@ -4182,6 +4358,12 @@ dependencies = [ "serde", ] +[[package]] +name = "uuid" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "744018581f9a3454a9e15beb8a33b017183f1e7c0cd170232a2d1453b23a51c4" + [[package]] name = "version_check" version = "0.9.4" From db2b8a11cfa28ef71ef20b37bbbd975afd62c0fd Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Fri, 29 Nov 2024 14:20:51 +0000 Subject: [PATCH 02/31] Increase the visibility of some IBC code Co-authored-by: Jacob Turner --- crates/ibc/src/context/token_transfer.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/ibc/src/context/token_transfer.rs b/crates/ibc/src/context/token_transfer.rs index da3bedc41c..fecc8d4d2d 100644 --- a/crates/ibc/src/context/token_transfer.rs +++ b/crates/ibc/src/context/token_transfer.rs @@ -25,8 +25,8 @@ pub struct TokenTransferContext where C: IbcCommonContext, { - inner: Rc>, - verifiers: Rc>>, + pub(crate) inner: Rc>, + pub(crate) verifiers: Rc>>, is_shielded: bool, } @@ -47,7 +47,7 @@ where } /// Insert a verifier address whose VP will verify the tx. - fn insert_verifier(&mut self, addr: &Address) { + pub(crate) fn insert_verifier(&mut self, addr: &Address) { self.verifiers.borrow_mut().insert(addr.clone()); } From 0c2649e2103a5f7a5ed5691e3cd9dd3411eba1b3 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Fri, 29 Nov 2024 14:17:14 +0000 Subject: [PATCH 03/31] Implement PFM module Co-authored-by: Jacob Turner --- crates/ibc/src/context/mod.rs | 1 + crates/ibc/src/context/pfm_mod.rs | 529 ++++++++++++++++++++++++++++++ 2 files changed, 530 insertions(+) create mode 100644 crates/ibc/src/context/pfm_mod.rs diff --git a/crates/ibc/src/context/mod.rs b/crates/ibc/src/context/mod.rs index d6e238c6c9..89a82b13e7 100644 --- a/crates/ibc/src/context/mod.rs +++ b/crates/ibc/src/context/mod.rs @@ -5,6 +5,7 @@ pub mod common; pub mod execution; pub mod nft_transfer; pub mod nft_transfer_mod; +pub mod pfm_mod; pub mod router; pub mod storage; pub mod token_transfer; diff --git a/crates/ibc/src/context/pfm_mod.rs b/crates/ibc/src/context/pfm_mod.rs new file mode 100644 index 0000000000..59ded9263b --- /dev/null +++ b/crates/ibc/src/context/pfm_mod.rs @@ -0,0 +1,529 @@ +//! Implementation of Packet Forward Middleware on top of the ICS-20 +//! [`TransferModule`]. + +use std::cell::RefCell; +use std::collections::BTreeSet; +use std::fmt::{Debug, Formatter}; +use std::marker::PhantomData; +use std::rc::Rc; + +use ibc::apps::transfer::context::TokenTransferExecutionContext; +use ibc::apps::transfer::handler::{ + refund_packet_token_execute, send_transfer_execute, +}; +use ibc::apps::transfer::types::msgs::transfer::MsgTransfer; +use ibc::apps::transfer::types::packet::PacketData; +use ibc::apps::transfer::types::{is_receiver_chain_source, TracePrefix}; +use ibc::core::channel::handler::{ + commit_packet_acknowledgment, emit_packet_acknowledgement_event, +}; +use ibc::core::channel::types::acknowledgement::Acknowledgement; +use ibc::core::channel::types::channel::{Counterparty, Order}; +use ibc::core::channel::types::error::{ChannelError, PacketError}; +use ibc::core::channel::types::packet::Packet; +use ibc::core::channel::types::timeout::TimeoutTimestamp; +use ibc::core::channel::types::Version; +use ibc::core::host::types::identifiers::{ + ChannelId, ConnectionId, PortId, Sequence, +}; +use ibc::core::router::module::Module; +use ibc::core::router::types::module::{ModuleExtras, ModuleId}; +use ibc::primitives::Signer; +use ibc_middleware_packet_forward::{ + InFlightPacket, InFlightPacketKey, PacketForwardMiddleware, PfmContext, +}; +use namada_core::address::{Address, IBC as IBC_ADDRESS, MULTITOKEN}; +use namada_core::storage::{self, KeySeg}; +use namada_state::{StorageRead, StorageWrite}; + +use crate::context::transfer_mod::TransferModule; +use crate::context::IbcContext; +use crate::{ + Error, IbcCommonContext, IbcStorageContext, ModuleWrapper, + TokenTransferContext, +}; + +const MIDDLEWARES_SUBKEY: &str = "middleware"; +const PFM_SUBKEY: &str = "pfm"; + +/// Get the Namada storage key associated to the provided `InFlightPacketKey`. +pub fn get_inflight_packet_key( + inflight_packet_key: &InFlightPacketKey, +) -> storage::Key { + let key: storage::Key = IBC_ADDRESS.to_db_key().into(); + key.with_segment(MIDDLEWARES_SUBKEY.to_string()) + .with_segment(PFM_SUBKEY.to_string()) + .with_segment(inflight_packet_key.port.to_string()) + .with_segment(inflight_packet_key.channel.to_string()) + .with_segment(inflight_packet_key.sequence.to_string()) +} + +/// A wrapper around an IBC transfer module necessary to +/// build execution contexts. This allows us to implement +/// packet forward middleware on this struct. +pub struct PfmTransferModule +where + C: IbcCommonContext + Debug, +{ + /// The main module + pub transfer_module: TransferModule, + #[allow(missing_docs)] + pub _phantom: PhantomData, +} + +impl PfmTransferModule +where + C: IbcCommonContext + Debug, +{ + /// Create a new [`PfmTransferModule`] + pub fn wrap( + ctx: Rc>, + verifiers: Rc>>, + ) -> PacketForwardMiddleware { + PacketForwardMiddleware::next(Self { + transfer_module: TransferModule::new(ctx, verifiers), + _phantom: Default::default(), + }) + } +} + +impl Debug + for PfmTransferModule +{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct(stringify!(PfmTransferModule)) + .field("transfer_module", &self.transfer_module) + .finish_non_exhaustive() + } +} + +impl Module for PfmTransferModule +where + C: IbcCommonContext + Debug, +{ + fn on_chan_open_init_validate( + &self, + order: Order, + connection_hops: &[ConnectionId], + port_id: &PortId, + channel_id: &ChannelId, + counterparty: &Counterparty, + version: &Version, + ) -> Result { + self.transfer_module.on_chan_open_init_validate( + order, + connection_hops, + port_id, + channel_id, + counterparty, + version, + ) + } + + fn on_chan_open_init_execute( + &mut self, + order: Order, + connection_hops: &[ConnectionId], + port_id: &PortId, + channel_id: &ChannelId, + counterparty: &Counterparty, + version: &Version, + ) -> Result<(ModuleExtras, Version), ChannelError> { + self.transfer_module.on_chan_open_init_execute( + order, + connection_hops, + port_id, + channel_id, + counterparty, + version, + ) + } + + fn on_chan_open_try_validate( + &self, + order: Order, + connection_hops: &[ConnectionId], + port_id: &PortId, + channel_id: &ChannelId, + counterparty: &Counterparty, + counterparty_version: &Version, + ) -> Result { + self.transfer_module.on_chan_open_try_validate( + order, + connection_hops, + port_id, + channel_id, + counterparty, + counterparty_version, + ) + } + + fn on_chan_open_try_execute( + &mut self, + order: Order, + connection_hops: &[ConnectionId], + port_id: &PortId, + channel_id: &ChannelId, + counterparty: &Counterparty, + counterparty_version: &Version, + ) -> Result<(ModuleExtras, Version), ChannelError> { + self.transfer_module.on_chan_open_try_execute( + order, + connection_hops, + port_id, + channel_id, + counterparty, + counterparty_version, + ) + } + + fn on_chan_open_ack_validate( + &self, + port_id: &PortId, + channel_id: &ChannelId, + counterparty_version: &Version, + ) -> Result<(), ChannelError> { + self.transfer_module.on_chan_open_ack_validate( + port_id, + channel_id, + counterparty_version, + ) + } + + fn on_chan_open_ack_execute( + &mut self, + port_id: &PortId, + channel_id: &ChannelId, + counterparty_version: &Version, + ) -> Result { + self.transfer_module.on_chan_open_ack_execute( + port_id, + channel_id, + counterparty_version, + ) + } + + fn on_chan_open_confirm_validate( + &self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> Result<(), ChannelError> { + self.transfer_module + .on_chan_open_confirm_validate(port_id, channel_id) + } + + fn on_chan_open_confirm_execute( + &mut self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> Result { + self.transfer_module + .on_chan_open_confirm_execute(port_id, channel_id) + } + + fn on_chan_close_init_validate( + &self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> Result<(), ChannelError> { + self.transfer_module + .on_chan_close_init_validate(port_id, channel_id) + } + + fn on_chan_close_init_execute( + &mut self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> Result { + self.transfer_module + .on_chan_close_init_execute(port_id, channel_id) + } + + fn on_chan_close_confirm_validate( + &self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> Result<(), ChannelError> { + self.transfer_module + .on_chan_close_confirm_validate(port_id, channel_id) + } + + fn on_chan_close_confirm_execute( + &mut self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> Result { + self.transfer_module + .on_chan_close_confirm_execute(port_id, channel_id) + } + + fn on_recv_packet_execute( + &mut self, + packet: &Packet, + relayer: &Signer, + ) -> (ModuleExtras, Option) { + self.transfer_module.on_recv_packet_execute(packet, relayer) + } + + fn on_acknowledgement_packet_validate( + &self, + packet: &Packet, + acknowledgement: &Acknowledgement, + relayer: &Signer, + ) -> Result<(), PacketError> { + self.transfer_module.on_acknowledgement_packet_validate( + packet, + acknowledgement, + relayer, + ) + } + + fn on_acknowledgement_packet_execute( + &mut self, + packet: &Packet, + acknowledgement: &Acknowledgement, + relayer: &Signer, + ) -> (ModuleExtras, Result<(), PacketError>) { + self.transfer_module.on_acknowledgement_packet_execute( + packet, + acknowledgement, + relayer, + ) + } + + fn on_timeout_packet_validate( + &self, + packet: &Packet, + relayer: &Signer, + ) -> Result<(), PacketError> { + self.transfer_module + .on_timeout_packet_validate(packet, relayer) + } + + fn on_timeout_packet_execute( + &mut self, + packet: &Packet, + relayer: &Signer, + ) -> (ModuleExtras, Result<(), PacketError>) { + self.transfer_module + .on_timeout_packet_execute(packet, relayer) + } +} + +impl PfmContext for PfmTransferModule +where + C: IbcCommonContext + Debug, + Params: namada_systems::parameters::Read<::Storage>, +{ + type Error = crate::Error; + + fn send_transfer_execute( + &mut self, + msg: MsgTransfer, + ) -> Result { + let seq = self + .transfer_module + .ctx + .inner + .borrow() + .get_next_sequence_send(&msg.port_id_on_a, &msg.chan_id_on_a) + .map_err(|e| Error::Context(Box::new(e)))?; + tracing::debug!(?seq, ?msg, "PFM send_transfer_execute"); + + let mut ctx = IbcContext::::new( + self.transfer_module.ctx.inner.clone(), + ); + let mut token_transfer_ctx = TokenTransferContext::new( + self.transfer_module.ctx.inner.clone(), + Default::default(), + ); + + self.transfer_module.ctx.insert_verifier(&MULTITOKEN); + + send_transfer_execute(&mut ctx, &mut token_transfer_ctx, msg) + .map_err(Error::TokenTransfer)?; + + Ok(seq) + } + + fn receive_refund_execute( + &mut self, + packet: &Packet, + data: PacketData, + ) -> Result<(), Self::Error> { + tracing::debug!(?packet, ?data, "PFM receive_refund_execute"); + let mut token_transfer_ctx = TokenTransferContext::new( + self.transfer_module.ctx.inner.clone(), + self.transfer_module.ctx.verifiers.clone(), + ); + self.transfer_module.ctx.insert_verifier(&MULTITOKEN); + refund_packet_token_execute(&mut token_transfer_ctx, packet, &data) + .map_err(Error::TokenTransfer) + } + + fn send_refund_execute( + &mut self, + msg: &InFlightPacket, + ) -> Result<(), Self::Error> { + tracing::debug!(?msg, "PFM send_refund_execute"); + + let packet_data: PacketData = serde_json::from_slice(&msg.packet_data) + .expect( + "The in-flight packet data should have belonged to an ICS-20 \ + packet", + ); + + let mut token_transfer_ctx = TokenTransferContext::new( + self.transfer_module.ctx.inner.clone(), + self.transfer_module.ctx.verifiers.clone(), + ); + + self.transfer_module.ctx.insert_verifier(&MULTITOKEN); + + if is_receiver_chain_source( + msg.packet_src_port_id.clone(), + msg.packet_src_channel_id.clone(), + &packet_data.token.denom, + ) { + let coin = { + let mut c = packet_data.token; + c.denom.remove_trace_prefix(&TracePrefix::new( + msg.packet_src_port_id.clone(), + msg.packet_src_channel_id.clone(), + )); + c + }; + + token_transfer_ctx + .escrow_coins_execute( + &IBC_ADDRESS, + &msg.refund_port_id, + &msg.refund_channel_id, + &coin, + &String::new().into(), + ) + .map_err(Error::TokenTransfer) + } else { + let coin = { + let mut c = packet_data.token; + c.denom.add_trace_prefix(TracePrefix::new( + msg.refund_port_id.clone(), + msg.refund_channel_id.clone(), + )); + c + }; + + token_transfer_ctx + .burn_coins_execute(&IBC_ADDRESS, &coin, &String::new().into()) + .map_err(Error::TokenTransfer) + } + } + + fn write_ack_and_events( + &mut self, + packet: &Packet, + acknowledgement: &Acknowledgement, + ) -> Result<(), Self::Error> { + tracing::debug!(?packet, ?acknowledgement, "PFM write_ack_and_events"); + let mut ctx = IbcContext::::new( + self.transfer_module.ctx.inner.clone(), + ); + commit_packet_acknowledgment(&mut ctx, packet, acknowledgement) + .map_err(|e| Error::Context(Box::new(e)))?; + emit_packet_acknowledgement_event( + &mut ctx, + packet.clone(), + acknowledgement.clone(), + ) + .map_err(|e| Error::Context(Box::new(e))) + } + + fn override_receiver( + &self, + _channel: &ChannelId, + _original_sender: &Signer, + ) -> Result { + Ok(IBC_ADDRESS.to_string().into()) + } + + #[allow(clippy::arithmetic_side_effects)] + fn timeout_timestamp( + &self, + timeout_duration: dur::Duration, + ) -> Result { + let timestamp = self + .transfer_module + .ctx + .inner + .borrow() + .host_timestamp() + .map_err(|e| Error::Other(e.to_string()))? + + timeout_duration.try_to_std().ok_or_else(|| { + Error::Other(format!( + "Packet timeout duration is too large: {timeout_duration}" + )) + })?; + let ts = timestamp + .map(TimeoutTimestamp::At) + .map_err(|e| Error::Other(e.to_string()))?; + tracing::debug!(timeout_timestamp = ?ts, "PFM timeout_timestamp"); + Ok(ts) + } + + fn store_inflight_packet( + &mut self, + key: InFlightPacketKey, + inflight_packet: InFlightPacket, + ) -> Result<(), Self::Error> { + tracing::debug!(?key, ?inflight_packet, "PFM store_inflight_packet"); + let mut ctx = self.transfer_module.ctx.inner.borrow_mut(); + let key = get_inflight_packet_key(&key); + ctx.storage_mut() + .write(&key, inflight_packet) + .map_err(Error::Storage) + } + + fn retrieve_inflight_packet( + &self, + key: &InFlightPacketKey, + ) -> Result, Self::Error> { + let mut ctx = self.transfer_module.ctx.inner.borrow_mut(); + let key = get_inflight_packet_key(key); + let packet = ctx.storage_mut().read(&key).map_err(Error::Storage); + + tracing::debug!(?key, ?packet, "PFM retrieve_inflight_packet"); + + packet + } + + fn delete_inflight_packet( + &mut self, + key: &InFlightPacketKey, + ) -> Result<(), Self::Error> { + tracing::debug!(?key, "PFM delete_inflight_packet"); + let mut ctx = self.transfer_module.ctx.inner.borrow_mut(); + let key = get_inflight_packet_key(key); + ctx.storage_mut().delete(&key).map_err(Error::Storage) + } +} + +impl ModuleWrapper for PacketForwardMiddleware +where + T: Module + PfmContext, +{ + fn as_module(&self) -> &dyn Module { + self + } + + fn as_module_mut(&mut self) -> &mut dyn Module { + self + } + + fn module_id(&self) -> ModuleId { + ModuleId::new(ibc::apps::transfer::types::MODULE_ID_STR.to_string()) + } + + fn port_id(&self) -> PortId { + PortId::transfer() + } +} From ad4582957c319e86e003ac7b44b13c41fb08ff27 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Fri, 29 Nov 2024 14:28:02 +0000 Subject: [PATCH 04/31] Hook up PFM middleware to ICS-20 transfer module Co-authored-by: Jacob Turner --- crates/benches/native_vps.rs | 15 ++++++++++----- crates/ibc/src/vp/mod.rs | 11 +++++++---- crates/tx_prelude/src/ibc.rs | 8 ++++++-- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/crates/benches/native_vps.rs b/crates/benches/native_vps.rs index c31d1901aa..8479a39d43 100644 --- a/crates/benches/native_vps.rs +++ b/crates/benches/native_vps.rs @@ -24,6 +24,7 @@ use namada_apps_lib::governance::pgf::storage::steward::StewardDetail; use namada_apps_lib::governance::storage::proposal::ProposalType; use namada_apps_lib::governance::storage::vote::ProposalVote; use namada_apps_lib::governance::{InitProposalData, VoteProposalData}; +use namada_apps_lib::ibc::context::pfm_mod::PfmTransferModule; use namada_apps_lib::ibc::core::channel::types::channel::Order; use namada_apps_lib::ibc::core::channel::types::msgs::MsgChannelOpenInit; use namada_apps_lib::ibc::core::channel::types::Version as ChannelVersion; @@ -35,9 +36,7 @@ use namada_apps_lib::ibc::core::host::types::identifiers::{ ClientId, ConnectionId, PortId, }; use namada_apps_lib::ibc::primitives::ToProto; -use namada_apps_lib::ibc::{ - IbcActions, NftTransferModule, TransferModule, COMMITMENT_PREFIX, -}; +use namada_apps_lib::ibc::{IbcActions, NftTransferModule, COMMITMENT_PREFIX}; use namada_apps_lib::masp_primitives::merkle_tree::CommitmentTree; use namada_apps_lib::masp_primitives::transaction::Transaction; use namada_apps_lib::masp_proofs::sapling::SaplingVerificationContextInner; @@ -1725,7 +1724,10 @@ fn ibc_vp_validate_action(c: &mut Criterion) { ); actions.set_validation_params(ibc.validation_params().unwrap()); - let module = TransferModule::new(ctx.clone(), verifiers); + let module = PfmTransferModule::<_, parameters::Store<_>>::wrap( + ctx.clone(), + verifiers, + ); actions.add_transfer_module(module); let module = NftTransferModule::<_, token::Store<()>>::new(ctx); actions.add_transfer_module(module); @@ -1786,7 +1788,10 @@ fn ibc_vp_execute_action(c: &mut Criterion) { ); actions.set_validation_params(ibc.validation_params().unwrap()); - let module = TransferModule::new(ctx.clone(), verifiers); + let module = PfmTransferModule::<_, parameters::Store<_>>::wrap( + ctx.clone(), + verifiers, + ); actions.add_transfer_module(module); let module = NftTransferModule::<_, token::Store<()>>::new(ctx); actions.add_transfer_module(module); diff --git a/crates/ibc/src/vp/mod.rs b/crates/ibc/src/vp/mod.rs index ebff0d9196..bfc0be1e90 100644 --- a/crates/ibc/src/vp/mod.rs +++ b/crates/ibc/src/vp/mod.rs @@ -27,6 +27,7 @@ use namada_vp::native_vp::{Ctx, CtxPreStorageRead, NativeVp, VpEvaluator}; use namada_vp::VpEnv; use thiserror::Error; +use crate::context::pfm_mod::PfmTransferModule; use crate::core::host::types::identifiers::ChainId as IbcChainId; use crate::core::host::types::path::UPGRADED_IBC_STATE; use crate::event::IbcEvent; @@ -36,8 +37,8 @@ use crate::storage::{ }; use crate::trace::calc_hash; use crate::{ - Error as ActionError, IbcActions, NftTransferModule, TransferModule, - ValidationParams, COMMITMENT_PREFIX, + Error as ActionError, IbcActions, NftTransferModule, ValidationParams, + COMMITMENT_PREFIX, }; #[allow(missing_docs)] @@ -246,7 +247,8 @@ where ctx.clone(), verifiers.clone(), ); - let module = TransferModule::new(ctx.clone(), verifiers); + let module = + PfmTransferModule::<_, ParamsPseudo>::wrap(ctx.clone(), verifiers); actions.add_transfer_module(module); let module = NftTransferModule::<_, Token>::new(ctx.clone()); actions.add_transfer_module(module); @@ -301,7 +303,8 @@ where IbcActions::<_, Params, Token>::new(ctx.clone(), verifiers.clone()); actions.set_validation_params(self.validation_params()?); - let module = TransferModule::new(ctx.clone(), verifiers); + let module = + PfmTransferModule::<_, Params>::wrap(ctx.clone(), verifiers); actions.add_transfer_module(module); let module = NftTransferModule::<_, Token>::new(ctx); actions.add_transfer_module(module); diff --git a/crates/tx_prelude/src/ibc.rs b/crates/tx_prelude/src/ibc.rs index 283dc0f723..436a6befc2 100644 --- a/crates/tx_prelude/src/ibc.rs +++ b/crates/tx_prelude/src/ibc.rs @@ -6,6 +6,7 @@ use std::rc::Rc; use namada_core::address::Address; use namada_core::token::Amount; +use namada_ibc::context::pfm_mod::PfmTransferModule; pub use namada_ibc::event::{IbcEvent, IbcEventType}; pub use namada_ibc::storage::{ burn_tokens, client_state_key, is_ibc_key, mint_limit_key, mint_tokens, @@ -19,7 +20,7 @@ pub use namada_ibc::{ }; use namada_tx_env::TxEnv; -use crate::{token, Ctx, Result}; +use crate::{parameters, token, Ctx, Result}; /// IBC actions to handle an IBC message. The `verifiers` inserted into the set /// must be inserted into the tx context with `Ctx::insert_verifier` after tx @@ -30,7 +31,10 @@ pub fn ibc_actions( let ctx = Rc::new(RefCell::new(ctx.clone())); let verifiers = Rc::new(RefCell::new(BTreeSet::
::new())); let mut actions = IbcActions::new(ctx.clone(), verifiers.clone()); - let module = TransferModule::new(ctx.clone(), verifiers); + let module = PfmTransferModule::<_, parameters::Store>::wrap( + ctx.clone(), + verifiers, + ); actions.add_transfer_module(module); let module = NftTransferModule::>::new(ctx); actions.add_transfer_module(module); From e52f793d1e8bccad437db7b070cb2d09d0957c43 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Fri, 29 Nov 2024 14:28:36 +0000 Subject: [PATCH 05/31] Add PFM e2e tests Co-authored-by: Jacob Turner Co-authored-by: Yuji Ito --- crates/tests/src/e2e/helpers.rs | 72 +- crates/tests/src/e2e/ibc_tests.rs | 1036 ++++++++++++++++++++++++++--- crates/tests/src/e2e/setup.rs | 66 +- 3 files changed, 1032 insertions(+), 142 deletions(-) diff --git a/crates/tests/src/e2e/helpers.rs b/crates/tests/src/e2e/helpers.rs index 5c3a9d25a1..3df93fddc7 100644 --- a/crates/tests/src/e2e/helpers.rs +++ b/crates/tests/src/e2e/helpers.rs @@ -31,8 +31,8 @@ use namada_sdk::wallet::Wallet; use toml::Value; use super::setup::{ - self, run_cosmos_cmd, sleep, NamadaBgCmd, NamadaCmd, Test, ENV_VAR_DEBUG, - ENV_VAR_USE_PREBUILT_BINARIES, + self, run_cosmos_cmd, sleep, NamadaBgCmd, NamadaCmd, Test, TestDir, + ENV_VAR_DEBUG, ENV_VAR_USE_PREBUILT_BINARIES, }; use crate::e2e::setup::{constants, Bin, CosmosChainType, Who, APPS_PACKAGE}; use crate::strings::{LEDGER_STARTED, TX_APPLIED_SUCCESS}; @@ -493,7 +493,11 @@ pub fn epochs_per_year_from_min_duration(min_duration: u64) -> u64 { } /// Make a Hermes config -pub fn make_hermes_config(test_a: &Test, test_b: &Test) -> Result<()> { +pub fn make_hermes_config( + hermes_dir: &TestDir, + test_a: &Test, + test_b: &Test, +) -> Result<()> { let mut config = toml::map::Map::new(); let mut global = toml::map::Map::new(); @@ -533,9 +537,9 @@ pub fn make_hermes_config(test_a: &Test, test_b: &Test) -> Result<()> { let chains = vec![ make_hermes_chain_config(test_a), match CosmosChainType::chain_type(test_b.net.chain_id.as_str()) { - Ok(chain_type) => { - make_hermes_chain_config_for_cosmos(chain_type, test_b) - } + Ok(chain_type) => make_hermes_chain_config_for_cosmos( + hermes_dir, chain_type, test_b, + ), Err(_) => make_hermes_chain_config(test_b), }, ]; @@ -543,16 +547,7 @@ pub fn make_hermes_config(test_a: &Test, test_b: &Test) -> Result<()> { config.insert("chains".to_owned(), Value::Array(chains)); let toml_string = toml::to_string(&Value::Table(config)).unwrap(); - let hermes_dir = test_a.test_dir.as_ref().join("hermes"); - std::fs::create_dir_all(&hermes_dir).unwrap(); - let config_path = hermes_dir.join("config.toml"); - let mut file = File::create(config_path).unwrap(); - file.write_all(toml_string.as_bytes()).map_err(|e| { - eyre!(format!("Writing a Hermes config failed: {}", e,)) - })?; - // One Hermes config.toml is OK, but add one more config.toml to execute - // Hermes from test_b - let hermes_dir = test_b.test_dir.as_ref().join("hermes"); + let hermes_dir = hermes_dir.as_ref().join("hermes"); std::fs::create_dir_all(&hermes_dir).unwrap(); let config_path = hermes_dir.join("config.toml"); let mut file = File::create(config_path).unwrap(); @@ -607,12 +602,14 @@ fn make_hermes_chain_config(test: &Test) -> Value { } fn make_hermes_chain_config_for_cosmos( + hermes_dir: &TestDir, chain_type: CosmosChainType, test: &Test, ) -> Value { let mut table = toml::map::Map::new(); table.insert("mode".to_owned(), Value::String("push".to_owned())); - let url = format!("ws://{}/websocket", setup::constants::COSMOS_RPC); + let offset = chain_type.get_offset(); + let url = format!("ws://127.0.0.1:6416{}/websocket", offset); table.insert("url".to_owned(), Value::String(url)); table.insert("batch_delay".to_owned(), Value::String("500ms".to_owned())); let event_source = Value::Table(table); @@ -623,14 +620,16 @@ fn make_hermes_chain_config_for_cosmos( Value::String(test.net.chain_id.to_string()), ); chain.insert("type".to_owned(), Value::String("CosmosSdk".to_owned())); + chain.insert( "rpc_addr".to_owned(), - Value::String(format!("http://{}", setup::constants::COSMOS_RPC)), + Value::String(format!("http://127.0.0.1:6416{}", offset)), ); chain.insert( "grpc_addr".to_owned(), - Value::String("http://127.0.0.1:9090".to_owned()), + Value::String(format!("http://127.0.0.1:{}", offset + 9090)), ); + chain.insert("event_source".to_owned(), event_source); chain.insert( "account_prefix".to_owned(), @@ -640,7 +639,8 @@ fn make_hermes_chain_config_for_cosmos( "key_name".to_owned(), Value::String(setup::constants::COSMOS_RELAYER.to_string()), ); - let key_dir = test.test_dir.as_ref().join("hermes/keys"); + let hermes_dir: &Path = hermes_dir.as_ref(); + let key_dir = hermes_dir.join("hermes/keys"); chain.insert( "key_store_folder".to_owned(), Value::String(key_dir.to_string_lossy().to_string()), @@ -672,6 +672,28 @@ pub fn update_cosmos_config(test: &Test) -> Result<()> { *timeout_propose = "1s".into(); } } + let offset = CosmosChainType::chain_type(test.net.chain_id.as_str()) + .unwrap() + .get_offset(); + let p2p = values + .get_mut("p2p") + .expect("Test failed") + .as_table_mut() + .expect("Test failed"); + let Some(laddr) = p2p.get_mut("laddr") else { + panic!("Test failed") + }; + *laddr = format!("tcp://0.0.0.0:266{}{}", offset, offset).into(); + let rpc = values + .get_mut("rpc") + .expect("Test failed") + .as_table_mut() + .expect("Test failed"); + let Some(laddr) = rpc.get_mut("laddr") else { + panic!("Test failed") + }; + *laddr = format!("tcp://0.0.0.0:6416{offset}").into(); + let mut file = OpenOptions::new() .write(true) .truncate(true) @@ -738,6 +760,13 @@ pub fn update_cosmos_config(test: &Test) -> Result<()> { Ok(()) } +pub fn get_cosmos_rpc_address(test: &Test) -> String { + let offset = CosmosChainType::chain_type(test.net.chain_id.as_str()) + .unwrap() + .get_offset(); + format!("127.0.0.1:6416{offset}") +} + pub fn find_cosmos_address( test: &Test, alias: impl AsRef, @@ -759,7 +788,8 @@ pub fn find_cosmos_address( } pub fn get_cosmos_gov_address(test: &Test) -> Result { - let args = ["query", "auth", "module-account", "gov"]; + let rpc = format!("tcp://{}", get_cosmos_rpc_address(test)); + let args = ["query", "auth", "module-account", "gov", "--node", &rpc]; let mut cosmos = run_cosmos_cmd(test, args, Some(40))?; let (_, matched) = cosmos.exp_regex("cosmos[a-z0-9]+")?; diff --git a/crates/tests/src/e2e/ibc_tests.rs b/crates/tests/src/e2e/ibc_tests.rs index e720a72f18..2e63db39f5 100644 --- a/crates/tests/src/e2e/ibc_tests.rs +++ b/crates/tests/src/e2e/ibc_tests.rs @@ -15,6 +15,8 @@ use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; use eyre::eyre; +use ibc_middleware_packet_forward::ForwardMetadata; +use itertools::Either; use namada_apps_lib::client::rpc::query_storage_value_bytes; use namada_apps_lib::config::ethereum_bridge; use namada_apps_lib::config::genesis::templates; @@ -48,7 +50,7 @@ use sha2::{Digest, Sha256}; use crate::e2e::helpers::{ epoch_sleep, epochs_per_year_from_min_duration, find_address, find_cosmos_address, find_payment_address, get_actor_rpc, - get_cosmos_gov_address, get_epoch, + get_cosmos_gov_address, get_cosmos_rpc_address, get_epoch, }; use crate::e2e::ledger_tests::{ start_namada_ledger_node_wait_wasm, write_json_file, @@ -56,8 +58,10 @@ use crate::e2e::ledger_tests::{ use crate::e2e::setup::{ self, apply_use_device, run_cosmos_cmd, run_hermes_cmd, set_ethereum_bridge_mode, setup_cosmos, setup_hermes, sleep, working_dir, - Bin, CosmosChainType, NamadaCmd, Test, Who, ENV_VAR_COSMWASM_CONTRACT_DIR, + Bin, CosmosChainType, NamadaCmd, Test, TestDir, Who, + ENV_VAR_COSMWASM_CONTRACT_DIR, }; +use crate::ibc::primitives::Signer; use crate::strings::TX_APPLIED_SUCCESS; use crate::{run, run_as}; @@ -101,14 +105,15 @@ fn ibc_transfers() -> Result<()> { setup::set_validators(1, genesis, base_dir, |_| 0, vec![]) }; let (ledger, gaia, test, test_gaia) = - run_namada_cosmos(CosmosChainType::Gaia, update_genesis)?; + run_namada_cosmos(CosmosChainType::Gaia(None), update_genesis)?; let _bg_ledger = ledger.background(); let _bg_gaia = gaia.background(); - setup_hermes(&test, &test_gaia)?; + let hermes_dir = setup_hermes(&test, &test_gaia)?; let port_id_namada = FT_PORT_ID.parse().unwrap(); let port_id_gaia = FT_PORT_ID.parse().unwrap(); let (channel_id_namada, channel_id_gaia) = create_channel_with_hermes( + &hermes_dir, &test, &test_gaia, &port_id_namada, @@ -116,7 +121,7 @@ fn ibc_transfers() -> Result<()> { )?; // Start relaying - let hermes = run_hermes(&test)?; + let hermes = run_hermes(&hermes_dir)?; let bg_hermes = hermes.background(); // 1. Transparent transfers @@ -137,7 +142,12 @@ fn ibc_transfers() -> Result<()> { None, false, )?; - wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; + wait_for_packet_relay( + &hermes_dir, + &port_id_namada, + &channel_id_namada, + &test, + )?; check_balance(&test, ALBERT, APFEL, 999_998)?; let token_addr = find_address(&test, APFEL)?; @@ -163,7 +173,7 @@ fn ibc_transfers() -> Result<()> { None, None, )?; - wait_for_packet_relay(&port_id_gaia, &channel_id_gaia, &test)?; + wait_for_packet_relay(&hermes_dir, &port_id_gaia, &channel_id_gaia, &test)?; // Check the balances check_balance(&test, ALBERT, APFEL, 999_999)?; @@ -186,7 +196,7 @@ fn ibc_transfers() -> Result<()> { None, None, )?; - wait_for_packet_relay(&port_id_gaia, &channel_id_gaia, &test)?; + wait_for_packet_relay(&hermes_dir, &port_id_gaia, &channel_id_gaia, &test)?; // Check the token on Namada let ibc_denom_on_namada = @@ -209,7 +219,12 @@ fn ibc_transfers() -> Result<()> { None, false, )?; - wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; + wait_for_packet_relay( + &hermes_dir, + &port_id_namada, + &channel_id_namada, + &test, + )?; // Check the balances check_balance(&test, ALBERT, &ibc_denom_on_namada, 100)?; @@ -244,10 +259,15 @@ fn ibc_transfers() -> Result<()> { 100, &port_id_gaia, &channel_id_gaia, - Some(shielding_data_path), + Some(Either::Left(shielding_data_path)), None, )?; - wait_for_packet_relay(&port_id_gaia, &channel_id_gaia, &test_gaia)?; + wait_for_packet_relay( + &hermes_dir, + &port_id_gaia, + &channel_id_gaia, + &test_gaia, + )?; // Check the token on Namada check_shielded_balance(&test, AA_VIEWING_KEY, &ibc_denom_on_namada, 100)?; check_cosmos_balance(&test_gaia, COSMOS_USER, COSMOS_COIN, 800)?; @@ -281,7 +301,12 @@ fn ibc_transfers() -> Result<()> { None, true, )?; - wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; + wait_for_packet_relay( + &hermes_dir, + &port_id_namada, + &channel_id_namada, + &test, + )?; check_shielded_balance(&test, AB_VIEWING_KEY, &ibc_denom_on_namada, 40)?; check_cosmos_balance(&test_gaia, COSMOS_USER, COSMOS_COIN, 810)?; @@ -305,10 +330,10 @@ fn ibc_transfers() -> Result<()> { 1_000_000, &port_id_gaia, &channel_id_gaia, - Some(memo_path), + Some(Either::Left(memo_path)), None, )?; - wait_for_packet_relay(&port_id_gaia, &channel_id_gaia, &test)?; + wait_for_packet_relay(&hermes_dir, &port_id_gaia, &channel_id_gaia, &test)?; // Check the token on Namada check_shielded_balance(&test, AA_VIEWING_KEY, APFEL, 1)?; @@ -330,7 +355,12 @@ fn ibc_transfers() -> Result<()> { None, false, )?; - wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; + wait_for_packet_relay( + &hermes_dir, + &port_id_namada, + &channel_id_namada, + &test, + )?; // The balance should not be changed check_balance(&test, ALBERT, APFEL, 999_999)?; @@ -357,10 +387,15 @@ fn ibc_transfers() -> Result<()> { sleep(10); // Restart relaying - let hermes = run_hermes(&test)?; + let hermes = run_hermes(&hermes_dir)?; let bg_hermes = hermes.background(); - wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; + wait_for_packet_relay( + &hermes_dir, + &port_id_namada, + &channel_id_namada, + &test, + )?; // The balance should not be changed check_balance(&test, ALBERT, &ibc_denom_on_namada, 100)?; @@ -380,7 +415,12 @@ fn ibc_transfers() -> Result<()> { None, true, )?; - wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; + wait_for_packet_relay( + &hermes_dir, + &port_id_namada, + &channel_id_namada, + &test, + )?; // Check the token has been refunded to the refund target check_shielded_balance(&test, AA_VIEWING_KEY, &ibc_denom_on_namada, 40)?; check_balance(&test, IBC_REFUND_TARGET_ALIAS, &ibc_denom_on_namada, 10)?; @@ -409,10 +449,15 @@ fn ibc_transfers() -> Result<()> { sleep(10); // Restart relaying - let hermes = run_hermes(&test)?; + let hermes = run_hermes(&hermes_dir)?; let _bg_hermes = hermes.background(); - wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; + wait_for_packet_relay( + &hermes_dir, + &port_id_namada, + &channel_id_namada, + &test, + )?; // Check the token has been refunded to the refund target check_shielded_balance(&test, AA_VIEWING_KEY, APFEL, 0)?; check_balance(&test, IBC_REFUND_TARGET_ALIAS, APFEL, 1)?; @@ -438,7 +483,12 @@ fn ibc_transfers() -> Result<()> { // MASP VP shall reject it, make it timeout Some(Duration::new(10, 0)), )?; - wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; + wait_for_packet_relay( + &hermes_dir, + &port_id_namada, + &channel_id_namada, + &test, + )?; // Check the balance didn't change check_shielded_balance(&test, AA_VIEWING_KEY, &ibc_denom_on_namada, 40)?; check_cosmos_balance(&test_gaia, COSMOS_USER, COSMOS_COIN, 810)?; @@ -462,11 +512,16 @@ fn ibc_transfers() -> Result<()> { 101, &port_id_gaia, &channel_id_gaia, - Some(shielding_data_path), + Some(Either::Left(shielding_data_path)), // MASP VP shall reject it, make it timeout Some(Duration::new(10, 0)), )?; - wait_for_packet_relay(&port_id_gaia, &channel_id_gaia, &test_gaia)?; + wait_for_packet_relay( + &hermes_dir, + &port_id_gaia, + &channel_id_gaia, + &test_gaia, + )?; // Check the balances didn't change check_shielded_balance(&test, AA_VIEWING_KEY, &ibc_denom_on_namada, 40)?; check_cosmos_balance(&test_gaia, COSMOS_USER, COSMOS_COIN, 810)?; @@ -493,7 +548,7 @@ fn ibc_nft_transfers() -> Result<()> { let _bg_ledger = ledger.background(); let _bg_wasmd = cosmwasm.background(); - setup_hermes(&test, &test_cosmwasm)?; + let hermes_dir = setup_hermes(&test, &test_cosmwasm)?; let port_id_namada: PortId = NFT_PORT_ID.parse().unwrap(); let (cw721_contract, ics721_contract) = @@ -504,6 +559,7 @@ fn ibc_nft_transfers() -> Result<()> { let port_id_cosmwasm = get_cosmwasm_port_id(&test_cosmwasm, &ics721_contract)?; let (channel_id_namada, channel_id_cosmwasm) = create_channel_with_hermes( + &hermes_dir, &test, &test_cosmwasm, &port_id_namada, @@ -528,7 +584,12 @@ fn ibc_nft_transfers() -> Result<()> { None, None, )?; - clear_packet(&port_id_cosmwasm, &channel_id_cosmwasm, &test_cosmwasm)?; + clear_packet( + &hermes_dir, + &port_id_cosmwasm, + &channel_id_cosmwasm, + &test_cosmwasm, + )?; check_balance(&test, &namada_receiver, &ibc_trace_on_namada, 1)?; // Namada to CosmWasm @@ -546,7 +607,7 @@ fn ibc_nft_transfers() -> Result<()> { None, false, )?; - clear_packet(&port_id_namada, &channel_id_namada, &test)?; + clear_packet(&hermes_dir, &port_id_namada, &channel_id_namada, &test)?; check_balance(&test, &namada_receiver, &ibc_trace_on_namada, 0)?; // 2. Shielding/Unshielding transfers @@ -572,7 +633,12 @@ fn ibc_nft_transfers() -> Result<()> { Some(shielding_data_path), None, )?; - clear_packet(&port_id_cosmwasm, &channel_id_cosmwasm, &test_cosmwasm)?; + clear_packet( + &hermes_dir, + &port_id_cosmwasm, + &channel_id_cosmwasm, + &test_cosmwasm, + )?; check_shielded_balance(&test, AA_VIEWING_KEY, &ibc_trace_on_namada, 1)?; // Shielded transfer on Namada @@ -604,7 +670,7 @@ fn ibc_nft_transfers() -> Result<()> { None, true, )?; - clear_packet(&port_id_namada, &channel_id_namada, &test)?; + clear_packet(&hermes_dir, &port_id_namada, &channel_id_namada, &test)?; check_shielded_balance(&test, AB_VIEWING_KEY, &ibc_trace_on_namada, 0)?; Ok(()) @@ -627,14 +693,15 @@ fn pgf_over_ibc() -> Result<()> { setup::set_validators(1, genesis, base_dir, |_| 0, vec![]) }; let (ledger, gaia, test, test_gaia) = - run_namada_cosmos(CosmosChainType::Gaia, update_genesis)?; + run_namada_cosmos(CosmosChainType::Gaia(None), update_genesis)?; let _bg_ledger = ledger.background(); let _bg_gaia = gaia.background(); - setup_hermes(&test, &test_gaia)?; + let hermes_dir = setup_hermes(&test, &test_gaia)?; let port_id_namada = FT_PORT_ID.parse().unwrap(); let port_id_gaia: PortId = FT_PORT_ID.parse().unwrap(); let (channel_id_namada, channel_id_gaia) = create_channel_with_hermes( + &hermes_dir, &test, &test_gaia, &port_id_namada, @@ -642,7 +709,7 @@ fn pgf_over_ibc() -> Result<()> { )?; // Start relaying - let hermes = run_hermes(&test)?; + let hermes = run_hermes(&hermes_dir)?; let _bg_hermes = hermes.background(); // Transfer to PGF account @@ -688,7 +755,12 @@ fn pgf_over_ibc() -> Result<()> { while epoch < grace_epoch { epoch = epoch_sleep(&test, &rpc, 120)?; } - wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; + wait_for_packet_relay( + &hermes_dir, + &port_id_namada, + &channel_id_namada, + &test, + )?; // Check balances after funding over IBC let token_addr = find_address(&test, NAM)?; @@ -724,7 +796,7 @@ fn fee_payment_with_ibc_token() -> Result<()> { setup::set_validators(1, genesis, base_dir, |_| 0, vec![]) }; let (ledger, gaia, test, test_gaia) = - run_namada_cosmos(CosmosChainType::Gaia, update_genesis)?; + run_namada_cosmos(CosmosChainType::Gaia(None), update_genesis)?; let _bg_ledger = ledger.background(); let _bg_gaia = gaia.background(); @@ -747,10 +819,11 @@ fn fee_payment_with_ibc_token() -> Result<()> { submit_votes(&test)?; // Create an IBC channel while waiting the grace epoch - setup_hermes(&test, &test_gaia)?; + let hermes_dir = setup_hermes(&test, &test_gaia)?; let port_id_gaia = FT_PORT_ID.parse().unwrap(); let port_id_namada = FT_PORT_ID.parse().unwrap(); let (channel_id_namada, channel_id_gaia) = create_channel_with_hermes( + &hermes_dir, &test, &test_gaia, &port_id_namada, @@ -759,7 +832,7 @@ fn fee_payment_with_ibc_token() -> Result<()> { let ibc_token_on_namada = format!("{port_id_namada}/{channel_id_namada}/{COSMOS_COIN}"); // Start relaying - let hermes = run_hermes(&test)?; + let hermes = run_hermes(&hermes_dir)?; let _bg_hermes = hermes.background(); // wait for the grace @@ -781,7 +854,7 @@ fn fee_payment_with_ibc_token() -> Result<()> { None, None, )?; - wait_for_packet_relay(&port_id_gaia, &channel_id_gaia, &test)?; + wait_for_packet_relay(&hermes_dir, &port_id_gaia, &channel_id_gaia, &test)?; // Check the token on Namada check_balance(&test, ALBERT_KEY, &ibc_token_on_namada, 250)?; @@ -830,7 +903,7 @@ fn ibc_token_inflation() -> Result<()> { setup::set_validators(1, genesis, base_dir, |_| 0, vec![]) }; let (ledger, gaia, test, test_gaia) = - run_namada_cosmos(CosmosChainType::Gaia, update_genesis)?; + run_namada_cosmos(CosmosChainType::Gaia(None), update_genesis)?; let _bg_ledger = ledger.background(); let _bg_gaia = gaia.background(); @@ -853,17 +926,18 @@ fn ibc_token_inflation() -> Result<()> { submit_votes(&test)?; // Create an IBC channel while waiting the grace epoch - setup_hermes(&test, &test_gaia)?; + let hermes_dir = setup_hermes(&test, &test_gaia)?; let port_id_namada = FT_PORT_ID.parse().unwrap(); let port_id_gaia = FT_PORT_ID.parse().unwrap(); let (channel_id_namada, channel_id_gaia) = create_channel_with_hermes( + &hermes_dir, &test, &test_gaia, &port_id_namada, &port_id_gaia, )?; // Start relaying - let hermes = run_hermes(&test)?; + let hermes = run_hermes(&hermes_dir)?; let _bg_hermes = hermes.background(); // wait for the grace @@ -893,10 +967,10 @@ fn ibc_token_inflation() -> Result<()> { 1, &port_id_gaia, &channel_id_gaia, - Some(shielding_data_path), + Some(Either::Left(shielding_data_path)), None, )?; - wait_for_packet_relay(&port_id_gaia, &channel_id_gaia, &test)?; + wait_for_packet_relay(&hermes_dir, &port_id_gaia, &channel_id_gaia, &test)?; // wait the next masp epoch to dispense the reward let mut epoch = get_epoch(&test, &rpc).unwrap(); @@ -922,14 +996,16 @@ fn ibc_upgrade_client() -> Result<()> { setup::set_validators(1, genesis, base_dir, |_| 0, vec![]) }; let (ledger, gaia, test, test_gaia) = - run_namada_cosmos(CosmosChainType::Gaia, update_genesis)?; + run_namada_cosmos(CosmosChainType::Gaia(None), update_genesis)?; let _bg_ledger = ledger.background(); let _bg_gaia = gaia.background(); + sleep(5); - setup_hermes(&test, &test_gaia)?; + let hermes_dir = setup_hermes(&test, &test_gaia)?; let port_id_namada = FT_PORT_ID.parse().unwrap(); let port_id_gaia: PortId = FT_PORT_ID.parse().unwrap(); create_channel_with_hermes( + &hermes_dir, &test, &test_gaia, &port_id_namada, @@ -954,7 +1030,7 @@ fn ibc_upgrade_client() -> Result<()> { } // Upgrade the IBC client of Gaia on Namada with Hermes - upgrade_client(&test, test.net.chain_id.to_string(), upgrade_height)?; + upgrade_client(&hermes_dir, test.net.chain_id.to_string(), upgrade_height)?; // Check the upgraded client let upgraded_client_state = @@ -993,14 +1069,15 @@ fn ibc_rate_limit() -> Result<()> { setup::set_validators(1, genesis, base_dir, |_| 0, vec![]) }; let (ledger, gaia, test, test_gaia) = - run_namada_cosmos(CosmosChainType::Gaia, update_genesis)?; + run_namada_cosmos(CosmosChainType::Gaia(None), update_genesis)?; let _bg_ledger = ledger.background(); let _bg_gaia = gaia.background(); - setup_hermes(&test, &test_gaia)?; + let hermes_dir = setup_hermes(&test, &test_gaia)?; let port_id_namada = FT_PORT_ID.parse().unwrap(); let port_id_gaia: PortId = FT_PORT_ID.parse().unwrap(); let (channel_id_namada, channel_id_gaia) = create_channel_with_hermes( + &hermes_dir, &test, &test_gaia, &port_id_namada, @@ -1008,7 +1085,7 @@ fn ibc_rate_limit() -> Result<()> { )?; // Start relaying - let hermes = run_hermes(&test)?; + let hermes = run_hermes(&hermes_dir)?; let _bg_hermes = hermes.background(); // wait for the next epoch @@ -1100,7 +1177,7 @@ fn ibc_rate_limit() -> Result<()> { None, Some(Duration::new(10, 0)), )?; - wait_for_packet_relay(&port_id_gaia, &channel_id_gaia, &test)?; + wait_for_packet_relay(&hermes_dir, &port_id_gaia, &channel_id_gaia, &test)?; // Check if Namada hasn't receive it let ibc_denom = @@ -1113,6 +1190,722 @@ fn ibc_rate_limit() -> Result<()> { Ok(()) } +/// Test the happy flows of ibc pfm +/// +/// Setup: Two instances of Gaia and one +/// Namada instance. +/// +/// 1. Test sending a transfer from first cosmos chain to the second via the PFM +/// module on Namada (henceforth denoted "via PFM") +/// 2. Test sending the above transfer back to first cosmos chain via PFM +/// 3. Send wrapped NAM from first cosmos chain to the second via PFM +/// 4. Reverse the transaction in the step above +#[test] +fn ibc_pfm_happy_flows() -> Result<()> { + let update_genesis = + |mut genesis: templates::All, base_dir: &_| { + genesis.parameters.parameters.epochs_per_year = + epochs_per_year_from_min_duration(1800); + genesis.parameters.ibc_params.default_mint_limit = + Amount::max_signed(); + genesis + .parameters + .ibc_params + .default_per_epoch_throughput_limit = Amount::max_signed(); + setup::set_validators(1, genesis, base_dir, |_| 0, vec![]) + }; + let (ledger, gaia_1, test, test_gaia_1) = + run_namada_cosmos(CosmosChainType::Gaia(Some(1)), update_genesis)?; + + // set up a second cosmos network + let test_gaia_2 = setup_cosmos(CosmosChainType::Gaia(Some(2)))?; + let gaia_2 = run_cosmos(&test_gaia_2, false)?; + sleep(5); + + let _bg_ledger = ledger.background(); + let _bg_gaia_1 = gaia_1.background(); + let _bg_gaia_2 = gaia_2.background(); + let hermes_gaia1_namada = setup_hermes(&test, &test_gaia_1)?; + let hermes_namada_gaia2 = setup_hermes(&test, &test_gaia_2)?; + sleep(5); + // create hermes relayers for connections between both cosmos chains and + // namada + let port_id_namada = FT_PORT_ID.parse().unwrap(); + let port_id_gaia_1 = FT_PORT_ID.parse().unwrap(); + let port_id_gaia_2 = FT_PORT_ID.parse().unwrap(); + + let (channel_id_gaia_1, channel_id_namada_1) = create_channel_with_hermes( + &hermes_gaia1_namada, + &test_gaia_1, + &test, + &port_id_namada, + &port_id_gaia_1, + )?; + let (channel_id_gaia_2, channel_id_namada_2) = create_channel_with_hermes( + &hermes_namada_gaia2, + &test_gaia_2, + &test, + &port_id_namada, + &port_id_gaia_2, + )?; + + // Start relaying + let hermes_1 = run_hermes(&hermes_gaia1_namada)?; + let hermes_2 = run_hermes(&hermes_namada_gaia2)?; + let _bg_hermes_1 = hermes_1.background(); + let _bg_hermes_2 = hermes_2.background(); + + // ------------------- Step 1. ------------------- + + // Bertha is our most trusted intermediary in all things + let namada_receiver = find_address(&test, BERTHA)?.to_string(); + // this will cause the ibc packet to be forwarded to the second + // cosmos chain. + let pfm_memo = packet_forward_memo( + find_cosmos_address(&test_gaia_2, COSMOS_USER)?.into(), + &port_id_namada, + &channel_id_namada_2, + None, + ); + transfer_from_cosmos( + &test_gaia_1, + COSMOS_USER, + &namada_receiver, + "samoleans", + 10, + &port_id_gaia_1, + &channel_id_gaia_1, + Some(Either::Right(pfm_memo)), + None, + )?; + wait_for_packet_relay( + &hermes_gaia1_namada, + &port_id_namada, + &channel_id_namada_1, + &test, + )?; + wait_for_packet_relay( + &hermes_namada_gaia2, + &port_id_gaia_2, + &channel_id_gaia_2, + &test_gaia_2, + )?; + // Check the samoleans have been received on the second cosmos chain + check_cosmos_balance( + &test_gaia_2, + COSMOS_USER, + format!( + "transfer/{channel_id_gaia_2}/transfer/{channel_id_namada_1}/\ + samoleans" + ), + 10, + )?; + + // Check the samoleans have been sent from the first cosmos chain + check_cosmos_balance(&test_gaia_1, COSMOS_USER, "samoleans", 1000 - 10)?; + + // ------------------- Step 2. ------------------- + + // this will cause the ibc packet to be forwarded to the first + // cosmos chain. + let pfm_memo = packet_forward_memo( + find_cosmos_address(&test_gaia_1, COSMOS_USER)?.into(), + &port_id_namada, + &channel_id_namada_1, + None, + ); + transfer_from_cosmos( + &test_gaia_2, + COSMOS_USER, + &namada_receiver, + format!( + "transfer/{channel_id_gaia_2}/transfer/{channel_id_namada_1}/\ + samoleans" + ), + 10, + &port_id_gaia_1, + &channel_id_gaia_1, + Some(Either::Right(pfm_memo)), + None, + )?; + + wait_for_packet_relay( + &hermes_namada_gaia2, + &port_id_namada, + &channel_id_namada_2, + &test, + )?; + wait_for_packet_relay( + &hermes_gaia1_namada, + &port_id_gaia_1, + &channel_id_gaia_1, + &test_gaia_1, + )?; + + // Check the samoleans have been received on the fist cosmos chain + check_cosmos_balance(&test_gaia_1, COSMOS_USER, "samoleans", 1000)?; + + // ------------------- Step 3. ------------------- + let nam_addr = find_address(&test, NAM)?; + // we first send some NAM to the first cosmos chain. + let gaia_receiver = find_cosmos_address(&test_gaia_1, COSMOS_USER)?; + transfer( + &test, + BERTHA, + gaia_receiver, + NAM, + 20, + Some(BERTHA_KEY), + &port_id_namada, + &channel_id_namada_1, + None, + None, + None, + false, + )?; + + wait_for_packet_relay( + &hermes_gaia1_namada, + &port_id_gaia_1, + &channel_id_gaia_1, + &test_gaia_1, + )?; + + // Check the NAM have been sent to the first cosmos chain + check_cosmos_balance( + &test_gaia_1, + COSMOS_USER, + format!("transfer/{channel_id_gaia_1}/{nam_addr}"), + 20_000_000, + )?; + + // this will cause the ibc packet to be forwarded to the second + // cosmos chain. + let pfm_memo = packet_forward_memo( + find_cosmos_address(&test_gaia_2, COSMOS_USER)?.into(), + &port_id_namada, + &channel_id_namada_2, + None, + ); + + transfer_from_cosmos( + &test_gaia_1, + COSMOS_USER, + &namada_receiver, + format!("transfer/{channel_id_gaia_1}/{nam_addr}"), + 10_000_000, + &port_id_gaia_1, + &channel_id_gaia_1, + Some(Either::Right(pfm_memo)), + None, + )?; + wait_for_packet_relay( + &hermes_gaia1_namada, + &port_id_namada, + &channel_id_namada_1, + &test, + )?; + wait_for_packet_relay( + &hermes_namada_gaia2, + &port_id_gaia_2, + &channel_id_gaia_2, + &test_gaia_2, + )?; + // Check the NAM have been received on the second cosmos chain + check_cosmos_balance( + &test_gaia_2, + COSMOS_USER, + format!("transfer/{channel_id_gaia_2}/{nam_addr}"), + 10_000_000, + )?; + + // Check the NAM have been sent from the first cosmos chain + check_cosmos_balance( + &test_gaia_1, + COSMOS_USER, + format!("transfer/{channel_id_gaia_1}/{nam_addr}"), + 20_000_000 - 10_000_000, + )?; + + // ------------------- Step 4. ------------------- + + // this will cause the ibc packet to be forwarded to the first + // cosmos chain. + let pfm_memo = packet_forward_memo( + find_cosmos_address(&test_gaia_1, COSMOS_USER)?.into(), + &port_id_namada, + &channel_id_namada_1, + None, + ); + transfer_from_cosmos( + &test_gaia_2, + COSMOS_USER, + &namada_receiver, + format!("transfer/{channel_id_gaia_2}/{nam_addr}"), + 10_000_000, + &port_id_gaia_1, + &channel_id_gaia_1, + Some(Either::Right(pfm_memo)), + None, + )?; + + wait_for_packet_relay( + &hermes_namada_gaia2, + &port_id_namada, + &channel_id_namada_2, + &test, + )?; + wait_for_packet_relay( + &hermes_gaia1_namada, + &port_id_gaia_1, + &channel_id_gaia_1, + &test_gaia_1, + )?; + + // Check the NAM have been received on the first cosmos chain + check_cosmos_balance( + &test_gaia_1, + COSMOS_USER, + format!("transfer/{channel_id_gaia_1}/{nam_addr}"), + 20_000_000, + )?; + + Ok(()) +} +/// Test the flows of ibc pfm where the packet cannot be +/// completed and refunds must be issued. +/// +/// Setup: Two instances of Gaia and one +/// Namada instance. +/// +/// 1. Test sending a transfer from first cosmos chain to the second via the PFM +/// module on Namada (henceforth denoted "via PFM"), failing on the second +/// cosmos chain due to an error. +/// 2. Same as above except that the failure occurs due to a time-out on the +/// second cosmos chain. +/// 3. Same as the first except that wrapped NAM is sent from the first cosmos +/// chain +/// 4. Same as above except that the failure occurs due to a time-out on the +/// second cosmos chain. +/// 5. Test sending assets from the second cosmos network to the first and then +/// failing to send it back to the second due to an error +/// 6. Same as above except that the failure occurs due to a time-out on the +/// second cosmos chain. +#[test] +fn ibc_pfm_unhappy_flows() -> Result<()> { + let update_genesis = + |mut genesis: templates::All, base_dir: &_| { + genesis.parameters.parameters.epochs_per_year = + epochs_per_year_from_min_duration(1800); + genesis.parameters.ibc_params.default_mint_limit = + Amount::max_signed(); + genesis + .parameters + .ibc_params + .default_per_epoch_throughput_limit = Amount::max_signed(); + setup::set_validators(1, genesis, base_dir, |_| 0, vec![]) + }; + let (ledger, gaia_1, test, test_gaia_1) = + run_namada_cosmos(CosmosChainType::Gaia(Some(1)), update_genesis)?; + + // set up a second cosmos network + let test_gaia_2 = setup_cosmos(CosmosChainType::Gaia(Some(2)))?; + let gaia_2 = run_cosmos(&test_gaia_2, false)?; + sleep(5); + + let _bg_ledger = ledger.background(); + let _bg_gaia_1 = gaia_1.background(); + let _bg_gaia_2 = gaia_2.background(); + let hermes_gaia1_namada = setup_hermes(&test, &test_gaia_1)?; + let hermes_namada_gaia2 = setup_hermes(&test, &test_gaia_2)?; + sleep(5); + // create hermes relayers for connections between both cosmos chains and + // namada + let port_id_namada = FT_PORT_ID.parse().unwrap(); + let port_id_gaia_1 = FT_PORT_ID.parse().unwrap(); + let port_id_gaia_2 = FT_PORT_ID.parse().unwrap(); + + let (channel_id_gaia_1, channel_id_namada_1) = create_channel_with_hermes( + &hermes_gaia1_namada, + &test_gaia_1, + &test, + &port_id_namada, + &port_id_gaia_1, + )?; + let (channel_id_gaia_2, channel_id_namada_2) = create_channel_with_hermes( + &hermes_namada_gaia2, + &test_gaia_2, + &test, + &port_id_namada, + &port_id_gaia_2, + )?; + + // Start relaying + let hermes_1 = run_hermes(&hermes_gaia1_namada)?; + let hermes_2 = run_hermes(&hermes_namada_gaia2)?; + let _bg_hermes_1 = hermes_1.background(); + let bg_hermes_2 = hermes_2.background(); + + // ------------------- Step 1. ------------------- + + // Bertha is our most trusted intermediary in all things + let namada_receiver = find_address(&test, BERTHA)?.to_string(); + // this will cause the ibc packet to be forwarded to the second + // cosmos chain. + let pfm_memo = packet_forward_memo( + // NB: since the receiver is invalid, the ICS-20 + // transfer will fail, and the first cosmos chain + // will receive an ack error + "Hodor".to_string().into(), + &port_id_namada, + &channel_id_namada_2, + None, + ); + transfer_from_cosmos( + &test_gaia_1, + COSMOS_USER, + &namada_receiver, + "samoleans", + 10, + &port_id_gaia_1, + &channel_id_gaia_1, + Some(Either::Right(pfm_memo)), + None, + )?; + wait_for_packet_relay( + &hermes_gaia1_namada, + &port_id_namada, + &channel_id_namada_1, + &test, + )?; + wait_for_packet_relay( + &hermes_namada_gaia2, + &port_id_gaia_2, + &channel_id_gaia_2, + &test_gaia_2, + )?; + + // Check the samoleans have been refunded on the first chain + check_cosmos_balance(&test_gaia_1, COSMOS_USER, "samoleans", 1000)?; + + // ------------------- Step 2. ------------------- + + let pfm_memo = packet_forward_memo( + find_cosmos_address(&test_gaia_1, COSMOS_USER)?.into(), + &port_id_namada, + &channel_id_namada_2, + Some(Duration::new(1, 0)), + ); + // Stop Hermes for timeout test + let mut hermes_2 = bg_hermes_2.foreground(); + hermes_2.interrupt()?; + + transfer_from_cosmos( + &test_gaia_1, + COSMOS_USER, + &namada_receiver, + "samoleans", + 10, + &port_id_gaia_1, + &channel_id_gaia_1, + Some(Either::Right(pfm_memo)), + None, + )?; + + // wait for the timeout + sleep(10); + + // Restart relaying + let hermes_2 = run_hermes(&hermes_namada_gaia2)?; + let bg_hermes_2 = hermes_2.background(); + + wait_for_packet_relay( + &hermes_gaia1_namada, + &port_id_namada, + &channel_id_namada_1, + &test, + )?; + wait_for_packet_relay( + &hermes_namada_gaia2, + &port_id_gaia_2, + &channel_id_gaia_2, + &test_gaia_2, + )?; + + // Check the samoleans have been refunded on the first chain + check_cosmos_balance(&test_gaia_1, COSMOS_USER, "samoleans", 1000)?; + + // ------------------- Step 3. ------------------- + + let nam_addr = find_address(&test, NAM)?; + // we first send some NAM to the first cosmos chain. + let gaia_receiver = find_cosmos_address(&test_gaia_1, COSMOS_USER)?; + transfer( + &test, + BERTHA, + gaia_receiver, + NAM, + 20, + Some(BERTHA_KEY), + &port_id_namada, + &channel_id_namada_1, + None, + None, + None, + false, + )?; + + wait_for_packet_relay( + &hermes_gaia1_namada, + &port_id_gaia_1, + &channel_id_gaia_1, + &test_gaia_1, + )?; + + // Check the NAM have been sent to the first cosmos chain + check_cosmos_balance( + &test_gaia_1, + COSMOS_USER, + format!("transfer/{channel_id_gaia_1}/{nam_addr}"), + 20_000_000, + )?; + + // this will cause the ibc packet to be forwarded to the second + // cosmos chain. + let pfm_memo = packet_forward_memo( + "Hodor".to_string().into(), + &port_id_namada, + &channel_id_namada_2, + None, + ); + transfer_from_cosmos( + &test_gaia_1, + COSMOS_USER, + &namada_receiver, + format!("transfer/{channel_id_gaia_1}/{nam_addr}"), + 10_000_000, + &port_id_gaia_1, + &channel_id_gaia_1, + Some(Either::Right(pfm_memo)), + None, + )?; + wait_for_packet_relay( + &hermes_gaia1_namada, + &port_id_namada, + &channel_id_namada_1, + &test, + )?; + wait_for_packet_relay( + &hermes_namada_gaia2, + &port_id_gaia_2, + &channel_id_gaia_2, + &test_gaia_2, + )?; + + // Check the NAM have been refunded on the first chain + check_cosmos_balance( + &test_gaia_1, + COSMOS_USER, + format!("transfer/{channel_id_gaia_1}/{nam_addr}"), + 20_000_000, + )?; + + // ------------------- Step 4. ------------------- + + let pfm_memo = packet_forward_memo( + find_cosmos_address(&test_gaia_2, COSMOS_USER)?.into(), + &port_id_namada, + &channel_id_namada_2, + Some(Duration::new(1, 0)), + ); + // Stop Hermes for timeout test + let mut hermes_2 = bg_hermes_2.foreground(); + hermes_2.interrupt()?; + + transfer_from_cosmos( + &test_gaia_1, + COSMOS_USER, + &namada_receiver, + format!("transfer/{channel_id_gaia_1}/{nam_addr}"), + 10_000_000, + &port_id_gaia_1, + &channel_id_gaia_1, + Some(Either::Right(pfm_memo)), + None, + )?; + + // wait for the timeout + sleep(10); + + // Restart relaying + let hermes_2 = run_hermes(&hermes_namada_gaia2)?; + let bg_hermes_2 = hermes_2.background(); + + wait_for_packet_relay( + &hermes_gaia1_namada, + &port_id_namada, + &channel_id_namada_1, + &test, + )?; + wait_for_packet_relay( + &hermes_namada_gaia2, + &port_id_gaia_2, + &channel_id_gaia_2, + &test_gaia_2, + )?; + + // Check the NAM have been refunded on the first chain + check_cosmos_balance( + &test_gaia_1, + COSMOS_USER, + format!("transfer/{channel_id_gaia_1}/{nam_addr}"), + 20_000_000, + )?; + + // ------------------- Step 5. ------------------- + + // we first send some samoleans to the first cosmos chain from the second. + let pfm_memo = packet_forward_memo( + find_cosmos_address(&test_gaia_1, COSMOS_USER)?.into(), + &port_id_namada, + &channel_id_namada_1, + None, + ); + transfer_from_cosmos( + &test_gaia_2, + COSMOS_USER, + &namada_receiver, + "samoleans", + 10, + &port_id_gaia_2, + &channel_id_gaia_2, + Some(Either::Right(pfm_memo)), + None, + )?; + + wait_for_packet_relay( + &hermes_gaia1_namada, + &port_id_gaia_1, + &channel_id_gaia_1, + &test_gaia_1, + )?; + + // Check the non-native samoleans have been sent to the first cosmos chain + check_cosmos_balance( + &test_gaia_1, + COSMOS_USER, + format!( + "transfer/{channel_id_gaia_1}/transfer/{channel_id_namada_2}/\ + samoleans" + ), + 10, + )?; + + // this will cause the ibc packet to be forwarded to the second + // cosmos chain. + let pfm_memo = packet_forward_memo( + "Hodor".to_string().into(), + &port_id_namada, + &channel_id_namada_2, + None, + ); + transfer_from_cosmos( + &test_gaia_1, + COSMOS_USER, + &namada_receiver, + format!( + "transfer/{channel_id_gaia_1}/transfer/{channel_id_namada_2}/\ + samoleans" + ), + 10, + &port_id_gaia_1, + &channel_id_gaia_1, + Some(Either::Right(pfm_memo)), + None, + )?; + wait_for_packet_relay( + &hermes_gaia1_namada, + &port_id_namada, + &channel_id_namada_1, + &test, + )?; + wait_for_packet_relay( + &hermes_namada_gaia2, + &port_id_gaia_2, + &channel_id_gaia_2, + &test_gaia_2, + )?; + + // Check the non-native samoleans have been refunded on the first chain + check_cosmos_balance( + &test_gaia_1, + COSMOS_USER, + format!( + "transfer/{channel_id_gaia_1}/transfer/{channel_id_namada_2}/\ + samoleans" + ), + 10, + )?; + + // ------------------- Step 6. ------------------- + let pfm_memo = packet_forward_memo( + find_cosmos_address(&test_gaia_2, COSMOS_USER)?.into(), + &port_id_namada, + &channel_id_namada_2, + Some(Duration::new(1, 0)), + ); + // Stop Hermes for timeout test + let mut hermes_2 = bg_hermes_2.foreground(); + hermes_2.interrupt()?; + + transfer_from_cosmos( + &test_gaia_1, + COSMOS_USER, + &namada_receiver, + format!( + "transfer/{channel_id_gaia_1}/transfer/{channel_id_namada_2}/\ + samoleans" + ), + 10, + &port_id_gaia_1, + &channel_id_gaia_1, + Some(Either::Right(pfm_memo)), + None, + )?; + + // wait for the timeout + sleep(10); + + // Restart relaying + let hermes_2 = run_hermes(&hermes_namada_gaia2)?; + let _bg_hermes_2 = hermes_2.background(); + + wait_for_packet_relay( + &hermes_gaia1_namada, + &port_id_namada, + &channel_id_namada_1, + &test, + )?; + wait_for_packet_relay( + &hermes_namada_gaia2, + &port_id_gaia_2, + &channel_id_gaia_2, + &test_gaia_2, + )?; + + // Check the non-native samoleans have been refunded on the first chain + check_cosmos_balance( + &test_gaia_1, + COSMOS_USER, + format!( + "transfer/{channel_id_gaia_1}/transfer/{channel_id_namada_2}/\ + samoleans" + ), + 10, + )?; + Ok(()) +} + fn run_namada_cosmos( chain_type: CosmosChainType, mut update_genesis: impl FnMut( @@ -1134,13 +1927,14 @@ fn run_namada_cosmos( // Cosmos let test_cosmos = setup_cosmos(chain_type)?; - let cosmos = run_cosmos(&test_cosmos)?; + let cosmos = run_cosmos(&test_cosmos, true)?; sleep(5); Ok((ledger, cosmos, test, test_cosmos)) } fn create_channel_with_hermes( + hermes_dir: &TestDir, test_a: &Test, test_b: &Test, port_id_a: &PortId, @@ -1170,7 +1964,7 @@ fn create_channel_with_hermes( "--yes", ]; - let mut hermes = run_hermes_cmd(test_a, args, Some(240))?; + let mut hermes = run_hermes_cmd(hermes_dir, args, Some(240))?; let (channel_id_a, channel_id_b) = get_channel_ids_from_hermes_output(&mut hermes)?; hermes.assert_success(); @@ -1192,35 +1986,32 @@ fn get_channel_ids_from_hermes_output( Ok((channel_id_a, channel_id_b)) } -fn run_hermes(test: &Test) -> Result { +fn run_hermes(hermes_dir: &TestDir) -> Result { let args = ["start"]; - let mut hermes = run_hermes_cmd(test, args, Some(40))?; + let mut hermes = run_hermes_cmd(hermes_dir, args, Some(40))?; hermes.exp_string("Hermes has started")?; Ok(hermes) } -fn run_cosmos(test: &Test) -> Result { +fn run_cosmos(test: &Test, kill: bool) -> Result { let chain_type = CosmosChainType::chain_type(test.net.chain_id.as_str())?; let cmd_path = chain_type.command_path(); // cosmos process is sometimes left lingering causing subsequent runs to // fail - std::process::Command::new("pkill") - .args(["-9", cmd_path]) - .output() - .unwrap(); - - let args = [ - "start", - "--pruning", - "nothing", - "--grpc.address", - "0.0.0.0:9090", - ]; + if kill { + std::process::Command::new("pkill") + .args(["-9", cmd_path]) + .output() + .unwrap(); + } + let port_arg = format!("0.0.0.0:{}", 9090 + chain_type.get_offset()); + let args = ["start", "--pruning", "nothing", "--grpc.address", &port_arg]; let cosmos = run_cosmos_cmd(test, args, Some(40))?; Ok(cosmos) } fn wait_for_packet_relay( + hermes_dir: &TestDir, port_id: &PortId, channel_id: &ChannelId, test: &Test, @@ -1239,7 +2030,7 @@ fn wait_for_packet_relay( ]; for _ in 0..10 { sleep(10); - let mut hermes = run_hermes_cmd(test, args, Some(40))?; + let mut hermes = run_hermes_cmd(hermes_dir, args, Some(40))?; // Check no pending packet if hermes .exp_string( @@ -1260,6 +2051,7 @@ fn wait_for_packet_relay( } fn clear_packet( + hermes_dir: &TestDir, port_id: &PortId, channel_id: &ChannelId, test: &Test, @@ -1274,14 +2066,14 @@ fn clear_packet( "--channel", channel_id.as_str(), ]; - let mut hermes = run_hermes_cmd(test, args, Some(40))?; + let mut hermes = run_hermes_cmd(hermes_dir, args, Some(40))?; hermes.assert_success(); Ok(()) } fn upgrade_client( - test: &Test, + hermes_dir: &TestDir, host_chain_id: impl AsRef, upgrade_height: u64, ) -> Result<()> { @@ -1295,7 +2087,7 @@ fn upgrade_client( "--upgrade-height", &upgrade_height.to_string(), ]; - let mut hermes = run_hermes_cmd(test, args, Some(120))?; + let mut hermes = run_hermes_cmd(hermes_dir, args, Some(120))?; hermes.exp_string("upgraded-chain")?; hermes.assert_success(); @@ -1674,7 +2466,7 @@ fn propose_upgrade_client( let proposal_json_path = test_gaia.test_dir.path().join("proposal.json"); write_json_file(proposal_json_path.as_path(), proposal_json); - let rpc = format!("tcp://{COSMOS_RPC}"); + let rpc = format!("tcp://{}", get_cosmos_rpc_address(test_gaia)); let submit_proposal_args = vec![ "tx", "gov", @@ -1744,7 +2536,8 @@ fn propose_gas_token(test: &Test) -> Result { } fn wait_for_pass(test: &Test) -> Result<()> { - let args = ["query", "gov", "proposal", "1"]; + let rpc = format!("tcp://{}", get_cosmos_rpc_address(test)); + let args = ["query", "gov", "proposal", "1", "--node", &rpc]; for _ in 0..10 { sleep(5); let mut gaia = run_cosmos_cmd(test, args, Some(40))?; @@ -1757,7 +2550,7 @@ fn wait_for_pass(test: &Test) -> Result<()> { } fn vote_on_gaia(test: &Test) -> Result<()> { - let rpc = format!("tcp://{COSMOS_RPC}"); + let rpc = format!("tcp://{}", get_cosmos_rpc_address(test)); let args = vec![ "tx", "gov", @@ -1833,13 +2626,16 @@ fn transfer_from_cosmos( amount: u64, port_id: &PortId, channel_id: &ChannelId, - memo_path: Option, + memo: Option>, timeout_sec: Option, ) -> Result<()> { let port_id = port_id.to_string(); let channel_id = channel_id.to_string(); let amount = format!("{}{}", amount, token.as_ref()); - let rpc = format!("tcp://{COSMOS_RPC}"); + let offset = CosmosChainType::chain_type(test.net.chain_id.as_str()) + .unwrap() + .get_offset(); + let rpc = format!("tcp://127.0.0.1:6416{offset}"); // If the receiver is a pyament address we want to mask it to the more // general MASP internal address to improve on privacy let receiver = match PaymentAddress::from_str(receiver.as_ref()) { @@ -1867,13 +2663,16 @@ fn transfer_from_cosmos( "--yes", ]; - let memo = memo_path - .as_ref() - .map(|path| { - std::fs::read_to_string(path).expect("Reading memo file failed") + let is_memo = memo.is_some(); + let memo = memo + .map(|m| match m { + Either::Left(path) => { + std::fs::read_to_string(path).expect("Reading memo file failed") + } + Either::Right(memo) => memo, }) .unwrap_or_default(); - if memo_path.is_some() { + if is_memo { args.push("--memo"); args.push(&memo); } @@ -1914,7 +2713,10 @@ fn check_tx_height(test: &Test, client: &mut NamadaCmd) -> Result { } fn query_height(test: &Test) -> Result { - let rpc = get_actor_rpc(test, Who::Validator(0)); + let rpc = match CosmosChainType::chain_type(test.net.chain_id.as_str()) { + Ok(_) => format!("http://{}", get_cosmos_rpc_address(test)), + Err(_) => get_actor_rpc(test, Who::Validator(0)), + }; let tendermint_url = Url::from_str(&rpc).unwrap(); let client = HttpClient::new(tendermint_url).unwrap(); @@ -1992,14 +2794,11 @@ fn check_cosmos_balance( expected_amount: u64, ) -> Result<()> { let addr = find_cosmos_address(test, owner)?; - let args = [ - "query", - "bank", - "balances", - &addr, - "--node", - &format!("tcp://{COSMOS_RPC}"), - ]; + let offset = CosmosChainType::chain_type(test.net.chain_id.as_str()) + .unwrap() + .get_offset(); + let rpc = format!("tcp://127.0.0.1:6416{offset}"); + let args = ["query", "bank", "balances", &addr, "--node", &rpc]; let mut cosmos = run_cosmos_cmd(test, args, Some(40))?; cosmos.exp_string(&format!("amount: \"{expected_amount}\""))?; let expected_denom = if denom.as_ref().contains('/') { @@ -2098,9 +2897,9 @@ fn initialize_nft_contracts(test: &Test) -> Result<(String, String)> { Ok(dir) => PathBuf::from(dir), Err(_) => working_dir(), }; - let rpc = format!("tcp://{COSMOS_RPC}"); + let rpc = format!("tcp://{}", get_cosmos_rpc_address(test)); let minter_addr = find_cosmos_address(test, COSMOS_USER)?; - + sleep(5); // Store cw721 contract let cw721_wasm_path = contract_dir.join(CW721_WASM).to_string_lossy().to_string(); @@ -2127,7 +2926,7 @@ fn initialize_nft_contracts(test: &Test) -> Result<(String, String)> { ]; let mut cosmos = run_cosmos_cmd(test, args, Some(40))?; cosmos.exp_eof()?; - sleep(1); + sleep(5); // Store ics721 contract let ics721_wasm_path = @@ -2157,10 +2956,6 @@ fn initialize_nft_contracts(test: &Test) -> Result<(String, String)> { cosmos.exp_eof()?; sleep(1); - let args = vec!["query", "wasm", "list-code"]; - let mut cosmos = run_cosmos_cmd(test, args, Some(40))?; - cosmos.assert_success(); - // Instantiate cw721 contract let json = serde_json::json!({ "name": "test_nft", @@ -2229,17 +3024,32 @@ fn initialize_nft_contracts(test: &Test) -> Result<(String, String)> { ]; let mut cosmos = run_cosmos_cmd(test, args, Some(40))?; cosmos.exp_eof()?; + sleep(1); // Check the CW721 contract - let args = vec!["query", "wasm", "list-contract-by-code", "1"]; + let args = vec![ + "query", + "wasm", + "list-contract-by-code", + "1", + "--node", + &rpc, + ]; let mut cosmos = run_cosmos_cmd(test, args, Some(40))?; let (_unread, matched) = cosmos.exp_regex("wasm.*")?; let cw721_contract = matched.trim().to_string(); cosmos.exp_eof()?; // Check the ICS721 contract - let args = vec!["query", "wasm", "list-contract-by-code", "2"]; + let args = vec![ + "query", + "wasm", + "list-contract-by-code", + "2", + "--node", + &rpc, + ]; let mut cosmos = run_cosmos_cmd(test, args, Some(40))?; let (_unread, matched) = cosmos.exp_regex("wasm.*")?; let ics721_contract = matched.trim().to_string(); @@ -2249,8 +3059,10 @@ fn initialize_nft_contracts(test: &Test) -> Result<(String, String)> { } fn get_cosmwasm_port_id(test: &Test, ics721_contract: &str) -> Result { + let rpc = format!("tcp://{}", get_cosmos_rpc_address(test)); // Get the port ID - let args = vec!["query", "wasm", "contract", ics721_contract]; + let args = + vec!["query", "wasm", "contract", ics721_contract, "--node", &rpc]; let mut cosmos = run_cosmos_cmd(test, args, Some(40))?; let (_unread, matched) = cosmos.exp_regex("ibc_port_id: wasm.*")?; let port_id = matched.trim().split(' ').last().expect("invalid output"); @@ -2266,7 +3078,7 @@ fn mint_nft( minter_addr: &str, token_id: &str, ) -> Result<()> { - let rpc = format!("tcp://{COSMOS_RPC}"); + let rpc = format!("tcp://{}", get_cosmos_rpc_address(test)); // Mint an NFT let json = serde_json::json!({ @@ -2319,7 +3131,7 @@ fn nft_transfer_from_cosmos( ) -> Result<()> { let channel_id = channel_id.to_string(); let timeout_height = timeout_height.unwrap_or(100000); - let rpc = format!("tcp://{COSMOS_RPC}"); + let rpc = format!("tcp://{}", get_cosmos_rpc_address(test)); let receiver = match PaymentAddress::from_str(receiver.as_ref()) { Ok(_) => MASP.to_string(), @@ -2382,3 +3194,27 @@ fn nft_transfer_from_cosmos( Ok(()) } + +/// Create a packet forward memo and serialize it +fn packet_forward_memo( + receiver: Signer, + port_id: &PortId, + channel_id: &ChannelId, + timeout: Option, +) -> String { + serde_json::to_string(&ibc_middleware_packet_forward::PacketMetadata { + forward: ForwardMetadata { + receiver, + port: port_id.clone(), + channel: channel_id.clone(), + timeout: timeout.map(|t| { + ibc_middleware_packet_forward::Duration::from_dur( + dur::Duration::from_std(t), + ) + }), + retries: Some(0), + next: None, + }, + }) + .expect("Test failed") +} diff --git a/crates/tests/src/e2e/setup.rs b/crates/tests/src/e2e/setup.rs index d7c9a663e9..d0bdb14f80 100644 --- a/crates/tests/src/e2e/setup.rs +++ b/crates/tests/src/e2e/setup.rs @@ -1239,10 +1239,12 @@ pub fn sleep(seconds: u64) { thread::sleep(time::Duration::from_secs(seconds)); } -pub fn setup_hermes(test_a: &Test, test_b: &Test) -> Result<()> { +pub fn setup_hermes(test_a: &Test, test_b: &Test) -> Result { + let hermes_dir = TestDir::new(); + println!("\n{}", "Setting up Hermes".underline().green(),); - make_hermes_config(test_a, test_b)?; + make_hermes_config(&hermes_dir, test_a, test_b)?; for test in [test_a, test_b] { let chain_id = test.net.chain_id.as_str(); @@ -1255,20 +1257,24 @@ pub fn setup_hermes(test_a: &Test, test_b: &Test) -> Result<()> { let args = [ "keys", "add", + // TODO: this overwrite is required because hermes keys are pulled + // from the namada chain dir... however, ideally we would store the + // `wallet.toml` file under hermes' own dir + "--overwrite", "--chain", chain_id, "--key-file", &key_file_path.to_string_lossy(), ]; - let mut hermes = run_hermes_cmd(test, args, Some(20))?; + let mut hermes = run_hermes_cmd(&hermes_dir, args, Some(20))?; hermes.assert_success(); } - Ok(()) + Ok(hermes_dir) } pub fn run_hermes_cmd( - test: &Test, + hermes_dir: &TestDir, args: I, timeout_sec: Option, ) -> Result @@ -1277,7 +1283,8 @@ where S: AsRef, { let mut run_cmd = Command::new("hermes"); - let hermes_dir = test.test_dir.as_ref().join("hermes"); + let hermes_dir: &Path = hermes_dir.as_ref(); + let hermes_dir = hermes_dir.join("hermes"); run_cmd.current_dir(hermes_dir.clone()); let config_path = hermes_dir.join("config.toml"); run_cmd.args(["--config", &config_path.to_string_lossy()]); @@ -1300,7 +1307,7 @@ where let log_path = { let mut rng = rand::thread_rng(); - let log_dir = test.get_base_dir(Who::NonValidator).join("logs"); + let log_dir = hermes_dir.join("logs"); std::fs::create_dir_all(&log_dir)?; log_dir.join(format!( "{}-hermes-{}.log", @@ -1332,46 +1339,63 @@ where #[derive(Clone, Copy, Debug)] pub enum CosmosChainType { - Gaia, + Gaia(Option), CosmWasm, } impl CosmosChainType { - pub fn chain_id(&self) -> &str { + pub fn chain_id(&self) -> String { match self { - Self::Gaia => constants::GAIA_CHAIN_ID, - Self::CosmWasm => constants::COSMWASM_CHAIN_ID, + Self::Gaia(Some(suffix)) => { + format!("{}{}", constants::GAIA_CHAIN_ID, suffix) + } + Self::Gaia(_) => constants::GAIA_CHAIN_ID.to_string(), + Self::CosmWasm => constants::COSMWASM_CHAIN_ID.to_string(), } } pub fn command_path(&self) -> &str { match self { - Self::Gaia => "gaiad", + Self::Gaia(_) => "gaiad", Self::CosmWasm => "wasmd", } } pub fn chain_type(chain_id: &str) -> Result { - match chain_id { - constants::GAIA_CHAIN_ID => Ok(Self::Gaia), - constants::COSMWASM_CHAIN_ID => Ok(Self::CosmWasm), - _ => Err(eyre!(format!("Unexpected Cosmos chain ID: {chain_id}"))), + if chain_id == constants::COSMWASM_CHAIN_ID { + return Ok(Self::CosmWasm); + } + match chain_id.strip_prefix(constants::GAIA_CHAIN_ID) { + Some("") => Ok(Self::Gaia(None)), + Some(suffix) => { + Ok(Self::Gaia(Some(suffix.parse().map_err(|_| { + eyre!("Unexpected Cosmos chain ID: {chain_id}") + })?))) + } + _ => Err(eyre!("Unexpected Cosmos chain ID: {chain_id}")), } } pub fn account_prefix(&self) -> &str { match self { - Self::Gaia => "cosmos", + Self::Gaia(_) => "cosmos", Self::CosmWasm => "wasm", } } + + pub fn get_offset(&self) -> u64 { + match self { + Self::Gaia(Some(off)) => *off, + _ => 0, + } + } } pub fn setup_cosmos(chain_type: CosmosChainType) -> Result { let working_dir = working_dir(); let test_dir = TestDir::new(); let chain_id = chain_type.chain_id(); - let cosmos_dir = test_dir.as_ref().join(chain_id); + let cosmos_dir = test_dir.as_ref().join(&chain_id); let net = Network { chain_id: ChainId(chain_id.to_string()), }; @@ -1383,7 +1407,7 @@ pub fn setup_cosmos(chain_type: CosmosChainType) -> Result { }; // initialize - let args = ["--chain-id", chain_id, "init", chain_id]; + let args = ["--chain-id", &chain_id, "init", &chain_id]; let mut cosmos = run_cosmos_cmd(&test, args, Some(10))?; cosmos.assert_success(); @@ -1448,7 +1472,7 @@ pub fn setup_cosmos(chain_type: CosmosChainType) -> Result { "--keyring-backend", "test", "--chain-id", - chain_id, + &chain_id, ]; let mut cosmos = run_cosmos_cmd(&test, args, Some(10))?; cosmos.assert_success(); @@ -1580,7 +1604,7 @@ pub mod constants { // Gaia or CosmWasm pub const GAIA_CHAIN_ID: &str = "gaia"; pub const COSMWASM_CHAIN_ID: &str = "cosmwasm"; - pub const COSMOS_RPC: &str = "127.0.0.1:26657"; + pub const COSMOS_RPC: &str = "127.0.0.1:64160"; pub const COSMOS_USER: &str = "user"; pub const COSMOS_RELAYER: &str = "relayer"; pub const COSMOS_VALIDATOR: &str = "validator"; From 69074943fb1ccf19eefb3daa75230d4c22363f85 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Fri, 29 Nov 2024 14:29:27 +0000 Subject: [PATCH 06/31] Enable PFM e2e tests in CI Co-authored-by: Jacob Turner --- .github/workflows/scripts/e2e.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/scripts/e2e.json b/.github/workflows/scripts/e2e.json index de3d28724d..c63422bf67 100644 --- a/.github/workflows/scripts/e2e.json +++ b/.github/workflows/scripts/e2e.json @@ -6,6 +6,8 @@ "e2e::ibc_tests::fee_payment_with_ibc_token": 357, "e2e::ibc_tests::ibc_token_inflation": 840, "e2e::ibc_tests::ibc_rate_limit": 485, + "e2e::ibc_tests::ibc_pfm_happy_flows": 485, + "e2e::ibc_tests::ibc_pfm_unhappy_flows": 485, "e2e::ibc_tests::ibc_upgrade_client": 280, "e2e::eth_bridge_tests::test_add_to_bridge_pool": 10, "e2e::ledger_tests::double_signing_gets_slashed": 12, From 014a23f4aaa3abdadcdea41667ab180f0f0ee9ca Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Fri, 29 Nov 2024 14:35:10 +0000 Subject: [PATCH 07/31] Changelog for #4082 --- .changelog/unreleased/features/4082-ibc-pfm.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/unreleased/features/4082-ibc-pfm.md diff --git a/.changelog/unreleased/features/4082-ibc-pfm.md b/.changelog/unreleased/features/4082-ibc-pfm.md new file mode 100644 index 0000000000..5aebd47ffc --- /dev/null +++ b/.changelog/unreleased/features/4082-ibc-pfm.md @@ -0,0 +1,3 @@ +- Implement compatibility with Strangelove's Packet Forward Middleware + in Namada, to allow forwarding ICS-20 packets over multiple chains. + ([\#4082](https://github.com/anoma/namada/pull/4082)) \ No newline at end of file From f201286abfb8218ccaf7986a646ee70e430e4dba Mon Sep 17 00:00:00 2001 From: satan Date: Mon, 2 Dec 2024 09:27:09 +0100 Subject: [PATCH 08/31] Remove receiver validation on pfm ibc packets --- crates/ibc/src/lib.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/crates/ibc/src/lib.rs b/crates/ibc/src/lib.rs index bd5aafc814..69a064dcb6 100644 --- a/crates/ibc/src/lib.rs +++ b/crates/ibc/src/lib.rs @@ -80,6 +80,7 @@ use ibc::core::host::types::identifiers::{ChannelId, PortId, Sequence}; use ibc::core::router::types::error::RouterError; use ibc::primitives::proto::Any; pub use ibc::*; +use ibc_middleware_packet_forward::PacketMetadata; use masp_primitives::transaction::Transaction as MaspTransaction; pub use msg::*; use namada_core::address::{self, Address}; @@ -793,6 +794,10 @@ where } } +fn is_packet_forward(data: &PacketData) -> bool { + serde_json::from_str::(data.memo.as_ref()).is_ok() +} + // Extract the involved namada address from the packet (either sender or // receiver) to trigger its vp. Returns None if an address could not be found fn get_envelope_verifier( @@ -802,9 +807,14 @@ fn get_envelope_verifier( MsgEnvelope::Packet(PacketMsg::Recv(msg)) => { match msg.packet.port_id_on_b.as_str() { FT_PORT_ID_STR => { - serde_json::from_slice::(&msg.packet.data) - .ok() - .map(|packet_data| packet_data.receiver) + let packet_data = + serde_json::from_slice::(&msg.packet.data) + .ok()?; + if is_packet_forward(&packet_data) { + None + } else { + Some(packet_data.receiver) + } } NFT_PORT_ID_STR => { serde_json::from_slice::(&msg.packet.data) From dad8f0e8ce0007af5352b121321a06439423b4aa Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Mon, 2 Dec 2024 14:20:09 +0100 Subject: [PATCH 09/31] Add function to build transfer middlewares stack --- crates/benches/native_vps.rs | 6 ++-- crates/ibc/src/context/middlewares.rs | 33 ++++++++++++++++++++ crates/ibc/src/context/mod.rs | 1 + crates/ibc/src/context/pfm_mod.rs | 44 +++------------------------ crates/ibc/src/storage.rs | 21 +++++++++++++ crates/ibc/src/vp/mod.rs | 10 +++--- crates/tx_prelude/src/ibc.rs | 4 +-- 7 files changed, 71 insertions(+), 48 deletions(-) create mode 100644 crates/ibc/src/context/middlewares.rs diff --git a/crates/benches/native_vps.rs b/crates/benches/native_vps.rs index 8479a39d43..9caa909e1c 100644 --- a/crates/benches/native_vps.rs +++ b/crates/benches/native_vps.rs @@ -24,7 +24,7 @@ use namada_apps_lib::governance::pgf::storage::steward::StewardDetail; use namada_apps_lib::governance::storage::proposal::ProposalType; use namada_apps_lib::governance::storage::vote::ProposalVote; use namada_apps_lib::governance::{InitProposalData, VoteProposalData}; -use namada_apps_lib::ibc::context::pfm_mod::PfmTransferModule; +use namada_apps_lib::ibc::context::middlewares::create_transfer_middlewares; use namada_apps_lib::ibc::core::channel::types::channel::Order; use namada_apps_lib::ibc::core::channel::types::msgs::MsgChannelOpenInit; use namada_apps_lib::ibc::core::channel::types::Version as ChannelVersion; @@ -1724,7 +1724,7 @@ fn ibc_vp_validate_action(c: &mut Criterion) { ); actions.set_validation_params(ibc.validation_params().unwrap()); - let module = PfmTransferModule::<_, parameters::Store<_>>::wrap( + let module = create_transfer_middlewares::<_, parameters::Store<_>>( ctx.clone(), verifiers, ); @@ -1788,7 +1788,7 @@ fn ibc_vp_execute_action(c: &mut Criterion) { ); actions.set_validation_params(ibc.validation_params().unwrap()); - let module = PfmTransferModule::<_, parameters::Store<_>>::wrap( + let module = create_transfer_middlewares::<_, parameters::Store<_>>( ctx.clone(), verifiers, ); diff --git a/crates/ibc/src/context/middlewares.rs b/crates/ibc/src/context/middlewares.rs new file mode 100644 index 0000000000..5c6d2ef2ea --- /dev/null +++ b/crates/ibc/src/context/middlewares.rs @@ -0,0 +1,33 @@ +//! Middleware entry points on Namada. + +use std::cell::RefCell; +use std::collections::BTreeSet; +use std::fmt::Debug; +use std::marker::PhantomData; +use std::rc::Rc; + +use ibc_middleware_packet_forward::PacketForwardMiddleware; +use namada_core::address::Address; + +use crate::context::pfm_mod::PfmTransferModule; +use crate::context::transfer_mod::TransferModule; +use crate::{IbcCommonContext, IbcStorageContext}; + +/// The stack of middlewares of the transfer module. +pub type TransferMiddlewares = + PacketForwardMiddleware>; + +/// Create a new instance of [`TransferMiddlewares`] +pub fn create_transfer_middlewares( + ctx: Rc>, + verifiers: Rc>>, +) -> TransferMiddlewares +where + C: IbcCommonContext + Debug, + Params: namada_systems::parameters::Read<::Storage>, +{ + PacketForwardMiddleware::next(PfmTransferModule { + transfer_module: TransferModule::new(ctx, verifiers), + _phantom: PhantomData, + }) +} diff --git a/crates/ibc/src/context/mod.rs b/crates/ibc/src/context/mod.rs index 89a82b13e7..441f46eeeb 100644 --- a/crates/ibc/src/context/mod.rs +++ b/crates/ibc/src/context/mod.rs @@ -3,6 +3,7 @@ pub mod client; pub mod common; pub mod execution; +pub mod middlewares; pub mod nft_transfer; pub mod nft_transfer_mod; pub mod pfm_mod; diff --git a/crates/ibc/src/context/pfm_mod.rs b/crates/ibc/src/context/pfm_mod.rs index 59ded9263b..d3df7444ad 100644 --- a/crates/ibc/src/context/pfm_mod.rs +++ b/crates/ibc/src/context/pfm_mod.rs @@ -1,11 +1,8 @@ //! Implementation of Packet Forward Middleware on top of the ICS-20 //! [`TransferModule`]. -use std::cell::RefCell; -use std::collections::BTreeSet; use std::fmt::{Debug, Formatter}; use std::marker::PhantomData; -use std::rc::Rc; use ibc::apps::transfer::context::TokenTransferExecutionContext; use ibc::apps::transfer::handler::{ @@ -32,32 +29,17 @@ use ibc::primitives::Signer; use ibc_middleware_packet_forward::{ InFlightPacket, InFlightPacketKey, PacketForwardMiddleware, PfmContext, }; -use namada_core::address::{Address, IBC as IBC_ADDRESS, MULTITOKEN}; -use namada_core::storage::{self, KeySeg}; +use namada_core::address::{IBC as IBC_ADDRESS, MULTITOKEN}; use namada_state::{StorageRead, StorageWrite}; use crate::context::transfer_mod::TransferModule; use crate::context::IbcContext; +use crate::storage::inflight_packet_key; use crate::{ Error, IbcCommonContext, IbcStorageContext, ModuleWrapper, TokenTransferContext, }; -const MIDDLEWARES_SUBKEY: &str = "middleware"; -const PFM_SUBKEY: &str = "pfm"; - -/// Get the Namada storage key associated to the provided `InFlightPacketKey`. -pub fn get_inflight_packet_key( - inflight_packet_key: &InFlightPacketKey, -) -> storage::Key { - let key: storage::Key = IBC_ADDRESS.to_db_key().into(); - key.with_segment(MIDDLEWARES_SUBKEY.to_string()) - .with_segment(PFM_SUBKEY.to_string()) - .with_segment(inflight_packet_key.port.to_string()) - .with_segment(inflight_packet_key.channel.to_string()) - .with_segment(inflight_packet_key.sequence.to_string()) -} - /// A wrapper around an IBC transfer module necessary to /// build execution contexts. This allows us to implement /// packet forward middleware on this struct. @@ -71,22 +53,6 @@ where pub _phantom: PhantomData, } -impl PfmTransferModule -where - C: IbcCommonContext + Debug, -{ - /// Create a new [`PfmTransferModule`] - pub fn wrap( - ctx: Rc>, - verifiers: Rc>>, - ) -> PacketForwardMiddleware { - PacketForwardMiddleware::next(Self { - transfer_module: TransferModule::new(ctx, verifiers), - _phantom: Default::default(), - }) - } -} - impl Debug for PfmTransferModule { @@ -477,7 +443,7 @@ where ) -> Result<(), Self::Error> { tracing::debug!(?key, ?inflight_packet, "PFM store_inflight_packet"); let mut ctx = self.transfer_module.ctx.inner.borrow_mut(); - let key = get_inflight_packet_key(&key); + let key = inflight_packet_key(&key); ctx.storage_mut() .write(&key, inflight_packet) .map_err(Error::Storage) @@ -488,7 +454,7 @@ where key: &InFlightPacketKey, ) -> Result, Self::Error> { let mut ctx = self.transfer_module.ctx.inner.borrow_mut(); - let key = get_inflight_packet_key(key); + let key = inflight_packet_key(key); let packet = ctx.storage_mut().read(&key).map_err(Error::Storage); tracing::debug!(?key, ?packet, "PFM retrieve_inflight_packet"); @@ -502,7 +468,7 @@ where ) -> Result<(), Self::Error> { tracing::debug!(?key, "PFM delete_inflight_packet"); let mut ctx = self.transfer_module.ctx.inner.borrow_mut(); - let key = get_inflight_packet_key(key); + let key = inflight_packet_key(key); ctx.storage_mut().delete(&key).map_err(Error::Storage) } } diff --git a/crates/ibc/src/storage.rs b/crates/ibc/src/storage.rs index 38b0d7e905..37754320ce 100644 --- a/crates/ibc/src/storage.rs +++ b/crates/ibc/src/storage.rs @@ -13,6 +13,7 @@ use ibc::core::host::types::path::{ ReceiptPath, SeqAckPath, SeqRecvPath, SeqSendPath, UpgradeClientStatePath, UpgradeConsensusStatePath, }; +use ibc_middleware_packet_forward::InFlightPacketKey; use namada_core::address::{Address, InternalAddress}; use namada_core::storage::{DbKeySeg, Key, KeySeg}; use namada_core::token::Amount; @@ -647,3 +648,23 @@ pub fn withdraw_key(token: &Address) -> Key { .push(&token.to_string().to_db_key()) .expect("Cannot obtain a storage key") } + +/// Get a middleware key prefix. +pub fn middlewares_prefix() -> Key { + const MIDDLEWARES_SUBKEY: &str = "middleware"; + + let key: Key = namada_core::address::IBC.to_db_key().into(); + key.with_segment(MIDDLEWARES_SUBKEY.to_string()) +} + +/// Get the Namada storage key associated with the provided +/// [`InFlightPacketKey`]. +pub fn inflight_packet_key(inflight_packet_key: &InFlightPacketKey) -> Key { + const PFM_SUBKEY: &str = "pfm"; + + middlewares_prefix() + .with_segment(PFM_SUBKEY.to_string()) + .with_segment(inflight_packet_key.port.to_string()) + .with_segment(inflight_packet_key.channel.to_string()) + .with_segment(inflight_packet_key.sequence.to_string()) +} diff --git a/crates/ibc/src/vp/mod.rs b/crates/ibc/src/vp/mod.rs index bfc0be1e90..410fd75f83 100644 --- a/crates/ibc/src/vp/mod.rs +++ b/crates/ibc/src/vp/mod.rs @@ -27,7 +27,7 @@ use namada_vp::native_vp::{Ctx, CtxPreStorageRead, NativeVp, VpEvaluator}; use namada_vp::VpEnv; use thiserror::Error; -use crate::context::pfm_mod::PfmTransferModule; +use crate::context::middlewares::create_transfer_middlewares; use crate::core::host::types::identifiers::ChainId as IbcChainId; use crate::core::host::types::path::UPGRADED_IBC_STATE; use crate::event::IbcEvent; @@ -247,8 +247,10 @@ where ctx.clone(), verifiers.clone(), ); - let module = - PfmTransferModule::<_, ParamsPseudo>::wrap(ctx.clone(), verifiers); + let module = create_transfer_middlewares::<_, ParamsPseudo>( + ctx.clone(), + verifiers, + ); actions.add_transfer_module(module); let module = NftTransferModule::<_, Token>::new(ctx.clone()); actions.add_transfer_module(module); @@ -304,7 +306,7 @@ where actions.set_validation_params(self.validation_params()?); let module = - PfmTransferModule::<_, Params>::wrap(ctx.clone(), verifiers); + create_transfer_middlewares::<_, Params>(ctx.clone(), verifiers); actions.add_transfer_module(module); let module = NftTransferModule::<_, Token>::new(ctx); actions.add_transfer_module(module); diff --git a/crates/tx_prelude/src/ibc.rs b/crates/tx_prelude/src/ibc.rs index 436a6befc2..25e2b27267 100644 --- a/crates/tx_prelude/src/ibc.rs +++ b/crates/tx_prelude/src/ibc.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use namada_core::address::Address; use namada_core::token::Amount; -use namada_ibc::context::pfm_mod::PfmTransferModule; +use namada_ibc::context::middlewares::create_transfer_middlewares; pub use namada_ibc::event::{IbcEvent, IbcEventType}; pub use namada_ibc::storage::{ burn_tokens, client_state_key, is_ibc_key, mint_limit_key, mint_tokens, @@ -31,7 +31,7 @@ pub fn ibc_actions( let ctx = Rc::new(RefCell::new(ctx.clone())); let verifiers = Rc::new(RefCell::new(BTreeSet::
::new())); let mut actions = IbcActions::new(ctx.clone(), verifiers.clone()); - let module = PfmTransferModule::<_, parameters::Store>::wrap( + let module = create_transfer_middlewares::<_, parameters::Store>( ctx.clone(), verifiers, ); From 9f542132ba1449e1d9542342494cac908dcbbcf4 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Mon, 2 Dec 2024 14:37:33 +0100 Subject: [PATCH 10/31] Move PFM to middlewares --- crates/ibc/src/context/middlewares.rs | 5 ++++- crates/ibc/src/context/{ => middlewares}/pfm_mod.rs | 0 crates/ibc/src/context/mod.rs | 1 - 3 files changed, 4 insertions(+), 2 deletions(-) rename crates/ibc/src/context/{ => middlewares}/pfm_mod.rs (100%) diff --git a/crates/ibc/src/context/middlewares.rs b/crates/ibc/src/context/middlewares.rs index 5c6d2ef2ea..76455a48f7 100644 --- a/crates/ibc/src/context/middlewares.rs +++ b/crates/ibc/src/context/middlewares.rs @@ -1,5 +1,8 @@ //! Middleware entry points on Namada. +pub mod pfm_mod; +// mod crossroads_mod; + use std::cell::RefCell; use std::collections::BTreeSet; use std::fmt::Debug; @@ -9,7 +12,7 @@ use std::rc::Rc; use ibc_middleware_packet_forward::PacketForwardMiddleware; use namada_core::address::Address; -use crate::context::pfm_mod::PfmTransferModule; +use self::pfm_mod::PfmTransferModule; use crate::context::transfer_mod::TransferModule; use crate::{IbcCommonContext, IbcStorageContext}; diff --git a/crates/ibc/src/context/pfm_mod.rs b/crates/ibc/src/context/middlewares/pfm_mod.rs similarity index 100% rename from crates/ibc/src/context/pfm_mod.rs rename to crates/ibc/src/context/middlewares/pfm_mod.rs diff --git a/crates/ibc/src/context/mod.rs b/crates/ibc/src/context/mod.rs index 441f46eeeb..447ed02fc5 100644 --- a/crates/ibc/src/context/mod.rs +++ b/crates/ibc/src/context/mod.rs @@ -6,7 +6,6 @@ pub mod execution; pub mod middlewares; pub mod nft_transfer; pub mod nft_transfer_mod; -pub mod pfm_mod; pub mod router; pub mod storage; pub mod token_transfer; From 79a96213b966feef47cec30b27295e773790d437 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Mon, 2 Dec 2024 14:53:26 +0100 Subject: [PATCH 11/31] Move module wrapper impl --- crates/ibc/src/context/middlewares.rs | 27 ++++++++++++++++- crates/ibc/src/context/middlewares/pfm_mod.rs | 30 ++----------------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/crates/ibc/src/context/middlewares.rs b/crates/ibc/src/context/middlewares.rs index 76455a48f7..26c218c531 100644 --- a/crates/ibc/src/context/middlewares.rs +++ b/crates/ibc/src/context/middlewares.rs @@ -9,7 +9,10 @@ use std::fmt::Debug; use std::marker::PhantomData; use std::rc::Rc; -use ibc_middleware_packet_forward::PacketForwardMiddleware; +use ibc::core::host::types::identifiers::PortId; +use ibc::core::router::module::Module; +use ibc::core::router::types::module::ModuleId; +use ibc_middleware_packet_forward::{PacketForwardMiddleware, PfmContext}; use namada_core::address::Address; use self::pfm_mod::PfmTransferModule; @@ -34,3 +37,25 @@ where _phantom: PhantomData, }) } + +impl crate::ModuleWrapper for TransferMiddlewares +where + C: IbcCommonContext + Debug, + PfmTransferModule: PfmContext, +{ + fn as_module(&self) -> &dyn Module { + self + } + + fn as_module_mut(&mut self) -> &mut dyn Module { + self + } + + fn module_id(&self) -> ModuleId { + ModuleId::new(ibc::apps::transfer::types::MODULE_ID_STR.to_string()) + } + + fn port_id(&self) -> PortId { + PortId::transfer() + } +} diff --git a/crates/ibc/src/context/middlewares/pfm_mod.rs b/crates/ibc/src/context/middlewares/pfm_mod.rs index d3df7444ad..862ec3d085 100644 --- a/crates/ibc/src/context/middlewares/pfm_mod.rs +++ b/crates/ibc/src/context/middlewares/pfm_mod.rs @@ -24,10 +24,10 @@ use ibc::core::host::types::identifiers::{ ChannelId, ConnectionId, PortId, Sequence, }; use ibc::core::router::module::Module; -use ibc::core::router::types::module::{ModuleExtras, ModuleId}; +use ibc::core::router::types::module::ModuleExtras; use ibc::primitives::Signer; use ibc_middleware_packet_forward::{ - InFlightPacket, InFlightPacketKey, PacketForwardMiddleware, PfmContext, + InFlightPacket, InFlightPacketKey, PfmContext, }; use namada_core::address::{IBC as IBC_ADDRESS, MULTITOKEN}; use namada_state::{StorageRead, StorageWrite}; @@ -35,10 +35,7 @@ use namada_state::{StorageRead, StorageWrite}; use crate::context::transfer_mod::TransferModule; use crate::context::IbcContext; use crate::storage::inflight_packet_key; -use crate::{ - Error, IbcCommonContext, IbcStorageContext, ModuleWrapper, - TokenTransferContext, -}; +use crate::{Error, IbcCommonContext, IbcStorageContext, TokenTransferContext}; /// A wrapper around an IBC transfer module necessary to /// build execution contexts. This allows us to implement @@ -472,24 +469,3 @@ where ctx.storage_mut().delete(&key).map_err(Error::Storage) } } - -impl ModuleWrapper for PacketForwardMiddleware -where - T: Module + PfmContext, -{ - fn as_module(&self) -> &dyn Module { - self - } - - fn as_module_mut(&mut self) -> &mut dyn Module { - self - } - - fn module_id(&self) -> ModuleId { - ModuleId::new(ibc::apps::transfer::types::MODULE_ID_STR.to_string()) - } - - fn port_id(&self) -> PortId { - PortId::transfer() - } -} From e074540643c04fc36a1e72f2b40f1c7aced8675e Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Mon, 2 Dec 2024 16:16:46 +0100 Subject: [PATCH 12/31] Handle receiving PFM packets with invalid receivers --- Cargo.lock | 64 +++++++++---------- Cargo.toml | 8 +-- crates/core/src/address.rs | 13 +++- crates/ibc/src/context/middlewares.rs | 2 +- crates/ibc/src/context/middlewares/pfm_mod.rs | 18 +++++- crates/ibc/src/context/token_transfer.rs | 31 +++++++++ wasm/Cargo.lock | 64 +++++++++---------- wasm_for_tests/Cargo.lock | 60 ++++++++--------- 8 files changed, 157 insertions(+), 103 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cc17140f7f..df2c54c921 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3350,7 +3350,7 @@ dependencies = [ [[package]] name = "ibc" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-apps", "ibc-clients", @@ -3363,7 +3363,7 @@ dependencies = [ [[package]] name = "ibc-app-nft-transfer" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-app-nft-transfer-types", "ibc-core", @@ -3373,7 +3373,7 @@ dependencies = [ [[package]] name = "ibc-app-nft-transfer-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "arbitrary", "base64 0.22.1", @@ -3395,7 +3395,7 @@ dependencies = [ [[package]] name = "ibc-app-transfer" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-app-transfer-types", "ibc-core", @@ -3405,7 +3405,7 @@ dependencies = [ [[package]] name = "ibc-app-transfer-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "arbitrary", "borsh", @@ -3424,7 +3424,7 @@ dependencies = [ [[package]] name = "ibc-apps" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-app-nft-transfer", "ibc-app-transfer", @@ -3433,7 +3433,7 @@ dependencies = [ [[package]] name = "ibc-client-tendermint" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "derive_more", "ibc-client-tendermint-types", @@ -3450,7 +3450,7 @@ dependencies = [ [[package]] name = "ibc-client-tendermint-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "displaydoc", "ibc-core-client-types", @@ -3467,7 +3467,7 @@ dependencies = [ [[package]] name = "ibc-client-wasm-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "base64 0.22.1", "displaydoc", @@ -3481,7 +3481,7 @@ dependencies = [ [[package]] name = "ibc-clients" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-client-tendermint", "ibc-client-wasm-types", @@ -3490,7 +3490,7 @@ dependencies = [ [[package]] name = "ibc-core" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-core-channel", "ibc-core-client", @@ -3506,7 +3506,7 @@ dependencies = [ [[package]] name = "ibc-core-channel" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-core-channel-types", "ibc-core-client", @@ -3521,7 +3521,7 @@ dependencies = [ [[package]] name = "ibc-core-channel-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "arbitrary", "borsh", @@ -3545,7 +3545,7 @@ dependencies = [ [[package]] name = "ibc-core-client" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-core-client-context", "ibc-core-client-types", @@ -3558,7 +3558,7 @@ dependencies = [ [[package]] name = "ibc-core-client-context" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "derive_more", "displaydoc", @@ -3574,7 +3574,7 @@ dependencies = [ [[package]] name = "ibc-core-client-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "arbitrary", "borsh", @@ -3595,7 +3595,7 @@ dependencies = [ [[package]] name = "ibc-core-commitment-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "arbitrary", "borsh", @@ -3615,7 +3615,7 @@ dependencies = [ [[package]] name = "ibc-core-connection" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-client-wasm-types", "ibc-core-client", @@ -3629,7 +3629,7 @@ dependencies = [ [[package]] name = "ibc-core-connection-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "arbitrary", "borsh", @@ -3651,7 +3651,7 @@ dependencies = [ [[package]] name = "ibc-core-handler" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-core-channel", "ibc-core-client", @@ -3666,7 +3666,7 @@ dependencies = [ [[package]] name = "ibc-core-handler-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "arbitrary", "borsh", @@ -3691,7 +3691,7 @@ dependencies = [ [[package]] name = "ibc-core-host" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "derive_more", "displaydoc", @@ -3709,7 +3709,7 @@ dependencies = [ [[package]] name = "ibc-core-host-cosmos" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "derive_more", "displaydoc", @@ -3732,7 +3732,7 @@ dependencies = [ [[package]] name = "ibc-core-host-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "arbitrary", "borsh", @@ -3748,7 +3748,7 @@ dependencies = [ [[package]] name = "ibc-core-router" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "derive_more", "displaydoc", @@ -3762,7 +3762,7 @@ dependencies = [ [[package]] name = "ibc-core-router-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "borsh", "derive_more", @@ -3781,7 +3781,7 @@ dependencies = [ [[package]] name = "ibc-derive" version = "0.8.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "proc-macro2", "quote", @@ -3790,8 +3790,8 @@ dependencies = [ [[package]] name = "ibc-middleware-packet-forward" -version = "0.6.0" -source = "git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.6.0#ca824cfbe550c529d30bf27a97026dd0a058cfdf" +version = "0.8.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.8.0#9c4a410063df8562c726c76009ff08b4e5a1894a" dependencies = [ "borsh", "dur", @@ -3810,7 +3810,7 @@ dependencies = [ [[package]] name = "ibc-primitives" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "arbitrary", "borsh", @@ -3851,7 +3851,7 @@ dependencies = [ [[package]] name = "ibc-query" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "displaydoc", "ibc", @@ -3862,7 +3862,7 @@ dependencies = [ [[package]] name = "ibc-testkit" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "basecoin-store", "derive_more", diff --git a/Cargo.toml b/Cargo.toml index 91e66c9baf..38a15f0d32 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -119,10 +119,10 @@ fs_extra = "1.2.0" futures = "0.3" git2 = { version = "0.18.1", default-features = false } # branch tiago/optional-ack -ibc = { git = "https://github.com/heliaxdev/cosmos-ibc-rs", rev = "aa229566e6bb688cc2626dab276c3849abc0c583", features = ["serde"] } -ibc-derive = { git = "https://github.com/heliaxdev/cosmos-ibc-rs", rev = "aa229566e6bb688cc2626dab276c3849abc0c583" } -ibc-middleware-packet-forward = { git = "https://github.com/heliaxdev/ibc-middleware", tag = "pfm/v0.6.0", features = ["borsh"] } -ibc-testkit = { git = "https://github.com/heliaxdev/cosmos-ibc-rs", rev = "aa229566e6bb688cc2626dab276c3849abc0c583", default-features = false } +ibc = { git = "https://github.com/heliaxdev/cosmos-ibc-rs", rev = "38489943c4e75206eaffeeeec6153c039c2499d1", features = ["serde"] } +ibc-derive = { git = "https://github.com/heliaxdev/cosmos-ibc-rs", rev = "38489943c4e75206eaffeeeec6153c039c2499d1" } +ibc-middleware-packet-forward = { git = "https://github.com/heliaxdev/ibc-middleware", tag = "pfm/v0.8.0", features = ["borsh"] } +ibc-testkit = { git = "https://github.com/heliaxdev/cosmos-ibc-rs", rev = "38489943c4e75206eaffeeeec6153c039c2499d1", default-features = false } ics23 = "0.12.0" usize-set = { version = "0.10.3", features = ["serialize-borsh", "serialize-serde"] } indexmap = { package = "nam-indexmap", version = "2.7.1-nam.0", features = ["borsh-schema", "serde"] } diff --git a/crates/core/src/address.rs b/crates/core/src/address.rs index 7023b70b4a..0590c695eb 100644 --- a/crates/core/src/address.rs +++ b/crates/core/src/address.rs @@ -393,11 +393,10 @@ impl Debug for Address { } } -// compute an Address from an IBC signer -impl TryFrom for Address { +impl TryFrom<&Signer> for Address { type Error = DecodeError; - fn try_from(signer: Signer) -> Result { + fn try_from(signer: &Signer) -> Result { // The given address should be an address or payment address. When // sending a token from a spending key, it has been already // replaced with the MASP address. @@ -412,6 +411,14 @@ impl TryFrom for Address { } } +impl TryFrom for Address { + type Error = DecodeError; + + fn try_from(signer: Signer) -> Result { + (&signer).try_into() + } +} + /// An established address is generated on-chain #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive( diff --git a/crates/ibc/src/context/middlewares.rs b/crates/ibc/src/context/middlewares.rs index 26c218c531..8d65666e63 100644 --- a/crates/ibc/src/context/middlewares.rs +++ b/crates/ibc/src/context/middlewares.rs @@ -32,7 +32,7 @@ where C: IbcCommonContext + Debug, Params: namada_systems::parameters::Read<::Storage>, { - PacketForwardMiddleware::next(PfmTransferModule { + PacketForwardMiddleware::wrap(PfmTransferModule { transfer_module: TransferModule::new(ctx, verifiers), _phantom: PhantomData, }) diff --git a/crates/ibc/src/context/middlewares/pfm_mod.rs b/crates/ibc/src/context/middlewares/pfm_mod.rs index 862ec3d085..70454fbf4a 100644 --- a/crates/ibc/src/context/middlewares/pfm_mod.rs +++ b/crates/ibc/src/context/middlewares/pfm_mod.rs @@ -225,7 +225,23 @@ where packet: &Packet, relayer: &Signer, ) -> (ModuleExtras, Option) { - self.transfer_module.on_recv_packet_execute(packet, relayer) + let Ok(packet_data) = + serde_json::from_slice::(&packet.data) + else { + return self + .transfer_module + .on_recv_packet_execute(packet, relayer); + }; + + if crate::is_packet_forward(&packet_data) { + self.transfer_module.ctx.enable_parse_addr_as_governance(); + let ret = + self.transfer_module.on_recv_packet_execute(packet, relayer); + self.transfer_module.ctx.disable_parse_addr_as_governance(); + ret + } else { + self.transfer_module.on_recv_packet_execute(packet, relayer) + } } fn on_acknowledgement_packet_validate( diff --git a/crates/ibc/src/context/token_transfer.rs b/crates/ibc/src/context/token_transfer.rs index fecc8d4d2d..789d7ca635 100644 --- a/crates/ibc/src/context/token_transfer.rs +++ b/crates/ibc/src/context/token_transfer.rs @@ -12,6 +12,7 @@ use ibc::apps::transfer::types::{Memo, PrefixedCoin, PrefixedDenom}; use ibc::core::channel::types::error::ChannelError; use ibc::core::handler::types::error::ContextError; use ibc::core::host::types::identifiers::{ChannelId, PortId}; +use ibc::core::primitives::Signer; use namada_core::address::{Address, InternalAddress, MASP}; use namada_core::token::Amount; use namada_core::uint::Uint; @@ -28,6 +29,7 @@ where pub(crate) inner: Rc>, pub(crate) verifiers: Rc>>, is_shielded: bool, + parse_addr_as_governance: bool, } impl TokenTransferContext @@ -43,6 +45,7 @@ where inner, verifiers, is_shielded: false, + parse_addr_as_governance: false, } } @@ -51,6 +54,16 @@ where self.verifiers.borrow_mut().insert(addr.clone()); } + /// Enable parsing ibc signers as the governance address + pub fn enable_parse_addr_as_governance(&mut self) { + self.parse_addr_as_governance = true; + } + + /// Disable parsing ibc signers as the governance address + pub fn disable_parse_addr_as_governance(&mut self) { + self.parse_addr_as_governance = false; + } + /// Set to enable a shielded transfer pub fn enable_shielded_transfer(&mut self) { self.is_shielded = true; @@ -179,6 +192,24 @@ where { type AccountId = Address; + fn sender_account_from_signer( + &self, + signer: &Signer, + ) -> Option { + Address::decode(signer.as_ref()).ok() + } + + fn receiver_account_from_signer( + &self, + signer: &Signer, + ) -> Option { + if self.parse_addr_as_governance { + Some(namada_core::address::GOV) + } else { + Address::try_from(signer).ok() + } + } + fn get_port(&self) -> Result { Ok(PortId::transfer()) } diff --git a/wasm/Cargo.lock b/wasm/Cargo.lock index 8fd208707f..6400887db7 100644 --- a/wasm/Cargo.lock +++ b/wasm/Cargo.lock @@ -2646,7 +2646,7 @@ dependencies = [ [[package]] name = "ibc" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-apps", "ibc-clients", @@ -2659,7 +2659,7 @@ dependencies = [ [[package]] name = "ibc-app-nft-transfer" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-app-nft-transfer-types", "ibc-core", @@ -2669,7 +2669,7 @@ dependencies = [ [[package]] name = "ibc-app-nft-transfer-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "base64 0.22.1", "borsh", @@ -2690,7 +2690,7 @@ dependencies = [ [[package]] name = "ibc-app-transfer" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-app-transfer-types", "ibc-core", @@ -2700,7 +2700,7 @@ dependencies = [ [[package]] name = "ibc-app-transfer-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "borsh", "derive_more", @@ -2718,7 +2718,7 @@ dependencies = [ [[package]] name = "ibc-apps" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-app-nft-transfer", "ibc-app-transfer", @@ -2727,7 +2727,7 @@ dependencies = [ [[package]] name = "ibc-client-tendermint" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "derive_more", "ibc-client-tendermint-types", @@ -2744,7 +2744,7 @@ dependencies = [ [[package]] name = "ibc-client-tendermint-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "displaydoc", "ibc-core-client-types", @@ -2761,7 +2761,7 @@ dependencies = [ [[package]] name = "ibc-client-wasm-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "base64 0.22.1", "displaydoc", @@ -2775,7 +2775,7 @@ dependencies = [ [[package]] name = "ibc-clients" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-client-tendermint", "ibc-client-wasm-types", @@ -2784,7 +2784,7 @@ dependencies = [ [[package]] name = "ibc-core" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-core-channel", "ibc-core-client", @@ -2800,7 +2800,7 @@ dependencies = [ [[package]] name = "ibc-core-channel" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-core-channel-types", "ibc-core-client", @@ -2815,7 +2815,7 @@ dependencies = [ [[package]] name = "ibc-core-channel-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "borsh", "derive_more", @@ -2838,7 +2838,7 @@ dependencies = [ [[package]] name = "ibc-core-client" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-core-client-context", "ibc-core-client-types", @@ -2851,7 +2851,7 @@ dependencies = [ [[package]] name = "ibc-core-client-context" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "derive_more", "displaydoc", @@ -2867,7 +2867,7 @@ dependencies = [ [[package]] name = "ibc-core-client-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "borsh", "derive_more", @@ -2887,7 +2887,7 @@ dependencies = [ [[package]] name = "ibc-core-commitment-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "borsh", "derive_more", @@ -2906,7 +2906,7 @@ dependencies = [ [[package]] name = "ibc-core-connection" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-client-wasm-types", "ibc-core-client", @@ -2920,7 +2920,7 @@ dependencies = [ [[package]] name = "ibc-core-connection-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "borsh", "derive_more", @@ -2941,7 +2941,7 @@ dependencies = [ [[package]] name = "ibc-core-handler" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-core-channel", "ibc-core-client", @@ -2956,7 +2956,7 @@ dependencies = [ [[package]] name = "ibc-core-handler-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "borsh", "derive_more", @@ -2980,7 +2980,7 @@ dependencies = [ [[package]] name = "ibc-core-host" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "derive_more", "displaydoc", @@ -2998,7 +2998,7 @@ dependencies = [ [[package]] name = "ibc-core-host-cosmos" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "derive_more", "displaydoc", @@ -3021,7 +3021,7 @@ dependencies = [ [[package]] name = "ibc-core-host-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "borsh", "derive_more", @@ -3036,7 +3036,7 @@ dependencies = [ [[package]] name = "ibc-core-router" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "derive_more", "displaydoc", @@ -3050,7 +3050,7 @@ dependencies = [ [[package]] name = "ibc-core-router-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "borsh", "derive_more", @@ -3069,7 +3069,7 @@ dependencies = [ [[package]] name = "ibc-derive" version = "0.8.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "proc-macro2", "quote", @@ -3078,8 +3078,8 @@ dependencies = [ [[package]] name = "ibc-middleware-packet-forward" -version = "0.6.0" -source = "git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.6.0#ca824cfbe550c529d30bf27a97026dd0a058cfdf" +version = "0.8.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.8.0#9c4a410063df8562c726c76009ff08b4e5a1894a" dependencies = [ "borsh", "dur", @@ -3098,7 +3098,7 @@ dependencies = [ [[package]] name = "ibc-primitives" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "borsh", "derive_more", @@ -3138,7 +3138,7 @@ dependencies = [ [[package]] name = "ibc-query" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "displaydoc", "ibc", @@ -3149,7 +3149,7 @@ dependencies = [ [[package]] name = "ibc-testkit" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "basecoin-store", "derive_more", diff --git a/wasm_for_tests/Cargo.lock b/wasm_for_tests/Cargo.lock index 590a861424..f993f3e33b 100644 --- a/wasm_for_tests/Cargo.lock +++ b/wasm_for_tests/Cargo.lock @@ -1280,7 +1280,7 @@ dependencies = [ [[package]] name = "ibc" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-apps", "ibc-clients", @@ -1293,7 +1293,7 @@ dependencies = [ [[package]] name = "ibc-app-nft-transfer" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-app-nft-transfer-types", "ibc-core", @@ -1303,7 +1303,7 @@ dependencies = [ [[package]] name = "ibc-app-nft-transfer-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "base64 0.22.1", "borsh", @@ -1324,7 +1324,7 @@ dependencies = [ [[package]] name = "ibc-app-transfer" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-app-transfer-types", "ibc-core", @@ -1334,7 +1334,7 @@ dependencies = [ [[package]] name = "ibc-app-transfer-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "borsh", "derive_more", @@ -1352,7 +1352,7 @@ dependencies = [ [[package]] name = "ibc-apps" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-app-nft-transfer", "ibc-app-transfer", @@ -1361,7 +1361,7 @@ dependencies = [ [[package]] name = "ibc-client-tendermint" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "derive_more", "ibc-client-tendermint-types", @@ -1378,7 +1378,7 @@ dependencies = [ [[package]] name = "ibc-client-tendermint-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "displaydoc", "ibc-core-client-types", @@ -1395,7 +1395,7 @@ dependencies = [ [[package]] name = "ibc-client-wasm-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "base64 0.22.1", "displaydoc", @@ -1409,7 +1409,7 @@ dependencies = [ [[package]] name = "ibc-clients" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-client-tendermint", "ibc-client-wasm-types", @@ -1418,7 +1418,7 @@ dependencies = [ [[package]] name = "ibc-core" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-core-channel", "ibc-core-client", @@ -1434,7 +1434,7 @@ dependencies = [ [[package]] name = "ibc-core-channel" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-core-channel-types", "ibc-core-client", @@ -1449,7 +1449,7 @@ dependencies = [ [[package]] name = "ibc-core-channel-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "borsh", "derive_more", @@ -1472,7 +1472,7 @@ dependencies = [ [[package]] name = "ibc-core-client" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-core-client-context", "ibc-core-client-types", @@ -1485,7 +1485,7 @@ dependencies = [ [[package]] name = "ibc-core-client-context" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "derive_more", "displaydoc", @@ -1501,7 +1501,7 @@ dependencies = [ [[package]] name = "ibc-core-client-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "borsh", "derive_more", @@ -1521,7 +1521,7 @@ dependencies = [ [[package]] name = "ibc-core-commitment-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "borsh", "derive_more", @@ -1540,7 +1540,7 @@ dependencies = [ [[package]] name = "ibc-core-connection" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-client-wasm-types", "ibc-core-client", @@ -1554,7 +1554,7 @@ dependencies = [ [[package]] name = "ibc-core-connection-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "borsh", "derive_more", @@ -1575,7 +1575,7 @@ dependencies = [ [[package]] name = "ibc-core-handler" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "ibc-core-channel", "ibc-core-client", @@ -1590,7 +1590,7 @@ dependencies = [ [[package]] name = "ibc-core-handler-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "borsh", "derive_more", @@ -1614,7 +1614,7 @@ dependencies = [ [[package]] name = "ibc-core-host" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "derive_more", "displaydoc", @@ -1632,7 +1632,7 @@ dependencies = [ [[package]] name = "ibc-core-host-cosmos" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "derive_more", "displaydoc", @@ -1655,7 +1655,7 @@ dependencies = [ [[package]] name = "ibc-core-host-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "borsh", "derive_more", @@ -1670,7 +1670,7 @@ dependencies = [ [[package]] name = "ibc-core-router" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "derive_more", "displaydoc", @@ -1684,7 +1684,7 @@ dependencies = [ [[package]] name = "ibc-core-router-types" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "borsh", "derive_more", @@ -1703,7 +1703,7 @@ dependencies = [ [[package]] name = "ibc-derive" version = "0.8.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "proc-macro2", "quote", @@ -1712,8 +1712,8 @@ dependencies = [ [[package]] name = "ibc-middleware-packet-forward" -version = "0.6.0" -source = "git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.6.0#ca824cfbe550c529d30bf27a97026dd0a058cfdf" +version = "0.8.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.8.0#9c4a410063df8562c726c76009ff08b4e5a1894a" dependencies = [ "borsh", "dur", @@ -1732,7 +1732,7 @@ dependencies = [ [[package]] name = "ibc-primitives" version = "0.54.0" -source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=aa229566e6bb688cc2626dab276c3849abc0c583#aa229566e6bb688cc2626dab276c3849abc0c583" +source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaffeeeec6153c039c2499d1#38489943c4e75206eaffeeeec6153c039c2499d1" dependencies = [ "borsh", "derive_more", From 6e1a56ea13bae18314c8652044df6a8464df0d74 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Mon, 2 Dec 2024 17:31:53 +0100 Subject: [PATCH 13/31] Changelog for #4134 --- .../unreleased/features/4134-ibc-pfm-with-invalid-addrs.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .changelog/unreleased/features/4134-ibc-pfm-with-invalid-addrs.md diff --git a/.changelog/unreleased/features/4134-ibc-pfm-with-invalid-addrs.md b/.changelog/unreleased/features/4134-ibc-pfm-with-invalid-addrs.md new file mode 100644 index 0000000000..ab53b5da5a --- /dev/null +++ b/.changelog/unreleased/features/4134-ibc-pfm-with-invalid-addrs.md @@ -0,0 +1,2 @@ +- Disable validation of IBC ICS-20 receivers, while handling PFM packets. + ([\#4134](https://github.com/anoma/namada/pull/4134)) \ No newline at end of file From 9a35a3f3cb85137daa06e0609ee20dae0c4d0a33 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Mon, 13 Jan 2025 13:37:47 +0000 Subject: [PATCH 14/31] Update IBC middleware stack Co-authored-by: Jacob Turner --- Cargo.lock | 94 +++++++++++++++++++++++++++++++++++++-- Cargo.toml | 5 ++- crates/ibc/Cargo.toml | 3 ++ crates/sdk/Cargo.toml | 1 + wasm/Cargo.lock | 94 +++++++++++++++++++++++++++++++++++++-- wasm_for_tests/Cargo.lock | 93 ++++++++++++++++++++++++++++++++++++-- 6 files changed, 277 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index df2c54c921..77940026d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3788,10 +3788,90 @@ dependencies = [ "syn 2.0.96", ] +[[package]] +name = "ibc-middleware-module" +version = "0.1.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=module/v0.1.0#3d3b436f7c58000c7498d68e88c15a955433a619" +dependencies = [ + "ibc-core-channel-types", + "ibc-core-host-types", + "ibc-core-router", + "ibc-core-router-types", + "ibc-primitives", +] + +[[package]] +name = "ibc-middleware-module" +version = "0.1.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=orm/v0.4.0#8d341de14ff5e2a637699796cffbf0fbbaee001f" +dependencies = [ + "ibc-core-channel-types", + "ibc-core-host-types", + "ibc-core-router", + "ibc-core-router-types", + "ibc-primitives", +] + +[[package]] +name = "ibc-middleware-module" +version = "0.1.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.9.0#3d3b436f7c58000c7498d68e88c15a955433a619" +dependencies = [ + "ibc-core-channel-types", + "ibc-core-host-types", + "ibc-core-router", + "ibc-core-router-types", + "ibc-primitives", +] + +[[package]] +name = "ibc-middleware-module-macros" +version = "0.1.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=module-macros/v0.1.0#3d3b436f7c58000c7498d68e88c15a955433a619" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "ibc-middleware-module-macros" +version = "0.1.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=orm/v0.4.0#8d341de14ff5e2a637699796cffbf0fbbaee001f" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "ibc-middleware-module-macros" +version = "0.1.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.9.0#3d3b436f7c58000c7498d68e88c15a955433a619" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "ibc-middleware-overflow-receive" +version = "0.4.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=orm/v0.4.0#8d341de14ff5e2a637699796cffbf0fbbaee001f" +dependencies = [ + "ibc-app-transfer-types", + "ibc-core-channel-types", + "ibc-core-host-types", + "ibc-core-router", + "ibc-core-router-types", + "ibc-middleware-module 0.1.0 (git+https://github.com/heliaxdev/ibc-middleware?tag=orm/v0.4.0)", + "ibc-middleware-module-macros 0.1.0 (git+https://github.com/heliaxdev/ibc-middleware?tag=orm/v0.4.0)", + "ibc-primitives", + "serde", + "serde_json", +] + [[package]] name = "ibc-middleware-packet-forward" -version = "0.8.0" -source = "git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.8.0#9c4a410063df8562c726c76009ff08b4e5a1894a" +version = "0.9.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.9.0#3d3b436f7c58000c7498d68e88c15a955433a619" dependencies = [ "borsh", "dur", @@ -3802,6 +3882,8 @@ dependencies = [ "ibc-core-host-types", "ibc-core-router", "ibc-core-router-types", + "ibc-middleware-module 0.1.0 (git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.9.0)", + "ibc-middleware-module-macros 0.1.0 (git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.9.0)", "ibc-primitives", "serde", "serde_json", @@ -5194,6 +5276,9 @@ dependencies = [ "dur", "ibc", "ibc-derive", + "ibc-middleware-module 0.1.0 (git+https://github.com/heliaxdev/ibc-middleware?tag=module/v0.1.0)", + "ibc-middleware-module-macros 0.1.0 (git+https://github.com/heliaxdev/ibc-middleware?tag=module-macros/v0.1.0)", + "ibc-middleware-overflow-receive", "ibc-middleware-packet-forward", "ibc-testkit", "ics23", @@ -5421,6 +5506,7 @@ dependencies = [ "arbitrary", "assert_matches", "async-trait", + "bech32 0.8.1", "bimap", "borsh", "circular-queue", @@ -6950,9 +7036,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.35" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] diff --git a/Cargo.toml b/Cargo.toml index 38a15f0d32..0592ba7ab6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -121,7 +121,10 @@ git2 = { version = "0.18.1", default-features = false } # branch tiago/optional-ack ibc = { git = "https://github.com/heliaxdev/cosmos-ibc-rs", rev = "38489943c4e75206eaffeeeec6153c039c2499d1", features = ["serde"] } ibc-derive = { git = "https://github.com/heliaxdev/cosmos-ibc-rs", rev = "38489943c4e75206eaffeeeec6153c039c2499d1" } -ibc-middleware-packet-forward = { git = "https://github.com/heliaxdev/ibc-middleware", tag = "pfm/v0.8.0", features = ["borsh"] } +ibc-middleware-module = { git = "https://github.com/heliaxdev/ibc-middleware", tag = "module/v0.1.0" } +ibc-middleware-module-macros = { git = "https://github.com/heliaxdev/ibc-middleware", tag = "module-macros/v0.1.0" } +ibc-middleware-overflow-receive = { git = "https://github.com/heliaxdev/ibc-middleware", tag = "orm/v0.4.0" } +ibc-middleware-packet-forward = { git = "https://github.com/heliaxdev/ibc-middleware", tag = "pfm/v0.9.0", features = ["borsh"] } ibc-testkit = { git = "https://github.com/heliaxdev/cosmos-ibc-rs", rev = "38489943c4e75206eaffeeeec6153c039c2499d1", default-features = false } ics23 = "0.12.0" usize-set = { version = "0.10.3", features = ["serialize-borsh", "serialize-serde"] } diff --git a/crates/ibc/Cargo.toml b/crates/ibc/Cargo.toml index f520e810c3..c6f2be9004 100644 --- a/crates/ibc/Cargo.toml +++ b/crates/ibc/Cargo.toml @@ -45,6 +45,9 @@ konst.workspace = true linkme = {workspace = true, optional = true} ibc.workspace = true ibc-derive.workspace = true +ibc-middleware-module.workspace = true +ibc-middleware-module-macros.workspace = true +ibc-middleware-overflow-receive.workspace = true ibc-middleware-packet-forward.workspace = true ibc-testkit = {workspace = true, optional = true} ics23.workspace = true diff --git a/crates/sdk/Cargo.toml b/crates/sdk/Cargo.toml index 517a0baaa1..f81e052373 100644 --- a/crates/sdk/Cargo.toml +++ b/crates/sdk/Cargo.toml @@ -91,6 +91,7 @@ namada_wallet = {path = "../wallet" } arbitrary = { workspace = true, optional = true } async-trait.workspace = true +bech32.workspace = true bimap.workspace = true borsh.workspace = true circular-queue.workspace = true diff --git a/wasm/Cargo.lock b/wasm/Cargo.lock index 6400887db7..1e6a4389fb 100644 --- a/wasm/Cargo.lock +++ b/wasm/Cargo.lock @@ -3076,10 +3076,90 @@ dependencies = [ "syn 2.0.96", ] +[[package]] +name = "ibc-middleware-module" +version = "0.1.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=module/v0.1.0#3d3b436f7c58000c7498d68e88c15a955433a619" +dependencies = [ + "ibc-core-channel-types", + "ibc-core-host-types", + "ibc-core-router", + "ibc-core-router-types", + "ibc-primitives", +] + +[[package]] +name = "ibc-middleware-module" +version = "0.1.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=orm/v0.4.0#8d341de14ff5e2a637699796cffbf0fbbaee001f" +dependencies = [ + "ibc-core-channel-types", + "ibc-core-host-types", + "ibc-core-router", + "ibc-core-router-types", + "ibc-primitives", +] + +[[package]] +name = "ibc-middleware-module" +version = "0.1.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.9.0#3d3b436f7c58000c7498d68e88c15a955433a619" +dependencies = [ + "ibc-core-channel-types", + "ibc-core-host-types", + "ibc-core-router", + "ibc-core-router-types", + "ibc-primitives", +] + +[[package]] +name = "ibc-middleware-module-macros" +version = "0.1.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=module-macros/v0.1.0#3d3b436f7c58000c7498d68e88c15a955433a619" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "ibc-middleware-module-macros" +version = "0.1.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=orm/v0.4.0#8d341de14ff5e2a637699796cffbf0fbbaee001f" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "ibc-middleware-module-macros" +version = "0.1.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.9.0#3d3b436f7c58000c7498d68e88c15a955433a619" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "ibc-middleware-overflow-receive" +version = "0.4.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=orm/v0.4.0#8d341de14ff5e2a637699796cffbf0fbbaee001f" +dependencies = [ + "ibc-app-transfer-types", + "ibc-core-channel-types", + "ibc-core-host-types", + "ibc-core-router", + "ibc-core-router-types", + "ibc-middleware-module 0.1.0 (git+https://github.com/heliaxdev/ibc-middleware?tag=orm/v0.4.0)", + "ibc-middleware-module-macros 0.1.0 (git+https://github.com/heliaxdev/ibc-middleware?tag=orm/v0.4.0)", + "ibc-primitives", + "serde", + "serde_json", +] + [[package]] name = "ibc-middleware-packet-forward" -version = "0.8.0" -source = "git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.8.0#9c4a410063df8562c726c76009ff08b4e5a1894a" +version = "0.9.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.9.0#3d3b436f7c58000c7498d68e88c15a955433a619" dependencies = [ "borsh", "dur", @@ -3090,6 +3170,8 @@ dependencies = [ "ibc-core-host-types", "ibc-core-router", "ibc-core-router-types", + "ibc-middleware-module 0.1.0 (git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.9.0)", + "ibc-middleware-module-macros 0.1.0 (git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.9.0)", "ibc-primitives", "serde", "serde_json", @@ -3991,6 +4073,9 @@ dependencies = [ "dur", "ibc", "ibc-derive", + "ibc-middleware-module 0.1.0 (git+https://github.com/heliaxdev/ibc-middleware?tag=module/v0.1.0)", + "ibc-middleware-module-macros 0.1.0 (git+https://github.com/heliaxdev/ibc-middleware?tag=module-macros/v0.1.0)", + "ibc-middleware-overflow-receive", "ibc-middleware-packet-forward", "ibc-testkit", "ics23", @@ -4102,6 +4187,7 @@ name = "namada_sdk" version = "0.46.1" dependencies = [ "async-trait", + "bech32 0.8.1", "bimap", "borsh", "circular-queue", @@ -5318,9 +5404,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.35" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] diff --git a/wasm_for_tests/Cargo.lock b/wasm_for_tests/Cargo.lock index f993f3e33b..f6e7a4aa12 100644 --- a/wasm_for_tests/Cargo.lock +++ b/wasm_for_tests/Cargo.lock @@ -1710,10 +1710,90 @@ dependencies = [ "syn 2.0.96", ] +[[package]] +name = "ibc-middleware-module" +version = "0.1.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=module/v0.1.0#3d3b436f7c58000c7498d68e88c15a955433a619" +dependencies = [ + "ibc-core-channel-types", + "ibc-core-host-types", + "ibc-core-router", + "ibc-core-router-types", + "ibc-primitives", +] + +[[package]] +name = "ibc-middleware-module" +version = "0.1.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=orm/v0.4.0#8d341de14ff5e2a637699796cffbf0fbbaee001f" +dependencies = [ + "ibc-core-channel-types", + "ibc-core-host-types", + "ibc-core-router", + "ibc-core-router-types", + "ibc-primitives", +] + +[[package]] +name = "ibc-middleware-module" +version = "0.1.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.9.0#3d3b436f7c58000c7498d68e88c15a955433a619" +dependencies = [ + "ibc-core-channel-types", + "ibc-core-host-types", + "ibc-core-router", + "ibc-core-router-types", + "ibc-primitives", +] + +[[package]] +name = "ibc-middleware-module-macros" +version = "0.1.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=module-macros/v0.1.0#3d3b436f7c58000c7498d68e88c15a955433a619" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "ibc-middleware-module-macros" +version = "0.1.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=orm/v0.4.0#8d341de14ff5e2a637699796cffbf0fbbaee001f" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "ibc-middleware-module-macros" +version = "0.1.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.9.0#3d3b436f7c58000c7498d68e88c15a955433a619" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "ibc-middleware-overflow-receive" +version = "0.4.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=orm/v0.4.0#8d341de14ff5e2a637699796cffbf0fbbaee001f" +dependencies = [ + "ibc-app-transfer-types", + "ibc-core-channel-types", + "ibc-core-host-types", + "ibc-core-router", + "ibc-core-router-types", + "ibc-middleware-module 0.1.0 (git+https://github.com/heliaxdev/ibc-middleware?tag=orm/v0.4.0)", + "ibc-middleware-module-macros 0.1.0 (git+https://github.com/heliaxdev/ibc-middleware?tag=orm/v0.4.0)", + "ibc-primitives", + "serde", + "serde_json", +] + [[package]] name = "ibc-middleware-packet-forward" -version = "0.8.0" -source = "git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.8.0#9c4a410063df8562c726c76009ff08b4e5a1894a" +version = "0.9.0" +source = "git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.9.0#3d3b436f7c58000c7498d68e88c15a955433a619" dependencies = [ "borsh", "dur", @@ -1724,6 +1804,8 @@ dependencies = [ "ibc-core-host-types", "ibc-core-router", "ibc-core-router-types", + "ibc-middleware-module 0.1.0 (git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.9.0)", + "ibc-middleware-module-macros 0.1.0 (git+https://github.com/heliaxdev/ibc-middleware?tag=pfm/v0.9.0)", "ibc-primitives", "serde", "serde_json", @@ -2363,6 +2445,9 @@ dependencies = [ "dur", "ibc", "ibc-derive", + "ibc-middleware-module 0.1.0 (git+https://github.com/heliaxdev/ibc-middleware?tag=module/v0.1.0)", + "ibc-middleware-module-macros 0.1.0 (git+https://github.com/heliaxdev/ibc-middleware?tag=module-macros/v0.1.0)", + "ibc-middleware-overflow-receive", "ibc-middleware-packet-forward", "ics23", "konst", @@ -3222,9 +3307,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.36" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] From 8056a78910a258fa5c851f4f897af0f1c558333b Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Mon, 13 Jan 2025 13:41:49 +0000 Subject: [PATCH 15/31] Refactor PFM module impl Co-authored-by: Jacob Turner --- crates/ibc/src/context/middlewares/pfm_mod.rs | 212 ++---------------- 1 file changed, 15 insertions(+), 197 deletions(-) diff --git a/crates/ibc/src/context/middlewares/pfm_mod.rs b/crates/ibc/src/context/middlewares/pfm_mod.rs index 70454fbf4a..f414695a5f 100644 --- a/crates/ibc/src/context/middlewares/pfm_mod.rs +++ b/crates/ibc/src/context/middlewares/pfm_mod.rs @@ -26,6 +26,8 @@ use ibc::core::host::types::identifiers::{ use ibc::core::router::module::Module; use ibc::core::router::types::module::ModuleExtras; use ibc::primitives::Signer; +use ibc_middleware_module::MiddlewareModule; +use ibc_middleware_module_macros::from_middleware; use ibc_middleware_packet_forward::{ InFlightPacket, InFlightPacketKey, PfmContext, }; @@ -60,167 +62,27 @@ impl Debug } } -impl Module for PfmTransferModule +from_middleware! { + impl Module for PfmTransferModule + where + C: IbcCommonContext + Debug, +} + +impl MiddlewareModule for PfmTransferModule where C: IbcCommonContext + Debug, { - fn on_chan_open_init_validate( - &self, - order: Order, - connection_hops: &[ConnectionId], - port_id: &PortId, - channel_id: &ChannelId, - counterparty: &Counterparty, - version: &Version, - ) -> Result { - self.transfer_module.on_chan_open_init_validate( - order, - connection_hops, - port_id, - channel_id, - counterparty, - version, - ) - } - - fn on_chan_open_init_execute( - &mut self, - order: Order, - connection_hops: &[ConnectionId], - port_id: &PortId, - channel_id: &ChannelId, - counterparty: &Counterparty, - version: &Version, - ) -> Result<(ModuleExtras, Version), ChannelError> { - self.transfer_module.on_chan_open_init_execute( - order, - connection_hops, - port_id, - channel_id, - counterparty, - version, - ) - } - - fn on_chan_open_try_validate( - &self, - order: Order, - connection_hops: &[ConnectionId], - port_id: &PortId, - channel_id: &ChannelId, - counterparty: &Counterparty, - counterparty_version: &Version, - ) -> Result { - self.transfer_module.on_chan_open_try_validate( - order, - connection_hops, - port_id, - channel_id, - counterparty, - counterparty_version, - ) - } - - fn on_chan_open_try_execute( - &mut self, - order: Order, - connection_hops: &[ConnectionId], - port_id: &PortId, - channel_id: &ChannelId, - counterparty: &Counterparty, - counterparty_version: &Version, - ) -> Result<(ModuleExtras, Version), ChannelError> { - self.transfer_module.on_chan_open_try_execute( - order, - connection_hops, - port_id, - channel_id, - counterparty, - counterparty_version, - ) - } - - fn on_chan_open_ack_validate( - &self, - port_id: &PortId, - channel_id: &ChannelId, - counterparty_version: &Version, - ) -> Result<(), ChannelError> { - self.transfer_module.on_chan_open_ack_validate( - port_id, - channel_id, - counterparty_version, - ) - } - - fn on_chan_open_ack_execute( - &mut self, - port_id: &PortId, - channel_id: &ChannelId, - counterparty_version: &Version, - ) -> Result { - self.transfer_module.on_chan_open_ack_execute( - port_id, - channel_id, - counterparty_version, - ) - } - - fn on_chan_open_confirm_validate( - &self, - port_id: &PortId, - channel_id: &ChannelId, - ) -> Result<(), ChannelError> { - self.transfer_module - .on_chan_open_confirm_validate(port_id, channel_id) - } + type NextMiddleware = TransferModule; - fn on_chan_open_confirm_execute( - &mut self, - port_id: &PortId, - channel_id: &ChannelId, - ) -> Result { - self.transfer_module - .on_chan_open_confirm_execute(port_id, channel_id) + fn next_middleware(&self) -> &Self::NextMiddleware { + &self.transfer_module } - fn on_chan_close_init_validate( - &self, - port_id: &PortId, - channel_id: &ChannelId, - ) -> Result<(), ChannelError> { - self.transfer_module - .on_chan_close_init_validate(port_id, channel_id) + fn next_middleware_mut(&mut self) -> &mut Self::NextMiddleware { + &mut self.transfer_module } - fn on_chan_close_init_execute( - &mut self, - port_id: &PortId, - channel_id: &ChannelId, - ) -> Result { - self.transfer_module - .on_chan_close_init_execute(port_id, channel_id) - } - - fn on_chan_close_confirm_validate( - &self, - port_id: &PortId, - channel_id: &ChannelId, - ) -> Result<(), ChannelError> { - self.transfer_module - .on_chan_close_confirm_validate(port_id, channel_id) - } - - fn on_chan_close_confirm_execute( - &mut self, - port_id: &PortId, - channel_id: &ChannelId, - ) -> Result { - self.transfer_module - .on_chan_close_confirm_execute(port_id, channel_id) - } - - fn on_recv_packet_execute( + fn middleware_on_recv_packet_execute( &mut self, packet: &Packet, relayer: &Signer, @@ -243,50 +105,6 @@ where self.transfer_module.on_recv_packet_execute(packet, relayer) } } - - fn on_acknowledgement_packet_validate( - &self, - packet: &Packet, - acknowledgement: &Acknowledgement, - relayer: &Signer, - ) -> Result<(), PacketError> { - self.transfer_module.on_acknowledgement_packet_validate( - packet, - acknowledgement, - relayer, - ) - } - - fn on_acknowledgement_packet_execute( - &mut self, - packet: &Packet, - acknowledgement: &Acknowledgement, - relayer: &Signer, - ) -> (ModuleExtras, Result<(), PacketError>) { - self.transfer_module.on_acknowledgement_packet_execute( - packet, - acknowledgement, - relayer, - ) - } - - fn on_timeout_packet_validate( - &self, - packet: &Packet, - relayer: &Signer, - ) -> Result<(), PacketError> { - self.transfer_module - .on_timeout_packet_validate(packet, relayer) - } - - fn on_timeout_packet_execute( - &mut self, - packet: &Packet, - relayer: &Signer, - ) -> (ModuleExtras, Result<(), PacketError>) { - self.transfer_module - .on_timeout_packet_execute(packet, relayer) - } } impl PfmContext for PfmTransferModule From e9fa6128050a397b926a93344c203b54d03b2dd8 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Mon, 13 Jan 2025 13:44:23 +0000 Subject: [PATCH 16/31] Fix IBC verifiers inclusion Co-authored-by: Jacob Turner --- crates/ibc/src/lib.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/ibc/src/lib.rs b/crates/ibc/src/lib.rs index 69a064dcb6..ea03869024 100644 --- a/crates/ibc/src/lib.rs +++ b/crates/ibc/src/lib.rs @@ -617,7 +617,7 @@ where tx_data: &[u8], ) -> Result<(Option, Option), Error> { let message = decode_message::(tx_data)?; - match message { + let result = match message { IbcMessage::Transfer(msg) => { let mut token_transfer_ctx = TokenTransferContext::new( self.ctx.inner.clone(), @@ -635,7 +635,6 @@ where )) })?, ); - self.insert_verifiers()?; if msg.transfer.is_some() { token_transfer_ctx.enable_shielded_transfer(); } @@ -665,7 +664,6 @@ where )) })?, ); - self.insert_verifiers()?; send_nft_transfer_execute( &mut self.ctx, &mut nft_transfer_ctx, @@ -685,7 +683,6 @@ where )) })?, ); - self.insert_verifiers()?; } execute(&mut self.ctx, &mut self.router, *envelope.clone()) .map_err(|e| Error::Context(Box::new(e)))?; @@ -710,7 +707,9 @@ where }; Ok((None, masp_tx)) } - } + }; + self.insert_verifiers()?; + result } /// Check the result of receiving the packet by checking the packet @@ -748,13 +747,12 @@ where let verifiers = Rc::new(RefCell::new(BTreeSet::
::new())); let message = decode_message::(tx_data)?; - match message { + let result = match message { IbcMessage::Transfer(msg) => { let mut token_transfer_ctx = TokenTransferContext::new( self.ctx.inner.clone(), verifiers.clone(), ); - self.insert_verifiers()?; if msg.transfer.is_some() { token_transfer_ctx.enable_shielded_transfer(); } @@ -782,7 +780,9 @@ where validate(&self.ctx, &self.router, *envelope) .map_err(|e| Error::Context(Box::new(e))) } - } + }; + self.insert_verifiers()?; + result } fn insert_verifiers(&self) -> Result<(), Error> { From f92bf284155e1286dae3f864a002fc00de7fe296 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Mon, 13 Jan 2025 13:57:39 +0000 Subject: [PATCH 17/31] Convert from address to signer Co-authored-by: Jacob Turner --- crates/core/src/address.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/crates/core/src/address.rs b/crates/core/src/address.rs index 0590c695eb..962b40d66c 100644 --- a/crates/core/src/address.rs +++ b/crates/core/src/address.rs @@ -393,6 +393,18 @@ impl Debug for Address { } } +impl From<&Address> for Signer { + fn from(address: &Address) -> Signer { + address.to_string().into() + } +} + +impl From
for Signer { + fn from(address: Address) -> Signer { + (&address).into() + } +} + impl TryFrom<&Signer> for Address { type Error = DecodeError; From da847b8fb351781138c320370a8243bda115957b Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Mon, 13 Jan 2025 13:58:04 +0000 Subject: [PATCH 18/31] Redenominate amounts Co-authored-by: Jacob Turner --- crates/core/src/token.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/crates/core/src/token.rs b/crates/core/src/token.rs index 7b1b4b8d62..09028217f9 100644 --- a/crates/core/src/token.rs +++ b/crates/core/src/token.rs @@ -534,6 +534,15 @@ impl DenominatedAmount { .ok_or(AmountParseError::PrecisionOverflow) } + /// Create a new [`DenominatedAmount`] with the same underlying + /// amout but a new denomination. + pub fn redenominate(self, new_denom: u8) -> Self { + Self { + amount: self.amount, + denom: new_denom.into(), + } + } + /// Multiply this number by 10^denom and return the computed integer if /// possible. Otherwise error out. pub fn scale( From 83893a7504a8413237e206fe8ce91a640c5f0000 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Mon, 13 Jan 2025 13:50:09 +0000 Subject: [PATCH 19/31] Add new Osmosis related IBC memos Co-authored-by: Jacob Turner --- crates/ibc/src/msg.rs | 140 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 3 deletions(-) diff --git a/crates/ibc/src/msg.rs b/crates/ibc/src/msg.rs index 8a15817c00..c5d75407df 100644 --- a/crates/ibc/src/msg.rs +++ b/crates/ibc/src/msg.rs @@ -1,4 +1,6 @@ use std::collections::BTreeMap; +use std::fmt; +use std::str::FromStr; use borsh::schema::{Declaration, Definition, Fields}; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; @@ -16,6 +18,106 @@ use ibc::core::host::types::identifiers::PortId; use ibc::primitives::proto::Protobuf; use masp_primitives::transaction::Transaction as MaspTransaction; use namada_core::borsh::BorshSerializeExt; +use namada_core::string_encoding::StringEncoded; +use serde::{Deserialize, Serialize}; + +trait Sealed {} + +/// Marker trait that denotes whether an IBC memo is valid +/// in Namada. +#[allow(private_bounds)] +pub trait ValidNamadaMemo: Sealed {} + +impl Sealed for NamadaMemo {} +impl ValidNamadaMemo for NamadaMemo {} + +impl Sealed for NamadaMemo {} +impl ValidNamadaMemo for NamadaMemo {} + +/// Osmosis swap memo data. +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub struct OsmosisSwapMemoData { + /// The inner memo data. + pub osmosis_swap: OsmosisSwapMemoDataInner, +} + +/// Osmosis swap inner memo data. +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub struct OsmosisSwapMemoDataInner { + /// Shielding transfer data. Hex encodes the borsh serialized MASP + /// transfer. + pub shielding_data: StringEncoded, + /// The amount that is shielded onto the MASP. Corresponds to the + /// minimum output amount from the swap. + pub shielded_amount: namada_core::token::Amount, + /// The receiver of the difference between the transferred tokens and + /// the minimum output amount. + pub overflow_receiver: namada_core::address::Address, +} + +impl From> for NamadaMemo { + fn from(memo: NamadaMemo) -> Self { + memo.namada.into() + } +} + +impl From for NamadaMemo { + fn from( + OsmosisSwapMemoData { + osmosis_swap: + OsmosisSwapMemoDataInner { + shielding_data, + shielded_amount, + overflow_receiver, + }, + }: OsmosisSwapMemoData, + ) -> Self { + Self { + namada: NamadaMemoData::OsmosisSwap { + overflow_receiver, + shielded_amount, + shielding_data, + }, + } + } +} + +impl From for NamadaMemo { + fn from(data: OsmosisSwapMemoData) -> Self { + Self { namada: data } + } +} + +/// Memo data serialized as a JSON object included +/// in IBC packets. +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub struct NamadaMemo { + /// The inner memo data. + pub namada: Data, +} + +/// Data included in a Namada memo. +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum NamadaMemoData { + /// Generic message sent over IBC. + Memo(String), + /// Osmosis swap message. + OsmosisSwap { + /// Shielding transfer data. Hex encodes the borsh serialized MASP + /// transfer. + shielding_data: StringEncoded, + /// The amount that is shielded onto the MASP. Corresponds to the + /// minimum output amount from the swap. + shielded_amount: namada_core::token::Amount, + /// The receiver of the difference between the transferred tokens and + /// the minimum output amount. + overflow_receiver: namada_core::address::Address, + }, +} /// The different variants of an Ibc message #[derive(Debug, Clone)] @@ -132,9 +234,32 @@ impl BorshSchema for MsgNftTransfer { #[derive(Debug, Clone, BorshDeserialize, BorshSerialize)] pub struct IbcShieldingData(pub MaspTransaction); +impl From<&IbcShieldingData> for String { + fn from(data: &IbcShieldingData) -> Self { + HEXUPPER.encode(&data.serialize_to_vec()) + } +} + impl From for String { fn from(data: IbcShieldingData) -> Self { - HEXUPPER.encode(&data.serialize_to_vec()) + (&data).into() + } +} + +impl fmt::Display for IbcShieldingData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", String::from(self)) + } +} + +impl FromStr for IbcShieldingData { + type Err = String; + + fn from_str(s: &str) -> Result { + let bytes = HEXUPPER + .decode(s.as_bytes()) + .map_err(|err| err.to_string())?; + IbcShieldingData::try_from_slice(&bytes).map_err(|err| err.to_string()) } } @@ -154,8 +279,17 @@ pub fn extract_masp_tx_from_envelope( pub fn decode_ibc_shielding_data( s: impl AsRef, ) -> Option { - let bytes = HEXUPPER.decode(s.as_ref().as_bytes()).ok()?; - IbcShieldingData::try_from_slice(&bytes).ok() + let sref = s.as_ref(); + + serde_json::from_str(sref).map_or_else( + |_| sref.parse().ok(), + |NamadaMemo { namada: memo_data }| match memo_data { + NamadaMemoData::Memo(memo) => memo.parse().ok(), + NamadaMemoData::OsmosisSwap { shielding_data, .. } => { + Some(shielding_data.raw) + } + }, + ) } /// Extract MASP transaction from IBC packet memo From 278de0f039129cfef1b7fbe2f1a9812377ed897a Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Mon, 13 Jan 2025 13:57:14 +0000 Subject: [PATCH 20/31] Implement shielded recv IBC middleware Co-authored-by: Jacob Turner --- crates/ibc/src/context/middlewares.rs | 18 +- .../src/context/middlewares/shielded_recv.rs | 213 ++++++++++++++++++ 2 files changed, 224 insertions(+), 7 deletions(-) create mode 100644 crates/ibc/src/context/middlewares/shielded_recv.rs diff --git a/crates/ibc/src/context/middlewares.rs b/crates/ibc/src/context/middlewares.rs index 8d65666e63..d563071bde 100644 --- a/crates/ibc/src/context/middlewares.rs +++ b/crates/ibc/src/context/middlewares.rs @@ -1,7 +1,7 @@ //! Middleware entry points on Namada. pub mod pfm_mod; -// mod crossroads_mod; +pub mod shielded_recv; use std::cell::RefCell; use std::collections::BTreeSet; @@ -12,16 +12,18 @@ use std::rc::Rc; use ibc::core::host::types::identifiers::PortId; use ibc::core::router::module::Module; use ibc::core::router::types::module::ModuleId; -use ibc_middleware_packet_forward::{PacketForwardMiddleware, PfmContext}; +use ibc_middleware_overflow_receive::OverflowReceiveMiddleware; +use ibc_middleware_packet_forward::PacketForwardMiddleware; use namada_core::address::Address; use self::pfm_mod::PfmTransferModule; +use self::shielded_recv::ShieldedRecvModule; use crate::context::transfer_mod::TransferModule; use crate::{IbcCommonContext, IbcStorageContext}; /// The stack of middlewares of the transfer module. pub type TransferMiddlewares = - PacketForwardMiddleware>; + OverflowReceiveMiddleware>; /// Create a new instance of [`TransferMiddlewares`] pub fn create_transfer_middlewares( @@ -32,16 +34,18 @@ where C: IbcCommonContext + Debug, Params: namada_systems::parameters::Read<::Storage>, { - PacketForwardMiddleware::wrap(PfmTransferModule { - transfer_module: TransferModule::new(ctx, verifiers), - _phantom: PhantomData, + OverflowReceiveMiddleware::wrap(ShieldedRecvModule { + next: PacketForwardMiddleware::wrap(PfmTransferModule { + transfer_module: TransferModule::new(ctx, verifiers), + _phantom: PhantomData, + }), }) } impl crate::ModuleWrapper for TransferMiddlewares where C: IbcCommonContext + Debug, - PfmTransferModule: PfmContext, + Params: namada_systems::parameters::Read<::Storage>, { fn as_module(&self) -> &dyn Module { self diff --git a/crates/ibc/src/context/middlewares/shielded_recv.rs b/crates/ibc/src/context/middlewares/shielded_recv.rs new file mode 100644 index 0000000000..56aa5d42d0 --- /dev/null +++ b/crates/ibc/src/context/middlewares/shielded_recv.rs @@ -0,0 +1,213 @@ +//! This middleware is to handle automatically shielding the results of a +//! shielded swap. +//! +//! Since we do not know the resulting amount of assets from the swap ahead of +//! time, we cannot create a MASP note at the onset. We instead, create a note +//! for the minimum amount, which will be shielded. All assets exceeding the +//! minimum amount will be transferred to an overflow address specified by +//! the user. + +use std::cell::RefCell; +use std::collections::BTreeSet; +use std::fmt::{Debug, Formatter}; +use std::rc::Rc; + +use ibc::apps::transfer::context::TokenTransferExecutionContext; +use ibc::apps::transfer::types::packet::PacketData; +use ibc::apps::transfer::types::{Coin, PrefixedDenom}; +use ibc::core::channel::types::acknowledgement::{ + Acknowledgement, AcknowledgementStatus, StatusValue as AckStatusValue, +}; +use ibc::core::channel::types::channel::{Counterparty, Order}; +use ibc::core::channel::types::error::{ChannelError, PacketError}; +use ibc::core::channel::types::packet::Packet; +use ibc::core::channel::types::Version; +use ibc::core::host::types::identifiers::{ChannelId, ConnectionId, PortId}; +use ibc::core::router::module::Module; +use ibc::core::router::types::module::ModuleExtras; +use ibc::primitives::Signer; +use ibc_middleware_module::MiddlewareModule; +use ibc_middleware_module_macros::from_middleware; +use ibc_middleware_overflow_receive::OverflowRecvContext; +use ibc_middleware_packet_forward::PacketForwardMiddleware; +use namada_core::address::{Address, MASP, MULTITOKEN}; +use namada_core::token; +use serde_json::{Map, Value}; + +use crate::context::middlewares::pfm_mod::PfmTransferModule; +use crate::msg::{NamadaMemo, OsmosisSwapMemoData}; +use crate::{Error, IbcCommonContext, IbcStorageContext, TokenTransferContext}; + +/// A middleware for handling IBC pockets received +/// after a shielded swap. The minimum amount will +/// be shielded and the rest placed in an overflow +/// account. +pub struct ShieldedRecvModule +where + C: IbcCommonContext + Debug, + Params: namada_systems::parameters::Read<::Storage>, +{ + /// The next middleware module + pub next: PacketForwardMiddleware>, +} + +impl ShieldedRecvModule +where + C: IbcCommonContext + Debug, + Params: namada_systems::parameters::Read<::Storage>, +{ + fn insert_verifier(&self, address: Address) { + self.next + .next() + .transfer_module + .ctx + .verifiers + .borrow_mut() + .insert(address); + } + + fn get_ctx(&self) -> Rc> { + self.next.next().transfer_module.ctx.inner.clone() + } + + fn get_verifiers(&self) -> Rc>> { + self.next.next().transfer_module.ctx.verifiers.clone() + } +} + +impl Debug for ShieldedRecvModule +where + C: IbcCommonContext + Debug, + Params: namada_systems::parameters::Read<::Storage>, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct(stringify!(ShieldedRecvModule)) + .field("next", &self.next) + .finish() + } +} + +from_middleware! { + impl Module for ShieldedRecvModule + where + C: IbcCommonContext + Debug, + Params: namada_systems::parameters::Read<::Storage>, +} + +impl MiddlewareModule for ShieldedRecvModule +where + C: IbcCommonContext + Debug, + Params: namada_systems::parameters::Read<::Storage>, +{ + type NextMiddleware = PacketForwardMiddleware>; + + fn next_middleware(&self) -> &Self::NextMiddleware { + &self.next + } + + fn next_middleware_mut(&mut self) -> &mut Self::NextMiddleware { + &mut self.next + } + + fn middleware_on_recv_packet_execute( + &mut self, + packet: &Packet, + relayer: &Signer, + ) -> (ModuleExtras, Option) { + let Ok(data) = serde_json::from_slice::(&packet.data) + else { + // NB: this isn't an ICS-20 packet + return self.next.on_recv_packet_execute(packet, relayer); + }; + let Ok(memo) = serde_json::from_str::>( + data.memo.as_ref(), + ) else { + // NB: this isn't a shielded recv packet + return self.next.on_recv_packet_execute(packet, relayer); + }; + + if data.receiver.as_ref() != MASP.to_string() { + let ack = AcknowledgementStatus::error( + AckStatusValue::new(format!( + "Shielded receive error: Address {:?} is not the MASP", + data.receiver.as_ref() + )) + .expect("Ack is not empty"), + ); + return (ModuleExtras::empty(), Some(ack.into())); + } + + self.insert_verifier(memo.namada.osmosis_swap.overflow_receiver); + self.insert_verifier(MULTITOKEN); + + self.next.on_recv_packet_execute(packet, relayer) + } +} + +impl ibc_middleware_overflow_receive::PacketMetadata + for NamadaMemo +{ + type AccountId = Address; + type Amount = token::Amount; + + fn is_overflow_receive_msg(msg: &Map) -> bool { + msg.get("namada").map_or(false, |maybe_namada_obj| { + maybe_namada_obj + .as_object() + .map_or(false, |namada| namada.contains_key("osmosis_swap")) + }) + } + + fn strip_middleware_msg( + json_obj_memo: Map, + ) -> Map { + json_obj_memo + } + + fn overflow_receiver(&self) -> &Address { + &self.namada.osmosis_swap.overflow_receiver + } + + fn target_amount(&self) -> &token::Amount { + &self.namada.osmosis_swap.shielded_amount + } +} + +impl OverflowRecvContext for ShieldedRecvModule +where + C: IbcCommonContext + Debug, + Params: namada_systems::parameters::Read<::Storage>, +{ + type Error = Error; + type PacketMetadata = NamadaMemo; + + fn mint_coins_execute( + &mut self, + receiver: &Address, + coin: &Coin, + ) -> Result<(), Self::Error> { + let ctx = self.get_ctx(); + let verifiers = self.get_verifiers(); + let mut token_transfer_context = + TokenTransferContext::new(ctx, verifiers); + token_transfer_context + .mint_coins_execute(receiver, coin) + .map_err(Error::TokenTransfer) + } + + fn unescrow_coins_execute( + &mut self, + receiver: &Address, + port: &PortId, + channel: &ChannelId, + coin: &Coin, + ) -> Result<(), Self::Error> { + let ctx = self.get_ctx(); + let verifiers = self.get_verifiers(); + let mut token_transfer_context = + TokenTransferContext::new(ctx, verifiers); + token_transfer_context + .unescrow_coins_execute(receiver, port, channel, coin) + .map_err(Error::TokenTransfer) + } +} From f5bbcdd564d27f1eb83f94b46507625831b5125d Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Mon, 13 Jan 2025 14:04:49 +0000 Subject: [PATCH 21/31] Implement Osmosis swap SDK functionality Co-authored-by: Jacob Turner --- crates/apps_lib/src/cli.rs | 25 ++- crates/sdk/src/args.rs | 337 +++++++++++++++++++++++++++++++- crates/sdk/src/rpc.rs | 384 ++++++++++++++++++++++++++++++++++++- crates/sdk/src/tx.rs | 45 +++-- 4 files changed, 759 insertions(+), 32 deletions(-) diff --git a/crates/apps_lib/src/cli.rs b/crates/apps_lib/src/cli.rs index ed74f4cf08..6a19c24781 100644 --- a/crates/apps_lib/src/cli.rs +++ b/crates/apps_lib/src/cli.rs @@ -6857,11 +6857,22 @@ pub mod args { query, output_folder: self.output_folder, target: chain_ctx.get(&self.target), - token: self.token, amount: self.amount, expiration: self.expiration, - port_id: self.port_id, - channel_id: self.channel_id, + asset: match self.asset { + IbcShieldingTransferAsset::LookupNamadaAddress { + port_id, + channel_id, + token, + } => IbcShieldingTransferAsset::LookupNamadaAddress { + port_id, + channel_id, + token, + }, + IbcShieldingTransferAsset::Address(addr) => { + IbcShieldingTransferAsset::Address(chain_ctx.get(&addr)) + } + }, }) } } @@ -6890,11 +6901,13 @@ pub mod args { query, output_folder, target, - token, amount, expiration, - port_id, - channel_id, + asset: IbcShieldingTransferAsset::LookupNamadaAddress { + port_id, + channel_id, + token, + }, } } diff --git a/crates/sdk/src/args.rs b/crates/sdk/src/args.rs index 84274231ff..f0f211db09 100644 --- a/crates/sdk/src/args.rs +++ b/crates/sdk/src/args.rs @@ -8,7 +8,7 @@ use std::time::Duration as StdDuration; use either::Either; use masp_primitives::transaction::components::sapling::builder::BuildParams; use masp_primitives::zip32::PseudoExtendedKey; -use namada_core::address::Address; +use namada_core::address::{Address, MASP}; use namada_core::chain::{BlockHeight, ChainId, Epoch}; use namada_core::collections::HashMap; use namada_core::dec::Dec; @@ -16,7 +16,9 @@ use namada_core::ethereum_events::EthAddress; use namada_core::keccak::KeccakHash; use namada_core::key::{common, SchemeType}; use namada_core::masp::{MaspEpoch, PaymentAddress}; +use namada_core::string_encoding::StringEncoded; use namada_core::time::DateTimeUtc; +use namada_core::token::Amount; use namada_core::{storage, token}; use namada_governance::cli::onchain::{ DefaultProposal, PgfFundingProposal, PgfStewardProposal, @@ -28,8 +30,14 @@ use namada_tx::Memo; use serde::{Deserialize, Serialize}; use zeroize::Zeroizing; +use crate::error::Error; use crate::eth_bridge::bridge_pool; use crate::ibc::core::host::types::identifiers::{ChannelId, PortId}; +use crate::ibc::{NamadaMemo, NamadaMemoData}; +use crate::rpc::{ + get_registry_from_xcs_osmosis_contract, osmosis_denom_from_namada_denom, + query_osmosis_pool_routes, +}; use crate::signing::SigningTxData; use crate::wallet::{DatedSpendingKey, DatedViewingKey}; use crate::{rpc, tx, Namada}; @@ -477,6 +485,309 @@ impl TxUnshieldingTransfer { } } +/// Individual hop of some route to take through Osmosis pools. +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct OsmosisPoolHop { + /// The id of the pool to use on Osmosis. + pub pool_id: String, + /// The output denomination expected from the + /// pool on Osmosis. + pub token_out_denom: String, +} + +impl FromStr for OsmosisPoolHop { + type Err = String; + + fn from_str(s: &str) -> Result { + s.split_once(':').map_or_else( + || { + Err(format!( + "Expected : string, but found \ + {s:?} instead" + )) + }, + |(pool_id, token_out_denom)| { + Ok(OsmosisPoolHop { + pool_id: pool_id.to_owned(), + token_out_denom: token_out_denom.to_owned(), + }) + }, + ) + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +/// Constraints on the osmosis swap +pub enum Slippage { + /// Specifies the minimum amount to be received + MinOutputAmount(Amount), + /// A time-weighted average price + Twap { + /// The maximum percentage difference allowed between the estimated and + /// actual trade price. This must be a decimal number in the range + /// `[0, 100]`. + slippage_percentage: String, + /// The time period (in seconds) over which the average price is + /// calculated + window_seconds: u64, + }, +} + +/// An token swap on Osmosis +#[derive(Debug, Clone)] +pub struct TxOsmosisSwap { + /// The IBC transfer data + pub transfer: TxIbcTransfer, + /// The token we wish to receive (on Namada) + pub output_denom: String, + /// Address of the recipient on Namada + pub recipient: Either, + /// Address to receive funds exceeding the minimum amount + pub overflow: Option, + /// Constraints on the osmosis swap + pub slippage: Slippage, + /// Recovery address (on Osmosis) in case of failure + pub local_recovery_addr: String, + /// The route to take through Osmosis pools + pub route: Option>, + /// A REST rpc endpoint to Osmosis + pub osmosis_rest_rpc: String, +} + +impl TxOsmosisSwap { + /// Create an IBC transfer from the input arguments + pub async fn into_ibc_transfer( + self, + ctx: &impl Namada, + ) -> crate::error::Result> { + #[derive(Serialize)] + struct Memo { + wasm: Wasm, + } + + #[derive(Serialize)] + struct Wasm { + contract: String, + msg: Message, + } + + #[derive(Serialize)] + struct Message { + osmosis_swap: OsmosisSwap, + } + + #[derive(Serialize)] + struct OsmosisSwap { + receiver: String, + output_denom: String, + slippage: Slippage, + on_failed_delivery: LocalRecoveryAddr, + route: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + final_memo: Option>, + } + + #[derive(Serialize)] + struct LocalRecoveryAddr { + local_recovery_addr: String, + } + + #[inline] + fn assert_json_obj( + value: serde_json::Value, + ) -> serde_json::Map { + match value { + serde_json::Value::Object(x) => x, + _ => unreachable!(), + } + } + + const OSMOSIS_SQS_SERVER: &str = "https://sqsprod.osmosis.zone"; + + let Self { + mut transfer, + recipient, + slippage, + local_recovery_addr, + route, + overflow, + osmosis_rest_rpc, + output_denom: namada_output_denom, + } = self; + + let recipient = recipient + .map_either(Some, |payment_addr| Some(payment_addr).zip(overflow)) + .factor_none() + .ok_or_else(|| { + Error::Other( + "Overflow receiver unspecified while attempting a fully \ + shielded swap" + .to_owned(), + ) + })?; + + // validate `local_recovery_addr` and the contract addr + if !bech32::decode(&local_recovery_addr) + .is_ok_and(|(hrp, _, _)| hrp == "osmo") + { + // TODO: validate that addr has 20 bytes? + return Err(Error::Other(format!( + "Invalid Osmosis recovery address {local_recovery_addr:?}" + ))); + } + if !bech32::decode(&transfer.receiver) + .is_ok_and(|(hrp, _, _)| hrp == "osmo") + { + // TODO: validate that addr has 32 bytes? + return Err(Error::Other(format!( + "Invalid Osmosis contract address {local_recovery_addr:?}" + ))); + } + + let registry_xcs_addr = get_registry_from_xcs_osmosis_contract( + &osmosis_rest_rpc, + &transfer.receiver, + ) + .await?; + + let (osmosis_output_denom, namada_output_addr) = + osmosis_denom_from_namada_denom( + &osmosis_rest_rpc, + ®istry_xcs_addr, + &namada_output_denom, + ) + .await?; + + let route = if let Some(route) = route { + route + } else { + query_osmosis_pool_routes( + ctx, + &transfer.token, + transfer.amount, + transfer.channel_id.clone(), + &osmosis_output_denom, + OSMOSIS_SQS_SERVER, + ) + .await? + .pop() + .ok_or_else(|| { + Error::Other(format!( + "No route found to swap {:?} of {} with {}", + transfer.amount, transfer.token, namada_output_addr, + )) + })? + }; + + let (receiver, slippage, final_memo) = match recipient { + Either::Left(transparent_recipient) => { + (transparent_recipient.to_string(), slippage, None) + } + Either::Right((payment_addr, overflow_receiver)) => { + let amount_to_shield = match slippage { + Slippage::MinOutputAmount(amount_to_shield) => { + amount_to_shield + } + Slippage::Twap { .. } => todo!( + "Cannot compute min output amount from slippage TWAP \ + yet" + ), + }; + + let shielding_tx = tx::gen_ibc_shielding_transfer( + ctx, + GenIbcShieldingTransfer { + query: Query { + ledger_address: transfer.tx.ledger_address.clone(), + }, + output_folder: None, + target: + namada_core::masp::TransferTarget::PaymentAddress( + payment_addr, + ), + asset: IbcShieldingTransferAsset::Address( + namada_output_addr, + ), + amount: InputAmount::Validated( + token::DenominatedAmount::new( + amount_to_shield, + 0u8.into(), + ), + ), + expiration: transfer.tx.expiration.clone(), + }, + ) + .await? + .ok_or_else(|| { + Error::Other( + "Failed to generate IBC shielding transfer".to_owned(), + ) + })?; + + let memo = assert_json_obj( + serde_json::to_value(&NamadaMemo { + namada: NamadaMemoData::OsmosisSwap { + shielding_data: StringEncoded::new( + IbcShieldingData(shielding_tx), + ), + shielded_amount: amount_to_shield, + overflow_receiver, + }, + }) + .unwrap(), + ); + + ( + MASP.to_string(), + Slippage::MinOutputAmount(amount_to_shield), + Some(memo), + ) + } + }; + + let cosmwasm_memo = Memo { + wasm: Wasm { + contract: transfer.receiver.clone(), + msg: Message { + osmosis_swap: OsmosisSwap { + output_denom: osmosis_output_denom, + slippage, + final_memo, + receiver, + on_failed_delivery: LocalRecoveryAddr { + local_recovery_addr, + }, + route, + }, + }, + }, + }; + let namada_memo = transfer.ibc_memo.take().map(|memo| { + assert_json_obj( + serde_json::to_value(&NamadaMemo { + namada: NamadaMemoData::Memo(memo), + }) + .unwrap(), + ) + }); + + let memo = { + let mut m = serde_json::to_value(&cosmwasm_memo).unwrap(); + let m_obj = m.as_object_mut().unwrap(); + + if let Some(mut namada_memo) = namada_memo { + m_obj.append(&mut namada_memo); + } + + m + }; + + transfer.ibc_memo = Some(serde_json::to_string(&memo).unwrap()); + Ok(transfer) + } +} + /// IBC transfer transaction arguments #[derive(Clone, Debug)] pub struct TxIbcTransfer { @@ -2918,14 +3229,26 @@ pub struct GenIbcShieldingTransfer { pub output_folder: Option, /// The target address pub target: C::TransferTarget, - /// The token address which could be a non-namada address - pub token: String, /// Transferred token amount pub amount: InputAmount, /// The optional expiration of the masp shielding transaction pub expiration: TxExpiration, - /// Port ID via which the token is received - pub port_id: PortId, - /// Channel ID via which the token is received - pub channel_id: ChannelId, + /// Asset to shield over IBC to Namada + pub asset: IbcShieldingTransferAsset, +} + +/// IBC shielding transfer asset, to be used by [`GenIbcShieldingTransfer`] +#[derive(Clone, Debug)] +pub enum IbcShieldingTransferAsset { + /// Attempt to look-up the address of the asset to shield on Namada + LookupNamadaAddress { + /// The token address which could be a non-namada address + token: String, + /// Port ID via which the token is received + port_id: PortId, + /// Channel ID via which the token is received + channel_id: ChannelId, + }, + /// Namada address of the token that will be received. + Address(C::Address), } diff --git a/crates/sdk/src/rpc.rs b/crates/sdk/src/rpc.rs index 2e9792b61c..eac8e2159e 100644 --- a/crates/sdk/src/rpc.rs +++ b/crates/sdk/src/rpc.rs @@ -2,6 +2,7 @@ #![allow(clippy::result_large_err)] +use core::str::FromStr; use std::cell::Cell; use std::collections::{BTreeMap, BTreeSet}; use std::ops::ControlFlow; @@ -16,6 +17,9 @@ use namada_core::arith::checked; use namada_core::chain::{BlockHeight, Epoch}; use namada_core::collections::{HashMap, HashSet}; use namada_core::hash::Hash; +use namada_core::ibc::apps::nft_transfer::types::TracePrefix; +use namada_core::ibc::apps::transfer::types::PrefixedDenom; +use namada_core::ibc::core::host::types::identifiers::ChannelId; use namada_core::ibc::IbcTokenHash; use namada_core::key::common; use namada_core::masp::MaspEpoch; @@ -36,9 +40,11 @@ use namada_governance::storage::proposal::{ use namada_governance::utils::{ compute_proposal_result, ProposalResult, ProposalVotes, Vote, }; +use namada_ibc::core::host::types::identifiers::PortId; use namada_ibc::storage::{ ibc_trace_key, ibc_trace_key_prefix, is_ibc_trace_key, }; +use namada_ibc::trace::calc_ibc_token_hash; use namada_io::{display_line, edisplay_line, Client, Io}; use namada_parameters::{storage as params_storage, EpochDuration}; use namada_proof_of_stake::parameters::PosParams; @@ -51,9 +57,9 @@ use namada_state::{BlockHeader, LastBlock}; use namada_token::masp::MaspTokenRewardData; use namada_tx::data::{BatchedTxResult, DryRunResult, ResultCode, TxResult}; use namada_tx::event::{Batch as BatchAttr, Code as CodeAttr}; -use serde::Serialize; +use serde::{Deserialize, Serialize}; -use crate::args::InputAmount; +use crate::args::{InputAmount, OsmosisPoolHop}; use crate::control_flow::time; use crate::error::{EncodingError, Error, QueryError, TxSubmitError}; use crate::events::{extend, Event}; @@ -65,6 +71,7 @@ use crate::queries::RPC; use crate::tendermint::block::Height; use crate::tendermint::merkle::proof::ProofOps; use crate::tendermint_rpc::query::Query; +use crate::tx::get_ibc_src_port_channel; use crate::{error, Namada, Tx}; /// Query an estimate of the maximum block time. @@ -1518,3 +1525,376 @@ pub async fn query_ibc_denom( token.as_ref().to_string() } + +/// Query the registry contract embedded in the state of +/// an input Crosschain Swaps Osmosis contract. +pub async fn get_registry_from_xcs_osmosis_contract( + rest_rpc_addr: &str, + xcs_contract_addr: &str, +) -> Result { + #[derive(Deserialize)] + struct RespData { + models: Vec, + } + + #[derive(Deserialize)] + struct Model { + key: String, + value: String, + } + + #[derive(Deserialize)] + struct XcsConfig { + registry_contract: String, + } + + let request_url = format!( + "{rest_rpc_addr}/cosmwasm/wasm/v1/contract/{xcs_contract_addr}/state" + ); + let RespData { models } = reqwest::get(&request_url) + .await + .map_err(|e| { + Error::Other(format!( + "Failed to fetch headers of request {request_url:?}: {e}" + )) + })? + .json() + .await + .map_err(|e| { + Error::Other(format!( + "Failed to fetch JSON body of request {request_url:?}: {e}" + )) + })?; + + let Some(Model { + value: base64_encoded_config, + .. + }) = models.into_iter().find(|Model { key, .. }| { + // NB: this value corresponds to the hex encoding of the + // string "config". the crosschain swaps contract of the set + // of xcs contracts stores, in its internal state, the params + // it was initialized with, namely the address of the registry + // contract. the point behind querying the initialization + // params is to ultimately query the address of the registry + // contract. + const HEX_ENCODED_CONFIG_KEY: &str = "636F6E666967"; + key == HEX_ENCODED_CONFIG_KEY + }) + else { + return Err(Error::Other(format!( + "Could not find config of XCS contract {xcs_contract_addr}" + ))); + }; + + let xcs_cfg_json = data_encoding::BASE64 + .decode(base64_encoded_config.as_bytes()) + .map_err(|e| Error::Other(e.to_string()))?; + + let XcsConfig { registry_contract } = serde_json::from_slice(&xcs_cfg_json) + .map_err(|e| Error::Other(e.to_string()))?; + + Ok(registry_contract) +} + +/// Given a Namada asset returned from an Osmosis swap, +/// find the corresponding asset denom on Osmosis. +/// +/// This is done by querying the XCS registry contract. The Namada asset +/// is also returned, parsed as an [`Address`]. +pub async fn osmosis_denom_from_namada_denom( + rest_rpc_addr: &str, + registry_contract_addr: &str, + namada_denom: &str, +) -> Result<(String, Address), Error> { + async fn fetch_contract_data( + contract_addr: &str, + rest_rpc_addr: &str, + json_query: &str, + ) -> Result { + #[derive(Deserialize)] + struct RespData { + data: String, + } + + let encoded_query = data_encoding::BASE64.encode(json_query.as_bytes()); + let request_url = format!( + "{rest_rpc_addr}/cosmwasm/wasm/v1/contract/{contract_addr}/smart/\ + {encoded_query}" + ); + + let RespData { data } = reqwest::get(&request_url) + .await + .map_err(|e| { + Error::Other(format!( + "Failed to fetch headers of request {request_url:?}: {e}" + )) + })? + .json() + .await + .map_err(|e| { + Error::Other(format!( + "Failed to fetch JSON body of request {request_url:?}: {e}" + )) + })?; + + Ok(data) + } + + let chain_name_req = |prefix| { + format!( + r#"{{"get_chain_name_from_bech32_prefix": {{"prefix": "{prefix}" }} }}"# + ) + }; + let channel_pair_req = |src, dest| { + format!( + r#"{{"get_channel_from_chain_pair": {{"source_chain": "{src}", "destination_chain": "{dest}" }} }}"# + ) + }; + let dest_chain_req = |on_chain, via_channel| { + format!( + r#"{{"get_destination_chain_from_source_chain_via_channel": {{"on_chain": "{on_chain}", "via_channel": "{via_channel}" }} }}"# + ) + }; + + //////////////////////////////////////////////////////////////////////////// + + let nam_denom = PrefixedDenom::from_str(namada_denom).map_err(|e| { + Error::Other(format!( + "Could not parse {namada_denom} as a trace path {e}" + )) + })?; + + let namada_chain_name = fetch_contract_data( + registry_contract_addr, + rest_rpc_addr, + &chain_name_req("tnam"), + ) + .await?; + let osmosis_chain_name = fetch_contract_data( + registry_contract_addr, + rest_rpc_addr, + &chain_name_req("osmo"), + ) + .await?; + + if nam_denom.trace_path.is_empty() { + // Namada native asset + + let address = nam_denom + .base_denom + .as_str() + .parse::
() + .map_err(|err| { + Error::Encode(EncodingError::Decoding(format!( + "Failed to parse base denom {} as Namada address: {err}", + nam_denom.base_denom + ))) + })?; + + // validate that the base denom is not another ibc token + if matches!(&address, Address::Internal(InternalAddress::IbcToken(_))) { + return Err(Error::Encode(EncodingError::Decoding(format!( + "Base denom {} cannot be an IBC token hash", + nam_denom.base_denom + )))); + } + + let channel_from_osmosis_to_namada = fetch_contract_data( + registry_contract_addr, + rest_rpc_addr, + &channel_pair_req(&osmosis_chain_name, &namada_chain_name), + ) + .await?; + + Ok(( + format!( + "transfer/{channel_from_osmosis_to_namada}/{}", + nam_denom.base_denom + ), + address, + )) + } else { + let channel_from_namada_to_src: ChannelId = nam_denom + .trace_path + .to_string() + .strip_prefix("transfer/") + .ok_or_else(|| { + Error::Other( + "Expected the output denom to originate from the transfer \ + port" + .to_string(), + ) + })? + .parse() + .map_err(|_| { + Error::Other(format!( + "Expected a single hop of the form `transfer/channel` in \ + {namada_denom}" + )) + })?; + + // we get chain name from which the base denom originated + let src_chain_name = fetch_contract_data( + registry_contract_addr, + rest_rpc_addr, + &dest_chain_req( + &namada_chain_name, + channel_from_namada_to_src.as_str(), + ), + ) + .await?; + + if src_chain_name == osmosis_chain_name { + // this is an osmosis native token + Ok(( + nam_denom.base_denom.to_string(), + namada_ibc::trace::ibc_token(namada_denom), + )) + } else { + // this asset is not native to osmosis + let channel_from_osmosis_to_src = fetch_contract_data( + registry_contract_addr, + rest_rpc_addr, + &channel_pair_req(&osmosis_chain_name, &src_chain_name), + ) + .await?; + + Ok(( + format!( + "transfer/{channel_from_osmosis_to_src}/{}", + nam_denom.base_denom + ), + namada_ibc::trace::ibc_token(namada_denom), + )) + } + } +} + +/// Query a route of Osmosis liquidity pools +/// for swapping betwixt token and output_denom +/// assets. +pub async fn query_osmosis_pool_routes( + ctx: &impl Namada, + token: &Address, + amount: InputAmount, + channel_id: ChannelId, + output_denom: &str, + osmosis_sqs_server_url: &str, +) -> Result>, Error> { + #[derive(Deserialize)] + struct PoolHop { + id: u64, + token_out_denom: String, + } + + impl From for OsmosisPoolHop { + fn from(value: PoolHop) -> Self { + Self { + pool_id: value.id.to_string(), + token_out_denom: value.token_out_denom, + } + } + } + + #[derive(Deserialize)] + struct Route { + pools: Vec, + } + + #[derive(Deserialize)] + struct ResponseOk { + route: Vec, + } + + #[derive(Deserialize)] + struct ResponseErr { + message: String, + } + + let coin = { + let denom = query_ibc_denom(ctx, token.to_string(), None).await; + let amount = validate_amount(ctx, amount, token, false).await?; + + let PrefixedDenom { + mut trace_path, + base_denom, + } = PrefixedDenom::from_str(&denom).map_err(|_| { + Error::Other(format!( + "Could not decode {token} as an IBC token address" + )) + })?; + + let prefix_on_namada = + TracePrefix::new(PortId::transfer(), channel_id.clone()); + + if trace_path.starts_with(&prefix_on_namada) { + // we received an asset from osmosis, so the asset we + // send back won't have our `transfer/channel` prefix + trace_path.remove_prefix(&prefix_on_namada); + } else { + // in this case, osmosis will prefix the asset it receives + // with the channel to namada + let channel = + get_ibc_src_port_channel(ctx, &PortId::transfer(), &channel_id) + .await? + .1; + trace_path + .add_prefix(TracePrefix::new(PortId::transfer(), channel)); + } + + let amount = amount.redenominate(0); + + let token_denom = if trace_path.is_empty() { + base_denom.to_string() + } else { + format!( + "ibc/{}", + calc_ibc_token_hash( + PrefixedDenom { + trace_path, + base_denom + } + .to_string() + ) + ) + }; + + format!("{amount}{token_denom}") + }; + + let client = reqwest::Client::new(); + let response = client + .get(format!("{osmosis_sqs_server_url}/router/quote")) + .query(&[ + ("tokenIn", coin.as_str()), + ("tokenOutDenom", output_denom), + ("humanDenoms", "false"), + ]) + .send() + .await + .map_err(|err| { + Error::Other(format!("Failed to query Osmosis SQS: {err}",)) + })?; + + if !response.status().is_success() { + let ResponseErr { message } = response.json().await.map_err(|err| { + Error::Other(format!( + "Failed to read failure response from HTTP request body: {err}" + )) + })?; + return Err(Error::Other(format!( + "Invalid Osmosis SQS query: {message}" + ))); + } + + let ResponseOk { route } = response.json().await.map_err(|err| { + Error::Other(format!( + "Failed to read success response from HTTP request body: {err}" + )) + })?; + + Ok(route + .into_iter() + .map(|r| r.pools.into_iter().map(OsmosisPoolHop::from).collect()) + .collect()) +} diff --git a/crates/sdk/src/tx.rs b/crates/sdk/src/tx.rs index 19a6a5ba17..9c8c3834e5 100644 --- a/crates/sdk/src/tx.rs +++ b/crates/sdk/src/tx.rs @@ -3884,22 +3884,33 @@ pub async fn gen_ibc_shielding_transfer( args: args::GenIbcShieldingTransfer, ) -> Result> { let source = IBC; - let (src_port_id, src_channel_id) = - get_ibc_src_port_channel(context, &args.port_id, &args.channel_id) - .await?; - let ibc_denom = - rpc::query_ibc_denom(context, &args.token, Some(&source)).await; - // Need to check the prefix - let token = namada_ibc::received_ibc_token( - &ibc_denom, - &src_port_id, - &src_channel_id, - &args.port_id, - &args.channel_id, - ) - .map_err(|e| { - Error::Other(format!("Getting IBC Token failed: error {e}")) - })?; + + let token = match args.asset { + args::IbcShieldingTransferAsset::Address(addr) => addr, + args::IbcShieldingTransferAsset::LookupNamadaAddress { + token, + port_id, + channel_id, + } => { + let (src_port_id, src_channel_id) = + get_ibc_src_port_channel(context, &port_id, &channel_id) + .await?; + let ibc_denom = + rpc::query_ibc_denom(context, &token, Some(&source)).await; + + namada_ibc::received_ibc_token( + &ibc_denom, + &src_port_id, + &src_channel_id, + &port_id, + &channel_id, + ) + .map_err(|e| { + Error::Other(format!("Getting IBC Token failed: error {e}")) + })? + } + }; + let validated_amount = validate_amount(context, args.amount, &token, false).await?; @@ -3936,7 +3947,7 @@ pub async fn gen_ibc_shielding_transfer( Ok(shielded_transfer.map(|st| st.masp_tx)) } -async fn get_ibc_src_port_channel( +pub(crate) async fn get_ibc_src_port_channel( context: &impl Namada, dest_port_id: &PortId, dest_channel_id: &ChannelId, From 5aedb84844d54f2d783bc59f3d4ccf31d8a52c0d Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Mon, 13 Jan 2025 14:09:00 +0000 Subject: [PATCH 22/31] Avoid full gen IBC shielding args clone Co-authored-by: Jacob Turner --- crates/apps_lib/src/client/tx.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/apps_lib/src/client/tx.rs b/crates/apps_lib/src/client/tx.rs index f954e43dc4..a2f8b03037 100644 --- a/crates/apps_lib/src/client/tx.rs +++ b/crates/apps_lib/src/client/tx.rs @@ -1909,12 +1909,13 @@ pub async fn gen_ibc_shielding_transfer( context: &impl Namada, args: args::GenIbcShieldingTransfer, ) -> Result<(), error::Error> { - if let Some(masp_tx) = - tx::gen_ibc_shielding_transfer(context, args.clone()).await? + let output_folder = args.output_folder.clone(); + + if let Some(masp_tx) = tx::gen_ibc_shielding_transfer(context, args).await? { let tx_id = masp_tx.txid().to_string(); let filename = format!("ibc_masp_tx_{}.memo", tx_id); - let output_path = match &args.output_folder { + let output_path = match output_folder { Some(path) => path.join(filename), None => filename.into(), }; From 0e87e704cb79ceac43de2d221071e445b719099e Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Mon, 13 Jan 2025 14:09:29 +0000 Subject: [PATCH 23/31] Expose Osmosis swaps via CLI Co-authored-by: Jacob Turner --- crates/apps/src/bin/namada/cli.rs | 1 + crates/apps_lib/src/cli.rs | 213 ++++++++++++++++++++++++++++++ crates/apps_lib/src/cli/client.rs | 15 +++ 3 files changed, 229 insertions(+) diff --git a/crates/apps/src/bin/namada/cli.rs b/crates/apps/src/bin/namada/cli.rs index f3165a4a41..bbe37d5959 100644 --- a/crates/apps/src/bin/namada/cli.rs +++ b/crates/apps/src/bin/namada/cli.rs @@ -50,6 +50,7 @@ fn handle_command(cmd: cli::cmds::Namada, raw_sub_cmd: String) -> Result<()> { | cli::cmds::Namada::TxShieldingTransfer(_) | cli::cmds::Namada::TxUnshieldingTransfer(_) | cli::cmds::Namada::TxIbcTransfer(_) + | cli::cmds::Namada::TxOsmosisSwap(_) | cli::cmds::Namada::TxUpdateAccount(_) | cli::cmds::Namada::TxRevealPk(_) | cli::cmds::Namada::TxInitProposal(_) diff --git a/crates/apps_lib/src/cli.rs b/crates/apps_lib/src/cli.rs index 6a19c24781..700e9ae64b 100644 --- a/crates/apps_lib/src/cli.rs +++ b/crates/apps_lib/src/cli.rs @@ -63,6 +63,7 @@ pub mod cmds { TxShieldingTransfer(TxShieldingTransfer), TxUnshieldingTransfer(TxUnshieldingTransfer), TxIbcTransfer(TxIbcTransfer), + TxOsmosisSwap(TxOsmosisSwap), TxUpdateAccount(TxUpdateAccount), TxInitProposal(TxInitProposal), TxVoteProposal(TxVoteProposal), @@ -84,6 +85,7 @@ pub mod cmds { .subcommand(TxShieldingTransfer::def().display_order(2)) .subcommand(TxUnshieldingTransfer::def().display_order(2)) .subcommand(TxIbcTransfer::def().display_order(2)) + .subcommand(TxOsmosisSwap::def().display_order(2)) .subcommand(TxUpdateAccount::def().display_order(2)) .subcommand(TxInitProposal::def().display_order(2)) .subcommand(TxVoteProposal::def().display_order(2)) @@ -107,6 +109,8 @@ pub mod cmds { SubCmd::parse(matches).map(Self::TxUnshieldingTransfer); let tx_ibc_transfer = SubCmd::parse(matches).map(Self::TxIbcTransfer); + let tx_osmosis_swap = + SubCmd::parse(matches).map(Self::TxOsmosisSwap); let tx_update_account = SubCmd::parse(matches).map(Self::TxUpdateAccount); let tx_init_proposal = @@ -124,6 +128,7 @@ pub mod cmds { .or(tx_shielding_transfer) .or(tx_unshielding_transfer) .or(tx_ibc_transfer) + .or(tx_osmosis_swap) .or(tx_update_account) .or(tx_init_proposal) .or(tx_vote_proposal) @@ -239,6 +244,7 @@ pub mod cmds { .subcommand(TxShieldingTransfer::def().display_order(1)) .subcommand(TxUnshieldingTransfer::def().display_order(1)) .subcommand(TxIbcTransfer::def().display_order(1)) + .subcommand(TxOsmosisSwap::def().display_order(1)) .subcommand(TxUpdateAccount::def().display_order(1)) .subcommand(TxInitAccount::def().display_order(1)) .subcommand(TxRevealPk::def().display_order(1)) @@ -314,6 +320,7 @@ pub mod cmds { let tx_unshielding_transfer = Self::parse_with_ctx(matches, TxUnshieldingTransfer); let tx_ibc_transfer = Self::parse_with_ctx(matches, TxIbcTransfer); + let tx_osmosis_swap = Self::parse_with_ctx(matches, TxOsmosisSwap); let tx_update_account = Self::parse_with_ctx(matches, TxUpdateAccount); let tx_init_account = Self::parse_with_ctx(matches, TxInitAccount); @@ -402,6 +409,7 @@ pub mod cmds { .or(tx_shielding_transfer) .or(tx_unshielding_transfer) .or(tx_ibc_transfer) + .or(tx_osmosis_swap) .or(tx_update_account) .or(tx_init_account) .or(tx_reveal_pk) @@ -496,6 +504,7 @@ pub mod cmds { TxShieldingTransfer(TxShieldingTransfer), TxUnshieldingTransfer(TxUnshieldingTransfer), TxIbcTransfer(TxIbcTransfer), + TxOsmosisSwap(TxOsmosisSwap), QueryResult(QueryResult), TxUpdateAccount(TxUpdateAccount), TxInitAccount(TxInitAccount), @@ -1407,6 +1416,25 @@ pub mod cmds { } } + #[derive(Clone, Debug)] + pub struct TxOsmosisSwap(pub args::TxOsmosisSwap); + + impl SubCmd for TxOsmosisSwap { + const CMD: &'static str = "osmosis-swap"; + + fn parse(matches: &ArgMatches) -> Option { + matches.subcommand_matches(Self::CMD).map(|matches| { + TxOsmosisSwap(args::TxOsmosisSwap::parse(matches)) + }) + } + + fn def() -> App { + App::new(Self::CMD) + .about(wrap!("Swap two asset kinds using Osmosis.")) + .add_args::>() + } + } + #[derive(Clone, Debug)] pub struct TxUpdateAccount(pub args::TxUpdateAccount); @@ -3356,6 +3384,7 @@ pub mod args { use crate::wrap; pub const ADDRESS: Arg = arg("address"); + pub const ADDRESS_OPT: ArgOpt = arg_opt("address"); pub const ADD_PERSISTENT_PEERS: ArgFlag = flag("add-persistent-peers"); pub const ALIAS_OPT: ArgOpt = ALIAS.opt(); pub const ALIAS: Arg = arg("alias"); @@ -3508,6 +3537,7 @@ pub mod args { pub const LIST_FIND_ADDRESSES_ONLY: ArgFlag = flag("addr"); pub const LIST_FIND_KEYS_ONLY: ArgFlag = flag("keys"); pub const LOCALHOST: ArgFlag = flag("localhost"); + pub const LOCAL_RECOVERY_ADDR: Arg = arg("local-recovery-addr"); pub const MASP_EPOCH: ArgOpt = arg_opt("masp-epoch"); pub const MAX_COMMISSION_RATE_CHANGE: Arg = arg("max-commission-rate-change"); @@ -3516,21 +3546,30 @@ pub mod args { pub const MAX_ETH_GAS: ArgOpt = arg_opt("max_eth-gas"); pub const MEMO_OPT: ArgOpt = arg_opt("memo"); pub const MIGRATION_PATH: ArgOpt = arg_opt("migration-path"); + pub const MINIMUM_AMOUNT: ArgOpt = + arg_opt("minimum-amount"); pub const MODE: ArgOpt = arg_opt("mode"); pub const NET_ADDRESS: Arg = arg("net-address"); pub const NAMADA_START_TIME: ArgOpt = arg_opt("time"); pub const NO_CONVERSIONS: ArgFlag = flag("no-conversions"); pub const NO_EXPIRATION: ArgFlag = flag("no-expiration"); pub const NUT: ArgFlag = flag("nut"); + pub const OSMOSIS_REST_RPC: Arg = arg("osmosis-rest-rpc"); pub const OUT_FILE_PATH_OPT: ArgOpt = arg_opt("out-file-path"); pub const OUTPUT: ArgOpt = arg_opt("output"); + pub const OUTPUT_DENOM: Arg = arg("output-denom"); pub const OUTPUT_FOLDER_PATH: ArgOpt = arg_opt("output-folder-path"); + pub const OSMOSIS_POOL_HOP: ArgMulti = + arg_multi("pool-hop"); + pub const OVERFLOW_OPT: ArgOpt = arg_opt("overflow-addr"); pub const OWNER: Arg = arg("owner"); pub const OWNER_OPT: ArgOpt = OWNER.opt(); pub const PATH: Arg = arg("path"); pub const PATH_OPT: ArgOpt = arg_opt("path"); pub const PAYMENT_ADDRESS_TARGET: Arg = arg("target"); + pub const PAYMENT_ADDRESS_TARGET_OPT: ArgOpt = + arg_opt("target-pa"); pub const PORT_ID: ArgDefault = arg_default( "port-id", DefaultFn(|| PortId::from_str("transfer").unwrap()), @@ -3578,6 +3617,7 @@ pub mod args { pub const SHIELDED: ArgFlag = flag("shielded"); pub const SHOW_IBC_TOKENS: ArgFlag = flag("show-ibc-tokens"); pub const SIGNER: ArgOpt = arg_opt("signer"); + pub const SLIPPAGE: ArgOpt = arg_opt("slippage-percentage"); pub const SIGNING_KEYS: ArgMulti = arg_multi("signing-keys"); pub const SIGNATURES: ArgMulti = arg_multi("signatures"); @@ -3591,6 +3631,7 @@ pub mod args { pub const STORAGE_KEY: Arg = arg("storage-key"); pub const SUSPEND_ACTION: ArgFlag = flag("suspend"); pub const TARGET: Arg = arg("target"); + pub const TARGET_OPT: ArgOpt = arg_opt("target"); pub const TEMPLATES_PATH: Arg = arg("templates-path"); pub const TIMEOUT_HEIGHT: ArgOpt = arg_opt("timeout-height"); pub const TIMEOUT_SEC_OFFSET: ArgOpt = arg_opt("timeout-sec-offset"); @@ -3634,6 +3675,7 @@ pub mod args { pub const WASM_CHECKSUMS_PATH: Arg = arg("wasm-checksums-path"); pub const WASM_DIR: ArgOpt = arg_opt("wasm-dir"); pub const WEBSITE_OPT: ArgOpt = arg_opt("website"); + pub const WINDOW_SECONDS: ArgOpt = arg_opt("window-seconds"); pub const WITH_INDEXER: ArgOpt = arg_opt("with-indexer"); pub const WRAPPER_SIGNATURE_OPT: ArgOpt = arg_opt("gas-signature"); pub const TX_PATH: Arg = arg("tx-path"); @@ -5028,6 +5070,177 @@ pub mod args { } } + impl CliToSdk> for TxOsmosisSwap { + type Error = std::io::Error; + + fn to_sdk( + self, + ctx: &mut Context, + ) -> Result, Self::Error> { + let chain_ctx = ctx.borrow_mut_chain_or_exit(); + let recipient = match self.recipient { + Either::Left(r) => Either::Left(chain_ctx.get(&r)), + Either::Right(r) => Either::Right(chain_ctx.get(&r)), + }; + let overflow = self.overflow.map(|r| chain_ctx.get(&r)); + Ok(TxOsmosisSwap { + transfer: self.transfer.to_sdk(ctx)?, + output_denom: self.output_denom, + recipient, + overflow, + slippage: self.slippage, + local_recovery_addr: self.local_recovery_addr, + route: self.route, + osmosis_rest_rpc: self.osmosis_rest_rpc, + }) + } + } + + impl Args for TxOsmosisSwap { + fn parse(matches: &ArgMatches) -> Self { + let transfer = TxIbcTransfer::parse(matches); + let osmosis_rest_rpc = OSMOSIS_REST_RPC.parse(matches); + let output_denom = OUTPUT_DENOM.parse(matches); + let maybe_trans_recipient = TARGET_OPT.parse(matches); + let maybe_shielded_recipient = + PAYMENT_ADDRESS_TARGET_OPT.parse(matches); + let maybe_overflow = OVERFLOW_OPT.parse(matches); + let slippage_percent = SLIPPAGE.parse(matches); + if slippage_percent + .is_some_and(|percent| !(0.0..=100.0).contains(&percent)) + { + panic!( + "The slippage percent must be a number between 0 and 100." + ) + } + let window_seconds = WINDOW_SECONDS.parse(matches); + let minimum_amount = MINIMUM_AMOUNT.parse(matches); + let slippage = minimum_amount + .map(|d| Slippage::MinOutputAmount(d.redenominate(0).amount())) + .or_else(|| { + Some(Slippage::Twap { + slippage_percentage: slippage_percent + .expect( + "If a minimum amount was not provided, \ + slippage-percentage and window-seconds must \ + be specified.", + ) + .to_string(), + window_seconds: window_seconds.expect( + "If a minimum amount was not provided, \ + slippage-percentage and window-seconds must be \ + specified.", + ), + }) + }) + .unwrap(); + let local_recovery_addr = LOCAL_RECOVERY_ADDR.parse(matches); + let route = match OSMOSIS_POOL_HOP.parse(matches) { + r if r.is_empty() => None, + r => Some(r), + }; + Self { + transfer, + output_denom, + recipient: if let Some(target) = maybe_trans_recipient { + Either::Left(target) + } else { + Either::Right(maybe_shielded_recipient.unwrap()) + }, + overflow: maybe_overflow, + slippage, + local_recovery_addr, + route, + osmosis_rest_rpc, + } + } + + fn def(app: App) -> App { + app.add_args::>() + .arg( + OSMOSIS_REST_RPC + .def() + .help(wrap!("A url pointing to an Osmosis REST rpc.")), + ) + .arg(OSMOSIS_POOL_HOP.def().help(wrap!( + "Individual hop of the route to take through Osmosis \ + pools. This value takes the form \ + :. When unspecified, \ + the optimal route is queried on the fly." + ))) + .arg(OUTPUT_DENOM.def().help(wrap!( + "The IBC denomination (on Namada) of the desired asset." + ))) + .arg( + TARGET_OPT + .def() + .conflicts_with(PAYMENT_ADDRESS_TARGET_OPT.name) + .help(wrap!( + "The transparent Namada address that shall \ + receive the swapped tokens." + )), + ) + .arg( + PAYMENT_ADDRESS_TARGET_OPT + .def() + .requires(OVERFLOW_OPT.name) + .conflicts_with(TARGET_OPT.name) + .help(wrap!( + "The shielded Namada address that shall receive \ + the minimum amount of swapped tokens." + )), + ) + .arg(OVERFLOW_OPT.def().help(wrap!( + "The transparent address that receives the amount of \ + target asset exceeding the minimum amount. If used in \ + conjunction with shielding, this address should not be \ + linkable to any of your transparent accounts." + ))) + .arg(SLIPPAGE.def().requires(WINDOW_SECONDS.name).help(wrap!( + "The slippage percentage as an integer between 0 and 100. \ + Represents the maximum acceptable deviation from the \ + expected price during a trade." + ))) + .arg(WINDOW_SECONDS.def().requires(SLIPPAGE.name).help(wrap!( + "The time period (in seconds) over which the average \ + price is calculated." + ))) + .arg( + MINIMUM_AMOUNT + .def() + .conflicts_with(SLIPPAGE.name) + .conflicts_with(WINDOW_SECONDS.name) + .help(wrap!( + "The minimum amount of target asset that the \ + trade should produce." + )), + ) + .arg(LOCAL_RECOVERY_ADDR.def().help(wrap!( + "An address on Osmosis from which to recover funds in \ + case of failure." + ))) + .group( + ArgGroup::new("slippage") + .args([SLIPPAGE.name, MINIMUM_AMOUNT.name]) + .required(true), + ) + .group( + ArgGroup::new("transfer-target") + .args([ + TARGET_OPT.name, + PAYMENT_ADDRESS_TARGET_OPT.name, + ]) + .required(true), + ) + .mut_arg(RECEIVER.name, |arg| { + arg.long("swap-contract").help(wrap!( + "The address of the Osmosis contract performing the \ + swap. It will be the receiver of the IBC transfer." + )) + }) + } + } + impl CliToSdk> for TxInitAccount { type Error = std::io::Error; diff --git a/crates/apps_lib/src/cli/client.rs b/crates/apps_lib/src/cli/client.rs index d926671e17..7899bdcc5d 100644 --- a/crates/apps_lib/src/cli/client.rs +++ b/crates/apps_lib/src/cli/client.rs @@ -113,6 +113,21 @@ impl CliApi { let namada = ctx.to_sdk(client, io); tx::submit_ibc_transfer(&namada, args).await?; } + Sub::TxOsmosisSwap(TxOsmosisSwap(args)) => { + let chain_ctx = ctx.borrow_mut_chain_or_exit(); + let ledger_address = + chain_ctx.get(&args.transfer.tx.ledger_address); + let client = client.unwrap_or_else(|| { + C::from_tendermint_address(&ledger_address) + }); + client.wait_until_node_is_synced(&io).await?; + + let args = args.to_sdk(&mut ctx)?; + let namada = ctx.to_sdk(client, io); + let args = args.into_ibc_transfer(&namada).await?; + + tx::submit_ibc_transfer(&namada, args).await?; + } Sub::TxUpdateAccount(TxUpdateAccount(args)) => { let chain_ctx = ctx.borrow_mut_chain_or_exit(); let ledger_address = From 7933d960e28165fd9c805114d06160a2803c1adf Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Mon, 13 Jan 2025 14:23:57 +0000 Subject: [PATCH 24/31] Accept shielded recv IBC memos in e2e tests Co-authored-by: Jacob Turner --- crates/tests/src/e2e/ibc_tests.rs | 133 ++++++++++++++++++++++++------ 1 file changed, 109 insertions(+), 24 deletions(-) diff --git a/crates/tests/src/e2e/ibc_tests.rs b/crates/tests/src/e2e/ibc_tests.rs index 2e63db39f5..79079b2156 100644 --- a/crates/tests/src/e2e/ibc_tests.rs +++ b/crates/tests/src/e2e/ibc_tests.rs @@ -41,6 +41,7 @@ use namada_sdk::ibc::core::host::types::identifiers::{ use namada_sdk::ibc::primitives::proto::Any; use namada_sdk::ibc::storage::*; use namada_sdk::ibc::trace::ibc_token; +use namada_sdk::ibc::IbcShieldingData; use namada_sdk::token::Amount; use namada_test_utils::TestWasms; use prost::Message; @@ -140,6 +141,7 @@ fn ibc_transfers() -> Result<()> { None, None, None, + None, false, )?; wait_for_packet_relay( @@ -217,6 +219,7 @@ fn ibc_transfers() -> Result<()> { None, None, None, + None, false, )?; wait_for_packet_relay( @@ -299,6 +302,7 @@ fn ibc_transfers() -> Result<()> { None, None, None, + None, true, )?; wait_for_packet_relay( @@ -353,6 +357,7 @@ fn ibc_transfers() -> Result<()> { None, None, None, + None, false, )?; wait_for_packet_relay( @@ -381,6 +386,7 @@ fn ibc_transfers() -> Result<()> { Some(Duration::new(10, 0)), None, None, + None, false, )?; // wait for the timeout @@ -413,6 +419,7 @@ fn ibc_transfers() -> Result<()> { None, None, None, + None, true, )?; wait_for_packet_relay( @@ -443,6 +450,7 @@ fn ibc_transfers() -> Result<()> { Some(Duration::new(10, 0)), None, None, + None, true, )?; // wait for the timeout @@ -605,6 +613,7 @@ fn ibc_nft_transfers() -> Result<()> { None, None, None, + None, false, )?; clear_packet(&hermes_dir, &port_id_namada, &channel_id_namada, &test)?; @@ -668,6 +677,7 @@ fn ibc_nft_transfers() -> Result<()> { None, None, None, + None, true, )?; clear_packet(&hermes_dir, &port_id_namada, &channel_id_namada, &test)?; @@ -1110,6 +1120,7 @@ fn ibc_rate_limit() -> Result<()> { None, None, None, + None, false, )?; @@ -1129,6 +1140,7 @@ fn ibc_rate_limit() -> Result<()> { Some( "Transfer exceeding the per-epoch throughput limit is not allowed", ), + None, false, )?; @@ -1152,6 +1164,7 @@ fn ibc_rate_limit() -> Result<()> { None, None, None, + None, false, )?; @@ -1190,6 +1203,81 @@ fn ibc_rate_limit() -> Result<()> { Ok(()) } +/// Create a packet forward memo and serialize it +fn packet_forward_memo( + receiver: Signer, + port_id: &PortId, + channel_id: &ChannelId, + timeout: Option, + next: Option>, +) -> String { + serde_json::to_string(&serde_json::Value::Object( + packet_forward_memo_value(receiver, port_id, channel_id, timeout, next), + )) + .expect("Test failed") +} + +fn packet_forward_memo_value( + receiver: Signer, + port_id: &PortId, + channel_id: &ChannelId, + timeout: Option, + next: Option>, +) -> serde_json::Map { + let value = + serde_json::to_value(&ibc_middleware_packet_forward::PacketMetadata { + forward: ForwardMetadata { + receiver, + port: port_id.clone(), + channel: channel_id.clone(), + timeout: timeout.map(|t| { + ibc_middleware_packet_forward::Duration::from_dur( + dur::Duration::from_std(t), + ) + }), + retries: Some(0), + next, + }, + }) + .expect("Test failed"); + + if let serde_json::Value::Object(memo) = value { + memo + } else { + unreachable!() + } +} + +#[allow(dead_code)] +fn shielded_recv_memo_value( + masp_transfer_path: &Path, + shielded_amount: Amount, + overflow_receiver: namada_core::address::Address, +) -> serde_json::Map { + use namada_core::string_encoding::StringEncoded; + use namada_sdk::ibc::{NamadaMemo, NamadaMemoData}; + + let transfer = + std::fs::read_to_string(masp_transfer_path).expect("Test failed"); + let tx = StringEncoded::new( + IbcShieldingData::from_str(&transfer).expect("Test failed"), + ); + let data = NamadaMemoData::OsmosisSwap { + shielding_data: tx, + shielded_amount, + overflow_receiver, + }; + + let value = serde_json::to_value(&NamadaMemo { namada: data }) + .expect("Test failed"); + + if let serde_json::Value::Object(memo) = value { + memo + } else { + unreachable!() + } +} + /// Test the happy flows of ibc pfm /// /// Setup: Two instances of Gaia and one @@ -1266,6 +1354,7 @@ fn ibc_pfm_happy_flows() -> Result<()> { &port_id_namada, &channel_id_namada_2, None, + None, ); transfer_from_cosmos( &test_gaia_1, @@ -1313,6 +1402,7 @@ fn ibc_pfm_happy_flows() -> Result<()> { &port_id_namada, &channel_id_namada_1, None, + None, ); transfer_from_cosmos( &test_gaia_2, @@ -1361,6 +1451,7 @@ fn ibc_pfm_happy_flows() -> Result<()> { None, None, None, + None, false, )?; @@ -1386,6 +1477,7 @@ fn ibc_pfm_happy_flows() -> Result<()> { &port_id_namada, &channel_id_namada_2, None, + None, ); transfer_from_cosmos( @@ -1436,6 +1528,7 @@ fn ibc_pfm_happy_flows() -> Result<()> { &port_id_namada, &channel_id_namada_1, None, + None, ); transfer_from_cosmos( &test_gaia_2, @@ -1472,6 +1565,7 @@ fn ibc_pfm_happy_flows() -> Result<()> { Ok(()) } + /// Test the flows of ibc pfm where the packet cannot be /// completed and refunds must be issued. /// @@ -1560,6 +1654,7 @@ fn ibc_pfm_unhappy_flows() -> Result<()> { &port_id_namada, &channel_id_namada_2, None, + None, ); transfer_from_cosmos( &test_gaia_1, @@ -1595,6 +1690,7 @@ fn ibc_pfm_unhappy_flows() -> Result<()> { &port_id_namada, &channel_id_namada_2, Some(Duration::new(1, 0)), + None, ); // Stop Hermes for timeout test let mut hermes_2 = bg_hermes_2.foreground(); @@ -1652,6 +1748,7 @@ fn ibc_pfm_unhappy_flows() -> Result<()> { None, None, None, + None, false, )?; @@ -1677,6 +1774,7 @@ fn ibc_pfm_unhappy_flows() -> Result<()> { &port_id_namada, &channel_id_namada_2, None, + None, ); transfer_from_cosmos( &test_gaia_1, @@ -1717,6 +1815,7 @@ fn ibc_pfm_unhappy_flows() -> Result<()> { &port_id_namada, &channel_id_namada_2, Some(Duration::new(1, 0)), + None, ); // Stop Hermes for timeout test let mut hermes_2 = bg_hermes_2.foreground(); @@ -1770,6 +1869,7 @@ fn ibc_pfm_unhappy_flows() -> Result<()> { &port_id_namada, &channel_id_namada_1, None, + None, ); transfer_from_cosmos( &test_gaia_2, @@ -1808,6 +1908,7 @@ fn ibc_pfm_unhappy_flows() -> Result<()> { &port_id_namada, &channel_id_namada_2, None, + None, ); transfer_from_cosmos( &test_gaia_1, @@ -1853,6 +1954,7 @@ fn ibc_pfm_unhappy_flows() -> Result<()> { &port_id_namada, &channel_id_namada_2, Some(Duration::new(1, 0)), + None, ); // Stop Hermes for timeout test let mut hermes_2 = bg_hermes_2.foreground(); @@ -2144,6 +2246,7 @@ fn try_invalid_transfers( None, // the IBC denom can't be parsed when using an invalid port Some(&format!("Invalid IBC denom: {nam_addr}")), + None, false, )?; @@ -2160,6 +2263,7 @@ fn try_invalid_transfers( None, None, Some("IBC token transfer error: context error: `ICS04 Channel error"), + None, false, )?; @@ -2215,6 +2319,7 @@ fn transfer( timeout_sec: Option, shielding_data_path: Option, expected_err: Option<&str>, + ibc_memo: Option<&str>, gen_refund_target: bool, ) -> Result { let rpc = get_actor_rpc(test, Who::Validator(0)); @@ -2242,6 +2347,10 @@ fn transfer( &rpc, ]); + if let Some(ibc_memo) = ibc_memo { + tx_args.extend_from_slice(&["--ibc-memo", ibc_memo]); + } + if let Some(signer) = signer { tx_args.extend_from_slice(&["--signing-keys", signer]); } else { @@ -3194,27 +3303,3 @@ fn nft_transfer_from_cosmos( Ok(()) } - -/// Create a packet forward memo and serialize it -fn packet_forward_memo( - receiver: Signer, - port_id: &PortId, - channel_id: &ChannelId, - timeout: Option, -) -> String { - serde_json::to_string(&ibc_middleware_packet_forward::PacketMetadata { - forward: ForwardMetadata { - receiver, - port: port_id.clone(), - channel: channel_id.clone(), - timeout: timeout.map(|t| { - ibc_middleware_packet_forward::Duration::from_dur( - dur::Duration::from_std(t), - ) - }), - retries: Some(0), - next: None, - }, - }) - .expect("Test failed") -} From dda46cf6845a29ae04f27ed86850c64b5026ae72 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Mon, 13 Jan 2025 14:11:29 +0000 Subject: [PATCH 25/31] Add shielded recv e2e tests Co-authored-by: Jacob Turner --- .github/workflows/scripts/e2e.json | 2 + crates/tests/src/e2e/ibc_tests.rs | 188 ++++++++++++++++++++++++++++- 2 files changed, 189 insertions(+), 1 deletion(-) diff --git a/.github/workflows/scripts/e2e.json b/.github/workflows/scripts/e2e.json index c63422bf67..30046d7243 100644 --- a/.github/workflows/scripts/e2e.json +++ b/.github/workflows/scripts/e2e.json @@ -9,6 +9,8 @@ "e2e::ibc_tests::ibc_pfm_happy_flows": 485, "e2e::ibc_tests::ibc_pfm_unhappy_flows": 485, "e2e::ibc_tests::ibc_upgrade_client": 280, + "e2e::ibc_tests::ibc_shielded_recv_middleware_happy_flow": 280, + "e2e::ibc_tests::ibc_shielded_recv_middleware_unhappy_flow": 280, "e2e::eth_bridge_tests::test_add_to_bridge_pool": 10, "e2e::ledger_tests::double_signing_gets_slashed": 12, "e2e::ledger_tests::ledger_many_txs_in_a_block": 55, diff --git a/crates/tests/src/e2e/ibc_tests.rs b/crates/tests/src/e2e/ibc_tests.rs index 79079b2156..d8e8ccf8db 100644 --- a/crates/tests/src/e2e/ibc_tests.rs +++ b/crates/tests/src/e2e/ibc_tests.rs @@ -1248,7 +1248,6 @@ fn packet_forward_memo_value( } } -#[allow(dead_code)] fn shielded_recv_memo_value( masp_transfer_path: &Path, shielded_amount: Amount, @@ -2008,6 +2007,193 @@ fn ibc_pfm_unhappy_flows() -> Result<()> { Ok(()) } +/// Test that we are able to use the shielded-receive +/// middleware to shield funds specified in the memo +/// message. +#[test] +fn ibc_shielded_recv_middleware_happy_flow() -> Result<()> { + let update_genesis = + |mut genesis: templates::All, base_dir: &_| { + genesis.parameters.parameters.epochs_per_year = + epochs_per_year_from_min_duration(1800); + genesis.parameters.ibc_params.default_mint_limit = + Amount::max_signed(); + genesis + .parameters + .ibc_params + .default_per_epoch_throughput_limit = Amount::max_signed(); + setup::set_validators(1, genesis, base_dir, |_| 0, vec![]) + }; + let (ledger, gaia, test, test_gaia) = + run_namada_cosmos(CosmosChainType::Gaia(None), update_genesis)?; + let _bg_ledger = ledger.background(); + let _bg_gaia = gaia.background(); + sleep(5); + + let hermes_dir = setup_hermes(&test, &test_gaia)?; + let port_id_namada = FT_PORT_ID.parse().unwrap(); + let port_id_gaia = FT_PORT_ID.parse().unwrap(); + let (channel_id_namada, channel_id_gaia) = create_channel_with_hermes( + &hermes_dir, + &test, + &test_gaia, + &port_id_namada, + &port_id_gaia, + )?; + + // Start relaying + let hermes = run_hermes(&hermes_dir)?; + let _bg_hermes = hermes.background(); + + // 1. Shield 10 NAM to AA_PAYMENT_ADDRESS + transfer_on_chain( + &test, + "shield", + ALBERT, + AA_PAYMENT_ADDRESS, + NAM, + 10, + ALBERT_KEY, + &[], + )?; + check_shielded_balance(&test, AA_VIEWING_KEY, NAM, 10)?; + + // 2. Unshield from A_SPENDING_KEY to B_SPENDING_KEY, + // using the packet forward and shielded receive + // middlewares + let nam_addr = find_address(&test, NAM)?; + let overflow_addr = "tnam1qrqzqa0l0rzzrlr20n487l6n865t8ndv6uhseulq"; + let ibc_denom_on_gaia = format!("transfer/{channel_id_gaia}/{nam_addr}"); + let memo_path = gen_ibc_shielding_data( + &test, + AB_PAYMENT_ADDRESS, + &ibc_denom_on_gaia, + 8, + &port_id_namada, + &channel_id_namada, + )?; + let memo = packet_forward_memo( + MASP.to_string().into(), + &PortId::transfer(), + &channel_id_namada, + None, + Some(shielded_recv_memo_value( + &memo_path, + Amount::native_whole(8), + overflow_addr.parse().unwrap(), + )), + ); + transfer( + &test, + A_SPENDING_KEY, + "PacketForwardMiddleware", + NAM, + 10, + Some(ALBERT_KEY), + &PortId::transfer(), + &channel_id_namada, + None, + None, + None, + Some(&memo), + true, + )?; + wait_for_packet_relay(&hermes_dir, &port_id_gaia, &channel_id_gaia, &test)?; + + // Check the token on Namada + check_shielded_balance(&test, AA_VIEWING_KEY, NAM, 0)?; + check_shielded_balance(&test, AB_VIEWING_KEY, NAM, 8)?; + check_balance(&test, overflow_addr, NAM, 2)?; + + Ok(()) +} + +/// Test that if the received amount underflows the minimum +/// amount, we error out and refund assets. +#[test] +fn ibc_shielded_recv_middleware_unhappy_flow() -> Result<()> { + let update_genesis = + |mut genesis: templates::All, base_dir: &_| { + genesis.parameters.parameters.epochs_per_year = + epochs_per_year_from_min_duration(1800); + genesis.parameters.ibc_params.default_mint_limit = + Amount::max_signed(); + genesis + .parameters + .ibc_params + .default_per_epoch_throughput_limit = Amount::max_signed(); + setup::set_validators(1, genesis, base_dir, |_| 0, vec![]) + }; + let (ledger, gaia, test, test_gaia) = + run_namada_cosmos(CosmosChainType::Gaia(None), update_genesis)?; + let _bg_ledger = ledger.background(); + let _bg_gaia = gaia.background(); + sleep(5); + + let hermes_dir = setup_hermes(&test, &test_gaia)?; + let port_id_namada = FT_PORT_ID.parse().unwrap(); + let port_id_gaia = FT_PORT_ID.parse().unwrap(); + let (channel_id_namada, channel_id_gaia) = create_channel_with_hermes( + &hermes_dir, + &test, + &test_gaia, + &port_id_namada, + &port_id_gaia, + )?; + + // Start relaying + let hermes = run_hermes(&hermes_dir)?; + let _bg_hermes = hermes.background(); + + let nam_addr = find_address(&test, NAM)?; + let overflow_addr = "tnam1qrqzqa0l0rzzrlr20n487l6n865t8ndv6uhseulq"; + let ibc_denom_on_gaia = format!("transfer/{channel_id_gaia}/{nam_addr}"); + check_balance(&test, ALBERT, NAM, 2_000_000)?; + + let memo_path = gen_ibc_shielding_data( + &test, + AB_PAYMENT_ADDRESS, + &ibc_denom_on_gaia, + 8, + &port_id_namada, + &channel_id_namada, + )?; + let memo = packet_forward_memo( + MASP.to_string().into(), + &PortId::transfer(), + &channel_id_namada, + None, + Some(shielded_recv_memo_value( + &memo_path, + Amount::native_whole(8), + overflow_addr.parse().unwrap(), + )), + ); + transfer( + &test, + ALBERT, + "PacketForwardMiddleware", + NAM, + 7, + Some(ALBERT_KEY), + &PortId::transfer(), + &channel_id_namada, + None, + None, + None, + Some(&memo), + false, + )?; + wait_for_packet_relay(&hermes_dir, &port_id_gaia, &channel_id_gaia, &test)?; + + // Check the token on Namada + check_balance(&test, ALBERT, NAM, 2_000_000)?; + check_shielded_balance(&test, AB_VIEWING_KEY, NAM, 0)?; + check_balance(&test, overflow_addr, NAM, 0)?; + + Ok(()) +} + fn run_namada_cosmos( chain_type: CosmosChainType, mut update_genesis: impl FnMut( From 37f9af61c2b1cba637d6b6511221cbbaa12e5d2f Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Mon, 13 Jan 2025 13:31:02 +0000 Subject: [PATCH 26/31] Add Osmosis contract bytecode fixtures Co-authored-by: Jacob Turner --- .../wasm_bytecode/crosschain_registry.wasm | Bin 0 -> 459445 bytes .../wasm_bytecode/crosschain_swaps.wasm | Bin 0 -> 473135 bytes .../osmosis_data/wasm_bytecode/swaprouter.wasm | Bin 0 -> 257863 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 crates/tests/fixtures/osmosis_data/wasm_bytecode/crosschain_registry.wasm create mode 100644 crates/tests/fixtures/osmosis_data/wasm_bytecode/crosschain_swaps.wasm create mode 100644 crates/tests/fixtures/osmosis_data/wasm_bytecode/swaprouter.wasm diff --git a/crates/tests/fixtures/osmosis_data/wasm_bytecode/crosschain_registry.wasm b/crates/tests/fixtures/osmosis_data/wasm_bytecode/crosschain_registry.wasm new file mode 100644 index 0000000000000000000000000000000000000000..ebd2324e65c77a7c18b25fc3b270d66911a1f233 GIT binary patch literal 459445 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

~Jya&R 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 literal 0 HcmV?d00001 diff --git a/crates/tests/fixtures/osmosis_data/wasm_bytecode/crosschain_swaps.wasm b/crates/tests/fixtures/osmosis_data/wasm_bytecode/crosschain_swaps.wasm new file mode 100644 index 0000000000000000000000000000000000000000..c79e7121df43752c104eb49d279013d7fc8daa39 GIT binary patch literal 473135 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 RIB}R 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͌OZ*Q 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 ~&pLb6y4EM3dhw;#UjOiiA8qc+ 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 literal 0 HcmV?d00001 diff --git a/crates/tests/fixtures/osmosis_data/wasm_bytecode/swaprouter.wasm b/crates/tests/fixtures/osmosis_data/wasm_bytecode/swaprouter.wasm new file mode 100644 index 0000000000000000000000000000000000000000..e43efcb25caf2d5cd138e144736f0482ee6b8a8f GIT binary patch literal 257863 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 literal 0 HcmV?d00001 From d8b07ce1fbec58b92a97256a6fd40b2cc86618e1 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Mon, 13 Jan 2025 14:31:53 +0000 Subject: [PATCH 27/31] Add Osmosis XCS e2e test Co-authored-by: Jacob Turner --- crates/tests/src/e2e/helpers.rs | 92 +++- crates/tests/src/e2e/ibc_tests.rs | 794 +++++++++++++++++++++++++++++- crates/tests/src/e2e/setup.rs | 321 ++++++++++-- 3 files changed, 1121 insertions(+), 86 deletions(-) diff --git a/crates/tests/src/e2e/helpers.rs b/crates/tests/src/e2e/helpers.rs index 3df93fddc7..1b911ce53b 100644 --- a/crates/tests/src/e2e/helpers.rs +++ b/crates/tests/src/e2e/helpers.rs @@ -497,6 +497,7 @@ pub fn make_hermes_config( hermes_dir: &TestDir, test_a: &Test, test_b: &Test, + relayer: Option<&str>, ) -> Result<()> { let mut config = toml::map::Map::new(); @@ -535,12 +536,17 @@ pub fn make_hermes_config( config.insert("telemetry".to_owned(), Value::Table(telemetry)); let chains = vec![ - make_hermes_chain_config(test_a), + match CosmosChainType::chain_type(test_a.net.chain_id.as_str()) { + Ok(chain_type) => make_hermes_chain_config_for_cosmos( + hermes_dir, chain_type, test_a, relayer, + ), + Err(_) => make_hermes_chain_config(hermes_dir, test_a), + }, match CosmosChainType::chain_type(test_b.net.chain_id.as_str()) { Ok(chain_type) => make_hermes_chain_config_for_cosmos( - hermes_dir, chain_type, test_b, + hermes_dir, chain_type, test_b, relayer, ), - Err(_) => make_hermes_chain_config(test_b), + Err(_) => make_hermes_chain_config(hermes_dir, test_b), }, ]; @@ -558,7 +564,7 @@ pub fn make_hermes_config( Ok(()) } -fn make_hermes_chain_config(test: &Test) -> Value { +fn make_hermes_chain_config(hermes_dir: &TestDir, test: &Test) -> Value { let chain_id = test.net.chain_id.as_str(); let rpc_addr = get_actor_rpc(test, Who::Validator(0)); let rpc_addr = rpc_addr.strip_prefix("http://").unwrap(); @@ -598,6 +604,13 @@ fn make_hermes_chain_config(test: &Test) -> Value { chain.insert("max_block_time".to_owned(), Value::String("60s".to_owned())); + let hermes_dir: &Path = hermes_dir.as_ref(); + let key_dir = hermes_dir.join("hermes/keys"); + chain.insert( + "key_store_folder".to_owned(), + Value::String(key_dir.to_string_lossy().to_string()), + ); + Value::Table(chain) } @@ -605,11 +618,14 @@ fn make_hermes_chain_config_for_cosmos( hermes_dir: &TestDir, chain_type: CosmosChainType, test: &Test, + relayer: Option<&str>, ) -> Value { let mut table = toml::map::Map::new(); table.insert("mode".to_owned(), Value::String("push".to_owned())); - let offset = chain_type.get_offset(); - let url = format!("ws://127.0.0.1:6416{}/websocket", offset); + let url = format!( + "ws://127.0.0.1:{}/websocket", + chain_type.get_rpc_port_number() + ); table.insert("url".to_owned(), Value::String(url)); table.insert("batch_delay".to_owned(), Value::String("500ms".to_owned())); let event_source = Value::Table(table); @@ -623,11 +639,17 @@ fn make_hermes_chain_config_for_cosmos( chain.insert( "rpc_addr".to_owned(), - Value::String(format!("http://127.0.0.1:6416{}", offset)), + Value::String(format!( + "http://127.0.0.1:{}", + chain_type.get_rpc_port_number() + )), ); chain.insert( "grpc_addr".to_owned(), - Value::String(format!("http://127.0.0.1:{}", offset + 9090)), + Value::String(format!( + "http://127.0.0.1:{}", + chain_type.get_grpc_port_number() + )), ); chain.insert("event_source".to_owned(), event_source); @@ -637,7 +659,7 @@ fn make_hermes_chain_config_for_cosmos( ); chain.insert( "key_name".to_owned(), - Value::String(setup::constants::COSMOS_RELAYER.to_string()), + Value::String(relayer.unwrap_or(constants::COSMOS_RELAYER).to_string()), ); let hermes_dir: &Path = hermes_dir.as_ref(); let key_dir = hermes_dir.join("hermes/keys"); @@ -646,10 +668,14 @@ fn make_hermes_chain_config_for_cosmos( Value::String(key_dir.to_string_lossy().to_string()), ); chain.insert("store_prefix".to_owned(), Value::String("ibc".to_owned())); - chain.insert("max_gas".to_owned(), Value::Integer(500_000)); - chain.insert("gas_multiplier".to_owned(), Value::Float(1.3)); + chain.insert("max_gas".to_owned(), Value::Integer(500_000_000)); + chain.insert("gas_multiplier".to_owned(), Value::Float(2.3)); let mut table = toml::map::Map::new(); - table.insert("price".to_owned(), Value::Float(0.001)); + if let CosmosChainType::Osmosis = chain_type { + table.insert("price".to_owned(), Value::Float(0.01)); + } else { + table.insert("price".to_owned(), Value::Float(0.001)); + } table.insert("denom".to_owned(), Value::String("stake".to_string())); chain.insert("gas_price".to_owned(), Value::Table(table)); @@ -672,9 +698,8 @@ pub fn update_cosmos_config(test: &Test) -> Result<()> { *timeout_propose = "1s".into(); } } - let offset = CosmosChainType::chain_type(test.net.chain_id.as_str()) - .unwrap() - .get_offset(); + let chain_type = + CosmosChainType::chain_type(test.net.chain_id.as_str()).unwrap(); let p2p = values .get_mut("p2p") .expect("Test failed") @@ -683,7 +708,8 @@ pub fn update_cosmos_config(test: &Test) -> Result<()> { let Some(laddr) = p2p.get_mut("laddr") else { panic!("Test failed") }; - *laddr = format!("tcp://0.0.0.0:266{}{}", offset, offset).into(); + *laddr = + format!("tcp://0.0.0.0:{}", chain_type.get_p2p_port_number()).into(); let rpc = values .get_mut("rpc") .expect("Test failed") @@ -692,7 +718,8 @@ pub fn update_cosmos_config(test: &Test) -> Result<()> { let Some(laddr) = rpc.get_mut("laddr") else { panic!("Test failed") }; - *laddr = format!("tcp://0.0.0.0:6416{offset}").into(); + *laddr = + format!("tcp://0.0.0.0:{}", chain_type.get_rpc_port_number()).into(); let mut file = OpenOptions::new() .write(true) @@ -757,14 +784,37 @@ pub fn update_cosmos_config(test: &Test) -> Result<()> { serde_json::to_writer_pretty(writer, &genesis) .expect("Writing Cosmos genesis.toml failed"); + if matches!(chain_type, CosmosChainType::Osmosis) { + let client_path = cosmos_dir.join("config/client.toml"); + let s = std::fs::read_to_string(&client_path) + .expect("Reading Osmosis client config failed"); + let mut values = s + .parse::() + .expect("Parsing Osmosis client config failed"); + let Some(laddr) = values.get_mut("node") else { + panic!("Test failed") + }; + *laddr = format!("tcp://0.0.0.0:{}", chain_type.get_rpc_port_number()) + .into(); + let mut file = OpenOptions::new() + .write(true) + .truncate(true) + .open(&client_path)?; + file.write_all(values.to_string().as_bytes()).map_err(|e| { + eyre!(format!( + "Writing a Osmosis client config file failed: {}", + e + )) + })?; + } + Ok(()) } pub fn get_cosmos_rpc_address(test: &Test) -> String { - let offset = CosmosChainType::chain_type(test.net.chain_id.as_str()) - .unwrap() - .get_offset(); - format!("127.0.0.1:6416{offset}") + let chain_type = + CosmosChainType::chain_type(test.net.chain_id.as_str()).unwrap(); + format!("127.0.0.1:{}", chain_type.get_rpc_port_number()) } pub fn find_cosmos_address( diff --git a/crates/tests/src/e2e/ibc_tests.rs b/crates/tests/src/e2e/ibc_tests.rs index d8e8ccf8db..e2698db993 100644 --- a/crates/tests/src/e2e/ibc_tests.rs +++ b/crates/tests/src/e2e/ibc_tests.rs @@ -11,6 +11,7 @@ use core::str::FromStr; use core::time::Duration; +use std::fs::File; use std::path::{Path, PathBuf}; use color_eyre::eyre::Result; @@ -45,6 +46,7 @@ use namada_sdk::ibc::IbcShieldingData; use namada_sdk::token::Amount; use namada_test_utils::TestWasms; use prost::Message; +use serde_json::json; use setup::constants::*; use sha2::{Digest, Sha256}; @@ -57,10 +59,10 @@ use crate::e2e::ledger_tests::{ start_namada_ledger_node_wait_wasm, write_json_file, }; use crate::e2e::setup::{ - self, apply_use_device, run_cosmos_cmd, run_hermes_cmd, - set_ethereum_bridge_mode, setup_cosmos, setup_hermes, sleep, working_dir, - Bin, CosmosChainType, NamadaCmd, Test, TestDir, Who, - ENV_VAR_COSMWASM_CONTRACT_DIR, + self, apply_use_device, osmosis_fixtures_dir, run_cosmos_cmd, + run_cosmos_cmd_homeless, run_hermes_cmd, set_ethereum_bridge_mode, + setup_cosmos, setup_hermes, sleep, working_dir, Bin, CosmosChainType, + NamadaCmd, Test, TestDir, Who, ENV_VAR_COSMWASM_CONTRACT_DIR, }; use crate::ibc::primitives::Signer; use crate::strings::TX_APPLIED_SUCCESS; @@ -2213,14 +2215,19 @@ fn run_namada_cosmos( let ledger = start_namada_ledger_node_wait_wasm(&test, Some(0), Some(40))?; - // Cosmos - let test_cosmos = setup_cosmos(chain_type)?; - let cosmos = run_cosmos(&test_cosmos, true)?; - sleep(5); + let (cosmos, test_cosmos) = setup_and_boot_cosmos(chain_type)?; Ok((ledger, cosmos, test, test_cosmos)) } +fn setup_and_boot_cosmos( + chain_type: CosmosChainType, +) -> Result<(NamadaCmd, Test)> { + let test_cosmos = setup_cosmos(chain_type)?; + let cosmos = run_cosmos(&test_cosmos, true)?; + Ok((cosmos, test_cosmos)) +} + fn create_channel_with_hermes( hermes_dir: &TestDir, test_a: &Test, @@ -2235,6 +2242,7 @@ fn create_channel_with_hermes( } else { FT_CHANNEL_VERSION }; + let args = [ "create", "channel", @@ -2292,7 +2300,7 @@ fn run_cosmos(test: &Test, kill: bool) -> Result { .output() .unwrap(); } - let port_arg = format!("0.0.0.0:{}", 9090 + chain_type.get_offset()); + let port_arg = format!("0.0.0.0:{}", chain_type.get_grpc_port_number()); let args = ["start", "--pruning", "nothing", "--grpc.address", &port_arg]; let cosmos = run_cosmos_cmd(test, args, Some(40))?; Ok(cosmos) @@ -2927,10 +2935,9 @@ fn transfer_from_cosmos( let port_id = port_id.to_string(); let channel_id = channel_id.to_string(); let amount = format!("{}{}", amount, token.as_ref()); - let offset = CosmosChainType::chain_type(test.net.chain_id.as_str()) - .unwrap() - .get_offset(); - let rpc = format!("tcp://127.0.0.1:6416{offset}"); + let chain_type = + CosmosChainType::chain_type(test.net.chain_id.as_str()).unwrap(); + let rpc = format!("tcp://127.0.0.1:{}", chain_type.get_rpc_port_number()); // If the receiver is a pyament address we want to mask it to the more // general MASP internal address to improve on privacy let receiver = match PaymentAddress::from_str(receiver.as_ref()) { @@ -3089,10 +3096,9 @@ fn check_cosmos_balance( expected_amount: u64, ) -> Result<()> { let addr = find_cosmos_address(test, owner)?; - let offset = CosmosChainType::chain_type(test.net.chain_id.as_str()) - .unwrap() - .get_offset(); - let rpc = format!("tcp://127.0.0.1:6416{offset}"); + let chain_type = + CosmosChainType::chain_type(test.net.chain_id.as_str()).unwrap(); + let rpc = format!("tcp://127.0.0.1:{}", chain_type.get_rpc_port_number()); let args = ["query", "bank", "balances", &addr, "--node", &rpc]; let mut cosmos = run_cosmos_cmd(test, args, Some(40))?; cosmos.exp_string(&format!("amount: \"{expected_amount}\""))?; @@ -3489,3 +3495,757 @@ fn nft_transfer_from_cosmos( Ok(()) } + +/// Basic Osmosis test that checks if the chain has been set up correctly. +#[test] +fn osmosis_basic() -> Result<()> { + let (osmosis, test_osmosis) = + setup_and_boot_cosmos(CosmosChainType::Osmosis)?; + + let _bg_osmosis = osmosis.background(); + sleep(5); + + check_cosmos_balance(&test_osmosis, COSMOS_USER, COSMOS_COIN, 1_000)?; + + Ok(()) +} + +#[test] +fn osmosis_xcs() -> Result<()> { + // ========================================================== + // This test requires quite a long setup. Jump to the next + // occurrence of `SETUP DONE` in order to skip all of this + // nonsense. + // ========================================================== + + // Set up a big Cosmos party + let update_genesis = + |mut genesis: templates::All, base_dir: &_| { + genesis.parameters.parameters.epochs_per_year = + epochs_per_year_from_min_duration(1800); + genesis.parameters.ibc_params.default_mint_limit = + Amount::max_signed(); + genesis + .parameters + .ibc_params + .default_per_epoch_throughput_limit = Amount::max_signed(); + setup::set_validators(1, genesis, base_dir, |_| 0, vec![]) + }; + let (namada, gaia, test_namada, test_gaia) = + run_namada_cosmos(CosmosChainType::Gaia(Some(1)), update_genesis)?; + + let (osmosis, test_osmosis) = + setup_and_boot_cosmos(CosmosChainType::Osmosis)?; + + let _bg_osmosis = osmosis.background(); + let _bg_ledger = namada.background(); + let _bg_gaia = gaia.background(); + + // The MC of the party + let osmosis_jones = find_cosmos_address(&test_osmosis, COSMOS_USER)?; + + // Everyone shall take a 5 second nap, partied too hard + // (big up MC Osmosis Jones) + sleep(5); + + // Create hermes relayers with the following config: + // ================================================= + // + // namada -- osmosis -- gaia + // \_____________________/ + + // Set up initial hermes configs + let hermes_gaia_namada = setup_hermes(&test_gaia, &test_namada) + .map_err(|_| eyre!("failed to join thread hermes_gaia_namada"))?; + let hermes_gaia_osmosis = setup_hermes(&test_gaia, &test_osmosis) + .map_err(|_| eyre!("failed to join thread hermes_gaia_osmosis"))?; + let hermes_namada_osmosis = setup_hermes(&test_namada, &test_osmosis) + .map_err(|_| eyre!("failed to join thread hermes_namada_osmosis"))?; + std::thread::sleep(Duration::from_secs(5)); + // Set up channels + let (channel_from_gaia_to_namada, channel_from_namada_to_gaia) = + create_channel_with_hermes( + &hermes_gaia_namada, + &test_gaia, + &test_namada, + &PortId::transfer(), + &PortId::transfer(), + )?; + + // Osmosis currently uses an older version of the Cosmos SDK + // that will error if txs are sent too close together. See + // https://github.com/cosmos/cosmos-sdk/issues/13621 + std::thread::sleep(Duration::from_secs(5)); + let (channel_from_gaia_to_osmosis, channel_from_osmosis_to_gaia) = + create_channel_with_hermes( + &hermes_gaia_osmosis, + &test_gaia, + &test_osmosis, + &PortId::transfer(), + &PortId::transfer(), + )?; + + let (channel_from_namada_to_osmosis, channel_from_osmosis_to_namada) = + create_channel_with_hermes( + &hermes_namada_osmosis, + &test_namada, + &test_osmosis, + &PortId::transfer(), + &PortId::transfer(), + )?; + + // Start relaying + let hermes_1 = run_hermes(&hermes_gaia_namada)?; + let hermes_2 = run_hermes(&hermes_gaia_osmosis)?; + let hermes_3 = run_hermes(&hermes_namada_osmosis)?; + let _bg_hermes_1 = hermes_1.background(); + let _bg_hermes_2 = hermes_2.background(); + let _bg_hermes_3 = hermes_3.background(); + + // Transfer assets to Osmosis, in order to create pools + + // Transfer NAM from Namada + transfer( + &test_namada, + ALBERT, + &osmosis_jones, + NAM, + 500, + Some(ALBERT_KEY), + &PortId::transfer(), + &channel_from_namada_to_osmosis, + None, + None, + None, + None, + false, + )?; + // Transfer Samoleans from Gaia + transfer_from_cosmos( + &test_gaia, + COSMOS_USER, + &osmosis_jones, + COSMOS_COIN, + 500, + &PortId::transfer(), + &channel_from_gaia_to_osmosis, + None, + None, + )?; + + // Related to the issue above. In general, it takes osmosis some time + // to update state. Thus calls to it should be spaced out accordingly. + std::thread::sleep(Duration::from_secs(5)); + + // Check balance of transferred assets on Osmosis + let nam_token_addr = find_address(&test_namada, NAM)?; + check_cosmos_balance( + &test_osmosis, + COSMOS_USER, + format!("transfer/{channel_from_osmosis_to_namada}/{nam_token_addr}"), + 500_000_000, + )?; + + check_cosmos_balance( + &test_osmosis, + COSMOS_USER, + format!("transfer/{channel_from_osmosis_to_gaia}/{COSMOS_COIN}"), + 500, + )?; + + // Set up contracts on Osmosis + let rpc_osmosis = + format!("tcp://{}", get_cosmos_rpc_address(&test_osmosis)); + + const CROSSCHAIN_REGISTRY_CODE_ID: &str = "1"; + const SWAPROUTER_CODE_ID: &str = "2"; + const CROSSCHAIN_SWAPS_CODE_ID: &str = "3"; + + const CROSSCHAIN_REGISTRY_SHA256_HASH: &str = + "3a90b1dc50ba2c63c40298b1645f3a56431d895857cab75f97c5b8266f64e4fa"; + const SWAPROUTER_CODE_SHA256_HASH: &str = + "bd579ce619c16d50118f4a14f98fa1b2724ce11c7de2f8c532a9b2587bd98bbd"; + const CROSSCHAIN_SWAPS_SHA256_HASH: &str = + "87c3c3422e876f117efc5cda6ae30b4c897054148d424815daeb2b3038ec6cfd"; + + // Deploy each contract's wasm bytecode + for wasm in [ + "crosschain_registry.wasm", + "swaprouter.wasm", + "crosschain_swaps.wasm", + ] { + let wasm_path = osmosis_fixtures_dir().join("wasm_bytecode").join(wasm); + let wasm_path_str = wasm_path.to_string_lossy(); + std::thread::sleep(Duration::from_secs(5)); + let args = cosmos_common_args( + "5000000", + None, + test_osmosis.net.chain_id.as_str(), + &rpc_osmosis, + vec!["tx", "wasm", "store", &wasm_path_str], + ); + let mut osmosis_cmd = run_cosmos_cmd(&test_osmosis, args, Some(40))?; + osmosis_cmd.assert_success(); + } + + // Instantiate `crosschain_registry.wasm` + let json = format!(r#"{{"owner":"{osmosis_jones}"}}"#); + std::thread::sleep(Duration::from_secs(5)); + let crosschain_registry_addr = build_contract_addr( + &test_osmosis, + CROSSCHAIN_REGISTRY_SHA256_HASH, + &osmosis_jones, + )?; + std::thread::sleep(Duration::from_secs(5)); + let args = cosmos_common_args( + "2500000", + Some("0.01stake"), + test_osmosis.net.chain_id.as_str(), + &rpc_osmosis, + vec![ + "tx", + "wasm", + "instantiate2", + CROSSCHAIN_REGISTRY_CODE_ID, + &json, + CONTRACT_SALT_HEX, + "--label", + "CrosschainRegistry", + "--no-admin", + "--hex", + ], + ); + let mut osmosis_cmd = run_cosmos_cmd(&test_osmosis, args, Some(40))?; + osmosis_cmd.assert_success(); + + // Instantiate `swaprouter.wasm` + let json = format!(r#"{{"owner":"{osmosis_jones}"}}"#); + std::thread::sleep(Duration::from_secs(10)); + let swaprouter_addr = build_contract_addr( + &test_osmosis, + SWAPROUTER_CODE_SHA256_HASH, + &osmosis_jones, + )?; + std::thread::sleep(Duration::from_secs(10)); + let args = cosmos_common_args( + "250000", + Some("0.01stake"), + test_osmosis.net.chain_id.as_str(), + &rpc_osmosis, + vec![ + "tx", + "wasm", + "instantiate2", + SWAPROUTER_CODE_ID, + &json, + CONTRACT_SALT_HEX, + "--label", + "SwapRouter", + "--no-admin", + "--hex", + ], + ); + let mut osmosis_cmd = run_cosmos_cmd(&test_osmosis, args, Some(40))?; + osmosis_cmd.assert_success(); + + // Instantiate `swaprouter.wasm` + std::thread::sleep(Duration::from_secs(10)); + let json = format!( + r#"{{"governor":"{osmosis_jones}","swap_contract":"{swaprouter_addr}","registry_contract":"{crosschain_registry_addr}"}}"# + ); + let crosschain_swaps_addr = build_contract_addr( + &test_osmosis, + CROSSCHAIN_SWAPS_SHA256_HASH, + &osmosis_jones, + )?; + std::thread::sleep(Duration::from_secs(10)); + let args = cosmos_common_args( + "500000", + Some("0.01stake"), + test_osmosis.net.chain_id.as_str(), + &rpc_osmosis, + vec![ + "tx", + "wasm", + "instantiate2", + CROSSCHAIN_SWAPS_CODE_ID, + &json, + CONTRACT_SALT_HEX, + "--label", + "CrosschainSwaps", + "--no-admin", + "--hex", + ], + ); + + let mut osmosis_cmd = run_cosmos_cmd(&test_osmosis, args, Some(40))?; + osmosis_cmd.assert_success(); + std::thread::sleep(Duration::from_secs(5)); + + // Modify the bech32 prefixes + let msg = serde_json::to_string(&json!({ + "modify_bech32_prefixes": { + "operations": [ + { + "operation": "set", + "chain_name": "namada", + "prefix": "tnam" + }, + { + "operation": "set", + "chain_name": "osmosis", + "prefix": "osmo" + }, + { + "operation": "set", + "chain_name": "gaia", + "prefix": "cosmo" + } + ] + }})) + .unwrap(); + + let args = cosmos_common_args( + "5000000", + Some("0.01stake"), + test_osmosis.net.chain_id.as_str(), + &rpc_osmosis, + vec!["tx", "wasm", "execute", &crosschain_registry_addr, &msg], + ); + let mut osmosis_cmd = run_cosmos_cmd(&test_osmosis, args, Some(40))?; + osmosis_cmd.assert_success(); + std::thread::sleep(Duration::from_secs(5)); + + // Modify the channel chain links + let msg = serde_json::to_string(&json!({ + "modify_chain_channel_links": { + "operations": [ + { + "operation": "set", + "source_chain": "namada", + "destination_chain": "osmosis", + "channel_id": channel_from_namada_to_osmosis + }, + { + "operation": "set", + "source_chain": "osmosis", + "destination_chain": "namada", + "channel_id": channel_from_osmosis_to_namada + }, + { + "operation": "set", + "source_chain": "namada", + "destination_chain": "gaia", + "channel_id": channel_from_namada_to_gaia + }, + { + "operation": "set", + "source_chain": "gaia", + "destination_chain": "namada", + "channel_id": channel_from_gaia_to_namada + }, + { + "operation": "set", + "source_chain": "gaia", + "destination_chain": "osmosis", + "channel_id": channel_from_gaia_to_osmosis + }, + { + "operation": "set", + "source_chain": "osmosis", + "destination_chain": "gaia", + "channel_id": channel_from_osmosis_to_gaia + } + ] + }})) + .unwrap(); + let args = cosmos_common_args( + "5000000", + Some("0.01stake"), + test_osmosis.net.chain_id.as_str(), + &rpc_osmosis, + vec!["tx", "wasm", "execute", &crosschain_registry_addr, &msg], + ); + let mut osmosis_cmd = run_cosmos_cmd(&test_osmosis, args, Some(40))?; + osmosis_cmd.assert_success(); + std::thread::sleep(Duration::from_secs(5)); + + // Enable PFM on gaia and namada + for (chain, token) in [ + ( + "namada", + get_gaia_denom_hash(format!( + "transfer/{channel_from_osmosis_to_namada}/{nam_token_addr}" + )), + ), + ( + "gaia", + get_gaia_denom_hash(format!( + "transfer/{channel_from_osmosis_to_gaia}/{COSMOS_COIN}" + )), + ), + ] { + let msg = format!(r#"{{"propose_pfm": {{"chain": "{chain}"}}}}"#); + let amount = format!("1{token}"); + let args = cosmos_common_args( + "5000000", + Some("0.01stake"), + test_osmosis.net.chain_id.as_str(), + &rpc_osmosis, + vec![ + "tx", + "wasm", + "execute", + &crosschain_registry_addr, + &msg, + "--amount", + &amount, + ], + ); + let mut osmosis_cmd = run_cosmos_cmd(&test_osmosis, args, Some(40))?; + osmosis_cmd.assert_success(); + std::thread::sleep(Duration::from_secs(5)); + } + + wait_for_packet_relay( + &hermes_namada_osmosis, + &PortId::transfer(), + &channel_from_osmosis_to_namada, + &test_osmosis, + )?; + wait_for_packet_relay( + &hermes_gaia_osmosis, + &PortId::transfer(), + &channel_from_osmosis_to_gaia, + &test_osmosis, + )?; + + // Check that the PFM was successfully enabled + // on the contract + for chain in ["namada", "gaia"] { + let msg = + format!(r#"{{"has_packet_forwarding": {{"chain": "{chain}"}}}}"#); + let args = vec![ + "query", + "wasm", + "contract-state", + "smart", + &crosschain_registry_addr, + &msg, + ]; + let mut osmosis_cmd = run_cosmos_cmd(&test_osmosis, args, Some(40))?; + osmosis_cmd.exp_string("data: true")?; + } + + // Create a LP on Osmosis with Samoleans and Nam + create_pool( + &test_osmosis, + &rpc_osmosis, + &[ + ( + &get_gaia_denom_hash(format!( + "transfer/{channel_from_osmosis_to_namada}/\ + {nam_token_addr}" + )), + 100, + ), + ( + &get_gaia_denom_hash(format!( + "transfer/{channel_from_osmosis_to_gaia}/{COSMOS_COIN}" + )), + 100, + ), + ], + )?; + run_cosmos_cmd( + &test_osmosis, + ["query", "poolmanager", "pool", "1"], + Some(40), + )? + .assert_success(); + + // Shield some nam + let rpc_namada = get_actor_rpc(&test_namada, Who::Validator(0)); + + run!( + &test_namada, + Bin::Client, + [ + "shield", + "--source", + BERTHA, + "--target", + AA_PAYMENT_ADDRESS, + "--amount", + "0.000056", + "--token", + NAM, + "--node", + &rpc_namada, + ], + Some(40) + )? + .assert_success(); + + shielded_sync(&test_namada, AA_VIEWING_KEY)?; + + let query_args = vec![ + "balance", + "--owner", + AA_VIEWING_KEY, + "--token", + NAM, + "--node", + &rpc_namada, + ]; + let mut client = run!(&test_namada, Bin::Client, query_args, Some(40))?; + client.exp_string("nam: 0.000056")?; + client.assert_success(); + + // ========================================================== + // SETUP DONE + // ========================================================== + // At this point, we have IBC channels between Osmosis, Gaia + // and Namada. There is a LP with nam and samoleans, that we + // can use to swap between the two assets. Moreover, we have + // shielded some nam tokens. + // ========================================================== + + // We wish to receive samoleans on namada + let output_denom_on_namada = + format!("transfer/{channel_from_namada_to_gaia}/{COSMOS_COIN}"); + + // But on osmosis, we will end up with this token + let output_denom_on_osmosis = get_gaia_denom_hash(format!( + "transfer/{channel_from_osmosis_to_gaia}/{COSMOS_COIN}" + )); + + // Transparently swap samoleans with nam + run!( + &test_namada, + Bin::Client, + [ + "osmosis-swap", + "--osmosis-rest-rpc", + "http://localhost:1317", + "--source", + BERTHA, + "--token", + NAM, + "--amount", + "0.000064", + "--channel-id", + channel_from_namada_to_osmosis.as_ref(), + "--output-denom", + &output_denom_on_namada, + "--local-recovery-addr", + &osmosis_jones, + "--swap-contract", + &crosschain_swaps_addr, + "--minimum-amount", + "1", + "--target", + BERTHA, + "--pool-hop", + &format!("1:{output_denom_on_osmosis}"), + "--node", + &rpc_namada, + ], + Some(40), + )? + .assert_success(); + + wait_for_packet_relay( + &hermes_namada_osmosis, + &PortId::transfer(), + &channel_from_osmosis_to_namada, + &test_osmosis, + )?; + wait_for_packet_relay( + &hermes_gaia_namada, + &PortId::transfer(), + &channel_from_gaia_to_namada, + &test_namada, + )?; + + // Check that the swap worked + // 39 is derived from the uniswap formula: + // floor( 100 - (100*100/(100 + 64)) ) + check_balance( + &test_namada, + BERTHA, + format!("transfer/{channel_from_namada_to_gaia}/{COSMOS_COIN}"), + 39, + )?; + + // Perform a shielded swap of samoleans and nam + run!( + &test_namada, + Bin::Client, + [ + "osmosis-swap", + "--osmosis-rest-rpc", + "http://localhost:1317", + "--source", + AA_VIEWING_KEY, + "--token", + NAM, + "--amount", + "0.000056", + "--channel-id", + channel_from_namada_to_osmosis.as_ref(), + "--output-denom", + &output_denom_on_namada, + "--local-recovery-addr", + &osmosis_jones, + "--swap-contract", + &crosschain_swaps_addr, + "--minimum-amount", + "10", + "--target-pa", + AA_PAYMENT_ADDRESS, + "--overflow-addr", + ALBERT, + "--pool-hop", + &format!("1:{output_denom_on_osmosis}"), + "--gas-payer", + ALBERT_KEY, + "--node", + &rpc_namada, + "--gas-limit", + "500000", + ], + Some(40), + )? + .assert_success(); + + wait_for_packet_relay( + &hermes_namada_osmosis, + &PortId::transfer(), + &channel_from_osmosis_to_namada, + &test_osmosis, + )?; + wait_for_packet_relay( + &hermes_gaia_namada, + &PortId::transfer(), + &channel_from_gaia_to_namada, + &test_namada, + )?; + + // Check that the minimum amount got shielded + check_shielded_balance( + &test_namada, + AA_VIEWING_KEY, + &output_denom_on_namada, + 10, + )?; + // 5 is derived from the uniswap formula: + // floor( 61 - ( 164 * 61 / (164 + 56) ) ) minus + // the minimum amount (10) which was shielded + check_balance(&test_namada, ALBERT, &output_denom_on_namada, 5)?; + + Ok(()) +} + +fn cosmos_common_args<'a>( + gas: &'a str, + gas_price: Option<&'a str>, + chain_id: &'a str, + rpc: &'a str, + mut args: Vec<&'a str>, +) -> Vec<&'a str> { + args.extend_from_slice(&[ + "--from", + COSMOS_USER, + "--gas", + gas, + "--gas-prices", + gas_price.unwrap_or("0.01stake"), + "--node", + rpc, + "--keyring-backend", + "test", + "--chain-id", + chain_id, + "--yes", + ]); + args +} + +fn build_contract_addr( + test: &Test, + wasm_bytecode_hash: &str, + creator_addr: &str, +) -> Result { + let osmosis_home = test.test_dir.as_ref().join("osmosis"); + let args = [ + "--home", + osmosis_home.to_str().unwrap(), + "query", + "wasm", + "build-address", + wasm_bytecode_hash, + creator_addr, + CONTRACT_SALT_HEX, + ]; + let mut cosmos = run_cosmos_cmd_homeless(test, args, Some(40))?; + let (_, matched) = cosmos.exp_regex("address: .*\n")?; + let mut parts = matched.split(':'); + parts.next().unwrap(); + Ok(parts.next().unwrap().trim().to_string()) +} + +/// Create a liquidity pool on osmosis. +/// All tokens will be 1:1 swappable in the provided +/// denoms. +fn create_pool( + test: &Test, + rpc: &str, + denoms_and_deposits: &[(&str, u64)], +) -> Result<()> { + let json_path = test.test_dir.path().join("pool.json"); + let mut weights = + denoms_and_deposits + .iter() + .fold(String::new(), |mut acc, (d, _)| { + acc.push_str(&format!("1{d},")); + acc + }); + weights.pop(); + let mut init_deposits = + denoms_and_deposits + .iter() + .fold(String::new(), |mut acc, (d, a)| { + acc.push_str(&format!("{a}{d},")); + acc + }); + init_deposits.pop(); + let pool_json = json!({ + "weights": weights, + "initial-deposit": init_deposits, + "swap-fee": "0.001", + "exit-fee": "0.000" + }); + let json_file = File::create(&json_path)?; + serde_json::to_writer(json_file, &pool_json)?; + let json_path = json_path.to_string_lossy(); + let args = cosmos_common_args( + "2500000", + Some("0.01stake"), + "osmosis", + rpc, + vec![ + "tx", + "poolmanager", + "create-pool", + "--pool-file", + &json_path, + ], + ); + let mut osmosis_cmd = run_cosmos_cmd(test, args, Some(40))?; + osmosis_cmd.assert_success(); + std::thread::sleep(Duration::from_secs(5)); + Ok(()) +} + +const CONTRACT_SALT_HEX: &str = "01020304"; diff --git a/crates/tests/src/e2e/setup.rs b/crates/tests/src/e2e/setup.rs index d0bdb14f80..4eec9b69be 100644 --- a/crates/tests/src/e2e/setup.rs +++ b/crates/tests/src/e2e/setup.rs @@ -42,8 +42,8 @@ use rand::Rng; use tempfile::{tempdir, tempdir_in, TempDir}; use crate::e2e::helpers::{ - find_cosmos_address, generate_bin_command, make_hermes_config, - update_cosmos_config, + find_cosmos_address, generate_bin_command, get_cosmos_rpc_address, + make_hermes_config, update_cosmos_config, }; /// For `color_eyre::install`, which fails if called more than once in the same @@ -844,6 +844,22 @@ pub fn working_dir() -> PathBuf { working_dir } +/// Return the path to all test fixture. +pub fn fixtures_dir() -> PathBuf { + let mut dir = working_dir(); + dir.push("crates"); + dir.push("tests"); + dir.push("fixtures"); + dir +} + +/// Return the path to all osmosis fixture. +pub fn osmosis_fixtures_dir() -> PathBuf { + let mut dir = fixtures_dir(); + dir.push("osmosis_data"); + dir +} + /// A command under test pub struct NamadaCmd { pub session: Session>, @@ -1243,31 +1259,126 @@ pub fn setup_hermes(test_a: &Test, test_b: &Test) -> Result { let hermes_dir = TestDir::new(); println!("\n{}", "Setting up Hermes".underline().green(),); - - make_hermes_config(&hermes_dir, test_a, test_b)?; + let chain_name_a = + CosmosChainType::chain_type(test_a.net.chain_id.as_str()) + .map(|c| c.chain_id()) + .ok(); + let chain_name_b = + CosmosChainType::chain_type(test_b.net.chain_id.as_str()) + .map(|c| c.chain_id()) + .ok(); + let relayer = chain_name_a + .zip(chain_name_b) + .map(|(a, b)| format!("{a}_{b}_relayer")); + make_hermes_config( + &hermes_dir, + test_a, + test_b, + relayer.as_ref().map(|s| s.as_ref()), + )?; for test in [test_a, test_b] { let chain_id = test.net.chain_id.as_str(); let chain_dir = test.test_dir.as_ref().join(chain_id); - let key_file_path = match CosmosChainType::chain_type(chain_id) { - Ok(_) => chain_dir - .join(format!("{}_seed.json", constants::COSMOS_RELAYER)), - Err(_) => wallet::wallet_file(chain_dir), + match CosmosChainType::chain_type(chain_id) { + Ok(_) => { + if let Some(relayer) = relayer.as_ref() { + // we create a new relayer for each ibc connection between + // to non-Namada chains + let key_file = + chain_dir.join(format!("{relayer}_seed.json")); + let args = [ + "keys", + "add", + relayer, + "--keyring-backend", + "test", + "--output", + "json", + ]; + let mut cosmos = run_cosmos_cmd(test, args, Some(10))?; + let result = cosmos.exp_string("\n")?; + let mut file = File::create(&key_file).unwrap(); + file.write_all(result.as_bytes()).map_err(|e| { + eyre!(format!( + "Writing a Cosmos key file failed: {}", + e + )) + })?; + + let account = find_cosmos_address(test, relayer)?; + // Add tokens to the new relayer account + let args = [ + "tx", + "bank", + "send", + constants::COSMOS_RELAYER, + &account, + "500000000stake", + "--from", + constants::COSMOS_RELAYER, + "--gas", + "250000", + "--gas-prices", + "0.01stake", + "--node", + &format!("http://{}", get_cosmos_rpc_address(test)), + "--keyring-backend", + "test", + "--chain-id", + chain_id, + "--yes", + ]; + + let mut cosmos = run_cosmos_cmd(test, args, Some(10))?; + cosmos.assert_success(); + + // add to hermes + let args = [ + "keys", + "add", + "--chain", + chain_id, + "--key-file", + &key_file.to_string_lossy(), + "--key-name", + relayer, + ]; + let mut hermes = + run_hermes_cmd(&hermes_dir, args, Some(20))?; + hermes.assert_success(); + } else { + let key_file_path = chain_dir.join(format!( + "{}_seed.json", + constants::COSMOS_RELAYER + )); + let args = [ + "keys", + "add", + "--chain", + chain_id, + "--key-file", + &key_file_path.to_string_lossy(), + ]; + let mut hermes = + run_hermes_cmd(&hermes_dir, args, Some(20))?; + hermes.assert_success(); + } + } + Err(_) => { + let key_file_path = wallet::wallet_file(&chain_dir); + let args = [ + "keys", + "add", + "--chain", + chain_id, + "--key-file", + &key_file_path.to_string_lossy(), + ]; + let mut hermes = run_hermes_cmd(&hermes_dir, args, Some(20))?; + hermes.assert_success(); + } }; - let args = [ - "keys", - "add", - // TODO: this overwrite is required because hermes keys are pulled - // from the namada chain dir... however, ideally we would store the - // `wallet.toml` file under hermes' own dir - "--overwrite", - "--chain", - chain_id, - "--key-file", - &key_file_path.to_string_lossy(), - ]; - let mut hermes = run_hermes_cmd(&hermes_dir, args, Some(20))?; - hermes.assert_success(); } Ok(hermes_dir) @@ -1341,9 +1452,46 @@ where pub enum CosmosChainType { Gaia(Option), CosmWasm, + Osmosis, } impl CosmosChainType { + fn genesis_cmd_args<'a>(&self, mut args: Vec<&'a str>) -> Vec<&'a str> { + if !matches!(self, CosmosChainType::Osmosis) { + args.insert(0, "genesis"); + } + args + } + + fn add_genesis_account_args<'a>( + &self, + account: &'a str, + coins: &'a str, + ) -> Vec<&'a str> { + self.genesis_cmd_args(vec!["add-genesis-account", account, coins]) + } + + fn gentx_args<'a>( + &self, + account: &'a str, + coins: &'a str, + chain_id: &'a str, + ) -> Vec<&'a str> { + self.genesis_cmd_args(vec![ + "gentx", + account, + coins, + "--keyring-backend", + "test", + "--chain-id", + chain_id, + ]) + } + + fn collect_gentxs_args<'a>(&self) -> Vec<&'a str> { + self.genesis_cmd_args(vec!["collect-gentxs"]) + } + pub fn chain_id(&self) -> String { match self { Self::Gaia(Some(suffix)) => { @@ -1351,6 +1499,7 @@ impl CosmosChainType { } Self::Gaia(_) => constants::GAIA_CHAIN_ID.to_string(), Self::CosmWasm => constants::COSMWASM_CHAIN_ID.to_string(), + Self::Osmosis => constants::OSMOSIS_CHAIN_ID.to_string(), } } @@ -1358,6 +1507,7 @@ impl CosmosChainType { match self { Self::Gaia(_) => "gaiad", Self::CosmWasm => "wasmd", + Self::Osmosis => "osmosisd", } } @@ -1365,6 +1515,9 @@ impl CosmosChainType { if chain_id == constants::COSMWASM_CHAIN_ID { return Ok(Self::CosmWasm); } + if chain_id == constants::OSMOSIS_CHAIN_ID { + return Ok(Self::Osmosis); + } match chain_id.strip_prefix(constants::GAIA_CHAIN_ID) { Some("") => Ok(Self::Gaia(None)), Some(suffix) => { @@ -1380,13 +1533,29 @@ impl CosmosChainType { match self { Self::Gaia(_) => "cosmos", Self::CosmWasm => "wasm", + Self::Osmosis => "osmo", } } - pub fn get_offset(&self) -> u64 { + pub fn get_p2p_port_number(&self) -> u64 { + 10_000 + self.get_offset() + } + + pub fn get_rpc_port_number(&self) -> u64 { + 20_000 + self.get_offset() + } + + pub fn get_grpc_port_number(&self) -> u64 { + 30_000 + self.get_offset() + } + + fn get_offset(&self) -> u64 { + // NB: ensure none of these ever conflict match self { - Self::Gaia(Some(off)) => *off, - _ => 0, + Self::CosmWasm => 0, + Self::Osmosis => 1, + Self::Gaia(None) => 2, + Self::Gaia(Some(off)) => 3 + *off, } } } @@ -1437,47 +1606,42 @@ pub fn setup_cosmos(chain_type: CosmosChainType) -> Result { // Add tokens to a user account let account = find_cosmos_address(&test, constants::COSMOS_USER)?; - let args = [ - "genesis", - "add-genesis-account", - &account, - "100000000stake,1000samoleans", - ]; + let args = if let CosmosChainType::Osmosis = chain_type { + chain_type.add_genesis_account_args( + &account, + "100000000stake,1000samoleans, 10000000000uosmo", + ) + } else { + chain_type + .add_genesis_account_args(&account, "100000000stake,1000samoleans") + }; let mut cosmos = run_cosmos_cmd(&test, args, Some(10))?; cosmos.assert_success(); // Add the stake token to the relayer let account = find_cosmos_address(&test, constants::COSMOS_RELAYER)?; - let args = ["genesis", "add-genesis-account", &account, "10000stake"]; + let args = + chain_type.add_genesis_account_args(&account, "10000000000stake"); let mut cosmos = run_cosmos_cmd(&test, args, Some(10))?; cosmos.assert_success(); // Add the stake token to the validator let validator = find_cosmos_address(&test, constants::COSMOS_VALIDATOR)?; - let args = [ - "genesis", - "add-genesis-account", - &validator, - "200000000000stake", - ]; + let args = + chain_type.add_genesis_account_args(&validator, "200000000000stake"); let mut cosmos = run_cosmos_cmd(&test, args, Some(10))?; cosmos.assert_success(); // stake - let args = [ - "genesis", - "gentx", + let args = chain_type.gentx_args( constants::COSMOS_VALIDATOR, "100000000000stake", - "--keyring-backend", - "test", - "--chain-id", &chain_id, - ]; + ); let mut cosmos = run_cosmos_cmd(&test, args, Some(10))?; cosmos.assert_success(); - let args = ["genesis", "collect-gentxs"]; + let args = chain_type.collect_gentxs_args(); let mut cosmos = run_cosmos_cmd(&test, args, Some(10))?; cosmos.assert_success(); @@ -1486,6 +1650,67 @@ pub fn setup_cosmos(chain_type: CosmosChainType) -> Result { Ok(test) } +pub fn run_cosmos_cmd_homeless( + test: &Test, + args: I, + timeout_sec: Option, +) -> Result +where + I: IntoIterator, + S: AsRef, +{ + let chain_id = test.net.chain_id.as_str(); + let chain_type = CosmosChainType::chain_type(chain_id)?; + let mut run_cmd = Command::new(chain_type.command_path()); + run_cmd.args(args); + + let args: String = + run_cmd.get_args().map(|s| s.to_string_lossy()).join(" "); + let cmd_str = + format!("{} {}", run_cmd.get_program().to_string_lossy(), args); + + let session = Session::spawn(run_cmd).map_err(|e| { + eyre!( + "\n\n{}: {}\n{}: {}", + "Failed to run Cosmos command".underline().red(), + cmd_str, + "Error".underline().red(), + e + ) + })?; + + let log_path = { + let mut rng = rand::thread_rng(); + let log_dir = test.get_base_dir(Who::NonValidator).join("logs"); + std::fs::create_dir_all(&log_dir)?; + log_dir.join(format!( + "{}-cosmos-{}.log", + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_micros(), + rng.gen::() + )) + }; + let logger = OpenOptions::new() + .write(true) + .create_new(true) + .open(&log_path)?; + let mut session = expectrl::session::log(session, logger).unwrap(); + + session.set_expect_timeout(timeout_sec.map(std::time::Duration::from_secs)); + + let cmd_process = NamadaCmd { + session, + cmd_str, + log_path, + }; + + println!("{}:\n{}", "> Running".underline().green(), &cmd_process); + + Ok(cmd_process) +} + pub fn run_cosmos_cmd( test: &Test, args: I, @@ -1601,10 +1826,10 @@ pub mod constants { pub const APFEL: &str = "Apfel"; pub const KARTOFFEL: &str = "Kartoffel"; - // Gaia or CosmWasm + // Gaia or CosmWasm or Osmosis pub const GAIA_CHAIN_ID: &str = "gaia"; + pub const OSMOSIS_CHAIN_ID: &str = "osmosis"; pub const COSMWASM_CHAIN_ID: &str = "cosmwasm"; - pub const COSMOS_RPC: &str = "127.0.0.1:64160"; pub const COSMOS_USER: &str = "user"; pub const COSMOS_RELAYER: &str = "relayer"; pub const COSMOS_VALIDATOR: &str = "validator"; From 616f77c910df10932343ea2934b61993792a5441 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Wed, 15 Jan 2025 17:05:05 +0000 Subject: [PATCH 28/31] Expose SDK function to gen disposable signing keys --- crates/sdk/src/signing.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/crates/sdk/src/signing.rs b/crates/sdk/src/signing.rs index a2e92b5cb7..1252373faa 100644 --- a/crates/sdk/src/signing.rs +++ b/crates/sdk/src/signing.rs @@ -410,11 +410,7 @@ pub async fn aux_signing_data( }; let fee_payer = if disposable_signing_key { - context - .wallet_mut() - .await - .gen_disposable_signing_key(&mut OsRng) - .to_public() + gen_disposable_signing_key(context).await } else { match &args.wrapper_fee_payer { Some(keypair) => keypair.clone(), @@ -497,6 +493,17 @@ pub async fn generate_tx_signatures( }) } +/// Generate a disposable signing key. +pub async fn gen_disposable_signing_key( + context: &impl Namada, +) -> common::PublicKey { + context + .wallet_mut() + .await + .gen_disposable_signing_key(&mut OsRng) + .to_public() +} + /// Information about the post-fee balance of the tx's source. Used to correctly /// handle balance validation in the inner tx #[derive(Debug)] From 573a9abaf911a7461d6d274c5e57ccbb1b3f396f Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Wed, 15 Jan 2025 17:38:03 +0000 Subject: [PATCH 29/31] Generate disposable overflow receivers --- crates/apps_lib/src/cli.rs | 13 ++++++++----- crates/sdk/src/args.rs | 39 +++++++++++++++++++++++++------------- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/crates/apps_lib/src/cli.rs b/crates/apps_lib/src/cli.rs index 700e9ae64b..a4951f218b 100644 --- a/crates/apps_lib/src/cli.rs +++ b/crates/apps_lib/src/cli.rs @@ -5174,6 +5174,7 @@ pub mod args { .arg( TARGET_OPT .def() + .conflicts_with(OVERFLOW_OPT.name) .conflicts_with(PAYMENT_ADDRESS_TARGET_OPT.name) .help(wrap!( "The transparent Namada address that shall \ @@ -5183,7 +5184,6 @@ pub mod args { .arg( PAYMENT_ADDRESS_TARGET_OPT .def() - .requires(OVERFLOW_OPT.name) .conflicts_with(TARGET_OPT.name) .help(wrap!( "The shielded Namada address that shall receive \ @@ -5191,10 +5191,13 @@ pub mod args { )), ) .arg(OVERFLOW_OPT.def().help(wrap!( - "The transparent address that receives the amount of \ - target asset exceeding the minimum amount. If used in \ - conjunction with shielding, this address should not be \ - linkable to any of your transparent accounts." + "Transparent address that receives the amount of target \ + asset exceeding the minimum trade amount. Only \ + applicable when shielding assets that have been swapped \ + on Osmosis. This address should not be linkable to any \ + of the user's personal accounts, to maximize the privacy \ + of the trade. If unspecified, a disposable address is \ + generated." ))) .arg(SLIPPAGE.def().requires(WINDOW_SECONDS.name).help(wrap!( "The slippage percentage as an integer between 0 and 100. \ diff --git a/crates/sdk/src/args.rs b/crates/sdk/src/args.rs index f0f211db09..24168c7b78 100644 --- a/crates/sdk/src/args.rs +++ b/crates/sdk/src/args.rs @@ -24,6 +24,7 @@ use namada_governance::cli::onchain::{ DefaultProposal, PgfFundingProposal, PgfStewardProposal, }; use namada_ibc::IbcShieldingData; +use namada_io::{display_line, Io}; use namada_token::masp::utils::RetryStrategy; use namada_tx::data::GasLimit; use namada_tx::Memo; @@ -38,7 +39,7 @@ use crate::rpc::{ get_registry_from_xcs_osmosis_contract, osmosis_denom_from_namada_denom, query_osmosis_pool_routes, }; -use crate::signing::SigningTxData; +use crate::signing::{gen_disposable_signing_key, SigningTxData}; use crate::wallet::{DatedSpendingKey, DatedViewingKey}; use crate::{rpc, tx, Namada}; @@ -543,7 +544,11 @@ pub struct TxOsmosisSwap { pub output_denom: String, /// Address of the recipient on Namada pub recipient: Either, - /// Address to receive funds exceeding the minimum amount + /// Address to receive funds exceeding the minimum amount, + /// in case of IBC shieldings + /// + /// If unspecified, a disposable address is generated to + /// receive funds with pub overflow: Option, /// Constraints on the osmosis swap pub slippage: Slippage, @@ -616,16 +621,22 @@ impl TxOsmosisSwap { output_denom: namada_output_denom, } = self; - let recipient = recipient - .map_either(Some, |payment_addr| Some(payment_addr).zip(overflow)) - .factor_none() - .ok_or_else(|| { - Error::Other( - "Overflow receiver unspecified while attempting a fully \ - shielded swap" - .to_owned(), - ) - })?; + let recipient = recipient.map_either( + |addr| addr, + |payment_addr| async move { + let overflow_receiver = if let Some(overflow) = overflow { + overflow + } else { + let addr = (&gen_disposable_signing_key(ctx).await).into(); + display_line!( + ctx.io(), + "Sending unshielded funds to disposable address {addr}", + ); + addr + }; + (payment_addr, overflow_receiver) + }, + ); // validate `local_recovery_addr` and the contract addr if !bech32::decode(&local_recovery_addr) @@ -684,7 +695,9 @@ impl TxOsmosisSwap { Either::Left(transparent_recipient) => { (transparent_recipient.to_string(), slippage, None) } - Either::Right((payment_addr, overflow_receiver)) => { + Either::Right(fut) => { + let (payment_addr, overflow_receiver) = fut.await; + let amount_to_shield = match slippage { Slippage::MinOutputAmount(amount_to_shield) => { amount_to_shield From e71c02bdc48875abe66e5d7b6171ed6aae79ea5e Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Wed, 15 Jan 2025 17:43:19 +0000 Subject: [PATCH 30/31] Improve Osmosis swaps CLI help msgs --- crates/apps_lib/src/cli.rs | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/crates/apps_lib/src/cli.rs b/crates/apps_lib/src/cli.rs index a4951f218b..6e715b86d5 100644 --- a/crates/apps_lib/src/cli.rs +++ b/crates/apps_lib/src/cli.rs @@ -5169,7 +5169,11 @@ pub mod args { the optimal route is queried on the fly." ))) .arg(OUTPUT_DENOM.def().help(wrap!( - "The IBC denomination (on Namada) of the desired asset." + "IBC trace path (on Namada) of the desired asset. This is \ + a string of the form \ + `transfer//`, where `` \ + is the channel that connects Namada to some counterparty \ + chain." ))) .arg( TARGET_OPT @@ -5177,8 +5181,8 @@ pub mod args { .conflicts_with(OVERFLOW_OPT.name) .conflicts_with(PAYMENT_ADDRESS_TARGET_OPT.name) .help(wrap!( - "The transparent Namada address that shall \ - receive the swapped tokens." + "Transparent Namada address that shall receive \ + the swapped tokens." )), ) .arg( @@ -5186,8 +5190,8 @@ pub mod args { .def() .conflicts_with(TARGET_OPT.name) .help(wrap!( - "The shielded Namada address that shall receive \ - the minimum amount of swapped tokens." + "Namada payment address that shall receive the \ + minimum amount of tokens swapped on Osmosis." )), ) .arg(OVERFLOW_OPT.def().help(wrap!( @@ -5200,13 +5204,13 @@ pub mod args { generated." ))) .arg(SLIPPAGE.def().requires(WINDOW_SECONDS.name).help(wrap!( - "The slippage percentage as an integer between 0 and 100. \ + "Slippage percentage, as a number between 0 and 100. \ Represents the maximum acceptable deviation from the \ expected price during a trade." ))) .arg(WINDOW_SECONDS.def().requires(SLIPPAGE.name).help(wrap!( - "The time period (in seconds) over which the average \ - price is calculated." + "Time period (in seconds) over which the average price is \ + calculated." ))) .arg( MINIMUM_AMOUNT @@ -5214,13 +5218,13 @@ pub mod args { .conflicts_with(SLIPPAGE.name) .conflicts_with(WINDOW_SECONDS.name) .help(wrap!( - "The minimum amount of target asset that the \ - trade should produce." + "Minimum amount of target asset that the trade \ + should produce." )), ) .arg(LOCAL_RECOVERY_ADDR.def().help(wrap!( - "An address on Osmosis from which to recover funds in \ - case of failure." + "Address on Osmosis from which to recover funds in case \ + of failure." ))) .group( ArgGroup::new("slippage") @@ -5237,8 +5241,8 @@ pub mod args { ) .mut_arg(RECEIVER.name, |arg| { arg.long("swap-contract").help(wrap!( - "The address of the Osmosis contract performing the \ - swap. It will be the receiver of the IBC transfer." + "Address of the Osmosis contract performing the swap. \ + It will be the receiver of the IBC transfer." )) }) } From 1d5de2c0e5935c5108e36389d2b3d33404389f87 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Mon, 13 Jan 2025 14:37:13 +0000 Subject: [PATCH 31/31] Changelog for #4133 --- .changelog/unreleased/features/4133-osmosis-swaps.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .changelog/unreleased/features/4133-osmosis-swaps.md diff --git a/.changelog/unreleased/features/4133-osmosis-swaps.md b/.changelog/unreleased/features/4133-osmosis-swaps.md new file mode 100644 index 0000000000..a6cd190100 --- /dev/null +++ b/.changelog/unreleased/features/4133-osmosis-swaps.md @@ -0,0 +1,4 @@ +- Integrate Namada and Osmosis, to allow swapping assets privately. Osmosis + is leveraged for its liquidity and DEX capabilities, while Namada is + leveraged for its shielded pool (i.e. MASP) and privacy guarantees. + ([\#4133](https://github.com/anoma/namada/pull/4133)) \ No newline at end of file