diff --git a/framework/Cargo.lock b/framework/Cargo.lock index ad64e20979..4d5474b249 100644 --- a/framework/Cargo.lock +++ b/framework/Cargo.lock @@ -185,7 +185,8 @@ dependencies = [ [[package]] name = "abstract-cw-orch-polytone" version = "5.0.0" -source = "git+https://github.com/AbstractSDK/polytone.git?branch=bump/cw2#95442e05d6ff3993d64c70a10a228821a46b6681" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4584809a6f01450c3852c70c191fa9b90f75243e5c0f8b3cb36a9b74c7e5d3a" dependencies = [ "abstract-polytone-note", "abstract-polytone-proxy", @@ -447,7 +448,7 @@ dependencies = [ [[package]] name = "abstract-polytone" version = "2.0.0" -source = "git+https://github.com/AbstractSDK/polytone.git?branch=bump/cw2#95442e05d6ff3993d64c70a10a228821a46b6681" +source = "git+https://github.com/AbstractSDK/polytone.git?branch=bump/cw2#0ef638cf6e591734495faf537fc04367a6ef4c9e" dependencies = [ "cosmwasm-schema", "cosmwasm-std", @@ -458,7 +459,8 @@ dependencies = [ [[package]] name = "abstract-polytone-note" version = "4.0.1" -source = "git+https://github.com/AbstractSDK/polytone.git?branch=bump/cw2#95442e05d6ff3993d64c70a10a228821a46b6681" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1874ade71ecb9fa8c0779fbbfb671ef22d116183d66beaa6d74f7adb6233a91e" dependencies = [ "abstract-polytone", "cosmwasm-schema", @@ -473,7 +475,8 @@ dependencies = [ [[package]] name = "abstract-polytone-proxy" version = "4.0.1" -source = "git+https://github.com/AbstractSDK/polytone.git?branch=bump/cw2#95442e05d6ff3993d64c70a10a228821a46b6681" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812eefeb84e5c7a291054cd942ae95b49258790e1a4c8d31710851729bf59924" dependencies = [ "abstract-polytone", "cosmwasm-schema", @@ -488,7 +491,8 @@ dependencies = [ [[package]] name = "abstract-polytone-voice" version = "4.0.1" -source = "git+https://github.com/AbstractSDK/polytone.git?branch=bump/cw2#95442e05d6ff3993d64c70a10a228821a46b6681" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4da410f8b3c895cf4137ab64982ed20f345fdb409bd31d8fb803514e118e2a56" dependencies = [ "abstract-polytone", "abstract-polytone-proxy", @@ -550,6 +554,8 @@ dependencies = [ "schemars", "semver", "serde", + "serde-cw-value", + "serde_json", "thiserror", "workspace-hack", ] @@ -772,7 +778,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -788,7 +794,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", "syn-solidity", "tiny-keccak", ] @@ -804,7 +810,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", "syn-solidity", ] @@ -836,9 +842,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" dependencies = [ "anstyle", "anstyle-parse", @@ -851,36 +857,36 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -891,9 +897,9 @@ checksum = "cb5f1dee23caf80904249463cc4493b6789c2250f88c8f8d9160de5c6099bfe7" [[package]] name = "anyhow" -version = "1.0.90" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37bf3594c4c988a53154954629820791dde498571819ae4ca50ca811e060cc95" +checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8" [[package]] name = "arc-swap" @@ -1060,7 +1066,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -1082,7 +1088,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -1093,7 +1099,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -1587,7 +1593,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -1598,9 +1604,9 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "concurrent-queue" @@ -1791,7 +1797,7 @@ checksum = "1b5658b1dc64e10b56ae7a449f678f96932a96f6cfad1769d608d1d1d656480a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -1815,7 +1821,7 @@ checksum = "c8ef1b5835a65fcca3ab8b9a02b4f4dacc78e233a5c2f20b270efb9db0666d12" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -1951,7 +1957,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -2082,7 +2088,7 @@ checksum = "bad52865e313bb7ed3f3938f7ad9d566e430fb6143a63476c22bed505ea78cd7" dependencies = [ "convert_case 0.6.0", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -2161,7 +2167,7 @@ dependencies = [ "convert_case 0.6.0", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -2172,7 +2178,7 @@ checksum = "85806182382aef051a318b9abb41af559e6d7733fbba3c04c42ed23cc03d8e1a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -2670,7 +2676,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -2692,7 +2698,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -2790,7 +2796,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -2810,7 +2816,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core 0.20.2", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -2823,7 +2829,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -2843,7 +2849,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", "unicode-xid", ] @@ -3091,9 +3097,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] @@ -3356,7 +3362,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -4343,7 +4349,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -4723,7 +4729,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -4962,7 +4968,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -4978,29 +4984,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -5112,9 +5118,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.88" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] @@ -5168,7 +5174,7 @@ dependencies = [ "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -5300,9 +5306,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -5552,7 +5558,7 @@ dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.82", + "syn 2.0.85", "walkdir", ] @@ -5786,7 +5792,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -5904,9 +5910,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.211" +version = "1.0.213" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ac55e59090389fb9f0dd9e0f3c09615afed1d19094284d0b200441f13550793" +checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1" dependencies = [ "serde_derive", ] @@ -5960,13 +5966,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.211" +version = "1.0.213" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54be4f245ce16bc58d57ef2716271d0d4519e0f6defa147f6e081005bcb278ff" +checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -5977,7 +5983,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -6010,7 +6016,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -6235,7 +6241,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -6272,9 +6278,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.82" +version = "2.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" +checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" dependencies = [ "proc-macro2", "quote", @@ -6290,7 +6296,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -6619,22 +6625,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -6756,7 +6762,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -6990,7 +6996,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -7310,7 +7316,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", "wasm-bindgen-shared", ] @@ -7344,7 +7350,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7690,7 +7696,7 @@ dependencies = [ "spki", "subtle", "syn 1.0.109", - "syn 2.0.82", + "syn 2.0.85", "tendermint 0.38.1", "tendermint-proto 0.38.1", "time", @@ -7736,7 +7742,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] [[package]] @@ -7756,5 +7762,15 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.85", ] + +[[patch.unused]] +name = "abstract-cw-orch-polytone" +version = "6.0.0" +source = "git+https://github.com/AbstractSDK/polytone.git?branch=bump/cw2#0ef638cf6e591734495faf537fc04367a6ef4c9e" + +[[patch.unused]] +name = "abstract-polytone-note" +version = "5.0.0" +source = "git+https://github.com/AbstractSDK/polytone.git?branch=bump/cw2#0ef638cf6e591734495faf537fc04367a6ef4c9e" diff --git a/framework/Cargo.toml b/framework/Cargo.toml index 0ff8889ff7..35d15b5ec3 100644 --- a/framework/Cargo.toml +++ b/framework/Cargo.toml @@ -44,6 +44,7 @@ cw-asset = { version = "4.0" } cw-ownable = { version = "2.0" } cw-address-like = { version = "2.0" } cw-clearable = { version = "0.2.0" } +serde-cw-value = "0.7.0" schemars = "0.8" serde = { version = "1.0", default-features = false, features = ["derive"] } diff --git a/framework/artifacts/abstract_account-xion.wasm b/framework/artifacts/abstract_account-xion.wasm index aa4f90d5ec..74d4bff43c 100644 Binary files a/framework/artifacts/abstract_account-xion.wasm and b/framework/artifacts/abstract_account-xion.wasm differ diff --git a/framework/artifacts/abstract_account.wasm b/framework/artifacts/abstract_account.wasm index 1fbe286cab..6de46422d0 100644 Binary files a/framework/artifacts/abstract_account.wasm and b/framework/artifacts/abstract_account.wasm differ diff --git a/framework/artifacts/abstract_ans_host.wasm b/framework/artifacts/abstract_ans_host.wasm index c834da7d22..e527d5f802 100644 Binary files a/framework/artifacts/abstract_ans_host.wasm and b/framework/artifacts/abstract_ans_host.wasm differ diff --git a/framework/artifacts/abstract_ibc_client.wasm b/framework/artifacts/abstract_ibc_client.wasm index 0c282814c3..d875e74e57 100644 Binary files a/framework/artifacts/abstract_ibc_client.wasm and b/framework/artifacts/abstract_ibc_client.wasm differ diff --git a/framework/artifacts/abstract_ibc_host.wasm b/framework/artifacts/abstract_ibc_host.wasm index f7eecf7f39..438443cfec 100644 Binary files a/framework/artifacts/abstract_ibc_host.wasm and b/framework/artifacts/abstract_ibc_host.wasm differ diff --git a/framework/artifacts/abstract_ica_client.wasm b/framework/artifacts/abstract_ica_client.wasm index fac90b4376..d75e8c8eb2 100644 Binary files a/framework/artifacts/abstract_ica_client.wasm and b/framework/artifacts/abstract_ica_client.wasm differ diff --git a/framework/artifacts/abstract_module_factory.wasm b/framework/artifacts/abstract_module_factory.wasm index ca9feb6a97..228b769830 100644 Binary files a/framework/artifacts/abstract_module_factory.wasm and b/framework/artifacts/abstract_module_factory.wasm differ diff --git a/framework/artifacts/abstract_registry.wasm b/framework/artifacts/abstract_registry.wasm index c0143de1ce..c4b985ccfc 100644 Binary files a/framework/artifacts/abstract_registry.wasm and b/framework/artifacts/abstract_registry.wasm differ diff --git a/framework/artifacts/checksums.txt b/framework/artifacts/checksums.txt index e6fe8a02c9..7b56b7da7c 100644 --- a/framework/artifacts/checksums.txt +++ b/framework/artifacts/checksums.txt @@ -1,8 +1,8 @@ -04f4407f6bcd706a28327afb3bf5b2f16a18d75d0adc376ef44f8a4768d41877 abstract_account-xion.wasm -55124e42532e6cbfa306a8d85d3c8a634ec92d2803fe4dfeb8ed7918cd7e0e0c abstract_account.wasm -5f94f255722d33689eeb631bc796fbc1598985f8922d1987573644525dab4a1c abstract_ans_host.wasm -5e920677063397df022ce9ca9dd5e4f799c5ab7f601b7927cef013ca6be2486e abstract_ibc_client.wasm -3a14e2a3beeecc21d830367be33406dd2b5a33ab6733302b07fed0f3046f45dd abstract_ibc_host.wasm -9fb8a8e96e94977fd0b17265f1d4276484fe728ed943e3adcf9b4eca35ebf96a abstract_ica_client.wasm -11f769be8bf52d69c4af2d0ed539747ae359586740e3d05cb4ef20b1f8589422 abstract_module_factory.wasm -dea92cb8f17c18cb3b8ab64b832951d187f7c28747727811eecd640a096d7b35 abstract_registry.wasm +29611e9e921466d6b5848019abb4a27d7a2b385d02997bd8dd3ded25133b6570 abstract_account-xion.wasm +73a9ee61aa92f9203a513e9657d106ecfa8e01d93454126b0144d336294da8e3 abstract_account.wasm +c406ce2d7bc972ea6c320a9a366cf0d3717add9a7ffe63128c17be95a2e76f53 abstract_ans_host.wasm +2b22bd8dfa7529682e66a9304c241c15ff94cb1f83e3ce86ab39401eef3f7e69 abstract_ibc_client.wasm +582f99ce30af486b5b8891e402715947e9d1ef42981dee6ce742ef5e19d7691e abstract_ibc_host.wasm +2154914284863ad50c710dde01c754fb7bd713e203585c5115175161a6f1be5e abstract_ica_client.wasm +1348f236fd26251ddeef941d3c03a9b7fcb323e608b680ef2581734105bd7f29 abstract_module_factory.wasm +97ec7bfd1f89693c1826689153fb7661512e577be2dde6c4dbda38731197a136 abstract_registry.wasm diff --git a/framework/contracts/account/src/execution.rs b/framework/contracts/account/src/execution.rs index 7f3c1cdc9e..17ba838670 100644 --- a/framework/contracts/account/src/execution.rs +++ b/framework/contracts/account/src/execution.rs @@ -340,6 +340,7 @@ mod test { exec_msg: to_json_binary(&abstract_std::ibc_client::ExecuteMsg::SendFunds { host_chain: "juno".parse()?, memo: None, + receiver: None, })?, funds: funds.clone(), }; @@ -386,6 +387,7 @@ mod test { msg: to_json_binary(&abstract_std::ibc_client::ExecuteMsg::SendFunds { host_chain: "juno".parse()?, memo: None, + receiver: None, })?, funds, },)) diff --git a/framework/contracts/native/ibc-client/src/commands.rs b/framework/contracts/native/ibc-client/src/commands.rs index cc29283f59..1c58f0a815 100644 --- a/framework/contracts/native/ibc-client/src/commands.rs +++ b/framework/contracts/native/ibc-client/src/commands.rs @@ -371,6 +371,7 @@ pub fn execute_send_funds( info: MessageInfo, host_chain: TruncatedChainId, memo: Option, + receiver: Option, ) -> IbcClientResult { host_chain.verify()?; @@ -380,13 +381,18 @@ pub fn execute_send_funds( let account = registry.assert_account(&info.sender, &deps.querier)?; - // get account_id of Account - let account_id = account.account_id(deps.as_ref())?; - // load remote account - let remote_addr = ACCOUNTS.load( - deps.storage, - (account_id.trace(), account_id.seq(), &host_chain), - )?; + let remote_addr = match receiver { + Some(addr) => addr, + None => { + // get account_id of Account + let account_id = account.account_id(deps.as_ref())?; + // load remote account + ACCOUNTS.load( + deps.storage, + (account_id.trace(), account_id.seq(), &host_chain), + )? + } + }; let ics20_channel_entry = ChannelEntry { connected_chain: host_chain, diff --git a/framework/contracts/native/ibc-client/src/contract.rs b/framework/contracts/native/ibc-client/src/contract.rs index 56b8ff7db0..a262c4d315 100644 --- a/framework/contracts/native/ibc-client/src/contract.rs +++ b/framework/contracts/native/ibc-client/src/contract.rs @@ -49,9 +49,12 @@ pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> I ExecuteMsg::RegisterInfrastructure { chain, note, host } => { commands::execute_register_infrastructure(deps, env, info, chain, host, note) } - ExecuteMsg::SendFunds { host_chain, memo } => { - commands::execute_send_funds(deps, env, info, host_chain, memo).map_err(Into::into) - } + ExecuteMsg::SendFunds { + host_chain, + receiver, + memo, + } => commands::execute_send_funds(deps, env, info, host_chain, memo, receiver) + .map_err(Into::into), ExecuteMsg::Register { host_chain, namespace, @@ -637,6 +640,7 @@ mod tests { let msg = ExecuteMsg::SendFunds { host_chain: chain_name, + receiver: None, memo: None, }; @@ -678,6 +682,7 @@ mod tests { let msg = ExecuteMsg::SendFunds { host_chain: chain_name.clone(), + receiver: None, memo: None, }; @@ -711,6 +716,7 @@ mod tests { let msg = ExecuteMsg::SendFunds { host_chain: chain_name, + receiver: None, memo: memo.clone(), }; diff --git a/framework/contracts/native/module-factory/Cargo.toml b/framework/contracts/native/module-factory/Cargo.toml index c5db87487c..262d6627b7 100644 --- a/framework/contracts/native/module-factory/Cargo.toml +++ b/framework/contracts/native/module-factory/Cargo.toml @@ -35,7 +35,7 @@ abstract-std = { workspace = true } abstract-macros = { workspace = true } cw-asset = { workspace = true } cw-ownable = { workspace = true } -serde-cw-value = "0.7.0" +serde-cw-value = { workspace = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] workspace-hack = { version = "0.1", path = "../../../workspace-hack" } diff --git a/framework/docs/src/releases/CHANGELOG.md b/framework/docs/src/releases/CHANGELOG.md index 95ade05646..cf742ec451 100644 --- a/framework/docs/src/releases/CHANGELOG.md +++ b/framework/docs/src/releases/CHANGELOG.md @@ -4,7 +4,8 @@ ### Added -- Abstract Account authentication when building account with `xion` feature. +- Added `PfmMemoBuilder` API for building middleware forwarding memo +- Added `HookMemoBuilder` API for building wasm ibc hook memo - `execute_with_funds` to Executor to attach funds to execution. - `stargate` feature for abstract-app, abstract-standalone and abstract-adapter packages. - New module type: `Service`, behaves the same as Native, but can be registered by any namespace. diff --git a/framework/packages/abstract-client/src/interchain/remote_account.rs b/framework/packages/abstract-client/src/interchain/remote_account.rs index 8d1e09c022..b9a8283936 100644 --- a/framework/packages/abstract-client/src/interchain/remote_account.rs +++ b/framework/packages/abstract-client/src/interchain/remote_account.rs @@ -429,6 +429,7 @@ impl> RemoteAccount AnyResult<()> { + dotenv::dotenv().ok(); + set_starship_env(); + env_logger::init(); + + let starship = Starship::new(None).unwrap(); + let interchain = starship.interchain_env(); + + let juno = interchain.get_chain(JUNO).unwrap(); + let juno2 = interchain.get_chain(JUNO2).unwrap(); + + // Create a channel between the 2 chains for the transfer ports + // JUNO>JUNO2 + let juno_juno2_channel = interchain + .create_channel( + JUNO, + JUNO2, + &PortId::transfer(), + &PortId::transfer(), + "ics20-1", + Some(cosmwasm_std::IbcOrder::Unordered), + )? + .interchain_channel; + + let abstr_juno = Abstract::deploy_on(juno.clone(), juno.sender_addr().to_string())?; + let abstr_juno2 = Abstract::deploy_on(juno2.clone(), juno2.sender_addr().to_string())?; + connect_one_way_to(&abstr_juno, &abstr_juno2, &interchain)?; + + // Faster to load if deployed + // let abstr_juno = Abstract::load_from(juno.clone())?; + // let abstr_juno2 = Abstract::load_from(juno2.clone())?; + + let counter_juno2 = init_counter(juno2.clone())?; + + let sender = juno.sender_addr().to_string(); + + let test_amount: u128 = 100_000_000_000; + let token_subdenom = format!( + "testtoken{}", + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs() + ); + + // Create Denom + create_denom(&juno, token_subdenom.as_str())?; + + // Mint Denom + mint(&juno, sender.as_str(), token_subdenom.as_str(), test_amount)?; + + // Register this channel with the abstract ibc implementation for sending tokens + abstr_juno.ans_host.update_channels( + vec![( + UncheckedChannelEntry { + connected_chain: TruncatedChainId::from_chain_id(JUNO2).to_string(), + protocol: ICS20.to_string(), + }, + juno_juno2_channel + .get_chain(JUNO)? + .channel + .unwrap() + .to_string(), + )], + vec![], + )?; + + // Create a test account + Remote account + + let origin_account = abstr_juno.account_factory.create_default_account( + abstract_client::GovernanceDetails::Monarchy { + monarch: juno.sender_addr().to_string(), + }, + )?; + origin_account.manager.set_ibc_status(true)?; + + // Send funds to the remote account + RUNTIME.block_on(juno.sender().bank_send( + &origin_account.proxy.address()?, + vec![coin(test_amount, get_denom(&juno, token_subdenom.as_str()))], + ))?; + + let memo = HookMemoBuilder::new( + counter_juno2.address()?, + &counter_contract::msg::ExecuteMsg::Increment {}, + ) + .build()?; + // We send from osmosis to juno funds with pfm memo that includes juno-stargaze channel + origin_account.manager.execute_on_module( + PROXY, + abstract_std::proxy::ExecuteMsg::IbcAction { + msg: abstract_std::ibc_client::ExecuteMsg::SendFunds { + host_chain: TruncatedChainId::from_chain_id(JUNO2), + funds: coins(10_000_000_000, get_denom(&juno, token_subdenom.as_str())), + memo: Some(memo.clone()), + receiver: Some(counter_juno2.addr_str()?), + }, + }, + )?; + origin_account.manager.execute_on_module( + PROXY, + abstract_std::proxy::ExecuteMsg::IbcAction { + msg: abstract_std::ibc_client::ExecuteMsg::SendFunds { + host_chain: TruncatedChainId::from_chain_id(JUNO2), + funds: coins(10_000_000_000, get_denom(&juno, token_subdenom.as_str())), + memo: Some(memo.clone()), + receiver: Some(counter_juno2.addr_str()?), + }, + }, + )?; + origin_account.manager.execute_on_module( + PROXY, + abstract_std::proxy::ExecuteMsg::IbcAction { + msg: abstract_std::ibc_client::ExecuteMsg::SendFunds { + host_chain: TruncatedChainId::from_chain_id(JUNO2), + funds: coins(10_000_000_000, get_denom(&juno, token_subdenom.as_str())), + memo: Some(memo), + receiver: Some(counter_juno2.addr_str()?), + }, + }, + )?; + log::info!("waiting for ibc_hook to finish tx"); + std::thread::sleep(Duration::from_secs(15)); + + let count_juno2 = counter_juno2.query(&counter_contract::msg::QueryMsg::GetCount {})?; + log::info!("count juno2: {count_juno2:?}"); + + // Verify the funds have been received + let count_juno2_balance = juno2 + .bank_querier() + .balance(&counter_juno2.address()?, None)?; + + log::info!("count_juno2 balance, {:?}", count_juno2_balance); + Ok(()) +} + +pub fn init_counter(chain: Chain) -> anyhow::Result> { + let counter = CounterContract::new(chain); + counter.upload()?; + counter.instantiate( + &counter_contract::msg::InstantiateMsg { count: 0 }, + None, + &[], + )?; + Ok(counter) +} + +pub fn main() { + test_pfm().unwrap(); +} diff --git a/framework/packages/abstract-interface/tests/interchain_integration/bin/pfm.rs b/framework/packages/abstract-interface/tests/interchain_integration/bin/pfm.rs new file mode 100644 index 0000000000..012c349218 --- /dev/null +++ b/framework/packages/abstract-interface/tests/interchain_integration/bin/pfm.rs @@ -0,0 +1,174 @@ +// This script is used for testing a connection between 2 chains +// This script sets up tokens and channels between transfer ports to transfer those tokens +// This also mints tokens to the chain sender for future interactions + +use std::time::{Duration, SystemTime, UNIX_EPOCH}; + +use abstract_interchain_tests::{ + interchain_accounts::create_test_remote_account, setup::set_starship_env, JUNO, +}; +use abstract_interface::{ + connection::connect_one_way_to, Abstract, AbstractAccount, ProxyQueryFns, +}; +use abstract_sdk::PfmMemoBuilder; +use abstract_std::{ + ans_host::ExecuteMsgFns, + objects::{TruncatedChainId, UncheckedChannelEntry}, + ICS20, PROXY, +}; +use anyhow::Result as AnyResult; +use cosmwasm_std::{coin, coins}; +use cw_orch::{daemon::RUNTIME, prelude::*}; +use cw_orch_interchain::prelude::*; +use cw_orch_proto::tokenfactory::{create_denom, get_denom, mint}; + +// Note: Truncated chain id have to be different +pub const JUNO2: &str = "junotwo-1"; +pub const JUNO3: &str = "junothree-1"; +pub const JUNO4: &str = "junofour-1"; + +pub fn test_pfm() -> AnyResult<()> { + dotenv::dotenv().ok(); + set_starship_env(); + env_logger::init(); + + let starship = Starship::new(None).unwrap(); + let interchain = starship.interchain_env(); + + let juno = interchain.get_chain(JUNO).unwrap(); + let juno2 = interchain.get_chain(JUNO2).unwrap(); + let juno4 = interchain.get_chain(JUNO4).unwrap(); + + // Create a channel between the 4 chains for the transfer ports + // JUNO>JUNO2>JUNO3>JUNO4 + let juno_juno2_channel = interchain + .create_channel( + JUNO, + JUNO2, + &PortId::transfer(), + &PortId::transfer(), + "ics20-1", + Some(cosmwasm_std::IbcOrder::Unordered), + )? + .interchain_channel; + + let juno2_juno3_channel = interchain + .create_channel( + JUNO2, + JUNO3, + &PortId::transfer(), + &PortId::transfer(), + "ics20-1", + Some(cosmwasm_std::IbcOrder::Unordered), + )? + .interchain_channel; + + let juno3_juno4_channel = interchain + .create_channel( + JUNO3, + JUNO4, + &PortId::transfer(), + &PortId::transfer(), + "ics20-1", + Some(cosmwasm_std::IbcOrder::Unordered), + )? + .interchain_channel; + + let abstr_juno = Abstract::deploy_on(juno.clone(), juno.sender_addr().to_string())?; + let abstr_juno2 = Abstract::deploy_on(juno2.clone(), juno2.sender_addr().to_string())?; + connect_one_way_to(&abstr_juno, &abstr_juno2, &interchain)?; + + // Faster to load if deployed + // let abstr_juno = Abstract::load_from(juno.clone())?; + // let abstr_juno2 = Abstract::load_from(juno2.clone())?; + + let sender = juno.sender_addr().to_string(); + + let test_amount: u128 = 100_000_000_000; + let token_subdenom = format!( + "testtoken{}", + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs() + ); + + // Create Denom + create_denom(&juno, token_subdenom.as_str())?; + + // Mint Denom + mint(&juno, sender.as_str(), token_subdenom.as_str(), test_amount)?; + + // Register this channel with the abstract ibc implementation for sending tokens + abstr_juno.ans_host.update_channels( + vec![( + UncheckedChannelEntry { + connected_chain: "junotwo".to_string(), + protocol: ICS20.to_string(), + }, + juno_juno2_channel + .get_chain(JUNO)? + .channel + .unwrap() + .to_string(), + )], + vec![], + )?; + + // Create a test account + Remote account + + let (origin_account, remote_account_id) = + create_test_remote_account(&abstr_juno, JUNO, JUNO2, &interchain, vec![])?; + + // Get the ibc client address + let remote_account = AbstractAccount::new(&abstr_juno2, remote_account_id.clone()); + let client = remote_account.proxy.config()?; + + log::info!("client adddress {:?}", client); + + // Send funds to the remote account + RUNTIME.block_on(juno.sender().bank_send( + &origin_account.proxy.address()?, + vec![coin(test_amount, get_denom(&juno, token_subdenom.as_str()))], + ))?; + let juno2_juno3_channel_port_juno2 = juno2_juno3_channel + .get_chain(JUNO2) + .unwrap() + .channel + .unwrap() + .to_string(); + let juno3_juno4_channel_port_juno3 = juno3_juno4_channel + .get_chain(JUNO3) + .unwrap() + .channel + .unwrap() + .to_string(); + + let memo = PfmMemoBuilder::new(juno2_juno3_channel_port_juno2) + .hop(juno3_juno4_channel_port_juno3) + .build(juno4.sender_addr())?; + origin_account.manager.execute_on_module( + PROXY, + abstract_std::proxy::ExecuteMsg::IbcAction { + msg: abstract_std::ibc_client::ExecuteMsg::SendFunds { + host_chain: TruncatedChainId::from_chain_id(JUNO2), + funds: coins(100_000_000_000, get_denom(&juno, token_subdenom.as_str())), + memo: Some(memo), + receiver: None, + }, + }, + )?; + log::info!("waiting for pfm bank send to finish"); + std::thread::sleep(Duration::from_secs(15)); + + // Verify the funds have been received + let balance = juno4.bank_querier().balance(&juno4.sender_addr(), None)?; + + log::info!("juno4 balance, {:?}", balance); + + Ok(()) +} + +pub fn main() { + test_pfm().unwrap(); +} diff --git a/framework/packages/abstract-interface/tests/interchain_integration/interchain_accounts.rs b/framework/packages/abstract-interface/tests/interchain_integration/interchain_accounts.rs index fbf821db6d..3a9aa7ddca 100644 --- a/framework/packages/abstract-interface/tests/interchain_integration/interchain_accounts.rs +++ b/framework/packages/abstract-interface/tests/interchain_integration/interchain_accounts.rs @@ -723,7 +723,9 @@ mod test { exec_msg: to_json_binary(&abstract_std::ibc_client::ExecuteMsg::SendFunds { host_chain: TruncatedChainId::from_chain_id(STARGAZE), memo: None, - })?, + receiver: None, + }) + .unwrap(), funds: coins(10, origin_denom), }, &[], diff --git a/framework/packages/abstract-sdk/Cargo.toml b/framework/packages/abstract-sdk/Cargo.toml index 096d418c8e..c5d25a0d78 100644 --- a/framework/packages/abstract-sdk/Cargo.toml +++ b/framework/packages/abstract-sdk/Cargo.toml @@ -39,6 +39,7 @@ abstract-std = { workspace = true } semver = { workspace = true } abstract-macros = { workspace = true } cw-clearable = { workspace = true } +serde-cw-value = { workspace = true } # test-utils feature abstract-testing = { workspace = true, optional = true } @@ -54,5 +55,6 @@ doc-comment = "0.3.3" # Set our own feature when running tests! abstract-sdk = { path = ".", features = ["test-utils"] } cw-ownable = { workspace = true } +serde_json = "1.0.79" coverage-helper = { workspace = true } diff --git a/framework/packages/abstract-sdk/src/apis.rs b/framework/packages/abstract-sdk/src/apis.rs index c19d0de4ab..a4d4d3d62f 100644 --- a/framework/packages/abstract-sdk/src/apis.rs +++ b/framework/packages/abstract-sdk/src/apis.rs @@ -5,6 +5,7 @@ pub mod app; pub mod bank; pub mod execution; pub mod ibc; +pub mod ibc_memo; pub mod modules; pub mod respond; mod splitter; diff --git a/framework/packages/abstract-sdk/src/apis/ibc.rs b/framework/packages/abstract-sdk/src/apis/ibc.rs index 0256dde691..5a8afff2c9 100644 --- a/framework/packages/abstract-sdk/src/apis/ibc.rs +++ b/framework/packages/abstract-sdk/src/apis/ibc.rs @@ -262,8 +262,16 @@ impl<'a, T: IbcInterface + AccountExecutor> IbcClient<'a, T> { host_chain: TruncatedChainId, funds: Vec, memo: Option, + receiver: Option, ) -> AbstractSdkResult { - self.execute(&IbcClientMsg::SendFunds { host_chain, memo }, funds) + self.execute( + &IbcClientMsg::SendFunds { + host_chain, + memo, + receiver, + }, + funds, + ) } /// A simple helper to install an app on an account @@ -408,6 +416,7 @@ mod test { TEST_HOST_CHAIN.parse().unwrap(), expected_funds.clone(), None, + None, ); assert!(msg.is_ok()); @@ -419,6 +428,7 @@ mod test { exec_msg: to_json_binary(&IbcClientMsg::SendFunds { host_chain: TEST_HOST_CHAIN.parse().unwrap(), memo: None, + receiver: None, }) .unwrap(), funds: expected_funds, diff --git a/framework/packages/abstract-sdk/src/apis/ibc_memo.rs b/framework/packages/abstract-sdk/src/apis/ibc_memo.rs new file mode 100644 index 0000000000..2c5eb8e5cd --- /dev/null +++ b/framework/packages/abstract-sdk/src/apis/ibc_memo.rs @@ -0,0 +1,114 @@ +mod hooks; +mod pfm; + +pub use hooks::HookMemoBuilder; +pub use pfm::PfmMemoBuilder; + +#[cfg(test)] +mod test { + use super::*; + use cosmwasm_std::Addr; + use serde_json::json; + + #[test] + fn memo_middleware() { + let minimal = PfmMemoBuilder::new("channel-1").build("foo").unwrap(); + let value: serde_json::Value = serde_json::from_str(&minimal).unwrap(); + let expected_value = json!({ + "forward": { + "channel": "channel-1", + "port": "transfer", + "receiver": "foo", + } + }); + assert_eq!(value, expected_value); + + let complete = PfmMemoBuilder::new("channel-1") + .port("different_port") + .timeout("10m") + .retries(4) + .hop("channel-2") + .build("foo") + .unwrap(); + let value: serde_json::Value = serde_json::from_str(&complete).unwrap(); + let expected_value = json!({ + "forward": { + "channel": "channel-1", + "port": "different_port", + "receiver": "pfm", + "timeout": "10m", + "retries": 4, + "next": { + "forward": { + "channel": "channel-2", + "port": "different_port", + "receiver": "foo", + } + } + } + }); + assert_eq!(value, expected_value); + + let multimultihop = PfmMemoBuilder::new("channel-1") + .hop("channel-2") + .hop("channel-3") + .build("receiver") + .unwrap(); + let value: serde_json::Value = serde_json::from_str(&multimultihop).unwrap(); + let expected_value = json!({ + "forward": { + "channel": "channel-1", + "port": "transfer", + "receiver": "pfm", + "next": { + "forward": { + "channel": "channel-2", + "port": "transfer", + "receiver": "pfm", + "next": { + "forward": { + "channel": "channel-3", + "port": "transfer", + "receiver": "receiver", + } + } + } + } + } + }); + assert_eq!(value, expected_value); + } + + #[test] + fn memo_wasm_hook() { + let msg = json!({ + "withdraw": {} + }); + + let minimal = HookMemoBuilder::new("mock_addr".to_owned(), &msg) + .build() + .unwrap(); + let value: serde_json::Value = serde_json::from_str(&minimal).unwrap(); + let expected_value = json!({ + "wasm": { + "contract": "mock_addr", + "msg": {"withdraw": {}} + } + }); + assert_eq!(value, expected_value); + + let complete = HookMemoBuilder::new("mock_addr".to_owned(), &msg) + .callback_contract(Addr::unchecked("callback_addr")) + .build() + .unwrap(); + let value: serde_json::Value = serde_json::from_str(&complete).unwrap(); + let expected_value = json!({ + "wasm": { + "contract": "mock_addr", + "msg": {"withdraw": {}}, + }, + "ibc_callback": "callback_addr" + }); + assert_eq!(value, expected_value); + } +} diff --git a/framework/packages/abstract-sdk/src/apis/ibc_memo/hooks.rs b/framework/packages/abstract-sdk/src/apis/ibc_memo/hooks.rs new file mode 100644 index 0000000000..1f26e4147c --- /dev/null +++ b/framework/packages/abstract-sdk/src/apis/ibc_memo/hooks.rs @@ -0,0 +1,57 @@ +use std::collections::BTreeMap; + +use cosmwasm_std::{from_json, to_json_binary, Addr, Binary}; +use serde_cw_value::Value; + +/// Builder for [IbcHooks](https://github.com/cosmos/ibc-apps/tree/main/modules/ibc-hooks) memo field. +pub struct HookMemoBuilder { + contract_addr: String, + msg: Binary, + ibc_callback: Option, +} + +impl HookMemoBuilder { + /// New Wasm Contract Memo IBC Hook + /// Note: contract_addr should be the same as "receiver" + pub fn new(contract_addr: impl Into, msg: &impl serde::Serialize) -> Self { + let msg = to_json_binary(&msg).unwrap(); + Self { + contract_addr: contract_addr.into(), + msg, + ibc_callback: None, + } + } + + /// Contract that will receive callback, see: + /// https://github.com/cosmos/ibc-apps/blob/main/modules/ibc-hooks/README.md#interface-for-receiving-the-acks-and-timeouts + pub fn callback_contract(mut self, callback_contract: Addr) -> Self { + self.ibc_callback = Some(callback_contract); + self + } + + /// Build memo json string + pub fn build(self) -> cosmwasm_std::StdResult { + let execute_wasm_value = BTreeMap::from([ + ( + Value::String("contract".to_owned()), + Value::String(self.contract_addr), + ), + ( + Value::String("msg".to_owned()), + from_json(&self.msg).expect("expected valid json message"), + ), + ]); + + let mut memo = BTreeMap::from([( + Value::String("wasm".to_owned()), + Value::Map(execute_wasm_value.into_iter().collect()), + )]); + if let Some(contract_addr) = self.ibc_callback { + memo.insert( + Value::String("ibc_callback".to_owned()), + Value::String(contract_addr.into_string()), + ); + } + cosmwasm_std::to_json_string(&memo) + } +} diff --git a/framework/packages/abstract-sdk/src/apis/ibc_memo/pfm.rs b/framework/packages/abstract-sdk/src/apis/ibc_memo/pfm.rs new file mode 100644 index 0000000000..2b34df8590 --- /dev/null +++ b/framework/packages/abstract-sdk/src/apis/ibc_memo/pfm.rs @@ -0,0 +1,133 @@ +use std::collections::BTreeMap; + +use serde_cw_value::Value; + +/// Builder for [Packet Forward Middleware](https://github.com/cosmos/ibc-apps/tree/main/middleware/packet-forward-middleware) memos. +pub struct PfmMemoBuilder { + port: Option, + hops: Vec, +} + +impl PfmMemoBuilder { + /// Forward memo builder + pub fn new(first_hop_channel: impl Into) -> Self { + Self { + port: None, + hops: vec![PacketForwardMiddlewareHop::new(first_hop_channel)], + } + } + + /// Port, defaults to "transfer" + pub fn port(mut self, port: impl Into) -> Self { + self.port = Some(port.into()); + self + } + + /// Channel hop + pub fn hop(mut self, channel: impl Into) -> Self { + self.hops.push(PacketForwardMiddlewareHop::new(channel)); + self + } + + /// Hop modifier (applies only on last added hop): + /// Timeout duration, for example: "10m" + pub fn timeout(mut self, timeout: impl Into) -> Self { + if let Some(last_hop) = self.hops.last_mut() { + last_hop.timeout = Some(timeout.into()); + } + self + } + + /// Hop modifier (applies only on last added hop): + /// Retries number + pub fn retries(mut self, retries: u8) -> Self { + if let Some(last_hop) = self.hops.last_mut() { + last_hop.retries = Some(retries); + } + self + } + + /// Build the memo json string + /// Receiver is an address of the packet receiver on remote chain + pub fn build(self, receiver: impl Into) -> cosmwasm_std::StdResult { + let PfmMemoBuilder { port, hops } = self; + let receiver = receiver.into(); + let port = port.unwrap_or("transfer".to_owned()); + + let mut forwards = hops + .into_iter() + .map(|hop| ForwardMemo { + receiver: None, + port: port.clone(), + channel: hop.channel, + timeout: hop.timeout, + retries: hop.retries, + }) + .collect::>(); + // Destination have to know receiver + if let Some(last_hop) = forwards.last_mut() { + last_hop.receiver = Some(receiver); + } + + // Building message from behind because it's easier to satisfy borrow checker this way + let mut head = BTreeMap::new(); + for forward in forwards.into_iter().rev() { + let mut forward_msg = forward.build_value_map(); + if !head.is_empty() { + let next = head; + forward_msg.insert(Value::String("next".to_owned()), Value::Map(next)); + } + head = BTreeMap::from([(Value::String("forward".to_owned()), Value::Map(forward_msg))]); + } + cosmwasm_std::to_json_string(&head) + } +} + +struct PacketForwardMiddlewareHop { + channel: String, + timeout: Option, + retries: Option, +} + +impl PacketForwardMiddlewareHop { + pub fn new(channel: impl Into) -> Self { + Self { + channel: channel.into(), + timeout: None, + retries: None, + } + } +} + +// Forward structure +struct ForwardMemo { + receiver: Option, + port: String, + channel: String, + timeout: Option, + retries: Option, +} + +impl ForwardMemo { + fn build_value_map(self) -> BTreeMap { + let receiver = self.receiver.unwrap_or("pfm".to_owned()); + let mut forward_value = BTreeMap::from([ + ( + Value::String("receiver".to_owned()), + Value::String(receiver), + ), + (Value::String("port".to_owned()), Value::String(self.port)), + ( + Value::String("channel".to_owned()), + Value::String(self.channel), + ), + ]); + if let Some(timeout) = self.timeout { + forward_value.insert(Value::String("timeout".to_owned()), Value::String(timeout)); + } + if let Some(retries) = self.retries { + forward_value.insert(Value::String("retries".to_owned()), Value::U8(retries)); + } + forward_value + } +} diff --git a/framework/packages/abstract-sdk/src/lib.rs b/framework/packages/abstract-sdk/src/lib.rs index f4cfb73e9a..01a9f73e9e 100644 --- a/framework/packages/abstract-sdk/src/lib.rs +++ b/framework/packages/abstract-sdk/src/lib.rs @@ -27,8 +27,8 @@ pub use error::{AbstractSdkError, EndpointError}; pub use crate::apis::{authz::*, distribution::*, feegrant::*}; pub use crate::{ apis::{ - adapter::*, app::*, bank::*, execution::*, ibc::*, modules::*, respond::*, verify::*, - version_registry::*, + adapter::*, app::*, bank::*, execution::*, ibc::*, ibc_memo::*, modules::*, respond::*, + verify::*, version_registry::*, }, features::AbstractNameServiceClient, }; diff --git a/framework/packages/abstract-std/src/native/ibc/ibc_client.rs b/framework/packages/abstract-std/src/native/ibc/ibc_client.rs index 9b90a55ba2..8b18b5e679 100644 --- a/framework/packages/abstract-std/src/native/ibc/ibc_client.rs +++ b/framework/packages/abstract-std/src/native/ibc/ibc_client.rs @@ -87,6 +87,9 @@ pub enum ExecuteMsg { /// host chain to be executed on /// Example: "osmosis" host_chain: TruncatedChainId, + /// Address of the token receiver on host chain + /// Defaults to address of the remote account + receiver: Option, memo: Option, }, /// Only callable by Account diff --git a/interchain/Cargo.toml b/interchain/Cargo.toml index b079c0e0c0..91518d1fab 100644 --- a/interchain/Cargo.toml +++ b/interchain/Cargo.toml @@ -108,6 +108,11 @@ abstract-polytone-note = { git = "https://github.com/AbstractSDK/polytone.git", abstract-cw-orch-polytone = { git = "https://github.com/AbstractSDK/polytone.git", branch = "bump/cw2" } # Backup release profile, will result in warnings during optimization + +[patch.'https://github.com/AbstractSDK/cw-orchestrator'] +cw-orch = { version = "0.26.0" } +cw-orch-interchain = { version = "=0.7.2" } + [profile.release] rpath = false lto = true diff --git a/interchain/four-chain-starship/Makefile b/interchain/four-chain-starship/Makefile new file mode 100644 index 0000000000..8d60c0cf33 --- /dev/null +++ b/interchain/four-chain-starship/Makefile @@ -0,0 +1,78 @@ +NAME = tutorial +FILE = ./configs/four-junos.yaml +TINY_FILE = ./configs/two-junos.yaml + +HELM_REPO = starship +HELM_CHART = devnet +HELM_VERSION = 0.2.3 + +############################################################################### +### All commands ### +############################################################################### + +.PHONY: setup +setup: setup-deps setup-helm setup-kind + +.PHONY: stop +stop: stop-forward delete + +.PHONY: clean +clean: stop clean-kind + +############################################################################### +### Dependency check ### +############################################################################### + +.PHONY: setup-deps +setup-deps: + npm install -g @starship-ci/cli + starship install + +############################################################################### +### Helm Charts ### +############################################################################### + +setup-helm: + starship setup + +install: + starship start --config $(FILE) + +install-two: + $(MAKE) install FILE=$(TINY_FILE) + +delete: + starship stop + +############################################################################### +### Port forward ### +############################################################################### + +.PHONY: port-forward +port-forward: + bash $(CURDIR)/port-forward.sh --config=$(FILE) + +.PHONY: port-forward-two +port-forward-two: + bash $(CURDIR)/port-forward.sh --config=$(TINY_FILE) + +.PHONY: stop-forward +stop-forward: + -pkill -f "port-forward" + +############################################################################### +### Local Kind Setup ### +############################################################################### +KIND_CLUSTER=starship + +.PHONY: setup-kind +setup-kind: + kind create cluster --name $(KIND_CLUSTER) + +.PHONY: watch-pods +watch-pods: + watch kubectl get pods + +.PHONY: clean-kind +clean-kind: + kind delete cluster --name $(KIND_CLUSTER) diff --git a/interchain/four-chain-starship/configs/four-junos.yaml b/interchain/four-chain-starship/configs/four-junos.yaml new file mode 100644 index 0000000000..33b017d86a --- /dev/null +++ b/interchain/four-chain-starship/configs/four-junos.yaml @@ -0,0 +1,67 @@ +chains: + - id: juno-1 + name: juno + numValidators: 1 + ports: + rest: 1313 + rpc: 26653 + grpc: 30658 + faucet: 8000 + - id: junotwo-1 + name: osmosis # Could be juno, but had problems on this spot and it was getting hard to debug with same addresses + numValidators: 1 + ports: + rest: 1317 + rpc: 26659 + grpc: 30660 + faucet: 8004 + - id: junothree-1 + name: juno + numValidators: 1 + ports: + rest: 1323 + rpc: 26657 + grpc: 30657 + faucet: 8001 + - id: junofour-1 + name: juno + numValidators: 1 + ports: + rest: 1328 + rpc: 26658 + grpc: 30659 + faucet: 8003 + +relayers: + - name: juno-juno2 + type: hermes + replicas: 1 + chains: + - juno-1 + - junotwo-1 + config: + event_source: + mode: "pull" # default is "push" + - name: juno2-juno3 + type: hermes + replicas: 1 + chains: + - junotwo-1 + - junothree-1 + config: + event_source: + mode: "pull" + - name: juno3-juno4 + type: hermes + replicas: 1 + chains: + - junothree-1 + - junofour-1 + config: + event_source: + mode: "pull" + +registry: + enabled: true + ports: + rest: 8081 diff --git a/interchain/four-chain-starship/configs/two-junos.yaml b/interchain/four-chain-starship/configs/two-junos.yaml new file mode 100644 index 0000000000..d2c5744ade --- /dev/null +++ b/interchain/four-chain-starship/configs/two-junos.yaml @@ -0,0 +1,33 @@ +chains: + - id: juno-1 + name: juno + numValidators: 1 + ports: + rest: 1313 + rpc: 26653 + grpc: 30658 + faucet: 8000 + - id: junotwo-1 + name: osmosis + numValidators: 1 + ports: + rest: 1317 + rpc: 26659 + grpc: 30660 + faucet: 8004 + +relayers: + - name: juno-juno2 + type: hermes + replicas: 1 + chains: + - juno-1 + - junotwo-1 + config: + event_source: + mode: "pull" # default is "push" + +registry: + enabled: true + ports: + rest: 8081 diff --git a/interchain/four-chain-starship/port-forward.sh b/interchain/four-chain-starship/port-forward.sh new file mode 100755 index 0000000000..8e1ef469c1 --- /dev/null +++ b/interchain/four-chain-starship/port-forward.sh @@ -0,0 +1,131 @@ +#!/bin/bash + +set -euo pipefail + +function color() { + local color=$1 + shift + local black=30 red=31 green=32 yellow=33 blue=34 magenta=35 cyan=36 white=37 + local color_code=${!color:-$green} + printf "\033[%sm%s\033[0m\n" "$color_code" "$*" +} + +function stop_port_forward() { + color green "Trying to stop all port-forward, if any...." + PIDS=$(ps -ef | grep -i -e 'kubectl port-forward' | grep -v 'grep' | cat | awk '{print $2}') || true + for p in $PIDS; do + kill -15 $p + done + sleep 2 +} + +# Default values +CHAIN_RPC_PORT=26657 +CHAIN_COMETMOCK_PORT=22331 +CHAIN_GRPC_PORT=9090 +CHAIN_LCD_PORT=1317 +CHAIN_EXPOSER_PORT=8081 +CHAIN_FAUCET_PORT=8000 +RELAYER_REST_PORT=3000 +RELAYER_EXPOSER_PORT=8081 +EXPLORER_LCD_PORT=8080 +REGISTRY_LCD_PORT=8080 +REGISTRY_GRPC_PORT=9090 +MONITORING_PROMETHEUS_PORT=8080 +MONITORING_GRAFANA_PORT=8080 + +for i in "$@"; do + case $i in + -c=*|--config=*) + CONFIGFILE="${i#*=}" + shift # past argument=value + ;; + -*|--*) + echo "Unknown option $i" + exit 1 + ;; + *) + ;; + esac +done + +stop_port_forward + +echo "Port forwarding for config ${CONFIGFILE}" +echo "Port forwarding all chains" +num_chains=$(yq -r ".chains | length - 1" ${CONFIGFILE}) +if [[ $num_chains -gt -1 ]]; then + for i in $(seq 0 $num_chains); do + # derive chain pod name from chain id + # https://github.com/cosmology-tech/starship/blob/main/charts/devnet/templates/_helpers.tpl#L56 + chain=$(yq -r ".chains[$i].id" ${CONFIGFILE} ) + chain=${chain/_/"-"} + localrpc=$(yq -r ".chains[$i].ports.rpc" ${CONFIGFILE} ) + localgrpc=$(yq -r ".chains[$i].ports.grpc" ${CONFIGFILE} ) + locallcd=$(yq -r ".chains[$i].ports.rest" ${CONFIGFILE} ) + localexp=$(yq -r ".chains[$i].ports.exposer" ${CONFIGFILE}) + localfaucet=$(yq -r ".chains[$i].ports.faucet" ${CONFIGFILE}) + color yellow "chains: forwarded $chain" + if [[ $(yq -r ".chains[$i].cometmock.enabled" $CONFIGFILE) == "true" ]]; + then + [[ "$localrpc" != "null" ]] && color yellow " cometmock rpc to http://localhost:$localrpc" && kubectl port-forward pods/$chain-cometmock-0 $localrpc:$CHAIN_COMETMOCK_PORT > /dev/null 2>&1 & + else + [[ "$localrpc" != "null" ]] && color yellow " rpc to http://localhost:$localrpc" && kubectl port-forward pods/$chain-genesis-0 $localrpc:$CHAIN_RPC_PORT > /dev/null 2>&1 & + fi + [[ "$localgrpc" != "null" ]] && color yellow " grpc to http://localhost:$localgrpc" && kubectl port-forward pods/$chain-genesis-0 $localgrpc:$CHAIN_GRPC_PORT > /dev/null 2>&1 & + [[ "$locallcd" != "null" ]] && color yellow " lcd to http://localhost:$locallcd" && kubectl port-forward pods/$chain-genesis-0 $locallcd:$CHAIN_LCD_PORT > /dev/null 2>&1 & + [[ "$localexp" != "null" ]] && color yellow " exposer to http://localhost:$localexp" && kubectl port-forward pods/$chain-genesis-0 $localexp:$CHAIN_EXPOSER_PORT > /dev/null 2>&1 & + [[ "$localfaucet" != "null" ]] && color yellow " faucet to http://localhost:$localfaucet" && kubectl port-forward pods/$chain-genesis-0 $localfaucet:$CHAIN_FAUCET_PORT > /dev/null 2>&1 & + sleep 1 + done +else + echo "No chains to port-forward: num: $num_chains" +fi + + +echo "Port forward relayers" +num_relayers=$(yq -r ".relayers | length - 1" ${CONFIGFILE}) +if [[ $num_relayers -gt -1 ]]; then + for i in $(seq 0 $num_relayers); do + # derive chain pod name from chain id + # https://github.com/cosmology-tech/starship/blob/main/charts/devnet/templates/_helpers.tpl#L56 + relayer=$(yq -r ".relayers[$i].name" ${CONFIGFILE} ) + relayer=$(yq -r ".relayers[$i].type" ${CONFIGFILE} )-${relayer/_/"-"} + localrest=$(yq -r ".relayers[$i].ports.rest" ${CONFIGFILE} ) + localexposer=$(yq -r ".relayers[$i].ports.exposer" ${CONFIGFILE} ) + color yellow "relayers: forwarded $relayer" + [[ "$localrest" != "null" ]] && color yellow " rpc to http://localhost:$localrest" && kubectl port-forward pods/$relayer-0 $localrest:$RELAYER_REST_PORT > /dev/null 2>&1 & + [[ "$localexposer" != "null" ]] && color yellow " rpc to http://localhost:$localexposer" && kubectl port-forward pods/$relayer-0 $localexposer:$RELAYER_EXPOSER_PORT > /dev/null 2>&1 & + sleep 1 + done +else + echo "No relayer to port-forward: num: $num_relayers" +fi + + +echo "Port forward services" + +if [[ $(yq -r ".registry.enabled" $CONFIGFILE) == "true" ]]; +then + kubectl port-forward service/registry 8081:$REGISTRY_LCD_PORT > /dev/null 2>&1 & + kubectl port-forward service/registry 9091:$REGISTRY_GRPC_PORT > /dev/null 2>&1 & + sleep 1 + color yellow "registry: forwarded registry lcd to grpc http://localhost:8081, to http://localhost:9091" +fi + +if [[ $(yq -r ".explorer.enabled" $CONFIGFILE) == "true" ]]; +then + kubectl port-forward service/explorer 8080:$EXPLORER_LCD_PORT > /dev/null 2>&1 & + sleep 1 + color green "Open the explorer to get started.... http://localhost:8080" +fi + +if [[ $(yq -r ".monitoring.enabled" $CONFIGFILE) == "true" ]]; +then + color yellow "monitoring port forward:" + localgrafana=$(yq -r ".monitoring.ports.grafana" ${CONFIGFILE}) + localprometheus=$(yq -r ".monitoring.ports.prometheus" ${CONFIGFILE}) + [[ "$localgrafana" != "null" ]] && color yellow " grafana to http://localhost:$localgrafana" && kubectl port-forward service/grafana $localgrafana:$MONITORING_GRAFANA_PORT > /dev/null 2>&1 & + [[ "$localprometheus" != "null" ]] && color yellow " prometheus to http://localhost:$localprometheus" && kubectl port-forward service/prometheus-service $localprometheus:$MONITORING_PROMETHEUS_PORT > /dev/null 2>&1 & + sleep 1 +fi diff --git a/interchain/interchain-end_to_end_testing/Cargo.toml b/interchain/interchain-end_to_end_testing/Cargo.toml index cd8949ed5d..26a202f055 100644 --- a/interchain/interchain-end_to_end_testing/Cargo.toml +++ b/interchain/interchain-end_to_end_testing/Cargo.toml @@ -28,6 +28,7 @@ tokio = { workspace = true } log = "0.4.14" anyhow = { workspace = true } env_logger = "0.11.3" +dotenv = "0.15.0" ibc-relayer-types = "0.29" @@ -38,3 +39,7 @@ cw-controllers = { workspace = true } cw-storage-plus.workspace = true thiserror.workspace = true base64 = "0.22.1" +# Testing contract +counter-contract = { git = "https://github.com/AbstractSDK/cw-orchestrator.git", branch = "main" } # Use tag if breaks + +ping-pong = { path = "../../modules/contracts/apps/ping-pong" } diff --git a/interchain/interchain-end_to_end_testing/src/bin/ibc_hook.rs b/interchain/interchain-end_to_end_testing/src/bin/ibc_hook.rs new file mode 100644 index 0000000000..b3dc202922 --- /dev/null +++ b/interchain/interchain-end_to_end_testing/src/bin/ibc_hook.rs @@ -0,0 +1,197 @@ +// This script is used for testing a connection between 4 chains +// This script checks ibc-hook memo implementation on ibc-client + +use std::{ + sync::Arc, + time::{Duration, SystemTime, UNIX_EPOCH}, +}; + +use abstract_interchain_tests::{abstract_starship_interfaces, set_starship_env, JUNO, JUNO2}; +use abstract_interface::AccountI; +use abstract_sdk::HookMemoBuilder; +use abstract_std::{ + ans_host::ExecuteMsgFns, + objects::{TruncatedChainId, UncheckedChannelEntry}, + IBC_CLIENT, ICS20, +}; +use anyhow::Result as AnyResult; +use cosmwasm_std::{coin, coins}; +use counter_contract::CounterContract; +use cw_orch::{ + daemon::{senders::CosmosSender, CosmosOptions, RUNTIME}, + prelude::*, +}; +use cw_orch_interchain::prelude::*; +use cw_orch_proto::tokenfactory::{create_denom, get_denom, mint}; +use networks::ChainKind; + +pub fn test_ibc_hook() -> AnyResult<()> { + dotenv::dotenv().ok(); + set_starship_env(); + env_logger::init(); + + let starship = Starship::new(None).unwrap(); + let interchain = starship.interchain_env(); + + let juno = interchain.get_chain(JUNO).unwrap(); + let juno2 = interchain.get_chain(JUNO2).unwrap(); + + // // Using chainkind local so we can use mnemonic from env + let juno_chain_info = ChainInfoOwned { + kind: ChainKind::Local, + ..juno.chain_info().clone() + }; + let juno2_chain_info = ChainInfoOwned { + kind: ChainKind::Local, + ..juno2.chain_info().clone() + }; + + let juno_abstract_deployer = juno.rt_handle.block_on(CosmosSender::new( + &Arc::new(juno_chain_info), + CosmosOptions::default(), + ))?; + let juno2_abstract_deployer = juno2.rt_handle.block_on(CosmosSender::new( + &Arc::new(juno2_chain_info), + CosmosOptions::default(), + ))?; + + // Create a channel between the 2 chains for the transfer ports + // JUNO>JUNO2 + let juno_juno2_channel = interchain + .create_channel( + JUNO, + JUNO2, + &PortId::transfer(), + &PortId::transfer(), + "ics20-1", + Some(cosmwasm_std::IbcOrder::Unordered), + )? + .interchain_channel; + + let (abstr_juno, abstr_juno2) = abstract_starship_interfaces( + &interchain, + &juno_abstract_deployer, + &juno2_abstract_deployer, + )?; + + let counter_juno2 = init_counter(juno2.clone())?; + + let sender = juno.sender_addr().to_string(); + + let test_amount: u128 = 100_000_000_000; + let token_subdenom = format!( + "testtoken{}", + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs() + ); + + // Create Denom + create_denom(&juno, token_subdenom.as_str())?; + + // Mint Denom + mint(&juno, sender.as_str(), token_subdenom.as_str(), test_amount)?; + + // Register this channel with the abstract ibc implementation for sending tokens + abstr_juno + .ans_host + .call_as(&juno_abstract_deployer) + .update_channels( + vec![( + UncheckedChannelEntry { + connected_chain: TruncatedChainId::from_chain_id(JUNO2).to_string(), + protocol: ICS20.to_string(), + }, + juno_juno2_channel + .get_chain(JUNO)? + .channel + .unwrap() + .to_string(), + )], + vec![], + )?; + + // Create a test account + Remote account + + let origin_account = AccountI::create_default_account( + &abstr_juno, + abstract_client::GovernanceDetails::Monarchy { + monarch: juno.sender_addr().to_string(), + }, + )?; + origin_account.set_ibc_status(true)?; + + // Send funds to the remote account + RUNTIME.block_on(juno.sender().bank_send( + &origin_account.address()?, + vec![coin(test_amount, get_denom(&juno, token_subdenom.as_str()))], + ))?; + + let memo = HookMemoBuilder::new( + counter_juno2.address()?, + &counter_contract::msg::ExecuteMsg::Increment {}, + ) + .build()?; + // We send from osmosis to juno funds with pfm memo that includes juno-stargaze channel + origin_account.execute_on_module( + IBC_CLIENT, + &abstract_std::ibc_client::ExecuteMsg::SendFunds { + host_chain: TruncatedChainId::from_chain_id(JUNO2), + memo: Some(memo.clone()), + receiver: Some(counter_juno2.addr_str()?), + }, + coins(10_000_000_000, get_denom(&juno, token_subdenom.as_str())), + )?; + + origin_account.execute_on_module( + IBC_CLIENT, + &abstract_std::ibc_client::ExecuteMsg::SendFunds { + host_chain: TruncatedChainId::from_chain_id(JUNO2), + memo: Some(memo.clone()), + receiver: Some(counter_juno2.addr_str()?), + }, + coins(10_000_000_000, get_denom(&juno, token_subdenom.as_str())), + )?; + + origin_account.execute_on_module( + IBC_CLIENT, + &abstract_std::ibc_client::ExecuteMsg::SendFunds { + host_chain: TruncatedChainId::from_chain_id(JUNO2), + memo: Some(memo.clone()), + receiver: Some(counter_juno2.addr_str()?), + }, + coins(10_000_000_000, get_denom(&juno, token_subdenom.as_str())), + )?; + + log::info!("waiting for ibc_hook to finish tx"); + std::thread::sleep(Duration::from_secs(15)); + + let counter_juno2 = CounterContract::new(juno2.clone()); + let count_juno2: counter_contract::msg::GetCountResponse = + counter_juno2.query(&counter_contract::msg::QueryMsg::GetCount {})?; + log::info!("count juno2: {count_juno2:?}"); + + // Verify the funds have been received + let count_juno2_balance = juno2 + .bank_querier() + .balance(&counter_juno2.address()?, None)?; + + log::info!("count_juno2 balance, {:?}", count_juno2_balance); + Ok(()) +} + +pub fn init_counter(chain: Chain) -> anyhow::Result> { + let counter = CounterContract::new(chain); + counter.upload()?; + counter.instantiate( + &counter_contract::msg::InstantiateMsg { count: 0 }, + None, + &[], + )?; + Ok(counter) +} + +pub fn main() { + test_ibc_hook().unwrap(); +} diff --git a/interchain/interchain-end_to_end_testing/src/bin/pfm.rs b/interchain/interchain-end_to_end_testing/src/bin/pfm.rs new file mode 100644 index 0000000000..80c01cc0f6 --- /dev/null +++ b/interchain/interchain-end_to_end_testing/src/bin/pfm.rs @@ -0,0 +1,195 @@ +// This script is used for testing a connection between 2 chains +// This script sets up tokens and channels between transfer ports to transfer those tokens +// This also mints tokens to the chain sender for future interactions + +use std::{ + sync::Arc, + time::{Duration, SystemTime, UNIX_EPOCH}, +}; + +use abstract_interchain_tests::{ + abstract_starship_interfaces, create_test_remote_account, set_starship_env, JUNO, +}; +use abstract_interface::{AccountI, AccountQueryFns}; +use abstract_sdk::PfmMemoBuilder; +use abstract_std::{ + ans_host::ExecuteMsgFns, + objects::{TruncatedChainId, UncheckedChannelEntry}, + IBC_CLIENT, ICS20, +}; +use anyhow::Result as AnyResult; +use cosmwasm_std::{coin, coins}; +use cw_orch::{ + daemon::{networks::ChainKind, senders::CosmosSender, CosmosOptions, RUNTIME}, + prelude::*, +}; +use cw_orch_interchain::prelude::*; +use cw_orch_proto::tokenfactory::{create_denom, get_denom, mint}; + +// Note: Truncated chain id have to be different +pub const JUNO2: &str = "junotwo-1"; +pub const JUNO3: &str = "junothree-1"; +pub const JUNO4: &str = "junofour-1"; + +pub fn test_pfm() -> AnyResult<()> { + dotenv::dotenv().ok(); + set_starship_env(); + env_logger::init(); + + let starship = Starship::new(None).unwrap(); + let interchain = starship.interchain_env(); + + let juno = interchain.get_chain(JUNO).unwrap(); + let juno2 = interchain.get_chain(JUNO2).unwrap(); + let juno4 = interchain.get_chain(JUNO4).unwrap(); + + // Using chainkind local so we can use mnemonic from env + let juno_chain_info = ChainInfoOwned { + kind: ChainKind::Local, + ..juno.chain_info().clone() + }; + let juno2_chain_info = ChainInfoOwned { + kind: ChainKind::Local, + ..juno2.chain_info().clone() + }; + + let juno_abstract_deployer = juno.rt_handle.block_on(CosmosSender::new( + &Arc::new(juno_chain_info), + CosmosOptions::default(), + ))?; + let juno2_abstract_deployer = juno2.rt_handle.block_on(CosmosSender::new( + &Arc::new(juno2_chain_info), + CosmosOptions::default(), + ))?; + + // Create a channel between the 4 chains for the transfer ports + // JUNO>JUNO2>JUNO3>JUNO4 + let juno_juno2_channel = interchain + .create_channel( + JUNO, + JUNO2, + &PortId::transfer(), + &PortId::transfer(), + "ics20-1", + Some(cosmwasm_std::IbcOrder::Unordered), + )? + .interchain_channel; + + let juno2_juno3_channel = interchain + .create_channel( + JUNO2, + JUNO3, + &PortId::transfer(), + &PortId::transfer(), + "ics20-1", + Some(cosmwasm_std::IbcOrder::Unordered), + )? + .interchain_channel; + + let juno3_juno4_channel = interchain + .create_channel( + JUNO3, + JUNO4, + &PortId::transfer(), + &PortId::transfer(), + "ics20-1", + Some(cosmwasm_std::IbcOrder::Unordered), + )? + .interchain_channel; + + let (abstr_juno, abstr_juno2) = abstract_starship_interfaces( + &interchain, + &juno_abstract_deployer, + &juno2_abstract_deployer, + )?; + + let sender = juno.sender_addr().to_string(); + + let test_amount: u128 = 100_000_000_000; + let token_subdenom = format!( + "testtoken{}", + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs() + ); + + // Create Denom + create_denom(&juno, token_subdenom.as_str())?; + + // Mint Denom + mint(&juno, sender.as_str(), token_subdenom.as_str(), test_amount)?; + + // Register this channel with the abstract ibc implementation for sending tokens + abstr_juno + .ans_host + .call_as(&juno_abstract_deployer) + .update_channels( + vec![( + UncheckedChannelEntry { + connected_chain: "junotwo".to_string(), + protocol: ICS20.to_string(), + }, + juno_juno2_channel + .get_chain(JUNO)? + .channel + .unwrap() + .to_string(), + )], + vec![], + )?; + + // Create a test account + Remote account + let (origin_account, remote_account_id) = + create_test_remote_account(&abstr_juno, JUNO, JUNO2, &interchain, vec![])?; + + // Get the ibc client address + let remote_account = AccountI::load_from(&abstr_juno2, remote_account_id.clone())?; + let client = remote_account.config()?; + + log::info!("client adddress {:?}", client); + + // Send funds to the remote account + RUNTIME.block_on(juno.sender().bank_send( + &origin_account.address()?, + vec![coin(test_amount, get_denom(&juno, token_subdenom.as_str()))], + ))?; + let juno2_juno3_channel_port_juno2 = juno2_juno3_channel + .get_chain(JUNO2) + .unwrap() + .channel + .unwrap() + .to_string(); + let juno3_juno4_channel_port_juno3 = juno3_juno4_channel + .get_chain(JUNO3) + .unwrap() + .channel + .unwrap() + .to_string(); + + let memo = PfmMemoBuilder::new(juno2_juno3_channel_port_juno2) + .hop(juno3_juno4_channel_port_juno3) + .build(juno4.sender_addr())?; + origin_account.execute_on_module( + IBC_CLIENT, + abstract_std::ibc_client::ExecuteMsg::SendFunds { + host_chain: TruncatedChainId::from_chain_id(JUNO2), + memo: Some(memo), + receiver: None, + }, + coins(100_000_000_000, get_denom(&juno, token_subdenom.as_str())), + )?; + log::info!("waiting for pfm bank send to finish"); + std::thread::sleep(Duration::from_secs(15)); + + // Verify the funds have been received + let balance = juno4.bank_querier().balance(&juno4.sender_addr(), None)?; + + log::info!("juno4 balance, {:?}", balance); + + Ok(()) +} + +pub fn main() { + test_pfm().unwrap(); +} diff --git a/interchain/interchain-end_to_end_testing/src/bin/setup_funds.rs b/interchain/interchain-end_to_end_testing/src/bin/setup_funds.rs index bf35d28d5c..6fcd6ccc1b 100644 --- a/interchain/interchain-end_to_end_testing/src/bin/setup_funds.rs +++ b/interchain/interchain-end_to_end_testing/src/bin/setup_funds.rs @@ -108,6 +108,7 @@ pub fn test_send_funds() -> AnyResult<()> { abstract_std::ibc_client::ExecuteMsg::SendFunds { host_chain: TruncatedChainId::from_chain_id(STARGAZE), memo: Some("sent_some_tokens".to_owned()), + receiver: None, }, funds, )?; diff --git a/interchain/interchain-end_to_end_testing/src/lib.rs b/interchain/interchain-end_to_end_testing/src/lib.rs index 0c1b3550ad..9da94c20db 100644 --- a/interchain/interchain-end_to_end_testing/src/lib.rs +++ b/interchain/interchain-end_to_end_testing/src/lib.rs @@ -1,13 +1,26 @@ -use abstract_interface::{Abstract, AccountDetails, AccountI, AccountQueryFns}; +use abstract_interface::{ + connection::connect_one_way_to, Abstract, AccountDetails, AccountI, AccountQueryFns, +}; use abstract_std::objects::{AccountId, AccountTrace, TruncatedChainId}; -use cosmwasm_std::Coin; -use cw_orch::prelude::*; -use cw_orch_interchain::core::{IbcQueryHandler, InterchainEnv}; +use anyhow::Result as AnyResult; +use cosmwasm_std::{coins, Coin}; +use cw_orch::{ + daemon::{TxSender, Wallet}, + prelude::*, +}; +use cw_orch_interchain::{ + core::{IbcQueryHandler, InterchainEnv}, + daemon::DaemonInterchain, + prelude::Starship, +}; pub const JUNO: &str = "juno-1"; pub const STARGAZE: &str = "stargaze-1"; pub const OSMOSIS: &str = "osmosis-1"; +// Note: Truncated chain id have to be different +pub const JUNO2: &str = "junotwo-1"; + pub const TEST_ACCOUNT_NAME: &str = "account-test"; pub const TEST_ACCOUNT_DESCRIPTION: &str = "Description of an account"; pub const TEST_ACCOUNT_LINK: &str = "https://google.com"; @@ -17,6 +30,12 @@ pub fn set_env() { std::env::set_var("ARTIFACTS_DIR", "../artifacts"); // Set in code for tests } +// Set in code for starship tests +pub fn set_starship_env() { + std::env::set_var("STATE_FILE", "starship-state.json"); + std::env::set_var("ARTIFACTS_DIR", "../artifacts"); +} + pub fn create_test_remote_account>( abstr_origin: &Abstract, origin_id: &str, @@ -69,3 +88,36 @@ pub fn create_test_remote_account, + juno_abstract_deployer: &Wallet, + juno2_abstract_deployer: &Wallet, +) -> AnyResult<(Abstract, Abstract)> { + let juno = interchain.get_chain(JUNO).unwrap(); + let juno2 = interchain.get_chain(JUNO2).unwrap(); + // Just return if already deployed + if let Ok(juno_deployment) = Abstract::load_from(juno.clone()) { + return Ok((juno_deployment, Abstract::load_from(juno2)?)); + } + // Deploy and connect if not deployed yet + + // Send some funds for deploying abstract + juno.rt_handle.block_on(juno.sender().bank_send( + &juno_abstract_deployer.address(), + coins(10_000_000_000_000, juno.chain_info().gas_denom.clone()), + ))?; + juno2.rt_handle.block_on(juno2.sender().bank_send( + &juno2_abstract_deployer.address(), + coins(10_000_000_000_000, juno2.chain_info().gas_denom.clone()), + ))?; + let abstr_juno = Abstract::deploy_on(juno.clone(), juno_abstract_deployer.clone())?; + let abstr_juno2 = Abstract::deploy_on(juno2.clone(), juno2_abstract_deployer.clone())?; + connect_one_way_to( + &abstr_juno.call_as(juno_abstract_deployer), + &abstr_juno2.call_as(juno2_abstract_deployer), + interchain, + )?; + + Ok((abstr_juno, abstr_juno2)) +} diff --git a/modules/contracts/adapters/cw-staking/src/handlers/execute.rs b/modules/contracts/adapters/cw-staking/src/handlers/execute.rs index e945e7bbf8..be6a7b2304 100644 --- a/modules/contracts/adapters/cw-staking/src/handlers/execute.rs +++ b/modules/contracts/adapters/cw-staking/src/handlers/execute.rs @@ -74,7 +74,7 @@ fn handle_ibc_request( // get the to-be-sent assets from the action let coins = resolve_assets_to_transfer(deps.as_ref(), action, ans.host())?; // construct the ics20 call(s) - let ics20_transfer_msg = ibc_client.ics20_transfer(host_chain.clone(), coins, None)?; + let ics20_transfer_msg = ibc_client.ics20_transfer(host_chain.clone(), coins, None, None)?; // construct the action to be called on the host // construct the action to be called on the host let host_action = abstract_adapter::std::ibc_host::HostAction::Dispatch { diff --git a/modules/contracts/adapters/dex/src/handlers/execute.rs b/modules/contracts/adapters/dex/src/handlers/execute.rs index 102f4a1969..49afa9ca54 100644 --- a/modules/contracts/adapters/dex/src/handlers/execute.rs +++ b/modules/contracts/adapters/dex/src/handlers/execute.rs @@ -123,7 +123,7 @@ fn handle_ibc_request( // get the to-be-sent assets from the action let coins = resolve_assets_to_transfer(deps.as_ref(), action, ans.host())?; // construct the ics20 call(s) - let ics20_transfer_msg = ibc_client.ics20_transfer(host_chain.clone(), coins, None)?; + let ics20_transfer_msg = ibc_client.ics20_transfer(host_chain.clone(), coins, None, None)?; // construct the action to be called on the host let host_action = abstract_adapter::std::ibc_host::HostAction::Dispatch { account_msgs: vec![ diff --git a/modules/contracts/standalones/ica-owner/starship/Makefile b/modules/contracts/standalones/ica-owner/starship/Makefile index 0e82b3e15c..13519a998c 100644 --- a/modules/contracts/standalones/ica-owner/starship/Makefile +++ b/modules/contracts/standalones/ica-owner/starship/Makefile @@ -1,5 +1,5 @@ NAME = tutorial -FILE = configs/osmo-juno.yaml +FILE = ./configs/osmo-juno.yaml HELM_REPO = starship HELM_CHART = devnet diff --git a/modules/contracts/standalones/ica-owner/starship/configs/osmo-juno.yaml b/modules/contracts/standalones/ica-owner/starship/configs/osmo-juno.yaml index 779219117d..5c46e7c85f 100644 --- a/modules/contracts/standalones/ica-owner/starship/configs/osmo-juno.yaml +++ b/modules/contracts/standalones/ica-owner/starship/configs/osmo-juno.yaml @@ -26,11 +26,8 @@ relayers: config: event_source: mode: "pull" # default is "push" - -explorer: - enabled: true - ports: - rest: 8080 + ports: + rest: 3001 registry: enabled: true diff --git a/modules/contracts/standalones/ica-owner/starship/port-forward.sh b/modules/contracts/standalones/ica-owner/starship/port-forward.sh index af861499e5..8e1ef469c1 100755 --- a/modules/contracts/standalones/ica-owner/starship/port-forward.sh +++ b/modules/contracts/standalones/ica-owner/starship/port-forward.sh @@ -21,13 +21,18 @@ function stop_port_forward() { # Default values CHAIN_RPC_PORT=26657 -CHAIN_LCD_PORT=1317 +CHAIN_COMETMOCK_PORT=22331 CHAIN_GRPC_PORT=9090 +CHAIN_LCD_PORT=1317 CHAIN_EXPOSER_PORT=8081 CHAIN_FAUCET_PORT=8000 +RELAYER_REST_PORT=3000 +RELAYER_EXPOSER_PORT=8081 EXPLORER_LCD_PORT=8080 REGISTRY_LCD_PORT=8080 REGISTRY_GRPC_PORT=9090 +MONITORING_PROMETHEUS_PORT=8080 +MONITORING_GRAFANA_PORT=8080 for i in "$@"; do case $i in @@ -49,25 +54,54 @@ stop_port_forward echo "Port forwarding for config ${CONFIGFILE}" echo "Port forwarding all chains" num_chains=$(yq -r ".chains | length - 1" ${CONFIGFILE}) -if [[ $num_chains -lt 0 ]]; then +if [[ $num_chains -gt -1 ]]; then + for i in $(seq 0 $num_chains); do + # derive chain pod name from chain id + # https://github.com/cosmology-tech/starship/blob/main/charts/devnet/templates/_helpers.tpl#L56 + chain=$(yq -r ".chains[$i].id" ${CONFIGFILE} ) + chain=${chain/_/"-"} + localrpc=$(yq -r ".chains[$i].ports.rpc" ${CONFIGFILE} ) + localgrpc=$(yq -r ".chains[$i].ports.grpc" ${CONFIGFILE} ) + locallcd=$(yq -r ".chains[$i].ports.rest" ${CONFIGFILE} ) + localexp=$(yq -r ".chains[$i].ports.exposer" ${CONFIGFILE}) + localfaucet=$(yq -r ".chains[$i].ports.faucet" ${CONFIGFILE}) + color yellow "chains: forwarded $chain" + if [[ $(yq -r ".chains[$i].cometmock.enabled" $CONFIGFILE) == "true" ]]; + then + [[ "$localrpc" != "null" ]] && color yellow " cometmock rpc to http://localhost:$localrpc" && kubectl port-forward pods/$chain-cometmock-0 $localrpc:$CHAIN_COMETMOCK_PORT > /dev/null 2>&1 & + else + [[ "$localrpc" != "null" ]] && color yellow " rpc to http://localhost:$localrpc" && kubectl port-forward pods/$chain-genesis-0 $localrpc:$CHAIN_RPC_PORT > /dev/null 2>&1 & + fi + [[ "$localgrpc" != "null" ]] && color yellow " grpc to http://localhost:$localgrpc" && kubectl port-forward pods/$chain-genesis-0 $localgrpc:$CHAIN_GRPC_PORT > /dev/null 2>&1 & + [[ "$locallcd" != "null" ]] && color yellow " lcd to http://localhost:$locallcd" && kubectl port-forward pods/$chain-genesis-0 $locallcd:$CHAIN_LCD_PORT > /dev/null 2>&1 & + [[ "$localexp" != "null" ]] && color yellow " exposer to http://localhost:$localexp" && kubectl port-forward pods/$chain-genesis-0 $localexp:$CHAIN_EXPOSER_PORT > /dev/null 2>&1 & + [[ "$localfaucet" != "null" ]] && color yellow " faucet to http://localhost:$localfaucet" && kubectl port-forward pods/$chain-genesis-0 $localfaucet:$CHAIN_FAUCET_PORT > /dev/null 2>&1 & + sleep 1 + done +else echo "No chains to port-forward: num: $num_chains" - exit 1 fi -for i in $(seq 0 $num_chains); do - chain=$(yq -r ".chains[$i].id" ${CONFIGFILE} ) - localrpc=$(yq -r ".chains[$i].ports.rpc" ${CONFIGFILE} ) - locallcd=$(yq -r ".chains[$i].ports.rest" ${CONFIGFILE} ) - localgrpc=$(yq -r ".chains[$i].ports.grpc" ${CONFIGFILE} ) - localexp=$(yq -r ".chains[$i].ports.exposer" ${CONFIGFILE}) - localfaucet=$(yq -r ".chains[$i].ports.faucet" ${CONFIGFILE}) - [[ "$localrpc" != "null" ]] && kubectl port-forward pods/$chain-genesis-0 $localrpc:$CHAIN_RPC_PORT > /dev/null 2>&1 & - [[ "$locallcd" != "null" ]] && kubectl port-forward pods/$chain-genesis-0 $locallcd:$CHAIN_LCD_PORT > /dev/null 2>&1 & - [[ "$localgrpc" != "null" ]] && kubectl port-forward pods/$chain-genesis-0 $localgrpc:$CHAIN_GRPC_PORT > /dev/null 2>&1 & - [[ "$localexp" != "null" ]] && kubectl port-forward pods/$chain-genesis-0 $localexp:$CHAIN_EXPOSER_PORT > /dev/null 2>&1 & - [[ "$localfaucet" != "null" ]] && kubectl port-forward pods/$chain-genesis-0 $localfaucet:$CHAIN_FAUCET_PORT > /dev/null 2>&1 & - sleep 1 - color yellow "chains: forwarded $chain lcd to http://localhost:$locallcd, rpc to http://localhost:$localrpc, grpc to http://localhost:$localfaucet, faucet to http://localhost:$localgrpc" -done + + +echo "Port forward relayers" +num_relayers=$(yq -r ".relayers | length - 1" ${CONFIGFILE}) +if [[ $num_relayers -gt -1 ]]; then + for i in $(seq 0 $num_relayers); do + # derive chain pod name from chain id + # https://github.com/cosmology-tech/starship/blob/main/charts/devnet/templates/_helpers.tpl#L56 + relayer=$(yq -r ".relayers[$i].name" ${CONFIGFILE} ) + relayer=$(yq -r ".relayers[$i].type" ${CONFIGFILE} )-${relayer/_/"-"} + localrest=$(yq -r ".relayers[$i].ports.rest" ${CONFIGFILE} ) + localexposer=$(yq -r ".relayers[$i].ports.exposer" ${CONFIGFILE} ) + color yellow "relayers: forwarded $relayer" + [[ "$localrest" != "null" ]] && color yellow " rpc to http://localhost:$localrest" && kubectl port-forward pods/$relayer-0 $localrest:$RELAYER_REST_PORT > /dev/null 2>&1 & + [[ "$localexposer" != "null" ]] && color yellow " rpc to http://localhost:$localexposer" && kubectl port-forward pods/$relayer-0 $localexposer:$RELAYER_EXPOSER_PORT > /dev/null 2>&1 & + sleep 1 + done +else + echo "No relayer to port-forward: num: $num_relayers" +fi + echo "Port forward services" @@ -85,3 +119,13 @@ then sleep 1 color green "Open the explorer to get started.... http://localhost:8080" fi + +if [[ $(yq -r ".monitoring.enabled" $CONFIGFILE) == "true" ]]; +then + color yellow "monitoring port forward:" + localgrafana=$(yq -r ".monitoring.ports.grafana" ${CONFIGFILE}) + localprometheus=$(yq -r ".monitoring.ports.prometheus" ${CONFIGFILE}) + [[ "$localgrafana" != "null" ]] && color yellow " grafana to http://localhost:$localgrafana" && kubectl port-forward service/grafana $localgrafana:$MONITORING_GRAFANA_PORT > /dev/null 2>&1 & + [[ "$localprometheus" != "null" ]] && color yellow " prometheus to http://localhost:$localprometheus" && kubectl port-forward service/prometheus-service $localprometheus:$MONITORING_PROMETHEUS_PORT > /dev/null 2>&1 & + sleep 1 +fi