From 16e188d115e9c3da61bedc3755f21cf0d5a88d72 Mon Sep 17 00:00:00 2001 From: bekauz Date: Sun, 4 Jun 2023 23:01:32 +0200 Subject: [PATCH 01/20] depositor instantiate & queries --- stride-covenant/.gitignore | 33 + stride-covenant/Cargo.lock | 802 ++++++++++++++++++ stride-covenant/Cargo.toml | 40 + stride-covenant/packages/depositor/Cargo.toml | 16 + stride-covenant/packages/depositor/LICENSE | 29 + .../packages/depositor/src/contract.rs | 69 ++ .../packages/depositor/src/error.rs | 17 + stride-covenant/packages/depositor/src/lib.rs | 7 + stride-covenant/packages/depositor/src/msg.rs | 29 + .../packages/depositor/src/state.rs | 13 + .../packages/depositor/src/tests/mod.rs | 2 + .../packages/depositor/src/tests/suite.rs | 118 +++ .../packages/depositor/src/tests/tests.rs | 22 + 13 files changed, 1197 insertions(+) create mode 100644 stride-covenant/.gitignore create mode 100644 stride-covenant/Cargo.lock create mode 100644 stride-covenant/Cargo.toml create mode 100644 stride-covenant/packages/depositor/Cargo.toml create mode 100644 stride-covenant/packages/depositor/LICENSE create mode 100644 stride-covenant/packages/depositor/src/contract.rs create mode 100644 stride-covenant/packages/depositor/src/error.rs create mode 100644 stride-covenant/packages/depositor/src/lib.rs create mode 100644 stride-covenant/packages/depositor/src/msg.rs create mode 100644 stride-covenant/packages/depositor/src/state.rs create mode 100644 stride-covenant/packages/depositor/src/tests/mod.rs create mode 100644 stride-covenant/packages/depositor/src/tests/suite.rs create mode 100644 stride-covenant/packages/depositor/src/tests/tests.rs diff --git a/stride-covenant/.gitignore b/stride-covenant/.gitignore new file mode 100644 index 00000000..0894b8ee --- /dev/null +++ b/stride-covenant/.gitignore @@ -0,0 +1,33 @@ +# macOS +.DS_Store + +# Text file backups +**/*.rs.bk + +# Build results +target/ + +# IDEs +.vscode/ +.idea/ +*.iml +**/.editorconfig + +# Auto-gen +.cargo-ok + +# Build artifacts +*.wasm +hash.txt +contracts.txt +artifacts/ + +# code coverage +tarpaulin-report.* + +# integration tests +gas_reports/ +ci/configs/cosm-orc/local.yaml + +contracts/**/Cargo.lock +packages/**/Cargo.lock \ No newline at end of file diff --git a/stride-covenant/Cargo.lock b/stride-covenant/Cargo.lock new file mode 100644 index 00000000..c86bafa6 --- /dev/null +++ b/stride-covenant/Cargo.lock @@ -0,0 +1,802 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "anyhow" +version = "1.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" + +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "const-oid" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" + +[[package]] +name = "cosmwasm-crypto" +version = "1.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75836a10cb9654c54e77ee56da94d592923092a10b369cdb0dbd56acefc16340" +dependencies = [ + "digest 0.10.7", + "ed25519-zebra", + "k256", + "rand_core 0.6.4", + "thiserror", +] + +[[package]] +name = "cosmwasm-derive" +version = "1.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c9f7f0e51bfc7295f7b2664fe8513c966428642aa765dad8a74acdab5e0c773" +dependencies = [ + "syn 1.0.109", +] + +[[package]] +name = "cosmwasm-schema" +version = "1.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f00b363610218eea83f24bbab09e1a7c3920b79f068334fdfcc62f6129ef9fc" +dependencies = [ + "cosmwasm-schema-derive", + "schemars", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cosmwasm-schema-derive" +version = "1.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae38f909b2822d32b275c9e2db9728497aa33ffe67dd463bc67c6a3b7092785c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "cosmwasm-std" +version = "1.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a49b85345e811c8e80ec55d0d091e4fcb4f00f97ab058f9be5f614c444a730cb" +dependencies = [ + "base64", + "cosmwasm-crypto", + "cosmwasm-derive", + "derivative", + "forward_ref", + "hex", + "schemars", + "serde", + "serde-json-wasm", + "sha2 0.10.6", + "thiserror", + "uint", +] + +[[package]] +name = "cpufeatures" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "cw-multi-test" +version = "0.16.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a18afd2e201221c6d72a57f0886ef2a22151bbc9e6db7af276fde8a91081042" +dependencies = [ + "anyhow", + "cosmwasm-std", + "cw-storage-plus", + "cw-utils", + "derivative", + "itertools", + "k256", + "prost", + "schemars", + "serde", + "thiserror", +] + +[[package]] +name = "cw-storage-plus" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053a5083c258acd68386734f428a5a171b29f7d733151ae83090c6fcc9417ffa" +dependencies = [ + "cosmwasm-std", + "schemars", + "serde", +] + +[[package]] +name = "cw-utils" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c80e93d1deccb8588db03945016a292c3c631e6325d349ebb35d2db6f4f946f7" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw2", + "schemars", + "semver", + "serde", + "thiserror", +] + +[[package]] +name = "cw2" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fb70cee2cf0b4a8ff7253e6bc6647107905e8eb37208f87d54f67810faa62f8" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus", + "schemars", + "serde", +] + +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", + "subtle", +] + +[[package]] +name = "dyn-clone" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" + +[[package]] +name = "ecdsa" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" +dependencies = [ + "der", + "elliptic-curve", + "rfc6979", + "signature", +] + +[[package]] +name = "ed25519-zebra" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" +dependencies = [ + "curve25519-dalek", + "hashbrown", + "hex", + "rand_core 0.6.4", + "serde", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "elliptic-curve" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" +dependencies = [ + "base16ct", + "crypto-bigint", + "der", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "forward_ref" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "k256" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "sha2 0.10.6", +] + +[[package]] +name = "libc" +version = "0.2.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc86cde3ff845662b8f4ef6cb50ea0e20c524eb3d29ae048287e06a1b3fa6a81" + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "proc-macro2" +version = "1.0.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "quote" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rfc6979" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" +dependencies = [ + "crypto-bigint", + "hmac", + "zeroize", +] + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "schemars" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 1.0.109", +] + +[[package]] +name = "sec1" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + +[[package]] +name = "serde" +version = "1.0.163" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-json-wasm" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16a62a1fad1e1828b24acac8f2b468971dade7b8c3c2e672bcadefefb1f8c137" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.163" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "serde_json" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stride-depositor" +version = "0.0.1" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-multi-test", + "cw-storage-plus", + "cw2", + "serde", + "thiserror", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-ident" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" diff --git a/stride-covenant/Cargo.toml b/stride-covenant/Cargo.toml new file mode 100644 index 00000000..68785c9c --- /dev/null +++ b/stride-covenant/Cargo.toml @@ -0,0 +1,40 @@ +[workspace] +members = [ + "packages/*", +] + +[workspace.package] +edition = "2021" +license = "BSD-3" +rust-version = "1.67" +version = "0.1.0" + +[profile.release] +codegen-units = 1 +debug = false +debug-assertions = false +incremental = false +lto = true +opt-level = 3 +overflow-checks = true # very important, do not turn these off. +panic = 'abort' +rpath = false + +[workspace.dependencies] +cosmwasm-schema = "1.2.1" +cosmwasm-std = { version = "1.2.4", features = ["ibc3"] } +cw-storage-plus = "1.0.1" +cw-utils = "1.0.1" +cw2 = "1.0.1" + +serde = { version = "1.0.145", default-features = false, features = ["derive"] } +thiserror = "1.0.31" +# the sha2 version here is the same as the one used by +# cosmwasm-std. when bumping cosmwasm-std, this should also be +# updated. to find cosmwasm_std's sha function: +# ```cargo tree --package cosmwasm-std``` +sha2 = "0.10.6" + +# dev-dependencies +cw-multi-test = "0.16.2" +anyhow = { version = "1.0.51" } \ No newline at end of file diff --git a/stride-covenant/packages/depositor/Cargo.toml b/stride-covenant/packages/depositor/Cargo.toml new file mode 100644 index 00000000..fe2b9af5 --- /dev/null +++ b/stride-covenant/packages/depositor/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "stride-depositor" +version = "0.0.1" +edition = "2021" +authors = ["benskey bekauz@protonmail.com"] +description = "Depositor module for stride covenant" +license = { workspace = true } + +[dependencies] +cosmwasm-schema = { workspace = true } +cosmwasm-std = { workspace = true } +cw-storage-plus = { workspace = true } +serde = { workspace = true } +cw2 = { workspace = true } +thiserror = { workspace = true } +cw-multi-test = { workspace = true } \ No newline at end of file diff --git a/stride-covenant/packages/depositor/LICENSE b/stride-covenant/packages/depositor/LICENSE new file mode 100644 index 00000000..0bdef96b --- /dev/null +++ b/stride-covenant/packages/depositor/LICENSE @@ -0,0 +1,29 @@ +Copyright 2023 Timewave + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the + distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/stride-covenant/packages/depositor/src/contract.rs b/stride-covenant/packages/depositor/src/contract.rs new file mode 100644 index 00000000..1db3bcaf --- /dev/null +++ b/stride-covenant/packages/depositor/src/contract.rs @@ -0,0 +1,69 @@ + +use cw2::set_contract_version; +use cosmwasm_std::{entry_point, DepsMut, Env, MessageInfo, Response, Deps, StdResult, Binary, to_binary, Addr}; + +use crate::msg::{InstantiateMsg, ExecuteMsg, QueryMsg}; +use crate::error::ContractError; +use crate::state::{STRIDE_ATOM_RECEIVER, CLOCK_ADDRESS, NATIVE_ATOM_RECEIVER}; + +const CONTRACT_NAME: &str = "crates.io:stride-depositor"; +const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn instantiate( + deps: DepsMut, + _env: Env, + info: MessageInfo, + msg: InstantiateMsg, +) -> Result { + set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + + // can we do better with validation here? + deps.api.addr_validate(&msg.st_atom_receiver.address)?; + deps.api.addr_validate(&msg.atom_receiver.address)?; + + // TODO: consider re-enabling + // let clock_contract = deps.querier.query_wasm_contract_info(msg.clock_address.to_string())?; + // // clock should already exist, and be instantiated by the same covenant contract + // if Addr::unchecked(clock_contract.creator) != info.sender { + // return Err(ContractError::InstantiatorMissmatch {}) + // } + + // avoid zero deposit configurations + if msg.st_atom_receiver.amount.is_zero() || msg.atom_receiver.amount.is_zero() { + return Err(ContractError::ZeroDeposit {}) + } + + // store the denominations and amounts + STRIDE_ATOM_RECEIVER.save(deps.storage, &msg.st_atom_receiver)?; + NATIVE_ATOM_RECEIVER.save(deps.storage, &msg.atom_receiver)?; + + // store the clock address that will be authorized to tick + CLOCK_ADDRESS.save(deps.storage, &msg.clock_address)?; + + Ok(Response::default()) +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn execute( + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: ExecuteMsg, +) -> Result { + match msg { + ExecuteMsg::Tick {} => todo!(), + ExecuteMsg::Received {} => todo!(), + } + + Ok(Response::default()) +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { + match msg { + QueryMsg::StAtomReceiver {} => to_binary(&STRIDE_ATOM_RECEIVER.may_load(deps.storage)?), + QueryMsg::AtomReceiver {} => to_binary(&NATIVE_ATOM_RECEIVER.may_load(deps.storage)?), + QueryMsg::ClockAddress {} => to_binary(&CLOCK_ADDRESS.may_load(deps.storage)?), + } +} \ No newline at end of file diff --git a/stride-covenant/packages/depositor/src/error.rs b/stride-covenant/packages/depositor/src/error.rs new file mode 100644 index 00000000..b116c0b5 --- /dev/null +++ b/stride-covenant/packages/depositor/src/error.rs @@ -0,0 +1,17 @@ +use cosmwasm_std::StdError; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum ContractError { + #[error("{0}")] + Std(#[from] StdError), + + #[error("Unauthorized")] + Unauthorized {}, + + #[error("Attempt to deposit zero")] + ZeroDeposit {}, + + // #[error("Depositor and clock should be instantiated by the same address")] + // InstantiatorMissmatch {}, +} \ No newline at end of file diff --git a/stride-covenant/packages/depositor/src/lib.rs b/stride-covenant/packages/depositor/src/lib.rs new file mode 100644 index 00000000..565bd28d --- /dev/null +++ b/stride-covenant/packages/depositor/src/lib.rs @@ -0,0 +1,7 @@ +pub mod contract; +pub mod error; +pub mod msg; +pub mod state; + +#[cfg(test)] +mod tests; \ No newline at end of file diff --git a/stride-covenant/packages/depositor/src/msg.rs b/stride-covenant/packages/depositor/src/msg.rs new file mode 100644 index 00000000..17fdc701 --- /dev/null +++ b/stride-covenant/packages/depositor/src/msg.rs @@ -0,0 +1,29 @@ +use cosmwasm_schema::cw_serde; +use cosmwasm_std::{Uint128, Addr}; + +#[cw_serde] +pub struct InstantiateMsg { + pub st_atom_receiver: WeightedReceiver, + pub atom_receiver: WeightedReceiver, + pub clock_address: Addr, +} + +#[cw_serde] +pub enum ExecuteMsg { + Tick {}, + Received {}, +} + +#[cw_serde] +pub enum QueryMsg { + StAtomReceiver {}, + AtomReceiver {}, + ClockAddress {}, +} + +#[cw_serde] +pub struct WeightedReceiver { + pub amount: Uint128, + pub address: String, +} + diff --git a/stride-covenant/packages/depositor/src/state.rs b/stride-covenant/packages/depositor/src/state.rs new file mode 100644 index 00000000..c62e9498 --- /dev/null +++ b/stride-covenant/packages/depositor/src/state.rs @@ -0,0 +1,13 @@ +use cosmwasm_std::Addr; +use cw_storage_plus::Item; + +use crate::msg::WeightedReceiver; + +// addr and amount of atom to liquid stake on stride +pub const STRIDE_ATOM_RECEIVER: Item = Item::new("stride_atom_receiver"); +// addr and amount of atom +pub const NATIVE_ATOM_RECEIVER: Item = Item::new("native_atom_receiver"); +// store the clock address to verify calls +pub const CLOCK_ADDRESS: Item = Item::new("clock_address"); + + diff --git a/stride-covenant/packages/depositor/src/tests/mod.rs b/stride-covenant/packages/depositor/src/tests/mod.rs new file mode 100644 index 00000000..b3e04424 --- /dev/null +++ b/stride-covenant/packages/depositor/src/tests/mod.rs @@ -0,0 +1,2 @@ +mod tests; +mod suite; \ No newline at end of file diff --git a/stride-covenant/packages/depositor/src/tests/suite.rs b/stride-covenant/packages/depositor/src/tests/suite.rs new file mode 100644 index 00000000..ae453de4 --- /dev/null +++ b/stride-covenant/packages/depositor/src/tests/suite.rs @@ -0,0 +1,118 @@ +use cosmwasm_std::{Addr, Empty, Uint128}; +use cw_multi_test::{App, Contract, ContractWrapper, Executor}; + +use crate::msg::{InstantiateMsg, WeightedReceiver, QueryMsg}; + +pub const CREATOR_ADDR: &str = "creator"; +pub const ST_ATOM_DENOM: &str = "stride-atom"; +pub const NATIVE_ATOM_DENOM: &str = "native-atom"; +pub const DEFAULT_RECEIVER_AMOUNT: Uint128 = Uint128::new(10); +pub const DEFAULT_CLOCK_ADDRESS: &str = "clock-address"; + +fn depositor_contract() -> Box> { + let contract = ContractWrapper::new( + crate::contract::execute, + crate::contract::instantiate, + crate::contract::query, + ); + Box::new(contract) +} + +pub(crate) struct Suite { + app: App, + pub _admin: Addr, + pub depositor_address: Addr, + pub depositor_code: u64, +} + +pub(crate) struct SuiteBuilder { + pub instantiate: InstantiateMsg, +} + + + +impl Default for SuiteBuilder { + fn default() -> Self { + Self { + instantiate: InstantiateMsg { + st_atom_receiver: WeightedReceiver { + amount: DEFAULT_RECEIVER_AMOUNT, + address: ST_ATOM_DENOM.to_string(), + }, + atom_receiver: WeightedReceiver { + amount: DEFAULT_RECEIVER_AMOUNT, + address: NATIVE_ATOM_DENOM.to_string(), + }, + clock_address: Addr::unchecked(DEFAULT_CLOCK_ADDRESS), + }, + } + } +} + +impl SuiteBuilder { + pub fn build(self) -> Suite { + let mut app = App::default(); + + let depositor_code = app.store_code(depositor_contract()); + + let depositor_address = app + .instantiate_contract( + depositor_code, + Addr::unchecked(CREATOR_ADDR), + &self.instantiate, + &[], + "depositor contract", + Some(CREATOR_ADDR.to_string()), + ) + .unwrap(); + + Suite { + app, + _admin: Addr::unchecked(CREATOR_ADDR), + depositor_address, + depositor_code, + } + } +} + +// queries +impl Suite { + pub fn query_stride_atom_receiver(&self) -> WeightedReceiver { + self.app + .wrap() + .query_wasm_smart(&self.depositor_address, &QueryMsg::StAtomReceiver {}) + .unwrap() + } + + pub fn query_native_atom_receiver(&self) -> WeightedReceiver { + self.app + .wrap() + .query_wasm_smart(&self.depositor_address, &QueryMsg::AtomReceiver {}) + .unwrap() + } + + pub fn query_clock_address(&self) -> Addr { + self.app + .wrap() + .query_wasm_smart(&self.depositor_address, &QueryMsg::ClockAddress {}) + .unwrap() + } +} + +// assertion helpers +impl Suite { + pub fn assert_stride_atom_receiver(&self, val: WeightedReceiver) { + let curr = self.query_stride_atom_receiver(); + assert_eq!(curr, val); + } + + pub fn assert_native_atom_receiver(&self, val: WeightedReceiver) { + let curr = self.query_native_atom_receiver(); + assert_eq!(curr, val); + } + + pub fn assert_clock_address(&self, val: Addr) { + let curr = self.query_clock_address(); + assert_eq!(curr, val); + } +} \ No newline at end of file diff --git a/stride-covenant/packages/depositor/src/tests/tests.rs b/stride-covenant/packages/depositor/src/tests/tests.rs new file mode 100644 index 00000000..f639b2db --- /dev/null +++ b/stride-covenant/packages/depositor/src/tests/tests.rs @@ -0,0 +1,22 @@ +use cosmwasm_std::Addr; + +use crate::msg::WeightedReceiver; + +use super::suite::{SuiteBuilder, DEFAULT_CLOCK_ADDRESS, DEFAULT_RECEIVER_AMOUNT, NATIVE_ATOM_DENOM, ST_ATOM_DENOM}; + + +#[test] +fn test_instantiate_happy() { + let suite = SuiteBuilder::default() + .build(); + + suite.assert_clock_address(Addr::unchecked(DEFAULT_CLOCK_ADDRESS)); + suite.assert_native_atom_receiver(WeightedReceiver { + amount: DEFAULT_RECEIVER_AMOUNT, + address: NATIVE_ATOM_DENOM.to_string(), + }); + suite.assert_stride_atom_receiver(WeightedReceiver { + amount: DEFAULT_RECEIVER_AMOUNT, + address: ST_ATOM_DENOM.to_string(), + }); +} \ No newline at end of file From 2b4af6862f72efd39f168363e4254e6a3d2ac812 Mon Sep 17 00:00:00 2001 From: bekauz Date: Mon, 5 Jun 2023 22:55:03 +0200 Subject: [PATCH 02/20] wip: ICA creation; tick logic --- stride-covenant/Cargo.lock | 284 +++++++++++++++++- stride-covenant/Cargo.toml | 4 +- stride-covenant/packages/depositor/Cargo.toml | 6 +- .../packages/depositor/src/contract.rs | 101 ++++++- .../packages/depositor/src/state.rs | 9 +- .../packages/depositor/src/tests/suite.rs | 1 + 6 files changed, 388 insertions(+), 17 deletions(-) diff --git a/stride-covenant/Cargo.lock b/stride-covenant/Cargo.lock index c86bafa6..e59bdf7f 100644 --- a/stride-covenant/Cargo.lock +++ b/stride-covenant/Cargo.lock @@ -19,6 +19,12 @@ version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "base16ct" version = "0.1.1" @@ -31,12 +37,24 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5" + [[package]] name = "base64ct" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + [[package]] name = "block-buffer" version = "0.9.0" @@ -66,6 +84,9 @@ name = "bytes" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +dependencies = [ + "serde", +] [[package]] name = "cfg-if" @@ -79,6 +100,28 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" +[[package]] +name = "cosmos-sdk-proto" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ca04d3795c18023c221a2143b29de9c70668ecb22d17783bc02ee780c6c404" +dependencies = [ + "prost 0.10.4", + "prost-types 0.10.1", + "tendermint-proto 0.23.7", +] + +[[package]] +name = "cosmos-sdk-proto" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4776e787b24d9568dd61d3237eeb4eb321d622fb881b858c7b82806420e87d4" +dependencies = [ + "prost 0.11.9", + "prost-types 0.11.9", + "tendermint-proto 0.27.0", +] + [[package]] name = "cosmwasm-crypto" version = "1.2.5" @@ -131,7 +174,7 @@ version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a49b85345e811c8e80ec55d0d091e4fcb4f00f97ab058f9be5f614c444a730cb" dependencies = [ - "base64", + "base64 0.13.1", "cosmwasm-crypto", "cosmwasm-derive", "derivative", @@ -139,7 +182,7 @@ dependencies = [ "hex", "schemars", "serde", - "serde-json-wasm", + "serde-json-wasm 0.5.1", "sha2 0.10.6", "thiserror", "uint", @@ -208,7 +251,7 @@ dependencies = [ "derivative", "itertools", "k256", - "prost", + "prost 0.9.0", "schemars", "serde", "thiserror", @@ -363,6 +406,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "flex-error" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c606d892c9de11507fa0dcffc116434f94e105d0bbdc4e405b61519464c49d7b" +dependencies = [ + "paste", +] + [[package]] name = "forward_ref" version = "1.0.0" @@ -458,6 +510,46 @@ version = "0.2.145" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc86cde3ff845662b8f4ef6cb50ea0e20c524eb3d29ae048287e06a1b3fa6a81" +[[package]] +name = "neutron-sdk" +version = "0.5.0" +source = "git+https://github.com/neutron-org/neutron-sdk#3841c59b765004de87496850b77bc4b2e7464d18" +dependencies = [ + "base64 0.20.0", + "bech32", + "cosmos-sdk-proto 0.16.0", + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus", + "prost 0.11.9", + "protobuf", + "schemars", + "serde", + "serde-json-wasm 0.4.1", + "serde_json", + "thiserror", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + [[package]] name = "once_cell" version = "1.18.0" @@ -470,6 +562,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "paste" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" + [[package]] name = "pkcs8" version = "0.9.0" @@ -496,7 +594,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.9.0", +] + +[[package]] +name = "prost" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71adf41db68aa0daaefc69bb30bcd68ded9b9abaad5d1fbb6304c4fb390e083e" +dependencies = [ + "bytes", + "prost-derive 0.10.1", +] + +[[package]] +name = "prost" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +dependencies = [ + "bytes", + "prost-derive 0.11.9", ] [[package]] @@ -512,6 +630,72 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "prost-derive" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b670f45da57fb8542ebdbb6105a925fe571b67f9e7ed9f47a06a84e72b4e7cc" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "prost-derive" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "prost-types" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d0a014229361011dc8e69c8a1ec6c2e8d0f2af7c91e3ea3f5b2170298461e68" +dependencies = [ + "bytes", + "prost 0.10.4", +] + +[[package]] +name = "prost-types" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +dependencies = [ + "prost 0.11.9", +] + +[[package]] +name = "protobuf" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55bad9126f378a853655831eb7363b7b01b81d19f8cb1218861086ca4a1a61e" +dependencies = [ + "bytes", + "once_cell", + "protobuf-support", + "thiserror", +] + +[[package]] +name = "protobuf-support" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d4d7b8601c814cfb36bcebb79f0e61e45e1e93640cf778837833bbed05c372" +dependencies = [ + "thiserror", +] + [[package]] name = "quote" version = "1.0.28" @@ -606,6 +790,15 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-json-wasm" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479b4dbc401ca13ee8ce902851b834893251404c4f3c65370a49e047a6be09a5" +dependencies = [ + "serde", +] + [[package]] name = "serde-json-wasm" version = "0.5.1" @@ -615,6 +808,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_bytes" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294" +dependencies = [ + "serde", +] + [[package]] name = "serde_derive" version = "1.0.163" @@ -702,11 +904,15 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" name = "stride-depositor" version = "0.0.1" dependencies = [ + "cosmos-sdk-proto 0.12.3", "cosmwasm-schema", "cosmwasm-std", "cw-multi-test", "cw-storage-plus", "cw2", + "neutron-sdk", + "protobuf", + "schemars", "serde", "thiserror", ] @@ -717,6 +923,15 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +[[package]] +name = "subtle-encoding" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcb1ed7b8330c5eed5441052651dd7a12c75e2ed88f2ec024ae1fa3a5e59945" +dependencies = [ + "zeroize", +] + [[package]] name = "syn" version = "1.0.109" @@ -739,6 +954,42 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tendermint-proto" +version = "0.23.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71f925d74903f4abbdc4af0110635a307b3cb05b175fdff4a7247c14a4d0874" +dependencies = [ + "bytes", + "flex-error", + "num-derive", + "num-traits", + "prost 0.10.4", + "prost-types 0.10.1", + "serde", + "serde_bytes", + "subtle-encoding", + "time", +] + +[[package]] +name = "tendermint-proto" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5895470f28c530f8ae8c4071bf8190304ce00bd131d25e81730453124a3375c" +dependencies = [ + "bytes", + "flex-error", + "num-derive", + "num-traits", + "prost 0.11.9", + "prost-types 0.11.9", + "serde", + "serde_bytes", + "subtle-encoding", + "time", +] + [[package]] name = "thiserror" version = "1.0.40" @@ -759,6 +1010,31 @@ dependencies = [ "syn 2.0.18", ] +[[package]] +name = "time" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc" +dependencies = [ + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" + +[[package]] +name = "time-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +dependencies = [ + "time-core", +] + [[package]] name = "typenum" version = "1.16.0" diff --git a/stride-covenant/Cargo.toml b/stride-covenant/Cargo.toml index 68785c9c..47f935d8 100644 --- a/stride-covenant/Cargo.toml +++ b/stride-covenant/Cargo.toml @@ -26,7 +26,9 @@ cosmwasm-std = { version = "1.2.4", features = ["ibc3"] } cw-storage-plus = "1.0.1" cw-utils = "1.0.1" cw2 = "1.0.1" - +neutron-sdk = { git = "https://github.com/neutron-org/neutron-sdk", default-features = false, version = "0.5.0" } +cosmos-sdk-proto = { version = "0.12.2", default-features = false } +protobuf = { version = "3", features = ["with-bytes"] } serde = { version = "1.0.145", default-features = false, features = ["derive"] } thiserror = "1.0.31" # the sha2 version here is the same as the one used by diff --git a/stride-covenant/packages/depositor/Cargo.toml b/stride-covenant/packages/depositor/Cargo.toml index fe2b9af5..319b4d78 100644 --- a/stride-covenant/packages/depositor/Cargo.toml +++ b/stride-covenant/packages/depositor/Cargo.toml @@ -13,4 +13,8 @@ cw-storage-plus = { workspace = true } serde = { workspace = true } cw2 = { workspace = true } thiserror = { workspace = true } -cw-multi-test = { workspace = true } \ No newline at end of file +cw-multi-test = { workspace = true } +neutron-sdk = { workspace = true } +cosmos-sdk-proto = { workspace = true } +protobuf = { workspace = true } +schemars = "0.8.10" \ No newline at end of file diff --git a/stride-covenant/packages/depositor/src/contract.rs b/stride-covenant/packages/depositor/src/contract.rs index 1db3bcaf..82525aee 100644 --- a/stride-covenant/packages/depositor/src/contract.rs +++ b/stride-covenant/packages/depositor/src/contract.rs @@ -1,21 +1,38 @@ - use cw2::set_contract_version; -use cosmwasm_std::{entry_point, DepsMut, Env, MessageInfo, Response, Deps, StdResult, Binary, to_binary, Addr}; +use cosmwasm_std::{entry_point, DepsMut, Env, MessageInfo, Response, Deps, StdResult, Binary, to_binary, StdError}; +use neutron_sdk::{NeutronResult, NeutronError}; +use neutron_sdk::bindings::msg::NeutronMsg; +use neutron_sdk::interchain_txs::helpers::get_port_id; +use serde::{Serialize, Deserialize}; +use schemars::JsonSchema; use crate::msg::{InstantiateMsg, ExecuteMsg, QueryMsg}; -use crate::error::ContractError; -use crate::state::{STRIDE_ATOM_RECEIVER, CLOCK_ADDRESS, NATIVE_ATOM_RECEIVER}; +use crate::state::{STRIDE_ATOM_RECEIVER, CLOCK_ADDRESS, NATIVE_ATOM_RECEIVER, INTERCHAIN_ACCOUNTS, ICS_PORT_ID}; + +// Default timeout for SubmitTX is two weeks +const DEFAULT_TIMEOUT_SECONDS: u64 = 60 * 60 * 24 * 7 * 2; const CONTRACT_NAME: &str = "crates.io:stride-depositor"; const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +struct OpenAckVersion { + version: String, + controller_connection_id: String, + host_connection_id: String, + address: String, + encoding: String, + tx_type: String, +} + #[cfg_attr(not(feature = "library"), entry_point)] pub fn instantiate( deps: DepsMut, _env: Env, info: MessageInfo, msg: InstantiateMsg, -) -> Result { +) -> NeutronResult> { set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; // can we do better with validation here? @@ -31,7 +48,9 @@ pub fn instantiate( // avoid zero deposit configurations if msg.st_atom_receiver.amount.is_zero() || msg.atom_receiver.amount.is_zero() { - return Err(ContractError::ZeroDeposit {}) + return Err(NeutronError::Std( + StdError::GenericErr { msg: "Zero deposit config".to_string() }) + ) } // store the denominations and amounts @@ -50,11 +69,75 @@ pub fn execute( env: Env, info: MessageInfo, msg: ExecuteMsg, -) -> Result { +) -> NeutronResult> { match msg { - ExecuteMsg::Tick {} => todo!(), - ExecuteMsg::Received {} => todo!(), + ExecuteMsg::Tick {} => try_tick(deps, env, info), + ExecuteMsg::Received {} => try_handle_received(), } +} + +fn try_tick(deps: DepsMut, env: Env, info: MessageInfo) -> NeutronResult> { + // retrieve the existing interchain account (s?) + let gaia_key = ICS_PORT_ID.load(deps.storage)?; + let gaia_interchain_account = INTERCHAIN_ACCOUNTS.load( + deps.as_ref().storage, + gaia_key + )?; + match gaia_interchain_account { + // if it's the first tick and no ica exist, create an ica + None => try_register_gaia_ica(deps, env), + // with an existing ica, proceed to transfers + Some((_, gaia_account_address) + ) => try_execute_transfers(deps, info, gaia_account_address), + } +} + +fn try_register_gaia_ica( + deps: DepsMut, + env: Env, +) -> NeutronResult> { + // store the account identifier + let gaia_acc_id = "gaia-acc"; + // or channel-0.. + let ics_connection_id = "channel-1"; + // register the ica + let register = NeutronMsg::register_interchain_account( + ics_connection_id.to_string(), + gaia_acc_id.to_string() + ); + + // Get the IBC port identifier generated by Neutron for the new interchain account. + let key = get_port_id(env.contract.address.as_str(), &gaia_acc_id); + ICS_PORT_ID.save(deps.storage, &key)?; + // Add an incomplete entry for the new account to the storage. + INTERCHAIN_ACCOUNTS.save(deps.storage, key, &None)?; + Ok(Response::new().add_message(register)) +} + +fn try_execute_transfers( + deps: DepsMut, + info: MessageInfo, + gaia_account_address: String +) -> NeutronResult> { + // validate that tick was triggered by the authorized clock + let clock = CLOCK_ADDRESS.load(deps.as_ref().storage)?; + if info.sender != clock { + return Err(NeutronError::Std( + StdError::GenericErr { msg: "Unauthorized".to_string() }) + ) + } + + let stride_atom_receiver = STRIDE_ATOM_RECEIVER.load(deps.storage)?; + let native_atom_receiver = NATIVE_ATOM_RECEIVER.load(deps.storage)?; + + // receiving a tick means depositor is ready to attempt to: + // 1. transfer 1/2 of atoms to liquid-staker module + // 2. transfer 1/2 of atoms from ICA to liquidity-pooler module + + Ok(Response::default()) +} + +fn try_handle_received() -> NeutronResult> { Ok(Response::default()) } diff --git a/stride-covenant/packages/depositor/src/state.rs b/stride-covenant/packages/depositor/src/state.rs index c62e9498..9a6fe809 100644 --- a/stride-covenant/packages/depositor/src/state.rs +++ b/stride-covenant/packages/depositor/src/state.rs @@ -1,13 +1,18 @@ use cosmwasm_std::Addr; -use cw_storage_plus::Item; +use cw_storage_plus::{Item, Map}; use crate::msg::WeightedReceiver; // addr and amount of atom to liquid stake on stride pub const STRIDE_ATOM_RECEIVER: Item = Item::new("stride_atom_receiver"); + // addr and amount of atom pub const NATIVE_ATOM_RECEIVER: Item = Item::new("native_atom_receiver"); + // store the clock address to verify calls pub const CLOCK_ADDRESS: Item = Item::new("clock_address"); - +// ICA +pub const INTERCHAIN_ACCOUNTS: Map> = + Map::new("interchain_accounts"); +pub const ICS_PORT_ID: Item = Item::new("ics_port_id"); \ No newline at end of file diff --git a/stride-covenant/packages/depositor/src/tests/suite.rs b/stride-covenant/packages/depositor/src/tests/suite.rs index ae453de4..9b18a7be 100644 --- a/stride-covenant/packages/depositor/src/tests/suite.rs +++ b/stride-covenant/packages/depositor/src/tests/suite.rs @@ -15,6 +15,7 @@ fn depositor_contract() -> Box> { crate::contract::instantiate, crate::contract::query, ); + // todo Box::new(contract) } From e395199759c575cc023430633557ab9cc8b78cd5 Mon Sep 17 00:00:00 2001 From: bekauz Date: Tue, 6 Jun 2023 18:04:59 +0200 Subject: [PATCH 03/20] justfile updates; attempt to instantiate depositor --- .../packages/depositor/.cargo/config | 6 + stride-covenant/packages/depositor/Cargo.toml | 89 +++- .../packages/depositor/examples/schema.rs | 22 + .../depositor/schema/execute_msg.json | 32 ++ .../depositor/schema/instantiate_msg.json | 48 +++ ...y_interchain_account_address_response.json | 14 + .../packages/depositor/schema/query_msg.json | 45 ++ .../packages/depositor/schema/sudo_msg.json | 269 ++++++++++++ .../packages/depositor/src/contract.rs | 385 +++++++++++++++++- stride-covenant/packages/depositor/src/lib.rs | 4 + stride-covenant/packages/depositor/src/msg.rs | 6 +- .../packages/depositor/src/state.rs | 83 +++- .../packages/depositor/src/tests/suite.rs | 22 +- 13 files changed, 980 insertions(+), 45 deletions(-) create mode 100644 stride-covenant/packages/depositor/.cargo/config create mode 100644 stride-covenant/packages/depositor/examples/schema.rs create mode 100644 stride-covenant/packages/depositor/schema/execute_msg.json create mode 100644 stride-covenant/packages/depositor/schema/instantiate_msg.json create mode 100644 stride-covenant/packages/depositor/schema/query_interchain_account_address_response.json create mode 100644 stride-covenant/packages/depositor/schema/query_msg.json create mode 100644 stride-covenant/packages/depositor/schema/sudo_msg.json diff --git a/stride-covenant/packages/depositor/.cargo/config b/stride-covenant/packages/depositor/.cargo/config new file mode 100644 index 00000000..1e91742c --- /dev/null +++ b/stride-covenant/packages/depositor/.cargo/config @@ -0,0 +1,6 @@ +[alias] +wasm = "build --release --target wasm32-unknown-unknown" +wasm-debug = "build --target wasm32-unknown-unknown" +unit-test = "test --lib --features backtraces" +integration-test = "test --test integration" +schema = "run --example schema" \ No newline at end of file diff --git a/stride-covenant/packages/depositor/Cargo.toml b/stride-covenant/packages/depositor/Cargo.toml index 319b4d78..4cd7779e 100644 --- a/stride-covenant/packages/depositor/Cargo.toml +++ b/stride-covenant/packages/depositor/Cargo.toml @@ -1,20 +1,83 @@ [package] name = "stride-depositor" version = "0.0.1" -edition = "2021" +edition = "2021" authors = ["benskey bekauz@protonmail.com"] description = "Depositor module for stride covenant" -license = { workspace = true } +license = "BSD-3" + +exclude = [ + "contract.wasm", + "hash.txt", +] + +[lib] +crate-type = ["cdylib", "rlib"] + +[profile.release] +opt-level = 3 +debug = false +rpath = false +lto = true +debug-assertions = false +codegen-units = 1 +panic = 'abort' +incremental = false +overflow-checks = true + +[features] +# for more explicit tests, cargo test --features=backtraces +backtraces = ["cosmwasm-std/backtraces"] +library = [] [dependencies] -cosmwasm-schema = { workspace = true } -cosmwasm-std = { workspace = true } -cw-storage-plus = { workspace = true } -serde = { workspace = true } -cw2 = { workspace = true } -thiserror = { workspace = true } -cw-multi-test = { workspace = true } -neutron-sdk = { workspace = true } -cosmos-sdk-proto = { workspace = true } -protobuf = { workspace = true } -schemars = "0.8.10" \ No newline at end of file +cosmwasm-schema = "1.2.1" +cosmwasm-std = { version = "1.2.4", features = ["ibc3"] } +cw-storage-plus = "1.0.1" +cw-utils = "1.0.1" +cw2 = "1.0.1" +serde = { version = "1.0.145", default-features = false, features = ["derive"] } +thiserror = "1.0.31" +# the sha2 version here is the same as the one used by +# cosmwasm-std. when bumping cosmwasm-std, this should also be +# updated. to find cosmwasm_std's sha function: +# ```cargo tree --package cosmwasm-std``` +sha2 = "0.10.6" +neutron-sdk = { git = "https://github.com/neutron-org/neutron-sdk", default-features = false, version = "0.5.0" } +cosmos-sdk-proto = { version = "0.14.0", default-features = false } +protobuf = { version = "3.2.0", features = ["with-bytes"] } +schemars = "0.8.10" +serde-json-wasm = { version = "0.4.1" } +base64 = "0.13.0" +prost = "0.11" +prost-types = "0.11" +bech32 = "0.9.0" + +# cosmwasm-schema = { workspace = true } +# cosmwasm-std = { workspace = true } +# cw-storage-plus = { workspace = true } +# serde = { workspace = true } +# cw2 = { workspace = true } +# thiserror = { workspace = true } +# cw-multi-test = { workspace = true } +# neutron-sdk = { workspace = true } +# cosmos-sdk-proto = { workspace = true } +# protobuf = { workspace = true } +# schemars = { workspace = true } +# prost = { workspace = true } +# prost-types = { workspace = true } +# serde-json-wasm = { workspace = true } + + +# # the sha2 version here is the same as the one used by +# # cosmwasm-std. when bumping cosmwasm-std, this should also be +# # updated. to find cosmwasm_std's sha function: +# # ```cargo tree --package cosmwasm-std``` +# sha2 = { workspace = true } + +# dev-dependencies +[dev-dependencies] +cw-multi-test = "0.16.2" +anyhow = { version = "1.0.51" } +# cw-multi-test = { workspace = true } +# anyhow = { workspace = true } diff --git a/stride-covenant/packages/depositor/examples/schema.rs b/stride-covenant/packages/depositor/examples/schema.rs new file mode 100644 index 00000000..29d4265e --- /dev/null +++ b/stride-covenant/packages/depositor/examples/schema.rs @@ -0,0 +1,22 @@ +use cosmwasm_schema::{export_schema, remove_schemas, schema_for}; +use stride_depositor::msg::{InstantiateMsg, ExecuteMsg, QueryMsg}; +use neutron_sdk::bindings::query::QueryInterchainAccountAddressResponse; +use neutron_sdk::sudo::msg::SudoMsg; +use std::env::current_dir; +use std::fs::create_dir_all; + +fn main() { + let mut out_dir = current_dir().unwrap(); + out_dir.push("schema"); + create_dir_all(&out_dir).unwrap(); + remove_schemas(&out_dir).unwrap(); + + export_schema(&schema_for!(InstantiateMsg), &out_dir); + export_schema(&schema_for!(SudoMsg), &out_dir); + export_schema(&schema_for!(QueryMsg), &out_dir); + export_schema(&schema_for!(ExecuteMsg), &out_dir); + export_schema( + &schema_for!(QueryInterchainAccountAddressResponse), + &out_dir, + ); +} \ No newline at end of file diff --git a/stride-covenant/packages/depositor/schema/execute_msg.json b/stride-covenant/packages/depositor/schema/execute_msg.json new file mode 100644 index 00000000..43ee8861 --- /dev/null +++ b/stride-covenant/packages/depositor/schema/execute_msg.json @@ -0,0 +1,32 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "type": "object", + "required": [ + "tick" + ], + "properties": { + "tick": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "received" + ], + "properties": { + "received": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] +} diff --git a/stride-covenant/packages/depositor/schema/instantiate_msg.json b/stride-covenant/packages/depositor/schema/instantiate_msg.json new file mode 100644 index 00000000..1dc0445e --- /dev/null +++ b/stride-covenant/packages/depositor/schema/instantiate_msg.json @@ -0,0 +1,48 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "InstantiateMsg", + "type": "object", + "required": [ + "atom_receiver", + "clock_address", + "st_atom_receiver" + ], + "properties": { + "atom_receiver": { + "$ref": "#/definitions/WeightedReceiver" + }, + "clock_address": { + "$ref": "#/definitions/Addr" + }, + "st_atom_receiver": { + "$ref": "#/definitions/WeightedReceiver" + } + }, + "additionalProperties": false, + "definitions": { + "Addr": { + "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", + "type": "string" + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + }, + "WeightedReceiver": { + "type": "object", + "required": [ + "address", + "amount" + ], + "properties": { + "address": { + "type": "string" + }, + "amount": { + "$ref": "#/definitions/Uint128" + } + }, + "additionalProperties": false + } + } +} diff --git a/stride-covenant/packages/depositor/schema/query_interchain_account_address_response.json b/stride-covenant/packages/depositor/schema/query_interchain_account_address_response.json new file mode 100644 index 00000000..acc40bcc --- /dev/null +++ b/stride-covenant/packages/depositor/schema/query_interchain_account_address_response.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "QueryInterchainAccountAddressResponse", + "type": "object", + "required": [ + "interchain_account_address" + ], + "properties": { + "interchain_account_address": { + "description": "*interchain_account_address** is a interchain account address on the remote chain", + "type": "string" + } + } +} diff --git a/stride-covenant/packages/depositor/schema/query_msg.json b/stride-covenant/packages/depositor/schema/query_msg.json new file mode 100644 index 00000000..17f885d0 --- /dev/null +++ b/stride-covenant/packages/depositor/schema/query_msg.json @@ -0,0 +1,45 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "QueryMsg", + "oneOf": [ + { + "type": "object", + "required": [ + "st_atom_receiver" + ], + "properties": { + "st_atom_receiver": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "atom_receiver" + ], + "properties": { + "atom_receiver": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "clock_address" + ], + "properties": { + "clock_address": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] +} diff --git a/stride-covenant/packages/depositor/schema/sudo_msg.json b/stride-covenant/packages/depositor/schema/sudo_msg.json new file mode 100644 index 00000000..92582ab6 --- /dev/null +++ b/stride-covenant/packages/depositor/schema/sudo_msg.json @@ -0,0 +1,269 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "SudoMsg", + "oneOf": [ + { + "type": "object", + "required": [ + "response" + ], + "properties": { + "response": { + "type": "object", + "required": [ + "data", + "request" + ], + "properties": { + "data": { + "$ref": "#/definitions/Binary" + }, + "request": { + "$ref": "#/definitions/RequestPacket" + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "object", + "required": [ + "details", + "request" + ], + "properties": { + "details": { + "type": "string" + }, + "request": { + "$ref": "#/definitions/RequestPacket" + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "timeout" + ], + "properties": { + "timeout": { + "type": "object", + "required": [ + "request" + ], + "properties": { + "request": { + "$ref": "#/definitions/RequestPacket" + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "open_ack" + ], + "properties": { + "open_ack": { + "type": "object", + "required": [ + "channel_id", + "counterparty_channel_id", + "counterparty_version", + "port_id" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "counterparty_channel_id": { + "type": "string" + }, + "counterparty_version": { + "type": "string" + }, + "port_id": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "tx_query_result" + ], + "properties": { + "tx_query_result": { + "type": "object", + "required": [ + "data", + "height", + "query_id" + ], + "properties": { + "data": { + "$ref": "#/definitions/Binary" + }, + "height": { + "$ref": "#/definitions/Height" + }, + "query_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "kv_query_result" + ], + "properties": { + "kv_query_result": { + "type": "object", + "required": [ + "query_id" + ], + "properties": { + "query_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + } + ], + "definitions": { + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", + "type": "string" + }, + "Height": { + "type": "object", + "properties": { + "revision_height": { + "description": "*height** is a height of remote chain", + "default": 0, + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "revision_number": { + "description": "the revision that the client is currently on", + "default": 0, + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + "RequestPacket": { + "type": "object", + "properties": { + "data": { + "anyOf": [ + { + "$ref": "#/definitions/Binary" + }, + { + "type": "null" + } + ] + }, + "destination_channel": { + "type": [ + "string", + "null" + ] + }, + "destination_port": { + "type": [ + "string", + "null" + ] + }, + "sequence": { + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "source_channel": { + "type": [ + "string", + "null" + ] + }, + "source_port": { + "type": [ + "string", + "null" + ] + }, + "timeout_height": { + "anyOf": [ + { + "$ref": "#/definitions/RequestPacketTimeoutHeight" + }, + { + "type": "null" + } + ] + }, + "timeout_timestamp": { + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + } + } + }, + "RequestPacketTimeoutHeight": { + "type": "object", + "properties": { + "revision_height": { + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "revision_number": { + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + } + } + } + } +} diff --git a/stride-covenant/packages/depositor/src/contract.rs b/stride-covenant/packages/depositor/src/contract.rs index 82525aee..f0990adc 100644 --- a/stride-covenant/packages/depositor/src/contract.rs +++ b/stride-covenant/packages/depositor/src/contract.rs @@ -1,16 +1,19 @@ +use cosmos_sdk_proto::cosmos::staking::v1beta1::{MsgDelegateResponse, MsgUndelegateResponse}; use cw2::set_contract_version; -use cosmwasm_std::{entry_point, DepsMut, Env, MessageInfo, Response, Deps, StdResult, Binary, to_binary, StdError}; +use cosmwasm_std::{entry_point, DepsMut, Env, MessageInfo, Response, Deps, StdResult, Binary, to_binary, StdError, CosmosMsg, SubMsg, Reply, CustomQuery}; +use neutron_sdk::bindings::query::NeutronQuery; +use neutron_sdk::sudo::msg::{SudoMsg, RequestPacket}; use neutron_sdk::{NeutronResult, NeutronError}; -use neutron_sdk::bindings::msg::NeutronMsg; -use neutron_sdk::interchain_txs::helpers::get_port_id; +use neutron_sdk::bindings::msg::{NeutronMsg, MsgSubmitTxResponse, IbcFee}; +use neutron_sdk::interchain_txs::helpers::{get_port_id, decode_message_response, decode_acknowledgement_response}; use serde::{Serialize, Deserialize}; use schemars::JsonSchema; - use crate::msg::{InstantiateMsg, ExecuteMsg, QueryMsg}; -use crate::state::{STRIDE_ATOM_RECEIVER, CLOCK_ADDRESS, NATIVE_ATOM_RECEIVER, INTERCHAIN_ACCOUNTS, ICS_PORT_ID}; +use crate::state::{STRIDE_ATOM_RECEIVER, CLOCK_ADDRESS, NATIVE_ATOM_RECEIVER, INTERCHAIN_ACCOUNTS, ICS_PORT_ID, AcknowledgementResult, ACKNOWLEDGEMENT_RESULTS, read_sudo_payload, add_error_to_queue, SudoPayload, save_reply_payload, SUDO_PAYLOAD_REPLY_ID, read_reply_payload, save_sudo_payload}; // Default timeout for SubmitTX is two weeks const DEFAULT_TIMEOUT_SECONDS: u64 = 60 * 60 * 24 * 7 * 2; +const FEE_DENOM: &str = "untrn"; const CONTRACT_NAME: &str = "crates.io:stride-depositor"; const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -36,18 +39,14 @@ pub fn instantiate( set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; // can we do better with validation here? - deps.api.addr_validate(&msg.st_atom_receiver.address)?; - deps.api.addr_validate(&msg.atom_receiver.address)?; - - // TODO: consider re-enabling - // let clock_contract = deps.querier.query_wasm_contract_info(msg.clock_address.to_string())?; - // // clock should already exist, and be instantiated by the same covenant contract - // if Addr::unchecked(clock_contract.creator) != info.sender { - // return Err(ContractError::InstantiatorMissmatch {}) - // } + let st_atom_receiver_address = deps.api.addr_validate(&msg.st_atom_receiver.address)?; + let atom_receiver_address = deps.api.addr_validate(&msg.atom_receiver.address)?; + let clock_address = deps.api.addr_validate(&msg.clock_address)?; + // TODO: consider validating that clock should already exist, + // and be instantiated by the same covenant contract // avoid zero deposit configurations - if msg.st_atom_receiver.amount.is_zero() || msg.atom_receiver.amount.is_zero() { + if msg.st_atom_receiver.amount == 0 || msg.atom_receiver.amount == 0 { return Err(NeutronError::Std( StdError::GenericErr { msg: "Zero deposit config".to_string() }) ) @@ -58,7 +57,7 @@ pub fn instantiate( NATIVE_ATOM_RECEIVER.save(deps.storage, &msg.atom_receiver)?; // store the clock address that will be authorized to tick - CLOCK_ADDRESS.save(deps.storage, &msg.clock_address)?; + CLOCK_ADDRESS.save(deps.storage, &clock_address)?; Ok(Response::default()) } @@ -77,6 +76,8 @@ pub fn execute( } fn try_tick(deps: DepsMut, env: Env, info: MessageInfo) -> NeutronResult> { + // validate called is clock + // retrieve the existing interchain account (s?) let gaia_key = ICS_PORT_ID.load(deps.storage)?; let gaia_interchain_account = INTERCHAIN_ACCOUNTS.load( @@ -149,4 +150,356 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { QueryMsg::AtomReceiver {} => to_binary(&NATIVE_ATOM_RECEIVER.may_load(deps.storage)?), QueryMsg::ClockAddress {} => to_binary(&CLOCK_ADDRESS.may_load(deps.storage)?), } +} + +// saves payload to process later to the storage and returns a SubmitTX Cosmos SubMsg with necessary reply id +fn msg_with_sudo_callback>, T>( + deps: DepsMut, + msg: C, + payload: SudoPayload, +) -> StdResult> { + save_reply_payload(deps.storage, payload)?; + Ok(SubMsg::reply_on_success(msg, SUDO_PAYLOAD_REPLY_ID)) +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn sudo(deps: DepsMut, env: Env, msg: SudoMsg) -> StdResult { + deps.api + .debug(format!("WASMDEBUG: sudo: received sudo msg: {:?}", msg).as_str()); + + match msg { + // For handling successful (non-error) acknowledgements. + SudoMsg::Response { request, data } => sudo_response(deps, request, data), + + // For handling error acknowledgements. + SudoMsg::Error { request, details } => sudo_error(deps, request, details), + + // For handling error timeouts. + SudoMsg::Timeout { request } => sudo_timeout(deps, env, request), + + // For handling successful registering of ICA + SudoMsg::OpenAck { + port_id, + channel_id, + counterparty_channel_id, + counterparty_version, + } => sudo_open_ack( + deps, + env, + port_id, + channel_id, + counterparty_channel_id, + counterparty_version, + ), + _ => Ok(Response::default()), + } +} + + +// handler +fn sudo_open_ack( + deps: DepsMut, + _env: Env, + port_id: String, + _channel_id: String, + _counterparty_channel_id: String, + counterparty_version: String, +) -> StdResult { + // The version variable contains a JSON value with multiple fields, + // including the generated account address. + let parsed_version: Result = + serde_json_wasm::from_str(counterparty_version.as_str()); + + // Update the storage record associated with the interchain account. + if let Ok(parsed_version) = parsed_version { + INTERCHAIN_ACCOUNTS.save( + deps.storage, + port_id, + &Some(( + parsed_version.address, + parsed_version.controller_connection_id, + )), + )?; + return Ok(Response::default()); + } + Err(StdError::generic_err("Can't parse counterparty_version")) +} + +fn sudo_response(deps: DepsMut, request: RequestPacket, data: Binary) -> StdResult { + deps.api.debug( + format!( + "WASMDEBUG: sudo_response: sudo received: {:?} {:?}", + request, data + ) + .as_str(), + ); + + // WARNING: RETURNING THIS ERROR CLOSES THE CHANNEL. + // AN ALTERNATIVE IS TO MAINTAIN AN ERRORS QUEUE AND PUT THE FAILED REQUEST THERE + // FOR LATER INSPECTION. + // In this particular case, we return an error because not having the sequence id + // in the request value implies that a fatal error occurred on Neutron side. + let seq_id = request + .sequence + .ok_or_else(|| StdError::generic_err("sequence not found"))?; + + // WARNING: RETURNING THIS ERROR CLOSES THE CHANNEL. + // AN ALTERNATIVE IS TO MAINTAIN AN ERRORS QUEUE AND PUT THE FAILED REQUEST THERE + // FOR LATER INSPECTION. + // In this particular case, we return an error because not having the sequence id + // in the request value implies that a fatal error occurred on Neutron side. + let channel_id = request + .source_channel + .ok_or_else(|| StdError::generic_err("channel_id not found"))?; + + // NOTE: NO ERROR IS RETURNED HERE. THE CHANNEL LIVES ON. + // In this particular example, this is a matter of developer's choice. Not being able to read + // the payload here means that there was a problem with the contract while submitting an + // interchain transaction. You can decide that this is not worth killing the channel, + // write an error log and / or save the acknowledgement to an errors queue for later manual + // processing. The decision is based purely on your application logic. + let payload = read_sudo_payload(deps.storage, channel_id, seq_id).ok(); + if payload.is_none() { + let error_msg = "WASMDEBUG: Error: Unable to read sudo payload"; + deps.api.debug(error_msg); + add_error_to_queue(deps.storage, error_msg.to_string()); + return Ok(Response::default()); + } + + deps.api + .debug(format!("WASMDEBUG: sudo_response: sudo payload: {:?}", payload).as_str()); + + // WARNING: RETURNING THIS ERROR CLOSES THE CHANNEL. + // AN ALTERNATIVE IS TO MAINTAIN AN ERRORS QUEUE AND PUT THE FAILED REQUEST THERE + // FOR LATER INSPECTION. + // In this particular case, we return an error because not being able to parse this data + // that a fatal error occurred on Neutron side, or that the remote chain sent us unexpected data. + // Both cases require immediate attention. + let parsed_data = decode_acknowledgement_response(data)?; + + let mut item_types = vec![]; + for item in parsed_data { + let item_type = item.msg_type.as_str(); + item_types.push(item_type.to_string()); + match item_type { + "/cosmos.staking.v1beta1.MsgUndelegate" => { + // WARNING: RETURNING THIS ERROR CLOSES THE CHANNEL. + // AN ALTERNATIVE IS TO MAINTAIN AN ERRORS QUEUE AND PUT THE FAILED REQUEST THERE + // FOR LATER INSPECTION. + // In this particular case, a mismatch between the string message type and the + // serialised data layout looks like a fatal error that has to be investigated. + let out: MsgUndelegateResponse = decode_message_response(&item.data)?; + + // NOTE: NO ERROR IS RETURNED HERE. THE CHANNEL LIVES ON. + // In this particular case, we demonstrate that minor errors should not + // close the channel, and should be treated in a forgiving manner. + let completion_time = out.completion_time.or_else(|| { + let error_msg = "WASMDEBUG: sudo_response: Recoverable error. Failed to get completion time"; + deps.api + .debug(error_msg); + add_error_to_queue(deps.storage, error_msg.to_string()); + Some(prost_types::Timestamp::default()) + }); + deps.api + .debug(format!("Undelegation completion time: {:?}", completion_time).as_str()); + } + "/cosmos.staking.v1beta1.MsgDelegate" => { + // WARNING: RETURNING THIS ERROR CLOSES THE CHANNEL. + // AN ALTERNATIVE IS TO MAINTAIN AN ERRORS QUEUE AND PUT THE FAILED REQUEST THERE + // FOR LATER INSPECTION. + // In this particular case, a mismatch between the string message type and the + // serialised data layout looks like a fatal error that has to be investigated. + let _out: MsgDelegateResponse = decode_message_response(&item.data)?; + } + _ => { + deps.api.debug( + format!( + "This type of acknowledgement is not implemented: {:?}", + payload + ) + .as_str(), + ); + } + } + } + + if let Some(payload) = payload { + // update but also check that we don't update same seq_id twice + ACKNOWLEDGEMENT_RESULTS.update( + deps.storage, + (payload.port_id, seq_id), + |maybe_ack| -> StdResult { + match maybe_ack { + Some(_ack) => Err(StdError::generic_err("trying to update same seq_id")), + None => Ok(AcknowledgementResult::Success(item_types)), + } + }, + )?; + } + + Ok(Response::default()) +} + +fn sudo_timeout(deps: DepsMut, _env: Env, request: RequestPacket) -> StdResult { + deps.api + .debug(format!("WASMDEBUG: sudo timeout request: {:?}", request).as_str()); + + // WARNING: RETURNING THIS ERROR CLOSES THE CHANNEL. + // AN ALTERNATIVE IS TO MAINTAIN AN ERRORS QUEUE AND PUT THE FAILED REQUEST THERE + // FOR LATER INSPECTION. + // In this particular case, we return an error because not having the sequence id + // in the request value implies that a fatal error occurred on Neutron side. + let seq_id = request + .sequence + .ok_or_else(|| StdError::generic_err("sequence not found"))?; + + // WARNING: RETURNING THIS ERROR CLOSES THE CHANNEL. + // AN ALTERNATIVE IS TO MAINTAIN AN ERRORS QUEUE AND PUT THE FAILED REQUEST THERE + // FOR LATER INSPECTION. + // In this particular case, we return an error because not having the sequence id + // in the request value implies that a fatal error occurred on Neutron side. + let channel_id = request + .source_channel + .ok_or_else(|| StdError::generic_err("channel_id not found"))?; + + // update but also check that we don't update same seq_id twice + // NOTE: NO ERROR IS RETURNED HERE. THE CHANNEL LIVES ON. + // In this particular example, this is a matter of developer's choice. Not being able to read + // the payload here means that there was a problem with the contract while submitting an + // interchain transaction. You can decide that this is not worth killing the channel, + // write an error log and / or save the acknowledgement to an errors queue for later manual + // processing. The decision is based purely on your application logic. + // Please be careful because it may lead to an unexpected state changes because state might + // has been changed before this call and will not be reverted because of supressed error. + let payload = read_sudo_payload(deps.storage, channel_id, seq_id).ok(); + if let Some(payload) = payload { + // update but also check that we don't update same seq_id twice + ACKNOWLEDGEMENT_RESULTS.update( + deps.storage, + (payload.port_id, seq_id), + |maybe_ack| -> StdResult { + match maybe_ack { + Some(_ack) => Err(StdError::generic_err("trying to update same seq_id")), + None => Ok(AcknowledgementResult::Timeout(payload.message)), + } + }, + )?; + } else { + let error_msg = "WASMDEBUG: Error: Unable to read sudo payload"; + deps.api.debug(error_msg); + add_error_to_queue(deps.storage, error_msg.to_string()); + } + + Ok(Response::default()) +} + +fn sudo_error(deps: DepsMut, request: RequestPacket, details: String) -> StdResult { + deps.api + .debug(format!("WASMDEBUG: sudo error: {}", details).as_str()); + deps.api + .debug(format!("WASMDEBUG: request packet: {:?}", request).as_str()); + + // WARNING: RETURNING THIS ERROR CLOSES THE CHANNEL. + // AN ALTERNATIVE IS TO MAINTAIN AN ERRORS QUEUE AND PUT THE FAILED REQUEST THERE + // FOR LATER INSPECTION. + // In this particular case, we return an error because not having the sequence id + // in the request value implies that a fatal error occurred on Neutron side. + let seq_id = request + .sequence + .ok_or_else(|| StdError::generic_err("sequence not found"))?; + + // WARNING: RETURNING THIS ERROR CLOSES THE CHANNEL. + // AN ALTERNATIVE IS TO MAINTAIN AN ERRORS QUEUE AND PUT THE FAILED REQUEST THERE + // FOR LATER INSPECTION. + // In this particular case, we return an error because not having the sequence id + // in the request value implies that a fatal error occurred on Neutron side. + let channel_id = request + .source_channel + .ok_or_else(|| StdError::generic_err("channel_id not found"))?; + let payload = read_sudo_payload(deps.storage, channel_id, seq_id).ok(); + + if let Some(payload) = payload { + // update but also check that we don't update same seq_id twice + ACKNOWLEDGEMENT_RESULTS.update( + deps.storage, + (payload.port_id, seq_id), + |maybe_ack| -> StdResult { + match maybe_ack { + Some(_ack) => Err(StdError::generic_err("trying to update same seq_id")), + None => Ok(AcknowledgementResult::Error((payload.message, details))), + } + }, + )?; + } else { + let error_msg = "WASMDEBUG: Error: Unable to read sudo payload"; + deps.api.debug(error_msg); + add_error_to_queue(deps.storage, error_msg.to_string()); + } + + Ok(Response::default()) +} + +// prepare_sudo_payload is called from reply handler +// The method is used to extract sequence id and channel from SubmitTxResponse to process sudo payload defined in msg_with_sudo_callback later in Sudo handler. +// Such flow msg_with_sudo_callback() -> reply() -> prepare_sudo_payload() -> sudo() allows you "attach" some payload to your SubmitTx message +// and process this payload when an acknowledgement for the SubmitTx message is received in Sudo handler +fn prepare_sudo_payload(mut deps: DepsMut, _env: Env, msg: Reply) -> StdResult { + let payload = read_reply_payload(deps.storage)?; + let resp: MsgSubmitTxResponse = serde_json_wasm::from_slice( + msg.result + .into_result() + .map_err(StdError::generic_err)? + .data + .ok_or_else(|| StdError::generic_err("no result"))? + .as_slice(), + ) + .map_err(|e| StdError::generic_err(format!("failed to parse response: {:?}", e)))?; + deps.api + .debug(format!("WASMDEBUG: reply msg: {:?}", resp).as_str()); + let seq_id = resp.sequence_id; + let channel_id = resp.channel; + save_sudo_payload(deps.branch().storage, channel_id, seq_id, payload)?; + Ok(Response::new()) +} + + +fn get_ica( + deps: Deps, + env: &Env, + interchain_account_id: &str, +) -> Result<(String, String), StdError> { + let key = get_port_id(env.contract.address.as_str(), interchain_account_id); + + INTERCHAIN_ACCOUNTS + .load(deps.storage, key)? + .ok_or_else(|| StdError::generic_err("Interchain account is not created yet")) +} + +#[entry_point] +pub fn reply(deps: DepsMut, env: Env, msg: Reply) -> StdResult { + deps.api + .debug(format!("WASMDEBUG: reply msg: {:?}", msg).as_str()); + match msg.id { + SUDO_PAYLOAD_REPLY_ID => prepare_sudo_payload(deps, env, msg), + _ => Err(StdError::generic_err(format!( + "unsupported reply message id {}", + msg.id + ))), + } +} + +fn min_ntrn_ibc_fee(fee: IbcFee) -> IbcFee { + IbcFee { + recv_fee: fee.recv_fee, + ack_fee: fee + .ack_fee + .into_iter() + .filter(|a| a.denom == FEE_DENOM) + .collect(), + timeout_fee: fee + .timeout_fee + .into_iter() + .filter(|a| a.denom == FEE_DENOM) + .collect(), + } } \ No newline at end of file diff --git a/stride-covenant/packages/depositor/src/lib.rs b/stride-covenant/packages/depositor/src/lib.rs index 565bd28d..4fe4610d 100644 --- a/stride-covenant/packages/depositor/src/lib.rs +++ b/stride-covenant/packages/depositor/src/lib.rs @@ -1,3 +1,7 @@ +#![warn(clippy::unwrap_used, clippy::expect_used)] + +extern crate core; + pub mod contract; pub mod error; pub mod msg; diff --git a/stride-covenant/packages/depositor/src/msg.rs b/stride-covenant/packages/depositor/src/msg.rs index 17fdc701..d6d0fb00 100644 --- a/stride-covenant/packages/depositor/src/msg.rs +++ b/stride-covenant/packages/depositor/src/msg.rs @@ -5,7 +5,7 @@ use cosmwasm_std::{Uint128, Addr}; pub struct InstantiateMsg { pub st_atom_receiver: WeightedReceiver, pub atom_receiver: WeightedReceiver, - pub clock_address: Addr, + pub clock_address: String, } #[cw_serde] @@ -23,7 +23,7 @@ pub enum QueryMsg { #[cw_serde] pub struct WeightedReceiver { - pub amount: Uint128, - pub address: String, + pub amount: u128, + pub address: String, } diff --git a/stride-covenant/packages/depositor/src/state.rs b/stride-covenant/packages/depositor/src/state.rs index 9a6fe809..4f50dff1 100644 --- a/stride-covenant/packages/depositor/src/state.rs +++ b/stride-covenant/packages/depositor/src/state.rs @@ -1,5 +1,7 @@ -use cosmwasm_std::Addr; +use cosmwasm_std::{Addr, Binary, from_binary, Storage, StdResult, to_vec, Order}; use cw_storage_plus::{Item, Map}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; use crate::msg::WeightedReceiver; @@ -15,4 +17,81 @@ pub const CLOCK_ADDRESS: Item = Item::new("clock_address"); // ICA pub const INTERCHAIN_ACCOUNTS: Map> = Map::new("interchain_accounts"); -pub const ICS_PORT_ID: Item = Item::new("ics_port_id"); \ No newline at end of file +pub const ICS_PORT_ID: Item = Item::new("ics_port_id"); + + +/// SudoPayload is a type that stores information about a transaction that we try to execute +/// on the host chain. This is a type introduced for our convenience. +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub struct SudoPayload { + pub message: String, + pub port_id: String, +} + +pub const SUDO_PAYLOAD_REPLY_ID: u64 = 1; + +pub const REPLY_ID_STORAGE: Item> = Item::new("reply_queue_id"); +pub const SUDO_PAYLOAD: Map<(String, u64), Vec> = Map::new("sudo_payload"); + +// interchain transaction responses - ack/err/timeout state to query later +pub const ACKNOWLEDGEMENT_RESULTS: Map<(String, u64), AcknowledgementResult> = + Map::new("acknowledgement_results"); + +pub const ERRORS_QUEUE: Map = Map::new("errors_queue"); + +/// Serves for storing acknowledgement calls for interchain transactions +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, JsonSchema, Debug)] +#[serde(rename_all = "snake_case")] +pub enum AcknowledgementResult { + /// Success - Got success acknowledgement in sudo with array of message item types in it + Success(Vec), + /// Error - Got error acknowledgement in sudo with payload message in it and error details + Error((String, String)), + /// Timeout - Got timeout acknowledgement in sudo with payload message in it + Timeout(String), +} + +pub fn save_reply_payload(store: &mut dyn Storage, payload: SudoPayload) -> StdResult<()> { + REPLY_ID_STORAGE.save(store, &to_vec(&payload)?) +} + +pub fn read_reply_payload(store: &mut dyn Storage) -> StdResult { + let data = REPLY_ID_STORAGE.load(store)?; + from_binary(&Binary(data)) +} + +pub fn add_error_to_queue(store: &mut dyn Storage, error_msg: String) -> Option<()> { + let result = ERRORS_QUEUE + .keys(store, None, None, Order::Descending) + .next() + .and_then(|data| data.ok()) + .map(|c| c + 1) + .or(Some(0)); + + result.and_then(|idx| ERRORS_QUEUE.save(store, idx, &error_msg).ok()) +} + +pub fn read_errors_from_queue(store: &dyn Storage) -> StdResult, String)>> { + ERRORS_QUEUE + .range_raw(store, None, None, Order::Ascending) + .collect() +} + +pub fn read_sudo_payload( + store: &mut dyn Storage, + channel_id: String, + seq_id: u64, +) -> StdResult { + let data = SUDO_PAYLOAD.load(store, (channel_id, seq_id))?; + from_binary(&Binary(data)) +} + +pub fn save_sudo_payload( + store: &mut dyn Storage, + channel_id: String, + seq_id: u64, + payload: SudoPayload, +) -> StdResult<()> { + SUDO_PAYLOAD.save(store, (channel_id, seq_id), &to_vec(&payload)?) +} \ No newline at end of file diff --git a/stride-covenant/packages/depositor/src/tests/suite.rs b/stride-covenant/packages/depositor/src/tests/suite.rs index 9b18a7be..711d6d4b 100644 --- a/stride-covenant/packages/depositor/src/tests/suite.rs +++ b/stride-covenant/packages/depositor/src/tests/suite.rs @@ -9,15 +9,15 @@ pub const NATIVE_ATOM_DENOM: &str = "native-atom"; pub const DEFAULT_RECEIVER_AMOUNT: Uint128 = Uint128::new(10); pub const DEFAULT_CLOCK_ADDRESS: &str = "clock-address"; -fn depositor_contract() -> Box> { - let contract = ContractWrapper::new( - crate::contract::execute, - crate::contract::instantiate, - crate::contract::query, - ); - // todo - Box::new(contract) -} +// fn depositor_contract() -> Box> { +// let contract = ContractWrapper::new( +// crate::contract::execute, +// crate::contract::instantiate, +// crate::contract::query, +// ); +// // todo +// Box::new(contract) +// } pub(crate) struct Suite { app: App, @@ -54,8 +54,8 @@ impl SuiteBuilder { pub fn build(self) -> Suite { let mut app = App::default(); - let depositor_code = app.store_code(depositor_contract()); - + // let depositor_code = app.store_code(depositor_contract()); + let depositor_code = 1; let depositor_address = app .instantiate_contract( depositor_code, From 367eec049c5d2890b2eb1025131b95d87def9050 Mon Sep 17 00:00:00 2001 From: bekauz Date: Tue, 6 Jun 2023 18:20:20 +0200 Subject: [PATCH 04/20] ics test update --- stride-covenant/Cargo.lock | 1078 ----------------- stride-covenant/Cargo.toml | 42 - stride-covenant/justfile | 13 +- .../tests/interchaintest/ics_test.go | 42 +- 4 files changed, 53 insertions(+), 1122 deletions(-) delete mode 100644 stride-covenant/Cargo.lock delete mode 100644 stride-covenant/Cargo.toml diff --git a/stride-covenant/Cargo.lock b/stride-covenant/Cargo.lock deleted file mode 100644 index e59bdf7f..00000000 --- a/stride-covenant/Cargo.lock +++ /dev/null @@ -1,1078 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "anyhow" -version = "1.0.71" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base16ct" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5" - -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bech32" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" -dependencies = [ - "serde", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "const-oid" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" - -[[package]] -name = "cosmos-sdk-proto" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ca04d3795c18023c221a2143b29de9c70668ecb22d17783bc02ee780c6c404" -dependencies = [ - "prost 0.10.4", - "prost-types 0.10.1", - "tendermint-proto 0.23.7", -] - -[[package]] -name = "cosmos-sdk-proto" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4776e787b24d9568dd61d3237eeb4eb321d622fb881b858c7b82806420e87d4" -dependencies = [ - "prost 0.11.9", - "prost-types 0.11.9", - "tendermint-proto 0.27.0", -] - -[[package]] -name = "cosmwasm-crypto" -version = "1.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75836a10cb9654c54e77ee56da94d592923092a10b369cdb0dbd56acefc16340" -dependencies = [ - "digest 0.10.7", - "ed25519-zebra", - "k256", - "rand_core 0.6.4", - "thiserror", -] - -[[package]] -name = "cosmwasm-derive" -version = "1.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c9f7f0e51bfc7295f7b2664fe8513c966428642aa765dad8a74acdab5e0c773" -dependencies = [ - "syn 1.0.109", -] - -[[package]] -name = "cosmwasm-schema" -version = "1.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f00b363610218eea83f24bbab09e1a7c3920b79f068334fdfcc62f6129ef9fc" -dependencies = [ - "cosmwasm-schema-derive", - "schemars", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "cosmwasm-schema-derive" -version = "1.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae38f909b2822d32b275c9e2db9728497aa33ffe67dd463bc67c6a3b7092785c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "cosmwasm-std" -version = "1.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a49b85345e811c8e80ec55d0d091e4fcb4f00f97ab058f9be5f614c444a730cb" -dependencies = [ - "base64 0.13.1", - "cosmwasm-crypto", - "cosmwasm-derive", - "derivative", - "forward_ref", - "hex", - "schemars", - "serde", - "serde-json-wasm 0.5.1", - "sha2 0.10.6", - "thiserror", - "uint", -] - -[[package]] -name = "cpufeatures" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" -dependencies = [ - "libc", -] - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-bigint" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" -dependencies = [ - "generic-array", - "rand_core 0.6.4", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "curve25519-dalek" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" -dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", - "subtle", - "zeroize", -] - -[[package]] -name = "cw-multi-test" -version = "0.16.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a18afd2e201221c6d72a57f0886ef2a22151bbc9e6db7af276fde8a91081042" -dependencies = [ - "anyhow", - "cosmwasm-std", - "cw-storage-plus", - "cw-utils", - "derivative", - "itertools", - "k256", - "prost 0.9.0", - "schemars", - "serde", - "thiserror", -] - -[[package]] -name = "cw-storage-plus" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053a5083c258acd68386734f428a5a171b29f7d733151ae83090c6fcc9417ffa" -dependencies = [ - "cosmwasm-std", - "schemars", - "serde", -] - -[[package]] -name = "cw-utils" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c80e93d1deccb8588db03945016a292c3c631e6325d349ebb35d2db6f4f946f7" -dependencies = [ - "cosmwasm-schema", - "cosmwasm-std", - "cw2", - "schemars", - "semver", - "serde", - "thiserror", -] - -[[package]] -name = "cw2" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb70cee2cf0b4a8ff7253e6bc6647107905e8eb37208f87d54f67810faa62f8" -dependencies = [ - "cosmwasm-schema", - "cosmwasm-std", - "cw-storage-plus", - "schemars", - "serde", -] - -[[package]] -name = "der" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" -dependencies = [ - "const-oid", - "zeroize", -] - -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer 0.10.4", - "crypto-common", - "subtle", -] - -[[package]] -name = "dyn-clone" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" - -[[package]] -name = "ecdsa" -version = "0.14.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" -dependencies = [ - "der", - "elliptic-curve", - "rfc6979", - "signature", -] - -[[package]] -name = "ed25519-zebra" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" -dependencies = [ - "curve25519-dalek", - "hashbrown", - "hex", - "rand_core 0.6.4", - "serde", - "sha2 0.9.9", - "zeroize", -] - -[[package]] -name = "either" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" - -[[package]] -name = "elliptic-curve" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" -dependencies = [ - "base16ct", - "crypto-bigint", - "der", - "digest 0.10.7", - "ff", - "generic-array", - "group", - "pkcs8", - "rand_core 0.6.4", - "sec1", - "subtle", - "zeroize", -] - -[[package]] -name = "ff" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" -dependencies = [ - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "flex-error" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c606d892c9de11507fa0dcffc116434f94e105d0bbdc4e405b61519464c49d7b" -dependencies = [ - "paste", -] - -[[package]] -name = "forward_ref" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e" - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "group" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" -dependencies = [ - "ff", - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash", -] - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" - -[[package]] -name = "k256" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" -dependencies = [ - "cfg-if", - "ecdsa", - "elliptic-curve", - "sha2 0.10.6", -] - -[[package]] -name = "libc" -version = "0.2.145" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc86cde3ff845662b8f4ef6cb50ea0e20c524eb3d29ae048287e06a1b3fa6a81" - -[[package]] -name = "neutron-sdk" -version = "0.5.0" -source = "git+https://github.com/neutron-org/neutron-sdk#3841c59b765004de87496850b77bc4b2e7464d18" -dependencies = [ - "base64 0.20.0", - "bech32", - "cosmos-sdk-proto 0.16.0", - "cosmwasm-schema", - "cosmwasm-std", - "cw-storage-plus", - "prost 0.11.9", - "protobuf", - "schemars", - "serde", - "serde-json-wasm 0.4.1", - "serde_json", - "thiserror", -] - -[[package]] -name = "num-derive" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "paste" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" - -[[package]] -name = "pkcs8" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "proc-macro2" -version = "1.0.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "prost" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" -dependencies = [ - "bytes", - "prost-derive 0.9.0", -] - -[[package]] -name = "prost" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71adf41db68aa0daaefc69bb30bcd68ded9b9abaad5d1fbb6304c4fb390e083e" -dependencies = [ - "bytes", - "prost-derive 0.10.1", -] - -[[package]] -name = "prost" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" -dependencies = [ - "bytes", - "prost-derive 0.11.9", -] - -[[package]] -name = "prost-derive" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "prost-derive" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b670f45da57fb8542ebdbb6105a925fe571b67f9e7ed9f47a06a84e72b4e7cc" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "prost-derive" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "prost-types" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d0a014229361011dc8e69c8a1ec6c2e8d0f2af7c91e3ea3f5b2170298461e68" -dependencies = [ - "bytes", - "prost 0.10.4", -] - -[[package]] -name = "prost-types" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" -dependencies = [ - "prost 0.11.9", -] - -[[package]] -name = "protobuf" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55bad9126f378a853655831eb7363b7b01b81d19f8cb1218861086ca4a1a61e" -dependencies = [ - "bytes", - "once_cell", - "protobuf-support", - "thiserror", -] - -[[package]] -name = "protobuf-support" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5d4d7b8601c814cfb36bcebb79f0e61e45e1e93640cf778837833bbed05c372" -dependencies = [ - "thiserror", -] - -[[package]] -name = "quote" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rfc6979" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" -dependencies = [ - "crypto-bigint", - "hmac", - "zeroize", -] - -[[package]] -name = "ryu" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" - -[[package]] -name = "schemars" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" -dependencies = [ - "dyn-clone", - "schemars_derive", - "serde", - "serde_json", -] - -[[package]] -name = "schemars_derive" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" -dependencies = [ - "proc-macro2", - "quote", - "serde_derive_internals", - "syn 1.0.109", -] - -[[package]] -name = "sec1" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" -dependencies = [ - "base16ct", - "der", - "generic-array", - "pkcs8", - "subtle", - "zeroize", -] - -[[package]] -name = "semver" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" - -[[package]] -name = "serde" -version = "1.0.163" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde-json-wasm" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479b4dbc401ca13ee8ce902851b834893251404c4f3c65370a49e047a6be09a5" -dependencies = [ - "serde", -] - -[[package]] -name = "serde-json-wasm" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16a62a1fad1e1828b24acac8f2b468971dade7b8c3c2e672bcadefefb1f8c137" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_bytes" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_derive" -version = "1.0.163" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.18", -] - -[[package]] -name = "serde_derive_internals" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "serde_json" -version = "1.0.96" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", -] - -[[package]] -name = "sha2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", -] - -[[package]] -name = "signature" -version = "1.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" -dependencies = [ - "digest 0.10.7", - "rand_core 0.6.4", -] - -[[package]] -name = "spki" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "stride-depositor" -version = "0.0.1" -dependencies = [ - "cosmos-sdk-proto 0.12.3", - "cosmwasm-schema", - "cosmwasm-std", - "cw-multi-test", - "cw-storage-plus", - "cw2", - "neutron-sdk", - "protobuf", - "schemars", - "serde", - "thiserror", -] - -[[package]] -name = "subtle" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" - -[[package]] -name = "subtle-encoding" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dcb1ed7b8330c5eed5441052651dd7a12c75e2ed88f2ec024ae1fa3a5e59945" -dependencies = [ - "zeroize", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tendermint-proto" -version = "0.23.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71f925d74903f4abbdc4af0110635a307b3cb05b175fdff4a7247c14a4d0874" -dependencies = [ - "bytes", - "flex-error", - "num-derive", - "num-traits", - "prost 0.10.4", - "prost-types 0.10.1", - "serde", - "serde_bytes", - "subtle-encoding", - "time", -] - -[[package]] -name = "tendermint-proto" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5895470f28c530f8ae8c4071bf8190304ce00bd131d25e81730453124a3375c" -dependencies = [ - "bytes", - "flex-error", - "num-derive", - "num-traits", - "prost 0.11.9", - "prost-types 0.11.9", - "serde", - "serde_bytes", - "subtle-encoding", - "time", -] - -[[package]] -name = "thiserror" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.18", -] - -[[package]] -name = "time" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc" -dependencies = [ - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" - -[[package]] -name = "time-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" -dependencies = [ - "time-core", -] - -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "uint" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" -dependencies = [ - "byteorder", - "crunchy", - "hex", - "static_assertions", -] - -[[package]] -name = "unicode-ident" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "zeroize" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" diff --git a/stride-covenant/Cargo.toml b/stride-covenant/Cargo.toml deleted file mode 100644 index 47f935d8..00000000 --- a/stride-covenant/Cargo.toml +++ /dev/null @@ -1,42 +0,0 @@ -[workspace] -members = [ - "packages/*", -] - -[workspace.package] -edition = "2021" -license = "BSD-3" -rust-version = "1.67" -version = "0.1.0" - -[profile.release] -codegen-units = 1 -debug = false -debug-assertions = false -incremental = false -lto = true -opt-level = 3 -overflow-checks = true # very important, do not turn these off. -panic = 'abort' -rpath = false - -[workspace.dependencies] -cosmwasm-schema = "1.2.1" -cosmwasm-std = { version = "1.2.4", features = ["ibc3"] } -cw-storage-plus = "1.0.1" -cw-utils = "1.0.1" -cw2 = "1.0.1" -neutron-sdk = { git = "https://github.com/neutron-org/neutron-sdk", default-features = false, version = "0.5.0" } -cosmos-sdk-proto = { version = "0.12.2", default-features = false } -protobuf = { version = "3", features = ["with-bytes"] } -serde = { version = "1.0.145", default-features = false, features = ["derive"] } -thiserror = "1.0.31" -# the sha2 version here is the same as the one used by -# cosmwasm-std. when bumping cosmwasm-std, this should also be -# updated. to find cosmwasm_std's sha function: -# ```cargo tree --package cosmwasm-std``` -sha2 = "0.10.6" - -# dev-dependencies -cw-multi-test = "0.16.2" -anyhow = { version = "1.0.51" } \ No newline at end of file diff --git a/stride-covenant/justfile b/stride-covenant/justfile index cb09aa1e..ca13756c 100644 --- a/stride-covenant/justfile +++ b/stride-covenant/justfile @@ -1,2 +1,13 @@ -test: +build: + cargo build + +optimize: + cd packages/* && docker run --platform linux/amd64 --rm -v "$(pwd)":/code \ + --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ + --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ + cosmwasm/rust-optimizer:0.12.13 + +test: optimize + mkdir -p tests/interchaintest/wasms + cp packages/*/artifacts/*.wasm tests/interchaintest/wasms cd tests/interchaintest && go test -v ./... \ No newline at end of file diff --git a/stride-covenant/tests/interchaintest/ics_test.go b/stride-covenant/tests/interchaintest/ics_test.go index 930420c4..196388e8 100644 --- a/stride-covenant/tests/interchaintest/ics_test.go +++ b/stride-covenant/tests/interchaintest/ics_test.go @@ -20,6 +20,17 @@ import ( "go.uber.org/zap/zaptest" ) +type InstantiateMsg struct { + StAtomReceiver WeightedReceiver `json:"st_atom_receiver"` + AtomReceiver WeightedReceiver `json:"atom_receiver"` + ClockAddress string `json:"clock_address,string"` +} + +type WeightedReceiver struct { + Amount uint64 `json:"amount,string"` + Address string `json:"address,string"` +} + // Sets custom fields for the Neutron genesis file that interchaintest isn't aware of by default. // // soft_opt_out_threshold - the bottom `soft_opt_out_threshold` @@ -238,5 +249,34 @@ func TestICS(t *testing.T) { // by interchaintest in the genesis file. users := ibctest.GetAndFundTestUsers(t, ctx, "default", int64(100_000_000), atom, neutron, stride) gaiaUser, neutronUser, strideUser := users[0], users[1], users[2] - _, _, _ = gaiaUser, neutronUser, strideUser + _, _ = gaiaUser, strideUser + + t.Run("depositor", func(t *testing.T) { + // Store and instantiate the Neutron ICA example contract. The + // wasm file is placed in `wasms/` by the `just test` command. + codeId, err := cosmosNeutron.StoreContract(ctx, neutronUser.KeyName, "wasms/stride_depositor.wasm") + require.NoError(t, err, "failed to store neutron ICA contract") + + msg := InstantiateMsg{ + StAtomReceiver: WeightedReceiver{ + Amount: 10, + Address: "st_atom_addr", + }, + AtomReceiver: WeightedReceiver{ + Amount: 10, + Address: "atom_addr", + }, + ClockAddress: "clock_addr", + } + + str, err := json.Marshal(msg) + require.NoError(t, err, "Failed to marshall instantiateMsg") + + address, err := cosmosNeutron.InstantiateContract(ctx, neutronUser.KeyName, codeId, string(str), true) + + require.NoError(t, err, "failed to instantiate ICA contract: ", err) + + print("contract: ", address) + }) + } From e3f86e675cda69c9e49cad9f39708bb03df5e87b Mon Sep 17 00:00:00 2001 From: bekauz Date: Tue, 6 Jun 2023 21:26:29 +0200 Subject: [PATCH 05/20] extending queries --- .../packages/depositor/src/contract.rs | 335 +++++++++++++++--- stride-covenant/packages/depositor/src/lib.rs | 1 + stride-covenant/packages/depositor/src/msg.rs | 62 +++- .../packages/depositor/src/state.rs | 2 +- .../packages/depositor/src/tests/suite.rs | 8 +- .../packages/depositor/src/tests/tests.rs | 20 +- .../tests/interchaintest/ics_test.go | 18 +- 7 files changed, 370 insertions(+), 76 deletions(-) diff --git a/stride-covenant/packages/depositor/src/contract.rs b/stride-covenant/packages/depositor/src/contract.rs index f0990adc..7aa40ec8 100644 --- a/stride-covenant/packages/depositor/src/contract.rs +++ b/stride-covenant/packages/depositor/src/contract.rs @@ -1,21 +1,45 @@ -use cosmos_sdk_proto::cosmos::staking::v1beta1::{MsgDelegateResponse, MsgUndelegateResponse}; +use cosmos_sdk_proto::cosmos::base::v1beta1::Coin; +use cosmos_sdk_proto::cosmos::staking::v1beta1::{ + MsgDelegate, MsgDelegateResponse, MsgUndelegate, MsgUndelegateResponse, +}; +#[cfg(not(feature = "library"))] +use cosmwasm_std::entry_point; +use cosmwasm_std::{ + to_binary, Binary, CosmosMsg, CustomQuery, Deps, DepsMut, Env, MessageInfo, Reply, Response, + StdError, StdResult, SubMsg, Addr, +}; use cw2::set_contract_version; -use cosmwasm_std::{entry_point, DepsMut, Env, MessageInfo, Response, Deps, StdResult, Binary, to_binary, StdError, CosmosMsg, SubMsg, Reply, CustomQuery}; -use neutron_sdk::bindings::query::NeutronQuery; -use neutron_sdk::sudo::msg::{SudoMsg, RequestPacket}; -use neutron_sdk::{NeutronResult, NeutronError}; -use neutron_sdk::bindings::msg::{NeutronMsg, MsgSubmitTxResponse, IbcFee}; -use neutron_sdk::interchain_txs::helpers::{get_port_id, decode_message_response, decode_acknowledgement_response}; -use serde::{Serialize, Deserialize}; +use prost::Message; use schemars::JsonSchema; -use crate::msg::{InstantiateMsg, ExecuteMsg, QueryMsg}; -use crate::state::{STRIDE_ATOM_RECEIVER, CLOCK_ADDRESS, NATIVE_ATOM_RECEIVER, INTERCHAIN_ACCOUNTS, ICS_PORT_ID, AcknowledgementResult, ACKNOWLEDGEMENT_RESULTS, read_sudo_payload, add_error_to_queue, SudoPayload, save_reply_payload, SUDO_PAYLOAD_REPLY_ID, read_reply_payload, save_sudo_payload}; +use serde::{Deserialize, Serialize}; + +use crate::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; +use neutron_sdk::bindings::msg::IbcFee; +use neutron_sdk::{ + bindings::{ + msg::{MsgSubmitTxResponse, NeutronMsg}, + query::{NeutronQuery, QueryInterchainAccountAddressResponse}, + types::ProtobufAny, + }, + interchain_txs::helpers::{ + decode_acknowledgement_response, decode_message_response, get_port_id, + }, + query::min_ibc_fee::query_min_ibc_fee, + sudo::msg::{RequestPacket, SudoMsg}, + NeutronError, NeutronResult, +}; + +use crate::state::{ + add_error_to_queue, read_errors_from_queue, read_reply_payload, read_sudo_payload, + save_reply_payload, save_sudo_payload, AcknowledgementResult, SudoPayload, + ACKNOWLEDGEMENT_RESULTS, INTERCHAIN_ACCOUNTS, SUDO_PAYLOAD_REPLY_ID, CLOCK_ADDRESS, STRIDE_ATOM_RECEIVER, NATIVE_ATOM_RECEIVER, ICS_PORT_ID, +}; // Default timeout for SubmitTX is two weeks const DEFAULT_TIMEOUT_SECONDS: u64 = 60 * 60 * 24 * 7 * 2; const FEE_DENOM: &str = "untrn"; -const CONTRACT_NAME: &str = "crates.io:stride-depositor"; +const CONTRACT_NAME: &str = concat!("crates.io:neutron-sdk__", env!("CARGO_PKG_NAME")); const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -33,49 +57,83 @@ struct OpenAckVersion { pub fn instantiate( deps: DepsMut, _env: Env, - info: MessageInfo, + _info: MessageInfo, msg: InstantiateMsg, ) -> NeutronResult> { + deps.api.debug("WASMDEBUG: instantiate"); set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; // can we do better with validation here? - let st_atom_receiver_address = deps.api.addr_validate(&msg.st_atom_receiver.address)?; - let atom_receiver_address = deps.api.addr_validate(&msg.atom_receiver.address)?; + // deps.api.addr_validate(&msg.st_atom_receiver.address)?; + // deps.api.addr_validate(&msg.atom_receiver.address)?; let clock_address = deps.api.addr_validate(&msg.clock_address)?; - // TODO: consider validating that clock should already exist, - // and be instantiated by the same covenant contract - + // avoid zero deposit configurations - if msg.st_atom_receiver.amount == 0 || msg.atom_receiver.amount == 0 { - return Err(NeutronError::Std( - StdError::GenericErr { msg: "Zero deposit config".to_string() }) - ) - } - - // store the denominations and amounts - STRIDE_ATOM_RECEIVER.save(deps.storage, &msg.st_atom_receiver)?; - NATIVE_ATOM_RECEIVER.save(deps.storage, &msg.atom_receiver)?; + // if msg.st_atom_receiver.amount == 0 || msg.atom_receiver.amount == 0 { + // return Err(NeutronError::Std( + // StdError::GenericErr { msg: "Zero deposit config".to_string() }) + // ) + // } - // store the clock address that will be authorized to tick - CLOCK_ADDRESS.save(deps.storage, &clock_address)?; + // minations and amounts + // STRIDE_ATOM_RECEIVER.save(deps.storage, &msg.st_atom_receiver)?; + // NATIVE_ATOM_RECEIVER.save(deps.storage, &msg.atom_receiver)?; + // CLOCK_ADDRESS.save(deps.storage, &clock_address)?; Ok(Response::default()) } -#[cfg_attr(not(feature = "library"), entry_point)] +#[entry_point] pub fn execute( - deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> NeutronResult> { + deps.api + .debug(format!("WASMDEBUG: execute: received msg: {:?}", msg).as_str()); match msg { - ExecuteMsg::Tick {} => try_tick(deps, env, info), - ExecuteMsg::Received {} => try_handle_received(), + ExecuteMsg::Tick { } => try_tick(deps, env, info), + ExecuteMsg::Received { } => try_handle_received(), + ExecuteMsg::Register { + connection_id, + interchain_account_id, + } => execute_register_ica(deps, env, connection_id, interchain_account_id), + ExecuteMsg::Delegate { + validator, + interchain_account_id, + amount, + denom, + timeout, + } => execute_delegate( + deps, + env, + interchain_account_id, + validator, + amount, + denom, + timeout, + ), + ExecuteMsg::Undelegate { + validator, + interchain_account_id, + amount, + denom, + timeout, + } => execute_undelegate( + deps, + env, + interchain_account_id, + validator, + amount, + denom, + timeout, + ), } } -fn try_tick(deps: DepsMut, env: Env, info: MessageInfo) -> NeutronResult> { + +fn try_tick(deps: DepsMut, env: Env, info: MessageInfo) -> NeutronResult> { // validate called is clock // retrieve the existing interchain account (s?) @@ -94,7 +152,7 @@ fn try_tick(deps: DepsMut, env: Env, info: MessageInfo) -> NeutronResult, env: Env, ) -> NeutronResult> { // store the account identifier @@ -116,7 +174,7 @@ fn try_register_gaia_ica( } fn try_execute_transfers( - deps: DepsMut, + deps: DepsMut, info: MessageInfo, gaia_account_address: String ) -> NeutronResult> { @@ -144,14 +202,75 @@ fn try_handle_received() -> NeutronResult> { } #[cfg_attr(not(feature = "library"), entry_point)] -pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { +pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> NeutronResult { match msg { - QueryMsg::StAtomReceiver {} => to_binary(&STRIDE_ATOM_RECEIVER.may_load(deps.storage)?), - QueryMsg::AtomReceiver {} => to_binary(&NATIVE_ATOM_RECEIVER.may_load(deps.storage)?), - QueryMsg::ClockAddress {} => to_binary(&CLOCK_ADDRESS.may_load(deps.storage)?), + QueryMsg::StAtomReceiver {} => Ok( + to_binary(&STRIDE_ATOM_RECEIVER.may_load(deps.storage)?)? + ), + QueryMsg::AtomReceiver {} => Ok( + to_binary(&NATIVE_ATOM_RECEIVER.may_load(deps.storage)?)? + ), + QueryMsg::ClockAddress {} => Ok( + to_binary(&CLOCK_ADDRESS.may_load(deps.storage)?)? + ), + QueryMsg::InterchainAccountAddress { + interchain_account_id, + connection_id, + } => query_interchain_address(deps, env, interchain_account_id, connection_id), + QueryMsg::InterchainAccountAddressFromContract { + interchain_account_id, + } => query_interchain_address_contract(deps, env, interchain_account_id), + QueryMsg::AcknowledgementResult { + interchain_account_id, + sequence_id, + } => query_acknowledgement_result(deps, env, interchain_account_id, sequence_id), + QueryMsg::ErrorsQueue {} => query_errors_queue(deps), } } +// returns ICA address from Neutron ICA SDK module +pub fn query_interchain_address( + deps: Deps, + env: Env, + interchain_account_id: String, + connection_id: String, +) -> NeutronResult { + let query = NeutronQuery::InterchainAccountAddress { + owner_address: env.contract.address.to_string(), + interchain_account_id, + connection_id, + }; + + let res: QueryInterchainAccountAddressResponse = deps.querier.query(&query.into())?; + Ok(to_binary(&res)?) +} + +// returns ICA address from the contract storage. The address was saved in sudo_open_ack method +pub fn query_interchain_address_contract( + deps: Deps, + env: Env, + interchain_account_id: String, +) -> NeutronResult { + Ok(to_binary(&get_ica(deps, &env, &interchain_account_id)?)?) +} + +// returns the result +pub fn query_acknowledgement_result( + deps: Deps, + env: Env, + interchain_account_id: String, + sequence_id: u64, +) -> NeutronResult { + let port_id = get_port_id(env.contract.address.as_str(), &interchain_account_id); + let res = ACKNOWLEDGEMENT_RESULTS.may_load(deps.storage, (port_id, sequence_id))?; + Ok(to_binary(&res)?) +} + +pub fn query_errors_queue(deps: Deps) -> NeutronResult { + let res = read_errors_from_queue(deps.storage)?; + Ok(to_binary(&res)?) +} + // saves payload to process later to the storage and returns a SubmitTX Cosmos SubMsg with necessary reply id fn msg_with_sudo_callback>, T>( deps: DepsMut, @@ -162,6 +281,138 @@ fn msg_with_sudo_callback>, T>( Ok(SubMsg::reply_on_success(msg, SUDO_PAYLOAD_REPLY_ID)) } +fn execute_register_ica( + deps: DepsMut, + env: Env, + connection_id: String, + interchain_account_id: String, +) -> NeutronResult> { + let register = + NeutronMsg::register_interchain_account(connection_id, interchain_account_id.clone()); + let key = get_port_id(env.contract.address.as_str(), &interchain_account_id); + // we are saving empty data here because we handle response of registering ICA in sudo_open_ack method + INTERCHAIN_ACCOUNTS.save(deps.storage, key, &None)?; + Ok(Response::new().add_message(register)) +} + +fn execute_delegate( + mut deps: DepsMut, + env: Env, + interchain_account_id: String, + validator: String, + amount: u128, + denom: String, + timeout: Option, +) -> NeutronResult> { + // contract must pay for relaying of acknowledgements + // See more info here: https://docs.neutron.org/neutron/feerefunder/overview + let fee = min_ntrn_ibc_fee(query_min_ibc_fee(deps.as_ref())?.min_fee); + let (delegator, connection_id) = get_ica(deps.as_ref(), &env, &interchain_account_id)?; + let delegate_msg = MsgDelegate { + delegator_address: delegator, + validator_address: validator, + amount: Some(Coin { + denom, + amount: amount.to_string(), + }), + }; + let mut buf = Vec::new(); + buf.reserve(delegate_msg.encoded_len()); + + if let Err(e) = delegate_msg.encode(&mut buf) { + return Err(NeutronError::Std(StdError::generic_err(format!( + "Encode error: {}", + e + )))); + } + + let any_msg = ProtobufAny { + type_url: "/cosmos.staking.v1beta1.MsgDelegate".to_string(), + value: Binary::from(buf), + }; + + let cosmos_msg = NeutronMsg::submit_tx( + connection_id, + interchain_account_id.clone(), + vec![any_msg], + "".to_string(), + timeout.unwrap_or(DEFAULT_TIMEOUT_SECONDS), + fee, + ); + + // We use a submessage here because we need the process message reply to save + // the outgoing IBC packet identifier for later. + let submsg = msg_with_sudo_callback( + deps.branch(), + cosmos_msg, + SudoPayload { + port_id: get_port_id(env.contract.address.as_str(), &interchain_account_id), + message: "message".to_string(), + }, + )?; + + Ok(Response::default().add_submessages(vec![submsg])) +} + +fn execute_undelegate( + mut deps: DepsMut, + env: Env, + interchain_account_id: String, + validator: String, + amount: u128, + denom: String, + timeout: Option, +) -> NeutronResult> { + // contract must pay for relaying of acknowledgements + // See more info here: https://docs.neutron.org/neutron/feerefunder/overview + let fee = min_ntrn_ibc_fee(query_min_ibc_fee(deps.as_ref())?.min_fee); + let (delegator, connection_id) = get_ica(deps.as_ref(), &env, &interchain_account_id)?; + let delegate_msg = MsgUndelegate { + delegator_address: delegator, + validator_address: validator, + amount: Some(Coin { + denom, + amount: amount.to_string(), + }), + }; + let mut buf = Vec::new(); + buf.reserve(delegate_msg.encoded_len()); + + if let Err(e) = delegate_msg.encode(&mut buf) { + return Err(NeutronError::Std(StdError::generic_err(format!( + "Encode error: {}", + e + )))); + } + + let any_msg = ProtobufAny { + type_url: "/cosmos.staking.v1beta1.MsgUndelegate".to_string(), + value: Binary::from(buf), + }; + + let cosmos_msg = NeutronMsg::submit_tx( + connection_id, + interchain_account_id.clone(), + vec![any_msg], + "".to_string(), + timeout.unwrap_or(DEFAULT_TIMEOUT_SECONDS), + fee, + ); + + // We use a submessage here because we need the process message reply to save + // the outgoing IBC packet identifier for later. + let submsg = msg_with_sudo_callback( + deps.branch(), + cosmos_msg, + SudoPayload { + port_id: get_port_id(env.contract.address.as_str(), &interchain_account_id), + message: "message".to_string(), + }, + )?; + + Ok(Response::default().add_submessages(vec![submsg])) +} + #[cfg_attr(not(feature = "library"), entry_point)] pub fn sudo(deps: DepsMut, env: Env, msg: SudoMsg) -> StdResult { deps.api @@ -195,6 +446,11 @@ pub fn sudo(deps: DepsMut, env: Env, msg: SudoMsg) -> StdResult { } } +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> StdResult { + deps.api.debug("WASMDEBUG: migrate"); + Ok(Response::default()) +} // handler fn sudo_open_ack( @@ -462,7 +718,6 @@ fn prepare_sudo_payload(mut deps: DepsMut, _env: Env, msg: Reply) -> StdResult, env: &Env, diff --git a/stride-covenant/packages/depositor/src/lib.rs b/stride-covenant/packages/depositor/src/lib.rs index 4fe4610d..878ef0ed 100644 --- a/stride-covenant/packages/depositor/src/lib.rs +++ b/stride-covenant/packages/depositor/src/lib.rs @@ -7,5 +7,6 @@ pub mod error; pub mod msg; pub mod state; +#[allow(clippy::unwrap_used)] #[cfg(test)] mod tests; \ No newline at end of file diff --git a/stride-covenant/packages/depositor/src/msg.rs b/stride-covenant/packages/depositor/src/msg.rs index d6d0fb00..f4e37355 100644 --- a/stride-covenant/packages/depositor/src/msg.rs +++ b/stride-covenant/packages/depositor/src/msg.rs @@ -1,29 +1,69 @@ -use cosmwasm_schema::cw_serde; -use cosmwasm_std::{Uint128, Addr}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; -#[cw_serde] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[serde(rename_all = "snake_case")] pub struct InstantiateMsg { pub st_atom_receiver: WeightedReceiver, pub atom_receiver: WeightedReceiver, pub clock_address: String, } -#[cw_serde] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub struct WeightedReceiver { + pub amount: u128, + pub address: String, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[serde(rename_all = "snake_case")] pub enum ExecuteMsg { Tick {}, Received {}, + Register { + connection_id: String, + interchain_account_id: String, + }, + Delegate { + interchain_account_id: String, + validator: String, + amount: u128, + denom: String, + timeout: Option, + }, + Undelegate { + interchain_account_id: String, + validator: String, + amount: u128, + denom: String, + timeout: Option, + }, } -#[cw_serde] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[serde(rename_all = "snake_case")] pub enum QueryMsg { StAtomReceiver {}, AtomReceiver {}, ClockAddress {}, + /// this query goes to neutron and get stored ICA with a specific query + InterchainAccountAddress { + interchain_account_id: String, + connection_id: String, + }, + // this query returns ICA from contract store, which saved from acknowledgement + InterchainAccountAddressFromContract { + interchain_account_id: String, + }, + // this query returns acknowledgement result after interchain transaction + AcknowledgementResult { + interchain_account_id: String, + sequence_id: u64, + }, + // this query returns non-critical errors list + ErrorsQueue {}, } -#[cw_serde] -pub struct WeightedReceiver { - pub amount: u128, - pub address: String, -} - +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +pub struct MigrateMsg {} diff --git a/stride-covenant/packages/depositor/src/state.rs b/stride-covenant/packages/depositor/src/state.rs index 4f50dff1..3a83c875 100644 --- a/stride-covenant/packages/depositor/src/state.rs +++ b/stride-covenant/packages/depositor/src/state.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{Addr, Binary, from_binary, Storage, StdResult, to_vec, Order}; +use cosmwasm_std::{from_binary, to_vec, Binary, Order, StdResult, Storage, Addr}; use cw_storage_plus::{Item, Map}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; diff --git a/stride-covenant/packages/depositor/src/tests/suite.rs b/stride-covenant/packages/depositor/src/tests/suite.rs index 711d6d4b..4017308f 100644 --- a/stride-covenant/packages/depositor/src/tests/suite.rs +++ b/stride-covenant/packages/depositor/src/tests/suite.rs @@ -1,7 +1,7 @@ use cosmwasm_std::{Addr, Empty, Uint128}; use cw_multi_test::{App, Contract, ContractWrapper, Executor}; -use crate::msg::{InstantiateMsg, WeightedReceiver, QueryMsg}; +use crate::msg::{InstantiateMsg, QueryMsg, WeightedReceiver}; pub const CREATOR_ADDR: &str = "creator"; pub const ST_ATOM_DENOM: &str = "stride-atom"; @@ -37,14 +37,14 @@ impl Default for SuiteBuilder { Self { instantiate: InstantiateMsg { st_atom_receiver: WeightedReceiver { - amount: DEFAULT_RECEIVER_AMOUNT, + amount: 10, address: ST_ATOM_DENOM.to_string(), }, atom_receiver: WeightedReceiver { - amount: DEFAULT_RECEIVER_AMOUNT, + amount: 10, address: NATIVE_ATOM_DENOM.to_string(), }, - clock_address: Addr::unchecked(DEFAULT_CLOCK_ADDRESS), + clock_address: "default-clock".to_string(), }, } } diff --git a/stride-covenant/packages/depositor/src/tests/tests.rs b/stride-covenant/packages/depositor/src/tests/tests.rs index f639b2db..e9addb31 100644 --- a/stride-covenant/packages/depositor/src/tests/tests.rs +++ b/stride-covenant/packages/depositor/src/tests/tests.rs @@ -1,7 +1,5 @@ use cosmwasm_std::Addr; -use crate::msg::WeightedReceiver; - use super::suite::{SuiteBuilder, DEFAULT_CLOCK_ADDRESS, DEFAULT_RECEIVER_AMOUNT, NATIVE_ATOM_DENOM, ST_ATOM_DENOM}; @@ -10,13 +8,13 @@ fn test_instantiate_happy() { let suite = SuiteBuilder::default() .build(); - suite.assert_clock_address(Addr::unchecked(DEFAULT_CLOCK_ADDRESS)); - suite.assert_native_atom_receiver(WeightedReceiver { - amount: DEFAULT_RECEIVER_AMOUNT, - address: NATIVE_ATOM_DENOM.to_string(), - }); - suite.assert_stride_atom_receiver(WeightedReceiver { - amount: DEFAULT_RECEIVER_AMOUNT, - address: ST_ATOM_DENOM.to_string(), - }); + // suite.assert_clock_address(Addr::unchecked(DEFAULT_CLOCK_ADDRESS)); + // suite.assert_native_atom_receiver(WeightedReceiver { + // amount: DEFAULT_RECEIVER_AMOUNT, + // address: NATIVE_ATOM_DENOM.to_string(), + // }); + // suite.assert_stride_atom_receiver(WeightedReceiver { + // amount: DEFAULT_RECEIVER_AMOUNT, + // address: ST_ATOM_DENOM.to_string(), + // }); } \ No newline at end of file diff --git a/stride-covenant/tests/interchaintest/ics_test.go b/stride-covenant/tests/interchaintest/ics_test.go index 196388e8..6b7d3f9f 100644 --- a/stride-covenant/tests/interchaintest/ics_test.go +++ b/stride-covenant/tests/interchaintest/ics_test.go @@ -258,14 +258,14 @@ func TestICS(t *testing.T) { require.NoError(t, err, "failed to store neutron ICA contract") msg := InstantiateMsg{ - StAtomReceiver: WeightedReceiver{ - Amount: 10, - Address: "st_atom_addr", - }, - AtomReceiver: WeightedReceiver{ - Amount: 10, - Address: "atom_addr", - }, + // StAtomReceiver: WeightedReceiver{ + // Amount: 10, + // Address: "st_atom_addr", + // }, + // AtomReceiver: WeightedReceiver{ + // Amount: 10, + // Address: "atom_addr", + // }, ClockAddress: "clock_addr", } @@ -276,7 +276,7 @@ func TestICS(t *testing.T) { require.NoError(t, err, "failed to instantiate ICA contract: ", err) - print("contract: ", address) + print("\n\ncontract: ", address) }) } From 5907ef1afb748e2d347166188d6e83cbc1d705a5 Mon Sep 17 00:00:00 2001 From: bekauz Date: Wed, 7 Jun 2023 00:10:15 +0200 Subject: [PATCH 06/20] instantiating depositor --- stride-covenant/packages/depositor/Cargo.toml | 2 +- stride-covenant/packages/depositor/src/contract.rs | 13 +++++++------ stride-covenant/packages/depositor/src/msg.rs | 1 - stride-covenant/tests/interchaintest/ics_test.go | 3 ++- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/stride-covenant/packages/depositor/Cargo.toml b/stride-covenant/packages/depositor/Cargo.toml index 4cd7779e..33472dbe 100644 --- a/stride-covenant/packages/depositor/Cargo.toml +++ b/stride-covenant/packages/depositor/Cargo.toml @@ -16,7 +16,7 @@ crate-type = ["cdylib", "rlib"] [profile.release] opt-level = 3 -debug = false +debug = true rpath = false lto = true debug-assertions = false diff --git a/stride-covenant/packages/depositor/src/contract.rs b/stride-covenant/packages/depositor/src/contract.rs index 7aa40ec8..a14e846e 100644 --- a/stride-covenant/packages/depositor/src/contract.rs +++ b/stride-covenant/packages/depositor/src/contract.rs @@ -66,19 +66,20 @@ pub fn instantiate( // can we do better with validation here? // deps.api.addr_validate(&msg.st_atom_receiver.address)?; // deps.api.addr_validate(&msg.atom_receiver.address)?; - let clock_address = deps.api.addr_validate(&msg.clock_address)?; - + // let clock_address = deps.api.addr_validate(&msg.clock_address)?; + // avoid zero deposit configurations // if msg.st_atom_receiver.amount == 0 || msg.atom_receiver.amount == 0 { // return Err(NeutronError::Std( // StdError::GenericErr { msg: "Zero deposit config".to_string() }) // ) // } - + deps.api + .debug(format!("WASMDEBUG: instantiate: received msg: {:?}", msg).as_str()); // minations and amounts - // STRIDE_ATOM_RECEIVER.save(deps.storage, &msg.st_atom_receiver)?; - // NATIVE_ATOM_RECEIVER.save(deps.storage, &msg.atom_receiver)?; - // CLOCK_ADDRESS.save(deps.storage, &clock_address)?; + STRIDE_ATOM_RECEIVER.save(deps.storage, &msg.st_atom_receiver)?; + NATIVE_ATOM_RECEIVER.save(deps.storage, &msg.atom_receiver)?; + CLOCK_ADDRESS.save(deps.storage, &Addr::unchecked(msg.clock_address))?; Ok(Response::default()) } diff --git a/stride-covenant/packages/depositor/src/msg.rs b/stride-covenant/packages/depositor/src/msg.rs index f4e37355..351b4078 100644 --- a/stride-covenant/packages/depositor/src/msg.rs +++ b/stride-covenant/packages/depositor/src/msg.rs @@ -10,7 +10,6 @@ pub struct InstantiateMsg { } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] -#[serde(rename_all = "snake_case")] pub struct WeightedReceiver { pub amount: u128, pub address: String, diff --git a/stride-covenant/tests/interchaintest/ics_test.go b/stride-covenant/tests/interchaintest/ics_test.go index 6b7d3f9f..d36e749f 100644 --- a/stride-covenant/tests/interchaintest/ics_test.go +++ b/stride-covenant/tests/interchaintest/ics_test.go @@ -17,6 +17,7 @@ import ( "github.com/strangelove-ventures/interchaintest/v3/testreporter" "github.com/strangelove-ventures/interchaintest/v3/testutil" "github.com/stretchr/testify/require" + "go.uber.org/zap" "go.uber.org/zap/zaptest" ) @@ -147,7 +148,7 @@ func TestICS(t *testing.T) { client, network := ibctest.DockerSetup(t) r := ibctest.NewBuiltinRelayerFactory( ibc.CosmosRly, - zaptest.NewLogger(t), + zaptest.NewLogger(t, zaptest.Level(zap.WarnLevel)), relayer.CustomDockerImage("ghcr.io/cosmos/relayer", "v2.3.1", rly.RlyDefaultUidGid), relayer.RelayerOptionExtraStartFlags{Flags: []string{"-d", "--log-format", "console"}}, ).Build(t, client, network) From 8c41bcb5d5c8eb56b5cc56d3dbfb06efb4eca185 Mon Sep 17 00:00:00 2001 From: bekauz Date: Wed, 7 Jun 2023 13:32:54 +0200 Subject: [PATCH 07/20] querying clock address --- .../tests/interchaintest/ics_test.go | 66 +++++++++++++++---- 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/stride-covenant/tests/interchaintest/ics_test.go b/stride-covenant/tests/interchaintest/ics_test.go index d36e749f..d5ff65ce 100644 --- a/stride-covenant/tests/interchaintest/ics_test.go +++ b/stride-covenant/tests/interchaintest/ics_test.go @@ -32,6 +32,41 @@ type WeightedReceiver struct { Address string `json:"address,string"` } +// A query against the Neutron example contract. Note the usage of +// `omitempty` on fields. This means that if that field has no value, +// it will not have a key in the serialized representaiton of the +// struct, thus mimicing the serialization of Rust enums. +type IcaExampleContractQuery struct { + InterchainAccountAddress InterchainAccountAddressQuery `json:"interchain_account_address,omitempty"` +} + +type DepositorContractQuery struct { + ClockAddress ClockAddressQuery `json:"clock_address"` +} + +type InterchainAccountAddressQuery struct { + InterchainAccountId string `json:"interchain_account_id"` + ConnectionId string `json:"connection_id"` +} + +type ClockAddressQuery struct{} + +type ClockQueryResponse struct { + Data string `json:"data"` +} + +// A query response from the Neutron contract. Note that when +// interchaintest returns query responses, it does so in the form +// `{"data": }`, so we need this outer data key, which is +// not present in the neutron contract, to properly deserialze. +type QueryResponse struct { + Data InterchainAccountAddressQueryResponse `json:"data"` +} + +type InterchainAccountAddressQueryResponse struct { + InterchainAccountAddress string `json:"interchain_account_address"` +} + // Sets custom fields for the Neutron genesis file that interchaintest isn't aware of by default. // // soft_opt_out_threshold - the bottom `soft_opt_out_threshold` @@ -88,7 +123,7 @@ func TestICS(t *testing.T) { ctx := context.Background() // Chain Factory - cf := ibctest.NewBuiltinChainFactory(zaptest.NewLogger(t), []*ibctest.ChainSpec{ + cf := ibctest.NewBuiltinChainFactory(zaptest.NewLogger(t, zaptest.Level(zap.WarnLevel)), []*ibctest.ChainSpec{ {Name: "gaia", Version: "v9.1.0", ChainConfig: ibc.ChainConfig{GasAdjustment: 1.5}}, { ChainConfig: ibc.ChainConfig{ @@ -148,7 +183,7 @@ func TestICS(t *testing.T) { client, network := ibctest.DockerSetup(t) r := ibctest.NewBuiltinRelayerFactory( ibc.CosmosRly, - zaptest.NewLogger(t, zaptest.Level(zap.WarnLevel)), + zaptest.NewLogger(t, zaptest.Level(zap.DebugLevel)), relayer.CustomDockerImage("ghcr.io/cosmos/relayer", "v2.3.1", rly.RlyDefaultUidGid), relayer.RelayerOptionExtraStartFlags{Flags: []string{"-d", "--log-format", "console"}}, ).Build(t, client, network) @@ -259,15 +294,15 @@ func TestICS(t *testing.T) { require.NoError(t, err, "failed to store neutron ICA contract") msg := InstantiateMsg{ - // StAtomReceiver: WeightedReceiver{ - // Amount: 10, - // Address: "st_atom_addr", - // }, - // AtomReceiver: WeightedReceiver{ - // Amount: 10, - // Address: "atom_addr", - // }, - ClockAddress: "clock_addr", + StAtomReceiver: WeightedReceiver{ + Amount: 10, + Address: "st_atom_addr", + }, + AtomReceiver: WeightedReceiver{ + Amount: 10, + Address: "atom_addr", + }, + ClockAddress: "clock_contract_addr", } str, err := json.Marshal(msg) @@ -277,7 +312,14 @@ func TestICS(t *testing.T) { require.NoError(t, err, "failed to instantiate ICA contract: ", err) - print("\n\ncontract: ", address) + var response ClockQueryResponse + err = cosmosNeutron.QueryContract(ctx, address, DepositorContractQuery{ + ClockAddress: ClockAddressQuery{}, + }, &response) + require.NoError(t, err, "failed to query clock address") + respStr, err := json.Marshal(response) + require.NoError(t, err, "failed to marshall clock address response") + print("\n query resp: ", string(respStr)) }) } From 19ba6bb9c9352569846f8b4825e4bceb74a4da2d Mon Sep 17 00:00:00 2001 From: bekauz Date: Wed, 7 Jun 2023 15:25:32 +0200 Subject: [PATCH 08/20] interchaintest instantiate --- .../tests/interchaintest/ics_test.go | 76 ++++++++++++++----- 1 file changed, 55 insertions(+), 21 deletions(-) diff --git a/stride-covenant/tests/interchaintest/ics_test.go b/stride-covenant/tests/interchaintest/ics_test.go index d5ff65ce..e054f00c 100644 --- a/stride-covenant/tests/interchaintest/ics_test.go +++ b/stride-covenant/tests/interchaintest/ics_test.go @@ -40,16 +40,30 @@ type IcaExampleContractQuery struct { InterchainAccountAddress InterchainAccountAddressQuery `json:"interchain_account_address,omitempty"` } +type InterchainAccountAddressQuery struct { + InterchainAccountId string `json:"interchain_account_id"` + ConnectionId string `json:"connection_id"` +} + type DepositorContractQuery struct { ClockAddress ClockAddressQuery `json:"clock_address"` } -type InterchainAccountAddressQuery struct { - InterchainAccountId string `json:"interchain_account_id"` - ConnectionId string `json:"connection_id"` +type StAtomWeightedReceiverQuery struct { + StAtomReceiver StAtomReceiverQuery `json:"st_atom_receiver"` +} + +type AtomWeightedReceiverQuery struct { + AtomReceiver AtomReceiverQuery `json:"atom_receiver"` } type ClockAddressQuery struct{} +type StAtomReceiverQuery struct{} +type AtomReceiverQuery struct{} + +type WeightedReceiverResponse struct { + Data WeightedReceiver `json:"data"` +} type ClockQueryResponse struct { Data string `json:"data"` @@ -287,22 +301,25 @@ func TestICS(t *testing.T) { gaiaUser, neutronUser, strideUser := users[0], users[1], users[2] _, _ = gaiaUser, strideUser - t.Run("depositor", func(t *testing.T) { + t.Run("instantiate depositor", func(t *testing.T) { // Store and instantiate the Neutron ICA example contract. The // wasm file is placed in `wasms/` by the `just test` command. codeId, err := cosmosNeutron.StoreContract(ctx, neutronUser.KeyName, "wasms/stride_depositor.wasm") require.NoError(t, err, "failed to store neutron ICA contract") + stAtomWeightedReceiver := WeightedReceiver{ + Amount: 10, + Address: "st_atom_addr", + } + atomWeightedReceiver := WeightedReceiver{ + Amount: 10, + Address: "atom_addr", + } + clockContractAddress := "clock_contract_address" msg := InstantiateMsg{ - StAtomReceiver: WeightedReceiver{ - Amount: 10, - Address: "st_atom_addr", - }, - AtomReceiver: WeightedReceiver{ - Amount: 10, - Address: "atom_addr", - }, - ClockAddress: "clock_contract_addr", + StAtomReceiver: stAtomWeightedReceiver, + AtomReceiver: atomWeightedReceiver, + ClockAddress: clockContractAddress, } str, err := json.Marshal(msg) @@ -312,14 +329,31 @@ func TestICS(t *testing.T) { require.NoError(t, err, "failed to instantiate ICA contract: ", err) - var response ClockQueryResponse - err = cosmosNeutron.QueryContract(ctx, address, DepositorContractQuery{ - ClockAddress: ClockAddressQuery{}, - }, &response) - require.NoError(t, err, "failed to query clock address") - respStr, err := json.Marshal(response) - require.NoError(t, err, "failed to marshall clock address response") - print("\n query resp: ", string(respStr)) + t.Run("query instantiated clock", func(t *testing.T) { + var response ClockQueryResponse + err = cosmosNeutron.QueryContract(ctx, address, DepositorContractQuery{ + ClockAddress: ClockAddressQuery{}, + }, &response) + require.NoError(t, err, "failed to query clock address") + expectedAddrJson, _ := json.Marshal(clockContractAddress) + require.Equal(t, string(expectedAddrJson), response.Data) + }) + + t.Run("query instantiated weighted receivers", func(t *testing.T) { + var stAtomReceiver WeightedReceiverResponse + err = cosmosNeutron.QueryContract(ctx, address, StAtomWeightedReceiverQuery{ + StAtomReceiver: StAtomReceiverQuery{}, + }, &stAtomReceiver) + require.NoError(t, err, "failed to query stAtom weighted receiver") + require.Equal(t, stAtomWeightedReceiver, stAtomReceiver.Data) + + var atomReceiver WeightedReceiverResponse + err = cosmosNeutron.QueryContract(ctx, address, AtomWeightedReceiverQuery{ + AtomReceiver: AtomReceiverQuery{}, + }, &atomReceiver) + require.NoError(t, err, "failed to query atom weighted receiver") + require.Equal(t, atomWeightedReceiver, atomReceiver.Data) + }) }) } From 8197543ec82ec2d596de070eda17b359a4f17abf Mon Sep 17 00:00:00 2001 From: bekauz Date: Wed, 7 Jun 2023 23:57:16 +0200 Subject: [PATCH 09/20] removing (un)delegate handlers --- .../packages/depositor/src/contract.rs | 226 ++++-------------- stride-covenant/packages/depositor/src/msg.rs | 15 +- .../tests/interchaintest/ics_test.go | 65 ++++- 3 files changed, 106 insertions(+), 200 deletions(-) diff --git a/stride-covenant/packages/depositor/src/contract.rs b/stride-covenant/packages/depositor/src/contract.rs index a14e846e..0112804c 100644 --- a/stride-covenant/packages/depositor/src/contract.rs +++ b/stride-covenant/packages/depositor/src/contract.rs @@ -74,8 +74,7 @@ pub fn instantiate( // StdError::GenericErr { msg: "Zero deposit config".to_string() }) // ) // } - deps.api - .debug(format!("WASMDEBUG: instantiate: received msg: {:?}", msg).as_str()); + // minations and amounts STRIDE_ATOM_RECEIVER.save(deps.storage, &msg.st_atom_receiver)?; NATIVE_ATOM_RECEIVER.save(deps.storage, &msg.atom_receiver)?; @@ -100,36 +99,6 @@ pub fn execute( connection_id, interchain_account_id, } => execute_register_ica(deps, env, connection_id, interchain_account_id), - ExecuteMsg::Delegate { - validator, - interchain_account_id, - amount, - denom, - timeout, - } => execute_delegate( - deps, - env, - interchain_account_id, - validator, - amount, - denom, - timeout, - ), - ExecuteMsg::Undelegate { - validator, - interchain_account_id, - amount, - denom, - timeout, - } => execute_undelegate( - deps, - env, - interchain_account_id, - validator, - amount, - denom, - timeout, - ), } } @@ -156,20 +125,30 @@ fn try_register_gaia_ica( deps: DepsMut, env: Env, ) -> NeutronResult> { - // store the account identifier - let gaia_acc_id = "gaia-acc"; - // or channel-0.. - let ics_connection_id = "channel-1"; - // register the ica + let gaia_acc_id = String::from("gaia-acc"); + let ics_connection_id = String::from("connection-1"); let register = NeutronMsg::register_interchain_account( - ics_connection_id.to_string(), - gaia_acc_id.to_string() + ics_connection_id, + gaia_acc_id.clone() ); - - // Get the IBC port identifier generated by Neutron for the new interchain account. let key = get_port_id(env.contract.address.as_str(), &gaia_acc_id); ICS_PORT_ID.save(deps.storage, &key)?; - // Add an incomplete entry for the new account to the storage. + + // we are saving empty data here because we handle response of registering ICA in sudo_open_ack method + INTERCHAIN_ACCOUNTS.save(deps.storage, key, &None)?; + Ok(Response::new().add_message(register)) +} + +fn execute_register_ica( + deps: DepsMut, + env: Env, + connection_id: String, + interchain_account_id: String, +) -> NeutronResult> { + let register = + NeutronMsg::register_interchain_account(connection_id, interchain_account_id.clone()); + let key = get_port_id(env.contract.address.as_str(), &interchain_account_id); + // we are saving empty data here because we handle response of registering ICA in sudo_open_ack method INTERCHAIN_ACCOUNTS.save(deps.storage, key, &None)?; Ok(Response::new().add_message(register)) } @@ -214,6 +193,7 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> NeutronResult QueryMsg::ClockAddress {} => Ok( to_binary(&CLOCK_ADDRESS.may_load(deps.storage)?)? ), + QueryMsg::DepositorInterchainAccountAddress {} => query_depositor_interchain_address(deps, env), QueryMsg::InterchainAccountAddress { interchain_account_id, connection_id, @@ -229,6 +209,26 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> NeutronResult } } +pub fn query_depositor_interchain_address( + deps: Deps, + env: Env, +) -> NeutronResult { + + let gaia_acc_id = String::from("gaia-acc"); + let ics_connection_id = String::from("connection-1"); + // let account_key = get_port_id(env.contract.address.as_str(), &gaia_acc_id); + // let interchain_account_addr = INTERCHAIN_ACCOUNTS.load(deps.storage, account_key)?; + + query_interchain_address(deps, env, gaia_acc_id, ics_connection_id) + // let query = NeutronQuery::InterchainAccountAddress { + // owner_address: env.contract.address.to_string(), + // interchain_account_id: gaia_acc_id, + // connection_id: ics_connection_id, + // }; + + // let res: QueryInterchainAccountAddressResponse = deps.querier.query(&query.into())?; +} + // returns ICA address from Neutron ICA SDK module pub fn query_interchain_address( deps: Deps, @@ -272,148 +272,6 @@ pub fn query_errors_queue(deps: Deps) -> NeutronResult { Ok(to_binary(&res)?) } -// saves payload to process later to the storage and returns a SubmitTX Cosmos SubMsg with necessary reply id -fn msg_with_sudo_callback>, T>( - deps: DepsMut, - msg: C, - payload: SudoPayload, -) -> StdResult> { - save_reply_payload(deps.storage, payload)?; - Ok(SubMsg::reply_on_success(msg, SUDO_PAYLOAD_REPLY_ID)) -} - -fn execute_register_ica( - deps: DepsMut, - env: Env, - connection_id: String, - interchain_account_id: String, -) -> NeutronResult> { - let register = - NeutronMsg::register_interchain_account(connection_id, interchain_account_id.clone()); - let key = get_port_id(env.contract.address.as_str(), &interchain_account_id); - // we are saving empty data here because we handle response of registering ICA in sudo_open_ack method - INTERCHAIN_ACCOUNTS.save(deps.storage, key, &None)?; - Ok(Response::new().add_message(register)) -} - -fn execute_delegate( - mut deps: DepsMut, - env: Env, - interchain_account_id: String, - validator: String, - amount: u128, - denom: String, - timeout: Option, -) -> NeutronResult> { - // contract must pay for relaying of acknowledgements - // See more info here: https://docs.neutron.org/neutron/feerefunder/overview - let fee = min_ntrn_ibc_fee(query_min_ibc_fee(deps.as_ref())?.min_fee); - let (delegator, connection_id) = get_ica(deps.as_ref(), &env, &interchain_account_id)?; - let delegate_msg = MsgDelegate { - delegator_address: delegator, - validator_address: validator, - amount: Some(Coin { - denom, - amount: amount.to_string(), - }), - }; - let mut buf = Vec::new(); - buf.reserve(delegate_msg.encoded_len()); - - if let Err(e) = delegate_msg.encode(&mut buf) { - return Err(NeutronError::Std(StdError::generic_err(format!( - "Encode error: {}", - e - )))); - } - - let any_msg = ProtobufAny { - type_url: "/cosmos.staking.v1beta1.MsgDelegate".to_string(), - value: Binary::from(buf), - }; - - let cosmos_msg = NeutronMsg::submit_tx( - connection_id, - interchain_account_id.clone(), - vec![any_msg], - "".to_string(), - timeout.unwrap_or(DEFAULT_TIMEOUT_SECONDS), - fee, - ); - - // We use a submessage here because we need the process message reply to save - // the outgoing IBC packet identifier for later. - let submsg = msg_with_sudo_callback( - deps.branch(), - cosmos_msg, - SudoPayload { - port_id: get_port_id(env.contract.address.as_str(), &interchain_account_id), - message: "message".to_string(), - }, - )?; - - Ok(Response::default().add_submessages(vec![submsg])) -} - -fn execute_undelegate( - mut deps: DepsMut, - env: Env, - interchain_account_id: String, - validator: String, - amount: u128, - denom: String, - timeout: Option, -) -> NeutronResult> { - // contract must pay for relaying of acknowledgements - // See more info here: https://docs.neutron.org/neutron/feerefunder/overview - let fee = min_ntrn_ibc_fee(query_min_ibc_fee(deps.as_ref())?.min_fee); - let (delegator, connection_id) = get_ica(deps.as_ref(), &env, &interchain_account_id)?; - let delegate_msg = MsgUndelegate { - delegator_address: delegator, - validator_address: validator, - amount: Some(Coin { - denom, - amount: amount.to_string(), - }), - }; - let mut buf = Vec::new(); - buf.reserve(delegate_msg.encoded_len()); - - if let Err(e) = delegate_msg.encode(&mut buf) { - return Err(NeutronError::Std(StdError::generic_err(format!( - "Encode error: {}", - e - )))); - } - - let any_msg = ProtobufAny { - type_url: "/cosmos.staking.v1beta1.MsgUndelegate".to_string(), - value: Binary::from(buf), - }; - - let cosmos_msg = NeutronMsg::submit_tx( - connection_id, - interchain_account_id.clone(), - vec![any_msg], - "".to_string(), - timeout.unwrap_or(DEFAULT_TIMEOUT_SECONDS), - fee, - ); - - // We use a submessage here because we need the process message reply to save - // the outgoing IBC packet identifier for later. - let submsg = msg_with_sudo_callback( - deps.branch(), - cosmos_msg, - SudoPayload { - port_id: get_port_id(env.contract.address.as_str(), &interchain_account_id), - message: "message".to_string(), - }, - )?; - - Ok(Response::default().add_submessages(vec![submsg])) -} - #[cfg_attr(not(feature = "library"), entry_point)] pub fn sudo(deps: DepsMut, env: Env, msg: SudoMsg) -> StdResult { deps.api diff --git a/stride-covenant/packages/depositor/src/msg.rs b/stride-covenant/packages/depositor/src/msg.rs index 351b4078..85261cac 100644 --- a/stride-covenant/packages/depositor/src/msg.rs +++ b/stride-covenant/packages/depositor/src/msg.rs @@ -24,20 +24,6 @@ pub enum ExecuteMsg { connection_id: String, interchain_account_id: String, }, - Delegate { - interchain_account_id: String, - validator: String, - amount: u128, - denom: String, - timeout: Option, - }, - Undelegate { - interchain_account_id: String, - validator: String, - amount: u128, - denom: String, - timeout: Option, - }, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] @@ -46,6 +32,7 @@ pub enum QueryMsg { StAtomReceiver {}, AtomReceiver {}, ClockAddress {}, + DepositorInterchainAccountAddress {}, /// this query goes to neutron and get stored ICA with a specific query InterchainAccountAddress { interchain_account_id: String, diff --git a/stride-covenant/tests/interchaintest/ics_test.go b/stride-covenant/tests/interchaintest/ics_test.go index e054f00c..35b1e018 100644 --- a/stride-covenant/tests/interchaintest/ics_test.go +++ b/stride-covenant/tests/interchaintest/ics_test.go @@ -45,6 +45,12 @@ type InterchainAccountAddressQuery struct { ConnectionId string `json:"connection_id"` } +type DepositorICAContractQuery struct { + DepositorInterchainAccountAddress DepositorInterchainAccountAddressQuery `json:"depositor_interchain_account_address,omitempty"` +} + +type DepositorInterchainAccountAddressQuery struct{} + type DepositorContractQuery struct { ClockAddress ClockAddressQuery `json:"clock_address"` } @@ -81,6 +87,10 @@ type InterchainAccountAddressQueryResponse struct { InterchainAccountAddress string `json:"interchain_account_address"` } +type DepositorInterchainAccountAddressQueryResponse struct { + DepositorInterchainAccountAddress string `json:"depositor_interchain_account_address"` +} + // Sets custom fields for the Neutron genesis file that interchaintest isn't aware of by default. // // soft_opt_out_threshold - the bottom `soft_opt_out_threshold` @@ -326,8 +336,7 @@ func TestICS(t *testing.T) { require.NoError(t, err, "Failed to marshall instantiateMsg") address, err := cosmosNeutron.InstantiateContract(ctx, neutronUser.KeyName, codeId, string(str), true) - - require.NoError(t, err, "failed to instantiate ICA contract: ", err) + require.NoError(t, err, "failed to instantiate depositor contract: ", err) t.Run("query instantiated clock", func(t *testing.T) { var response ClockQueryResponse @@ -354,6 +363,58 @@ func TestICS(t *testing.T) { require.NoError(t, err, "failed to query atom weighted receiver") require.Equal(t, atomWeightedReceiver, atomReceiver.Data) }) + + t.Run("first tick instantiates ICA", func(t *testing.T) { + cmd = []string{"neutrond", "tx", "wasm", "execute", address, + `{"tick":{}}`, + "--from", neutronUser.KeyName, + "--gas-prices", "0.0untrn", + "--gas-adjustment", `10.5`, + "--output", "json", + "--home", "/var/cosmos-chain/neutron-2", + "--node", neutron.GetRPCAddress(), + "--home", neutron.HomeDir(), + "--chain-id", neutron.Config().ChainID, + "--from", "faucet", + "--gas", "100.0untrn", + "--keyring-backend", keyring.BackendTest, + "-y", + } + + _, _, err = neutron.Exec(ctx, cmd, nil) + require.NoError(t, err) + + // Wait a bit for the ICA packet to get relayed. This takes a + // long time as the relayer has to do an entire IBC handshake + // because ICA creates a channel per account. + err = testutil.WaitForBlocks(ctx, 10, atom, neutron) + require.NoError(t, err, "failed to wait for blocks") + + connections, err := r.GetConnections(ctx, eRep, "neutron-2") + require.NoError(t, err, "failed to get neturon-2 IBC connections from relayer") + var connectionId string + for _, connection := range connections { + for _, version := range connection.Versions { + if version.String() != "transfer" { + connectionId = connection.ID + break + } + } + } + print("\n connection id : ", connectionId, " \n") + // Finally, we query the contract for the address of the + // account on Atom. + var response QueryResponse + err = cosmosNeutron.QueryContract(ctx, address, IcaExampleContractQuery{ + InterchainAccountAddress: InterchainAccountAddressQuery{ + InterchainAccountId: "gaia-acc", + ConnectionId: connectionId, + }, + }, &response) + print(string(response.Data.InterchainAccountAddress)) + require.NoError(t, err, "failed to query ICA account address") + require.NotEmpty(t, response.Data.InterchainAccountAddress, "an account should have been created") + }) }) } From 82bc61bf5c92ac741831272ab57e5ec612560a9c Mon Sep 17 00:00:00 2001 From: bekauz Date: Thu, 8 Jun 2023 18:37:29 +0200 Subject: [PATCH 10/20] tick instantiates ica; query for ica address --- .../packages/depositor/src/contract.rs | 45 ++++++++------ .../packages/depositor/src/state.rs | 1 + .../tests/interchaintest/ics_test.go | 61 +++++++++++-------- 3 files changed, 60 insertions(+), 47 deletions(-) diff --git a/stride-covenant/packages/depositor/src/contract.rs b/stride-covenant/packages/depositor/src/contract.rs index 0112804c..220e93b8 100644 --- a/stride-covenant/packages/depositor/src/contract.rs +++ b/stride-covenant/packages/depositor/src/contract.rs @@ -32,7 +32,7 @@ use neutron_sdk::{ use crate::state::{ add_error_to_queue, read_errors_from_queue, read_reply_payload, read_sudo_payload, save_reply_payload, save_sudo_payload, AcknowledgementResult, SudoPayload, - ACKNOWLEDGEMENT_RESULTS, INTERCHAIN_ACCOUNTS, SUDO_PAYLOAD_REPLY_ID, CLOCK_ADDRESS, STRIDE_ATOM_RECEIVER, NATIVE_ATOM_RECEIVER, ICS_PORT_ID, + ACKNOWLEDGEMENT_RESULTS, INTERCHAIN_ACCOUNTS, SUDO_PAYLOAD_REPLY_ID, CLOCK_ADDRESS, STRIDE_ATOM_RECEIVER, NATIVE_ATOM_RECEIVER, ICS_PORT_ID, ICA_ADDRESS, }; // Default timeout for SubmitTX is two weeks @@ -104,20 +104,13 @@ pub fn execute( fn try_tick(deps: DepsMut, env: Env, info: MessageInfo) -> NeutronResult> { - // validate called is clock - - // retrieve the existing interchain account (s?) - let gaia_key = ICS_PORT_ID.load(deps.storage)?; - let gaia_interchain_account = INTERCHAIN_ACCOUNTS.load( - deps.as_ref().storage, - gaia_key - )?; - match gaia_interchain_account { + // TODO: validate caller is clock + let ica_address = ICA_ADDRESS.load(deps.storage); + match ica_address { + Ok(gaia_account_address) => try_execute_transfers(deps, info, gaia_account_address), // if it's the first tick and no ica exist, create an ica - None => try_register_gaia_ica(deps, env), // with an existing ica, proceed to transfers - Some((_, gaia_account_address) - ) => try_execute_transfers(deps, info, gaia_account_address), + _ => try_register_gaia_ica(deps, env), } } @@ -125,7 +118,7 @@ fn try_register_gaia_ica( deps: DepsMut, env: Env, ) -> NeutronResult> { - let gaia_acc_id = String::from("gaia-acc"); + let gaia_acc_id = String::from("test"); let ics_connection_id = String::from("connection-1"); let register = NeutronMsg::register_interchain_account( ics_connection_id, @@ -213,13 +206,24 @@ pub fn query_depositor_interchain_address( deps: Deps, env: Env, ) -> NeutronResult { - - let gaia_acc_id = String::from("gaia-acc"); - let ics_connection_id = String::from("connection-1"); + let addr = ICA_ADDRESS.load(deps.storage); + + match addr { + Ok(val) => { + let address_response = QueryInterchainAccountAddressResponse { + interchain_account_address: val, + }; + Ok(to_binary(&address_response)?) + }, + Err(_) => Err(NeutronError::Std(StdError::not_found("no ica stored"))), + } + + // let gaia_acc_id = String::from("gaia-acc"); + // let ics_connection_id = String::from("connection-1"); // let account_key = get_port_id(env.contract.address.as_str(), &gaia_acc_id); // let interchain_account_addr = INTERCHAIN_ACCOUNTS.load(deps.storage, account_key)?; - query_interchain_address(deps, env, gaia_acc_id, ics_connection_id) + // query_interchain_address(deps, env, gaia_acc_id, ics_connection_id) // let query = NeutronQuery::InterchainAccountAddress { // owner_address: env.contract.address.to_string(), // interchain_account_id: gaia_acc_id, @@ -331,10 +335,11 @@ fn sudo_open_ack( deps.storage, port_id, &Some(( - parsed_version.address, - parsed_version.controller_connection_id, + parsed_version.clone().address, + parsed_version.clone().controller_connection_id, )), )?; + ICA_ADDRESS.save(deps.storage, &parsed_version.address)?; return Ok(Response::default()); } Err(StdError::generic_err("Can't parse counterparty_version")) diff --git a/stride-covenant/packages/depositor/src/state.rs b/stride-covenant/packages/depositor/src/state.rs index 3a83c875..c86ca4c0 100644 --- a/stride-covenant/packages/depositor/src/state.rs +++ b/stride-covenant/packages/depositor/src/state.rs @@ -14,6 +14,7 @@ pub const NATIVE_ATOM_RECEIVER: Item = Item::new("native_atom_ // store the clock address to verify calls pub const CLOCK_ADDRESS: Item = Item::new("clock_address"); +pub const ICA_ADDRESS: Item = Item::new("ica_address"); // ICA pub const INTERCHAIN_ACCOUNTS: Map> = Map::new("interchain_accounts"); diff --git a/stride-covenant/tests/interchaintest/ics_test.go b/stride-covenant/tests/interchaintest/ics_test.go index 35b1e018..6586eb10 100644 --- a/stride-covenant/tests/interchaintest/ics_test.go +++ b/stride-covenant/tests/interchaintest/ics_test.go @@ -45,11 +45,21 @@ type InterchainAccountAddressQuery struct { ConnectionId string `json:"connection_id"` } -type DepositorICAContractQuery struct { - DepositorInterchainAccountAddress DepositorInterchainAccountAddressQuery `json:"depositor_interchain_account_address,omitempty"` +type QueryResponse struct { + Data InterchainAccountAddressQueryResponse `json:"data"` } -type DepositorInterchainAccountAddressQuery struct{} +type ICAQueryResponse struct { + Data DepositorInterchainAccountAddressQueryResponse `json:"data"` +} + +type InterchainAccountAddressQueryResponse struct { + InterchainAccountAddress string `json:"interchain_account_address"` +} + +type DepositorICAAddressQuery struct { + DepositorInterchainAccountAddress DepositorInterchainAccountAddressQuery `json:"depositor_interchain_account_address"` +} type DepositorContractQuery struct { ClockAddress ClockAddressQuery `json:"clock_address"` @@ -66,6 +76,7 @@ type AtomWeightedReceiverQuery struct { type ClockAddressQuery struct{} type StAtomReceiverQuery struct{} type AtomReceiverQuery struct{} +type DepositorInterchainAccountAddressQuery struct{} type WeightedReceiverResponse struct { Data WeightedReceiver `json:"data"` @@ -79,13 +90,6 @@ type ClockQueryResponse struct { // interchaintest returns query responses, it does so in the form // `{"data": }`, so we need this outer data key, which is // not present in the neutron contract, to properly deserialze. -type QueryResponse struct { - Data InterchainAccountAddressQueryResponse `json:"data"` -} - -type InterchainAccountAddressQueryResponse struct { - InterchainAccountAddress string `json:"interchain_account_address"` -} type DepositorInterchainAccountAddressQueryResponse struct { DepositorInterchainAccountAddress string `json:"depositor_interchain_account_address"` @@ -365,18 +369,20 @@ func TestICS(t *testing.T) { }) t.Run("first tick instantiates ICA", func(t *testing.T) { + // should remain constant + connectionId := "connection-1" cmd = []string{"neutrond", "tx", "wasm", "execute", address, `{"tick":{}}`, "--from", neutronUser.KeyName, "--gas-prices", "0.0untrn", - "--gas-adjustment", `10.5`, + "--gas-adjustment", `1.5`, "--output", "json", "--home", "/var/cosmos-chain/neutron-2", "--node", neutron.GetRPCAddress(), "--home", neutron.HomeDir(), "--chain-id", neutron.Config().ChainID, "--from", "faucet", - "--gas", "100.0untrn", + "--gas", "auto", "--keyring-backend", keyring.BackendTest, "-y", } @@ -390,30 +396,31 @@ func TestICS(t *testing.T) { err = testutil.WaitForBlocks(ctx, 10, atom, neutron) require.NoError(t, err, "failed to wait for blocks") - connections, err := r.GetConnections(ctx, eRep, "neutron-2") - require.NoError(t, err, "failed to get neturon-2 IBC connections from relayer") - var connectionId string - for _, connection := range connections { - for _, version := range connection.Versions { - if version.String() != "transfer" { - connectionId = connection.ID - break - } - } - } - print("\n connection id : ", connectionId, " \n") // Finally, we query the contract for the address of the // account on Atom. var response QueryResponse err = cosmosNeutron.QueryContract(ctx, address, IcaExampleContractQuery{ InterchainAccountAddress: InterchainAccountAddressQuery{ - InterchainAccountId: "gaia-acc", + InterchainAccountId: "test", ConnectionId: connectionId, }, }, &response) - print(string(response.Data.InterchainAccountAddress)) require.NoError(t, err, "failed to query ICA account address") - require.NotEmpty(t, response.Data.InterchainAccountAddress, "an account should have been created") + require.NotEmpty(t, response.Data.InterchainAccountAddress) + + var addrResponse QueryResponse + err = cosmosNeutron.QueryContract(ctx, address, DepositorICAAddressQuery{ + DepositorInterchainAccountAddress: DepositorInterchainAccountAddressQuery{}, + }, &addrResponse) + require.NoError(t, err, "failed to query ICA account address") + require.NotEmpty(t, addrResponse.Data.InterchainAccountAddress) + + // validate that querying an address via neutron query + // and by retrieving it from store is the same + require.EqualValues(t, + response.Data.InterchainAccountAddress, + addrResponse.Data.InterchainAccountAddress, + ) }) }) From 3113502d69141408357d80d65cc12d47f9e15b50 Mon Sep 17 00:00:00 2001 From: bekauz Date: Fri, 9 Jun 2023 18:45:25 +0200 Subject: [PATCH 11/20] funding depositor ICA account; wip: second tick --- .../packages/depositor/src/contract.rs | 203 +++++++++++++++--- .../tests/interchaintest/ics_test.go | 91 +++++++- 2 files changed, 266 insertions(+), 28 deletions(-) diff --git a/stride-covenant/packages/depositor/src/contract.rs b/stride-covenant/packages/depositor/src/contract.rs index 220e93b8..204a0b50 100644 --- a/stride-covenant/packages/depositor/src/contract.rs +++ b/stride-covenant/packages/depositor/src/contract.rs @@ -1,14 +1,19 @@ -use cosmos_sdk_proto::cosmos::base::v1beta1::Coin; +use cosmos_sdk_proto::cosmos::base::v1beta1; use cosmos_sdk_proto::cosmos::staking::v1beta1::{ - MsgDelegate, MsgDelegateResponse, MsgUndelegate, MsgUndelegateResponse, + MsgDelegateResponse, MsgUndelegateResponse, }; +use cosmos_sdk_proto::ibc::applications::transfer::v1::MsgTransfer; #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ to_binary, Binary, CosmosMsg, CustomQuery, Deps, DepsMut, Env, MessageInfo, Reply, Response, - StdError, StdResult, SubMsg, Addr, + StdError, StdResult, SubMsg, Addr, Coin, Uint128, }; use cw2::set_contract_version; +use neutron_sdk::bindings::types::ProtobufAny; +use neutron_sdk::interchain_queries::v045::new_register_transfers_query_msg; +use neutron_sdk::query::min_ibc_fee::query_min_ibc_fee; +use neutron_sdk::sudo::msg::RequestPacketTimeoutHeight; use prost::Message; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -19,25 +24,27 @@ use neutron_sdk::{ bindings::{ msg::{MsgSubmitTxResponse, NeutronMsg}, query::{NeutronQuery, QueryInterchainAccountAddressResponse}, - types::ProtobufAny, }, interchain_txs::helpers::{ decode_acknowledgement_response, decode_message_response, get_port_id, }, - query::min_ibc_fee::query_min_ibc_fee, sudo::msg::{RequestPacket, SudoMsg}, NeutronError, NeutronResult, }; use crate::state::{ add_error_to_queue, read_errors_from_queue, read_reply_payload, read_sudo_payload, - save_reply_payload, save_sudo_payload, AcknowledgementResult, SudoPayload, - ACKNOWLEDGEMENT_RESULTS, INTERCHAIN_ACCOUNTS, SUDO_PAYLOAD_REPLY_ID, CLOCK_ADDRESS, STRIDE_ATOM_RECEIVER, NATIVE_ATOM_RECEIVER, ICS_PORT_ID, ICA_ADDRESS, + save_sudo_payload, AcknowledgementResult, + ACKNOWLEDGEMENT_RESULTS, INTERCHAIN_ACCOUNTS, SUDO_PAYLOAD_REPLY_ID, CLOCK_ADDRESS, STRIDE_ATOM_RECEIVER, NATIVE_ATOM_RECEIVER, ICS_PORT_ID, ICA_ADDRESS, SudoPayload, save_reply_payload, }; // Default timeout for SubmitTX is two weeks const DEFAULT_TIMEOUT_SECONDS: u64 = 60 * 60 * 24 * 7 * 2; +const DEFAULT_TIMEOUT_HEIGHT: u64 = 10000000; const FEE_DENOM: &str = "untrn"; +const ATOM_DENOM: &str = "uatom"; +const DEFAULT_CONNECTION: &str = "connection-1"; +const IBC_CONNECTION: &str = "connection-0"; const CONTRACT_NAME: &str = concat!("crates.io:neutron-sdk__", env!("CARGO_PKG_NAME")); const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -53,6 +60,12 @@ struct OpenAckVersion { tx_type: String, } +// #[derive(Serialize, Deserialize)] +// pub enum SudoPayload { +// HandlerPayload1(Type1), +// HandlerPayload2(Type2), +// } + #[cfg_attr(not(feature = "library"), entry_point)] pub fn instantiate( deps: DepsMut, @@ -85,7 +98,7 @@ pub fn instantiate( #[entry_point] pub fn execute( - deps: DepsMut, + mut deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, @@ -103,11 +116,11 @@ pub fn execute( } -fn try_tick(deps: DepsMut, env: Env, info: MessageInfo) -> NeutronResult> { +fn try_tick(mut deps: DepsMut, env: Env, info: MessageInfo) -> NeutronResult> { // TODO: validate caller is clock let ica_address = ICA_ADDRESS.load(deps.storage); match ica_address { - Ok(gaia_account_address) => try_execute_transfers(deps, info, gaia_account_address), + Ok(gaia_account_address) => try_execute_transfers(deps, env, info, gaia_account_address), // if it's the first tick and no ica exist, create an ica // with an existing ica, proceed to transfers _ => try_register_gaia_ica(deps, env), @@ -115,7 +128,7 @@ fn try_tick(deps: DepsMut, env: Env, info: MessageInfo) -> Neutron } fn try_register_gaia_ica( - deps: DepsMut, + mut deps: DepsMut, env: Env, ) -> NeutronResult> { let gaia_acc_id = String::from("test"); @@ -133,7 +146,7 @@ fn try_register_gaia_ica( } fn execute_register_ica( - deps: DepsMut, + deps: DepsMut, env: Env, connection_id: String, interchain_account_id: String, @@ -147,26 +160,168 @@ fn execute_register_ica( } fn try_execute_transfers( - deps: DepsMut, + mut deps: DepsMut, + env: Env, info: MessageInfo, gaia_account_address: String ) -> NeutronResult> { // validate that tick was triggered by the authorized clock - let clock = CLOCK_ADDRESS.load(deps.as_ref().storage)?; - if info.sender != clock { - return Err(NeutronError::Std( - StdError::GenericErr { msg: "Unauthorized".to_string() }) - ) + // validate whether ICA has enough atom? + + let stride_atom_receiver = STRIDE_ATOM_RECEIVER.load(deps.branch().storage)?; + let native_atom_receiver = NATIVE_ATOM_RECEIVER.load(deps.branch().storage)?; + + // match bal { + // Ok(coin) => { + // validate depositor ICA has enough atoms to perform both transfers? + + // 1. transfer 1/2 of atoms to liquid-staker module + + // // 2. transfer 1/2 of atoms from ICA to liquidity-pooler module + + // let fee = min_ntrn_ibc_fee(query_min_ibc_fee(deps.as_ref())?.min_fee); + let fee = IbcFee { + recv_fee: vec![], // must be empty + ack_fee: vec![Coin::new(1000u128, "untrn")], + timeout_fee: vec![Coin::new(1000u128, "untrn")], + }; + + let ls_coin = v1beta1::Coin { + denom: ATOM_DENOM.to_string(), + amount: stride_atom_receiver.amount.to_string(), + }; + let lp_coin = v1beta1::Coin { + denom: ATOM_DENOM.to_string(), + amount: native_atom_receiver.amount.to_string(), + }; + + let ls_msg = MsgTransfer { + source_port: "transfer".to_string(), + source_channel: "channel-0".to_string(), + token: Some(ls_coin), + sender: gaia_account_address.clone(), + receiver: stride_atom_receiver.address, + timeout_height: None, + timeout_timestamp: 0, + }; + + + let lp_msg = MsgTransfer { + source_port: "transfer".to_string(), + source_channel: "channel-0".to_string(), + token: Some(lp_coin), + sender: gaia_account_address.clone(), + receiver: native_atom_receiver.address, + timeout_height: None, + timeout_timestamp: 0, + }; + + // Serialize the Transfer messages + let mut ls_buf = Vec::new(); + ls_buf.reserve(ls_msg.encoded_len()); + + if let Err(e) = ls_msg.encode(&mut ls_buf) { + return Err(StdError::generic_err(format!("Encode error: {}", e)).into()); } - let stride_atom_receiver = STRIDE_ATOM_RECEIVER.load(deps.storage)?; - let native_atom_receiver = NATIVE_ATOM_RECEIVER.load(deps.storage)?; + let mut lp_buf = Vec::new(); + lp_buf.reserve(lp_msg.encoded_len()); - // receiving a tick means depositor is ready to attempt to: - // 1. transfer 1/2 of atoms to liquid-staker module - // 2. transfer 1/2 of atoms from ICA to liquidity-pooler module + if let Err(e) = lp_msg.encode(&mut lp_buf) { + return Err(StdError::generic_err(format!("Encode error: {}", e)).into()); + } - Ok(Response::default()) + let ls_protobuf = ProtobufAny { + type_url: "/ibc.applications.transfer.v1.MsgTransfer".to_string(), + value: Binary::from(ls_buf), + }; + let lp_protobuf = ProtobufAny { + type_url: "/ibc.applications.transfer.v1.MsgTransfer".to_string(), + value: Binary::from(lp_buf), + }; + + let ls_cosmos_msg = NeutronMsg::submit_tx( + DEFAULT_CONNECTION.to_string(), + "test".to_string(), + vec![ls_protobuf], + "".to_string(), + DEFAULT_TIMEOUT_SECONDS, + fee.clone() + ); + let lp_cosmos_msg = NeutronMsg::submit_tx( + DEFAULT_CONNECTION.to_string(), + "test".to_string(), + vec![lp_protobuf], + "".to_string(), + DEFAULT_TIMEOUT_SECONDS, + fee + ); + + let ls_submsg = msg_with_sudo_callback( + deps.branch(), + ls_cosmos_msg, + SudoPayload { + port_id: get_port_id( + env.contract.address.to_string(), + "test".to_string(), + ), + // Here you can store some information about the transaction to help you parse + // the acknowledgement later. + message: "ls transfer".to_string(), + }, + )?; + + let lp_submsg = msg_with_sudo_callback( + deps, + lp_cosmos_msg, + SudoPayload { + port_id: get_port_id( + env.contract.address.to_string(), + "test".to_string() + ), + // Here you can store some information about the transaction to help you parse + // the acknowledgement later. + message: "lp transfer".to_string(), + }, + )?; + + Ok(Response::default() + .add_submessages(vec![ls_submsg, lp_submsg]) + ) + // }, + // Err(_) => return Err(NeutronError::from(StdError::generic_err("failed to query atom balance on depositor"))), + // } + +} + +fn msg_with_sudo_callback>, T>( + deps: DepsMut, + msg: C, + payload: SudoPayload, +) -> StdResult> { + save_reply_payload(deps.storage, payload)?; + Ok(SubMsg::reply_on_success(msg, SUDO_PAYLOAD_REPLY_ID)) +} + +// fn msg_with_sudo_callback>, T>( +// deps: DepsMut, +// msg: C, +// payload: SudoPayload, +// ) -> StdResult> { +// let id = save_reply_payload(deps.storage, payload)?; +// Ok(SubMsg::reply_on_success(msg, id)) +// } + +pub fn register_transfers_query( + connection_id: String, + recipient: String, + update_period: u64, + min_height: Option, +) -> NeutronResult> { + let msg = + new_register_transfers_query_msg(connection_id, recipient, update_period, min_height)?; + + Ok(Response::new().add_message(msg)) } fn try_handle_received() -> NeutronResult> { diff --git a/stride-covenant/tests/interchaintest/ics_test.go b/stride-covenant/tests/interchaintest/ics_test.go index 6586eb10..971e5ad1 100644 --- a/stride-covenant/tests/interchaintest/ics_test.go +++ b/stride-covenant/tests/interchaintest/ics_test.go @@ -8,6 +8,7 @@ import ( "time" "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/types" "github.com/icza/dyno" ibctest "github.com/strangelove-ventures/interchaintest/v3" "github.com/strangelove-ventures/interchaintest/v3/chain/cosmos" @@ -205,7 +206,6 @@ func TestICS(t *testing.T) { // support, and another for a Cosmos blockchain. atom, neutron, stride := chains[0], chains[1], chains[2] _, cosmosNeutron := atom.(*cosmos.CosmosChain), neutron.(*cosmos.CosmosChain) - _ = cosmosNeutron // Relayer Factory client, network := ibctest.DockerSetup(t) @@ -314,6 +314,14 @@ func TestICS(t *testing.T) { users := ibctest.GetAndFundTestUsers(t, ctx, "default", int64(100_000_000), atom, neutron, stride) gaiaUser, neutronUser, strideUser := users[0], users[1], users[2] _, _ = gaiaUser, strideUser + neutron.CreateKey(ctx, "lper") + neutron.CreateKey(ctx, "lser") + + lpAddressBytes, _ := neutron.GetAddress(ctx, "lper") + lsAddressBytes, _ := neutron.GetAddress(ctx, "lser") + + lpAddress, err := types.Bech32ifyAddressBytes(neutron.Config().Bech32Prefix, lpAddressBytes) + lsAddress, err := types.Bech32ifyAddressBytes(neutron.Config().Bech32Prefix, lsAddressBytes) t.Run("instantiate depositor", func(t *testing.T) { // Store and instantiate the Neutron ICA example contract. The @@ -322,11 +330,11 @@ func TestICS(t *testing.T) { require.NoError(t, err, "failed to store neutron ICA contract") stAtomWeightedReceiver := WeightedReceiver{ Amount: 10, - Address: "st_atom_addr", + Address: "neutron1ud6resqzgewt92njs826m5st98n9r6kkjnurup", } atomWeightedReceiver := WeightedReceiver{ Amount: 10, - Address: "atom_addr", + Address: "neutron1q0z62s0q29ecay5x7vc3lj6yq7md4lmyafqs5p", } clockContractAddress := "clock_contract_address" @@ -368,6 +376,18 @@ func TestICS(t *testing.T) { require.Equal(t, atomWeightedReceiver, atomReceiver.Data) }) + var addrResponse QueryResponse + gaiaChannels, err := r.GetChannels(ctx, eRep, "gaia-1") + require.NoError(t, err, "failed to get gaia-1 IBC channels from relayer") + gaiaChans, _ := json.Marshal(gaiaChannels) + print(string(gaiaChans)) + + neutronChannels, err := r.GetChannels(ctx, eRep, "neutron-2") + require.NoError(t, err, "failed to get neutron-2 IBC channels from relayer") + neutronChans, _ := json.Marshal(neutronChannels) + print(string(neutronChans)) + + // TODO: determine gaia-neutron channels for ibc transfers t.Run("first tick instantiates ICA", func(t *testing.T) { // should remain constant connectionId := "connection-1" @@ -408,7 +428,6 @@ func TestICS(t *testing.T) { require.NoError(t, err, "failed to query ICA account address") require.NotEmpty(t, response.Data.InterchainAccountAddress) - var addrResponse QueryResponse err = cosmosNeutron.QueryContract(ctx, address, DepositorICAAddressQuery{ DepositorInterchainAccountAddress: DepositorInterchainAccountAddressQuery{}, }, &addrResponse) @@ -422,6 +441,70 @@ func TestICS(t *testing.T) { addrResponse.Data.InterchainAccountAddress, ) }) + + t.Run("multisig transfers atom to ICA account", func(t *testing.T) { + // transfer funds from gaiaUser to the newly generated ICA account + err := atom.SendFunds(ctx, gaiaUser.KeyName, ibc.WalletAmount{ + Address: addrResponse.Data.InterchainAccountAddress, + Amount: 20, + Denom: atom.Config().Denom, + }) + + require.NoError(t, err, "failed to send funds from gaia to neutron ICA") + err = testutil.WaitForBlocks(ctx, 10, atom, neutron) + require.NoError(t, err, "failed to wait for blocks") + + atomBal, err := atom.GetBalance(ctx, addrResponse.Data.InterchainAccountAddress, atom.Config().Denom) + require.NoError(t, err, "failed to get ICA balance") + require.EqualValues(t, 20, atomBal) + }) + + t.Run("second tick transfers", func(t *testing.T) { + initLiquidStakerAtomBal, err := neutron.GetBalance(ctx, lsAddress, "uatom") + require.NoError(t, err, "failed to get LSer balance") + initLiquidityPoolerAtomBal, err := neutron.GetBalance(ctx, lpAddress, "uatom") + require.NoError(t, err, "failed to get LPer balance") + require.EqualValues(t, initLiquidStakerAtomBal, 0) + require.EqualValues(t, initLiquidityPoolerAtomBal, 0) + + print("\n ticking...\n") + cmd = []string{"neutrond", "tx", "wasm", "execute", address, + `{"tick":{}}`, + "--from", neutronUser.KeyName, + "--gas-prices", "0.0untrn", + "--gas-adjustment", `1.5`, + "--output", "json", + "--home", "/var/cosmos-chain/neutron-2", + "--node", neutron.GetRPCAddress(), + "--home", neutron.HomeDir(), + "--chain-id", neutron.Config().ChainID, + "--from", "faucet", + "--gas", "100.0untrn", + "--keyring-backend", keyring.BackendTest, + "-y", + } + + _, _, err = neutron.Exec(ctx, cmd, nil) + require.NoError(t, err) + + // Wait a bit for the ICA packet to get relayed. This takes a + // long time as the relayer has to do an entire IBC handshake + // because ICA creates a channel per account. + err = testutil.WaitForBlocks(ctx, 10, atom, neutron) + require.NoError(t, err, "failed to wait for blocks") + + atomICABal, err := atom.GetBalance(ctx, addrResponse.Data.InterchainAccountAddress, "uatom") + require.NoError(t, err, "failed to ICA balance") + require.Equal(t, 0, atomICABal) + + // query respective accounts and validate they received the funds + liquidStakerAtomBal, err := cosmosNeutron.GetBalance(ctx, lsAddress, "uatom") + require.NoError(t, err, "failed to get LSer balance") + liquidityPoolerAtomBal, err := cosmosNeutron.GetBalance(ctx, lpAddress, "uatom") + require.NoError(t, err, "failed to get LPer balance") + require.EqualValues(t, liquidStakerAtomBal, 10, "LS did not receive atom") + require.EqualValues(t, liquidityPoolerAtomBal, 10, "LP did not receive atom") + }) }) } From 006f6d602ff7d4fd0a631287461907d648d77f74 Mon Sep 17 00:00:00 2001 From: bekauz Date: Sat, 10 Jun 2023 23:58:21 +0200 Subject: [PATCH 12/20] wip: transfer from ica to depositor --- .../packages/depositor/src/contract.rs | 90 +++++++++++++++++-- .../tests/interchaintest/ics_test.go | 52 +++++++---- 2 files changed, 122 insertions(+), 20 deletions(-) diff --git a/stride-covenant/packages/depositor/src/contract.rs b/stride-covenant/packages/depositor/src/contract.rs index 204a0b50..6ef05c9d 100644 --- a/stride-covenant/packages/depositor/src/contract.rs +++ b/stride-covenant/packages/depositor/src/contract.rs @@ -118,15 +118,96 @@ pub fn execute( fn try_tick(mut deps: DepsMut, env: Env, info: MessageInfo) -> NeutronResult> { // TODO: validate caller is clock + // TODO: introduce some state variable to determine next action let ica_address = ICA_ADDRESS.load(deps.storage); match ica_address { - Ok(gaia_account_address) => try_execute_transfers(deps, env, info, gaia_account_address), + Ok(gaia_account_address) => { + let atom_bal = deps.querier.query_balance( + env.clone().contract.address, + ATOM_DENOM, + )?; + // if atom_bal.amount.is_zero() { + try_receive_atom_from_ica(deps, env, info, gaia_account_address) + // } + // else { + // try_execute_transfers(deps, env, info, gaia_account_address) + // } + }, // if it's the first tick and no ica exist, create an ica // with an existing ica, proceed to transfers _ => try_register_gaia_ica(deps, env), } } +fn try_receive_atom_from_ica( + mut deps: DepsMut, + env: Env, + info: MessageInfo, + gaia_account_address: String +) -> NeutronResult> { + let (gaia_ica, connection_id) = get_ica(deps.as_ref(), &env, &"test")?; + + let fee = IbcFee { + recv_fee: vec![], // must be empty + ack_fee: vec![Coin::new(1000u128, "untrn")], + timeout_fee: vec![Coin::new(1000u128, "untrn")], + }; + + let coin = v1beta1::Coin { + denom: ATOM_DENOM.to_string(), + amount: Uint128::new(20).to_string(), + }; + + let msg = MsgTransfer { + source_port: "transfer".to_string(), + source_channel: "channel-0".to_string(), + token: Some(coin), + sender: gaia_account_address.clone(), + receiver: env.contract.address.to_string(), + timeout_height: None, + timeout_timestamp: 0, + }; + + + // Serialize the Transfer messages + let mut buf = Vec::new(); + buf.reserve(msg.encoded_len()); + + if let Err(e) = msg.encode(&mut buf) { + return Err(StdError::generic_err(format!("Encode error: {}", e)).into()); + } + + let protobuf = ProtobufAny { + type_url: "/ibc.applications.transfer.v1.MsgTransfer".to_string(), + value: Binary::from(buf), + }; + + let cosmos_msg = NeutronMsg::submit_tx( + connection_id, + "test".to_string(), + vec![protobuf], + "".to_string(), + DEFAULT_TIMEOUT_SECONDS, + fee.clone() + ); + + let submsg = msg_with_sudo_callback( + deps.branch(), + cosmos_msg, + SudoPayload { + port_id: get_port_id( + env.contract.address.to_string(), + "test".to_string(), + ), + message: "ica transfer".to_string(), + }, + )?; + + Ok(Response::default() + .add_submessage(submsg) + ) +} + fn try_register_gaia_ica( mut deps: DepsMut, env: Env, @@ -204,7 +285,6 @@ fn try_execute_transfers( timeout_height: None, timeout_timestamp: 0, }; - let lp_msg = MsgTransfer { source_port: "transfer".to_string(), @@ -234,14 +314,14 @@ fn try_execute_transfers( let ls_protobuf = ProtobufAny { type_url: "/ibc.applications.transfer.v1.MsgTransfer".to_string(), value: Binary::from(ls_buf), - }; + }; let lp_protobuf = ProtobufAny { type_url: "/ibc.applications.transfer.v1.MsgTransfer".to_string(), value: Binary::from(lp_buf), }; let ls_cosmos_msg = NeutronMsg::submit_tx( - DEFAULT_CONNECTION.to_string(), + IBC_CONNECTION.to_string(), "test".to_string(), vec![ls_protobuf], "".to_string(), @@ -249,7 +329,7 @@ fn try_execute_transfers( fee.clone() ); let lp_cosmos_msg = NeutronMsg::submit_tx( - DEFAULT_CONNECTION.to_string(), + IBC_CONNECTION.to_string(), "test".to_string(), vec![lp_protobuf], "".to_string(), diff --git a/stride-covenant/tests/interchaintest/ics_test.go b/stride-covenant/tests/interchaintest/ics_test.go index 971e5ad1..d4f3efde 100644 --- a/stride-covenant/tests/interchaintest/ics_test.go +++ b/stride-covenant/tests/interchaintest/ics_test.go @@ -377,16 +377,6 @@ func TestICS(t *testing.T) { }) var addrResponse QueryResponse - gaiaChannels, err := r.GetChannels(ctx, eRep, "gaia-1") - require.NoError(t, err, "failed to get gaia-1 IBC channels from relayer") - gaiaChans, _ := json.Marshal(gaiaChannels) - print(string(gaiaChans)) - - neutronChannels, err := r.GetChannels(ctx, eRep, "neutron-2") - require.NoError(t, err, "failed to get neutron-2 IBC channels from relayer") - neutronChans, _ := json.Marshal(neutronChannels) - print(string(neutronChans)) - // TODO: determine gaia-neutron channels for ibc transfers t.Run("first tick instantiates ICA", func(t *testing.T) { // should remain constant @@ -459,7 +449,39 @@ func TestICS(t *testing.T) { require.EqualValues(t, 20, atomBal) }) - t.Run("second tick transfers", func(t *testing.T) { + t.Run("second tick ibc transfers atom from ICA account to neutron", func(t *testing.T) { + cmd = []string{"neutrond", "tx", "wasm", "execute", address, + `{"tick":{}}`, + "--from", neutronUser.KeyName, + "--gas-prices", "0.0untrn", + "--gas-adjustment", `1.5`, + "--output", "json", + "--home", "/var/cosmos-chain/neutron-2", + "--node", neutron.GetRPCAddress(), + "--home", neutron.HomeDir(), + "--chain-id", neutron.Config().ChainID, + "--from", "faucet", + "--gas", "50000.0untrn", + "--keyring-backend", keyring.BackendTest, + "-y", + } + + _, _, err = neutron.Exec(ctx, cmd, nil) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, atom, neutron) + require.NoError(t, err, "failed to wait for blocks") + + atomICABal, err := atom.GetBalance(ctx, addrResponse.Data.InterchainAccountAddress, "uatom") + require.NoError(t, err, "failed to query ICA balance") + require.Equal(t, 0, atomICABal) + + neutronAtomBal, err := neutron.GetBalance(ctx, address, "uatom") + require.NoError(t, err, "failed to query neutron atom balance") + require.Equal(t, 20, neutronAtomBal) + }) + + t.Run("third tick transfers to LS and LP modules", func(t *testing.T) { initLiquidStakerAtomBal, err := neutron.GetBalance(ctx, lsAddress, "uatom") require.NoError(t, err, "failed to get LSer balance") initLiquidityPoolerAtomBal, err := neutron.GetBalance(ctx, lpAddress, "uatom") @@ -479,7 +501,7 @@ func TestICS(t *testing.T) { "--home", neutron.HomeDir(), "--chain-id", neutron.Config().ChainID, "--from", "faucet", - "--gas", "100.0untrn", + "--gas", "50000.0untrn", "--keyring-backend", keyring.BackendTest, "-y", } @@ -493,9 +515,9 @@ func TestICS(t *testing.T) { err = testutil.WaitForBlocks(ctx, 10, atom, neutron) require.NoError(t, err, "failed to wait for blocks") - atomICABal, err := atom.GetBalance(ctx, addrResponse.Data.InterchainAccountAddress, "uatom") - require.NoError(t, err, "failed to ICA balance") - require.Equal(t, 0, atomICABal) + depositorAtomBal, err := neutron.GetBalance(ctx, address, "uatom") + require.NoError(t, err, "failed to query depositor atom balance") + require.Equal(t, 0, depositorAtomBal) // query respective accounts and validate they received the funds liquidStakerAtomBal, err := cosmosNeutron.GetBalance(ctx, lsAddress, "uatom") From e572f0a27995d8217dd5ae6e4d3b8d0f87b724c8 Mon Sep 17 00:00:00 2001 From: bekauz Date: Sun, 11 Jun 2023 16:05:11 +0200 Subject: [PATCH 13/20] adding readme and contract state enum; wip: gas debugging for ica transfer --- stride-covenant/packages/depositor/README.md | 11 ++ .../packages/depositor/src/contract.rs | 130 ++++++++--------- .../packages/depositor/src/state.rs | 10 ++ .../tests/interchaintest/ics_test.go | 131 +++++++++++++----- 4 files changed, 187 insertions(+), 95 deletions(-) create mode 100644 stride-covenant/packages/depositor/README.md diff --git a/stride-covenant/packages/depositor/README.md b/stride-covenant/packages/depositor/README.md new file mode 100644 index 00000000..fda8e5dd --- /dev/null +++ b/stride-covenant/packages/depositor/README.md @@ -0,0 +1,11 @@ +# Depositor + +This module is the depositor in stride-covenant system. +It is responsible for the following tasks: +1. Instantiating an ICA on gaia +1. Transfering Atom from gaia ICA to itself via IBC +1. Splitting the available Atom in half and funding the LP and LS modules + +The contract determines the next actions to take purely based on its own state. +After receiving a `tick: {}` message from the clock, it attempts to advance the state. + diff --git a/stride-covenant/packages/depositor/src/contract.rs b/stride-covenant/packages/depositor/src/contract.rs index 6ef05c9d..ffc0f599 100644 --- a/stride-covenant/packages/depositor/src/contract.rs +++ b/stride-covenant/packages/depositor/src/contract.rs @@ -1,4 +1,6 @@ -use cosmos_sdk_proto::cosmos::base::v1beta1; +use cosmos_sdk_proto::cosmos; +use cosmos_sdk_proto::cosmos::base::v1beta1::Coin; + use cosmos_sdk_proto::cosmos::staking::v1beta1::{ MsgDelegateResponse, MsgUndelegateResponse, }; @@ -7,13 +9,11 @@ use cosmos_sdk_proto::ibc::applications::transfer::v1::MsgTransfer; use cosmwasm_std::entry_point; use cosmwasm_std::{ to_binary, Binary, CosmosMsg, CustomQuery, Deps, DepsMut, Env, MessageInfo, Reply, Response, - StdError, StdResult, SubMsg, Addr, Coin, Uint128, + StdError, StdResult, SubMsg, Addr, Uint128, }; use cw2::set_contract_version; use neutron_sdk::bindings::types::ProtobufAny; use neutron_sdk::interchain_queries::v045::new_register_transfers_query_msg; -use neutron_sdk::query::min_ibc_fee::query_min_ibc_fee; -use neutron_sdk::sudo::msg::RequestPacketTimeoutHeight; use prost::Message; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -35,16 +35,19 @@ use neutron_sdk::{ use crate::state::{ add_error_to_queue, read_errors_from_queue, read_reply_payload, read_sudo_payload, save_sudo_payload, AcknowledgementResult, - ACKNOWLEDGEMENT_RESULTS, INTERCHAIN_ACCOUNTS, SUDO_PAYLOAD_REPLY_ID, CLOCK_ADDRESS, STRIDE_ATOM_RECEIVER, NATIVE_ATOM_RECEIVER, ICS_PORT_ID, ICA_ADDRESS, SudoPayload, save_reply_payload, + ACKNOWLEDGEMENT_RESULTS, INTERCHAIN_ACCOUNTS, SUDO_PAYLOAD_REPLY_ID, CLOCK_ADDRESS, STRIDE_ATOM_RECEIVER, NATIVE_ATOM_RECEIVER, ICS_PORT_ID, ICA_ADDRESS, SudoPayload, save_reply_payload, CONTRACT_STATE, ContractState, }; // Default timeout for SubmitTX is two weeks const DEFAULT_TIMEOUT_SECONDS: u64 = 60 * 60 * 24 * 7 * 2; const DEFAULT_TIMEOUT_HEIGHT: u64 = 10000000; -const FEE_DENOM: &str = "untrn"; +const NEUTRON_DENOM: &str = "untrn"; const ATOM_DENOM: &str = "uatom"; -const DEFAULT_CONNECTION: &str = "connection-1"; const IBC_CONNECTION: &str = "connection-0"; +const ICS_CONNECTION_ID: &str = "connection-1"; +const INTERCHAIN_ACCOUNT_ID: &str = "test"; +const TRANSFER_PORT: &str = "transfer"; +const GAIA_NEUTRON_IBC_CHANNEL_ID: &str = "channel-0"; const CONTRACT_NAME: &str = concat!("crates.io:neutron-sdk__", env!("CARGO_PKG_NAME")); const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -60,12 +63,6 @@ struct OpenAckVersion { tx_type: String, } -// #[derive(Serialize, Deserialize)] -// pub enum SudoPayload { -// HandlerPayload1(Type1), -// HandlerPayload2(Type2), -// } - #[cfg_attr(not(feature = "library"), entry_point)] pub fn instantiate( deps: DepsMut, @@ -92,7 +89,8 @@ pub fn instantiate( STRIDE_ATOM_RECEIVER.save(deps.storage, &msg.st_atom_receiver)?; NATIVE_ATOM_RECEIVER.save(deps.storage, &msg.atom_receiver)?; CLOCK_ADDRESS.save(deps.storage, &Addr::unchecked(msg.clock_address))?; - + CONTRACT_STATE.save(deps.storage, &ContractState::INSTANTIATED)?; + Ok(Response::default()) } @@ -117,25 +115,19 @@ pub fn execute( fn try_tick(mut deps: DepsMut, env: Env, info: MessageInfo) -> NeutronResult> { + let current_state = CONTRACT_STATE.load(deps.storage)?; + let ica_address: Result = ICA_ADDRESS.load(deps.storage); + let gaia_account_address = match ica_address { + Ok(addr) => addr, + Err(_) => "todo".to_string(), + }; // TODO: validate caller is clock - // TODO: introduce some state variable to determine next action - let ica_address = ICA_ADDRESS.load(deps.storage); - match ica_address { - Ok(gaia_account_address) => { - let atom_bal = deps.querier.query_balance( - env.clone().contract.address, - ATOM_DENOM, - )?; - // if atom_bal.amount.is_zero() { - try_receive_atom_from_ica(deps, env, info, gaia_account_address) - // } - // else { - // try_execute_transfers(deps, env, info, gaia_account_address) - // } - }, - // if it's the first tick and no ica exist, create an ica - // with an existing ica, proceed to transfers - _ => try_register_gaia_ica(deps, env), + + match current_state { + ContractState::INSTANTIATED => try_register_gaia_ica(deps, env), + ContractState::ICA_CREATED => try_receive_atom_from_ica(deps, env, info, gaia_account_address), + ContractState::RECEIVED_FUNDS => try_execute_transfers(deps, env, info, gaia_account_address), + ContractState::COMPLETE => Ok(Response::default()), } } @@ -145,34 +137,38 @@ fn try_receive_atom_from_ica( info: MessageInfo, gaia_account_address: String ) -> NeutronResult> { - let (gaia_ica, connection_id) = get_ica(deps.as_ref(), &env, &"test")?; - let fee = IbcFee { recv_fee: vec![], // must be empty - ack_fee: vec![Coin::new(1000u128, "untrn")], - timeout_fee: vec![Coin::new(1000u128, "untrn")], + ack_fee: vec![cosmwasm_std::Coin { + denom: NEUTRON_DENOM.to_string(), + amount: Uint128::new(1000u128) + }], + timeout_fee: vec![cosmwasm_std::Coin { + denom: NEUTRON_DENOM.to_string(), + amount: Uint128::new(1000u128) + }], }; - let coin = v1beta1::Coin { + let (ica, connection_id) = get_ica(deps.as_ref(), &env, &INTERCHAIN_ACCOUNT_ID)?; + + let coin = Coin { denom: ATOM_DENOM.to_string(), amount: Uint128::new(20).to_string(), }; let msg = MsgTransfer { - source_port: "transfer".to_string(), - source_channel: "channel-0".to_string(), + source_port: TRANSFER_PORT.to_string(), + source_channel: GAIA_NEUTRON_IBC_CHANNEL_ID.to_string(), token: Some(coin), - sender: gaia_account_address.clone(), + sender: ica.clone(), receiver: env.contract.address.to_string(), timeout_height: None, timeout_timestamp: 0, }; - - // Serialize the Transfer messages + // Serialize the Transfer message let mut buf = Vec::new(); buf.reserve(msg.encoded_len()); - if let Err(e) = msg.encode(&mut buf) { return Err(StdError::generic_err(format!("Encode error: {}", e)).into()); } @@ -183,10 +179,10 @@ fn try_receive_atom_from_ica( }; let cosmos_msg = NeutronMsg::submit_tx( - connection_id, - "test".to_string(), + connection_id.clone(), + INTERCHAIN_ACCOUNT_ID.to_string(), vec![protobuf], - "".to_string(), + "ica transaction memo".to_string(), DEFAULT_TIMEOUT_SECONDS, fee.clone() ); @@ -201,9 +197,11 @@ fn try_receive_atom_from_ica( ), message: "ica transfer".to_string(), }, - )?; + )?.with_gas_limit(252814); Ok(Response::default() + .add_attribute("ica address: ", ica) + .add_attribute("connection_id: ", connection_id) .add_submessage(submsg) ) } @@ -212,8 +210,9 @@ fn try_register_gaia_ica( mut deps: DepsMut, env: Env, ) -> NeutronResult> { - let gaia_acc_id = String::from("test"); - let ics_connection_id = String::from("connection-1"); + let gaia_acc_id = INTERCHAIN_ACCOUNT_ID.to_string(); + // let ibc_connection_id = String::from("connection-0"); + let ics_connection_id = ICS_CONNECTION_ID.to_string(); let register = NeutronMsg::register_interchain_account( ics_connection_id, gaia_acc_id.clone() @@ -223,6 +222,8 @@ fn try_register_gaia_ica( // we are saving empty data here because we handle response of registering ICA in sudo_open_ack method INTERCHAIN_ACCOUNTS.save(deps.storage, key, &None)?; + + CONTRACT_STATE.save(deps.storage, &ContractState::ICA_CREATED)?; Ok(Response::new().add_message(register)) } @@ -257,27 +258,30 @@ fn try_execute_transfers( // validate depositor ICA has enough atoms to perform both transfers? // 1. transfer 1/2 of atoms to liquid-staker module - - // // 2. transfer 1/2 of atoms from ICA to liquidity-pooler module + // 2. transfer 1/2 of atoms from ICA to liquidity-pooler module // let fee = min_ntrn_ibc_fee(query_min_ibc_fee(deps.as_ref())?.min_fee); + let neutron_coin = Coin { + denom: NEUTRON_DENOM.to_string(), + amount: 1000u128.to_string(), + }; let fee = IbcFee { recv_fee: vec![], // must be empty - ack_fee: vec![Coin::new(1000u128, "untrn")], - timeout_fee: vec![Coin::new(1000u128, "untrn")], + ack_fee: vec![cosmwasm_std::Coin { denom: NEUTRON_DENOM.to_string(), amount: Uint128::new(1000u128) }], + timeout_fee: vec![cosmwasm_std::Coin { denom: NEUTRON_DENOM.to_string(), amount: Uint128::new(1000u128) }], }; - let ls_coin = v1beta1::Coin { + let ls_coin = Coin { denom: ATOM_DENOM.to_string(), amount: stride_atom_receiver.amount.to_string(), }; - let lp_coin = v1beta1::Coin { + let lp_coin = Coin { denom: ATOM_DENOM.to_string(), amount: native_atom_receiver.amount.to_string(), }; let ls_msg = MsgTransfer { - source_port: "transfer".to_string(), + source_port: TRANSFER_PORT.to_string(), source_channel: "channel-0".to_string(), token: Some(ls_coin), sender: gaia_account_address.clone(), @@ -287,7 +291,7 @@ fn try_execute_transfers( }; let lp_msg = MsgTransfer { - source_port: "transfer".to_string(), + source_port: TRANSFER_PORT.to_string(), source_channel: "channel-0".to_string(), token: Some(lp_coin), sender: gaia_account_address.clone(), @@ -322,7 +326,7 @@ fn try_execute_transfers( let ls_cosmos_msg = NeutronMsg::submit_tx( IBC_CONNECTION.to_string(), - "test".to_string(), + INTERCHAIN_ACCOUNT_ID.to_string(), vec![ls_protobuf], "".to_string(), DEFAULT_TIMEOUT_SECONDS, @@ -330,7 +334,7 @@ fn try_execute_transfers( ); let lp_cosmos_msg = NeutronMsg::submit_tx( IBC_CONNECTION.to_string(), - "test".to_string(), + INTERCHAIN_ACCOUNT_ID.to_string(), vec![lp_protobuf], "".to_string(), DEFAULT_TIMEOUT_SECONDS, @@ -343,7 +347,7 @@ fn try_execute_transfers( SudoPayload { port_id: get_port_id( env.contract.address.to_string(), - "test".to_string(), + INTERCHAIN_ACCOUNT_ID.to_string(), ), // Here you can store some information about the transaction to help you parse // the acknowledgement later. @@ -357,7 +361,7 @@ fn try_execute_transfers( SudoPayload { port_id: get_port_id( env.contract.address.to_string(), - "test".to_string() + INTERCHAIN_ACCOUNT_ID.to_string() ), // Here you can store some information about the transaction to help you parse // the acknowledgement later. @@ -848,12 +852,12 @@ fn min_ntrn_ibc_fee(fee: IbcFee) -> IbcFee { ack_fee: fee .ack_fee .into_iter() - .filter(|a| a.denom == FEE_DENOM) + .filter(|a| a.denom == NEUTRON_DENOM) .collect(), timeout_fee: fee .timeout_fee .into_iter() - .filter(|a| a.denom == FEE_DENOM) + .filter(|a| a.denom == NEUTRON_DENOM) .collect(), } } \ No newline at end of file diff --git a/stride-covenant/packages/depositor/src/state.rs b/stride-covenant/packages/depositor/src/state.rs index c86ca4c0..f7607a07 100644 --- a/stride-covenant/packages/depositor/src/state.rs +++ b/stride-covenant/packages/depositor/src/state.rs @@ -20,6 +20,16 @@ pub const INTERCHAIN_ACCOUNTS: Map> = Map::new("interchain_accounts"); pub const ICS_PORT_ID: Item = Item::new("ics_port_id"); +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum ContractState { + INSTANTIATED, + ICA_CREATED, + RECEIVED_FUNDS, + COMPLETE, +} + +pub const CONTRACT_STATE: Item = Item::new("contract_state"); /// SudoPayload is a type that stores information about a transaction that we try to execute /// on the host chain. This is a type introduced for our convenience. diff --git a/stride-covenant/tests/interchaintest/ics_test.go b/stride-covenant/tests/interchaintest/ics_test.go index d4f3efde..9d450abe 100644 --- a/stride-covenant/tests/interchaintest/ics_test.go +++ b/stride-covenant/tests/interchaintest/ics_test.go @@ -153,7 +153,10 @@ func TestICS(t *testing.T) { // Chain Factory cf := ibctest.NewBuiltinChainFactory(zaptest.NewLogger(t, zaptest.Level(zap.WarnLevel)), []*ibctest.ChainSpec{ - {Name: "gaia", Version: "v9.1.0", ChainConfig: ibc.ChainConfig{GasAdjustment: 1.5}}, + {Name: "gaia", Version: "v9.1.0", ChainConfig: ibc.ChainConfig{ + GasAdjustment: 1.3, + GasPrices: "0.0atom", + }}, { ChainConfig: ibc.ChainConfig{ Type: "cosmos", @@ -169,8 +172,8 @@ func TestICS(t *testing.T) { Bin: "neutrond", Bech32Prefix: "neutron", Denom: "untrn", - GasPrices: "0.0untrn", - GasAdjustment: 10.3, + GasPrices: "0.0untrn,0.0uatom", + GasAdjustment: 1.3, TrustingPeriod: "1197504s", NoHostMount: false, ModifyGenesis: setupNeutronGenesis("0.05", []string{"untrn"}, []string{"uatom"}), @@ -216,6 +219,9 @@ func TestICS(t *testing.T) { relayer.RelayerOptionExtraStartFlags{Flags: []string{"-d", "--log-format", "console"}}, ).Build(t, client, network) + const clockContractAddress = "clock_contract_address" + const icaAccountId = "test" + var icaAccountAddress string // Prep Interchain const gaiaNeutronICSPath = "gn-ics-path" const gaiaNeutronIBCPath = "gn-ibc-path" @@ -278,6 +284,18 @@ func TestICS(t *testing.T) { err = testutil.WaitForBlocks(ctx, 2, atom, neutron, stride) require.NoError(t, err, "failed to wait for blocks") + connections, err := r.GetConnections(ctx, eRep, "neutron-2") + require.NoError(t, err, "failed to get neutron-2 IBC connections from relayer") + var neutronIcsConnectionId string + for _, connection := range connections { + for _, version := range connection.Versions { + if version.String() != "transfer" { + neutronIcsConnectionId = connection.ID + break + } + } + } + // Before receiving a validator set change (VSC) packet, // consumer chains disallow bank transfers. To trigger a VSC // packet, this creates a validator (from a random public key) @@ -323,6 +341,13 @@ func TestICS(t *testing.T) { lpAddress, err := types.Bech32ifyAddressBytes(neutron.Config().Bech32Prefix, lpAddressBytes) lsAddress, err := types.Bech32ifyAddressBytes(neutron.Config().Bech32Prefix, lsAddressBytes) + neutronUserBal, err := neutron.GetBalance( + ctx, + neutronUser.Bech32Address(neutron.Config().Bech32Prefix), + neutron.Config().Denom) + require.NoError(t, err, "failed to fund neutron user") + require.EqualValues(t, int64(100_000_000), neutronUserBal) + t.Run("instantiate depositor", func(t *testing.T) { // Store and instantiate the Neutron ICA example contract. The // wasm file is placed in `wasms/` by the `just test` command. @@ -336,7 +361,6 @@ func TestICS(t *testing.T) { Amount: 10, Address: "neutron1q0z62s0q29ecay5x7vc3lj6yq7md4lmyafqs5p", } - clockContractAddress := "clock_contract_address" msg := InstantiateMsg{ StAtomReceiver: stAtomWeightedReceiver, @@ -377,10 +401,8 @@ func TestICS(t *testing.T) { }) var addrResponse QueryResponse - // TODO: determine gaia-neutron channels for ibc transfers t.Run("first tick instantiates ICA", func(t *testing.T) { // should remain constant - connectionId := "connection-1" cmd = []string{"neutrond", "tx", "wasm", "execute", address, `{"tick":{}}`, "--from", neutronUser.KeyName, @@ -391,7 +413,7 @@ func TestICS(t *testing.T) { "--node", neutron.GetRPCAddress(), "--home", neutron.HomeDir(), "--chain-id", neutron.Config().ChainID, - "--from", "faucet", + "--from", neutronUser.KeyName, "--gas", "auto", "--keyring-backend", keyring.BackendTest, "-y", @@ -411,12 +433,13 @@ func TestICS(t *testing.T) { var response QueryResponse err = cosmosNeutron.QueryContract(ctx, address, IcaExampleContractQuery{ InterchainAccountAddress: InterchainAccountAddressQuery{ - InterchainAccountId: "test", - ConnectionId: connectionId, + InterchainAccountId: icaAccountId, + ConnectionId: neutronIcsConnectionId, }, }, &response) require.NoError(t, err, "failed to query ICA account address") require.NotEmpty(t, response.Data.InterchainAccountAddress) + icaAccountAddress = response.Data.InterchainAccountAddress err = cosmosNeutron.QueryContract(ctx, address, DepositorICAAddressQuery{ DepositorInterchainAccountAddress: DepositorInterchainAccountAddressQuery{}, @@ -428,14 +451,14 @@ func TestICS(t *testing.T) { // and by retrieving it from store is the same require.EqualValues(t, response.Data.InterchainAccountAddress, - addrResponse.Data.InterchainAccountAddress, + icaAccountAddress, ) }) t.Run("multisig transfers atom to ICA account", func(t *testing.T) { // transfer funds from gaiaUser to the newly generated ICA account err := atom.SendFunds(ctx, gaiaUser.KeyName, ibc.WalletAmount{ - Address: addrResponse.Data.InterchainAccountAddress, + Address: icaAccountAddress, Amount: 20, Denom: atom.Config().Denom, }) @@ -444,50 +467,67 @@ func TestICS(t *testing.T) { err = testutil.WaitForBlocks(ctx, 10, atom, neutron) require.NoError(t, err, "failed to wait for blocks") - atomBal, err := atom.GetBalance(ctx, addrResponse.Data.InterchainAccountAddress, atom.Config().Denom) + atomBal, err := atom.GetBalance(ctx, icaAccountAddress, atom.Config().Denom) require.NoError(t, err, "failed to get ICA balance") require.EqualValues(t, 20, atomBal) }) + t.Run("fund depositor contract with some neutron", func(t *testing.T) { + err := neutron.SendFunds(ctx, neutronUser.KeyName, ibc.WalletAmount{ + Address: address, + Amount: 500001, + Denom: neutron.Config().Denom, + }) + + require.NoError(t, err, "failed to send funds from neutron user to depositor contract") + err = testutil.WaitForBlocks(ctx, 10, atom, neutron) + require.NoError(t, err, "failed to wait for blocks") + + neutronBal, err := neutron.GetBalance(ctx, address, neutron.Config().Denom) + require.NoError(t, err, "failed to get depositor neutron balance") + require.EqualValues(t, 500001, neutronBal) + }) + t.Run("second tick ibc transfers atom from ICA account to neutron", func(t *testing.T) { cmd = []string{"neutrond", "tx", "wasm", "execute", address, `{"tick":{}}`, "--from", neutronUser.KeyName, - "--gas-prices", "0.0untrn", - "--gas-adjustment", `1.5`, + // "--gas-prices", "0.0025untrn", + "--gas-adjustment", `1.3`, "--output", "json", "--home", "/var/cosmos-chain/neutron-2", "--node", neutron.GetRPCAddress(), "--home", neutron.HomeDir(), "--chain-id", neutron.Config().ChainID, - "--from", "faucet", - "--gas", "50000.0untrn", + "--gas", "auto", + "--fees", "500000untrn", "--keyring-backend", keyring.BackendTest, "-y", } - _, _, err = neutron.Exec(ctx, cmd, nil) + stdout, _, err := neutron.Exec(ctx, cmd, nil) require.NoError(t, err) + print("\n ", string(stdout)) - err = testutil.WaitForBlocks(ctx, 10, atom, neutron) + err = testutil.WaitForBlocks(ctx, 20, atom, neutron) require.NoError(t, err, "failed to wait for blocks") - atomICABal, err := atom.GetBalance(ctx, addrResponse.Data.InterchainAccountAddress, "uatom") + atomICABal, err := atom.GetBalance(ctx, icaAccountAddress, atom.Config().Denom) require.NoError(t, err, "failed to query ICA balance") - require.Equal(t, 0, atomICABal) + require.Equal(t, int64(0), atomICABal) - neutronAtomBal, err := neutron.GetBalance(ctx, address, "uatom") + neutronAtomBal, err := neutron.GetBalance(ctx, address, atom.Config().Denom) require.NoError(t, err, "failed to query neutron atom balance") - require.Equal(t, 20, neutronAtomBal) + require.Equal(t, int64(20), neutronAtomBal) }) t.Run("third tick transfers to LS and LP modules", func(t *testing.T) { - initLiquidStakerAtomBal, err := neutron.GetBalance(ctx, lsAddress, "uatom") + initLiquidStakerAtomBal, err := neutron.GetBalance(ctx, lsAddress, atom.Config().Denom) require.NoError(t, err, "failed to get LSer balance") - initLiquidityPoolerAtomBal, err := neutron.GetBalance(ctx, lpAddress, "uatom") + initLiquidityPoolerAtomBal, err := neutron.GetBalance(ctx, lpAddress, atom.Config().Denom) require.NoError(t, err, "failed to get LPer balance") - require.EqualValues(t, initLiquidStakerAtomBal, 0) - require.EqualValues(t, initLiquidityPoolerAtomBal, 0) + require.EqualValues(t, int64(0), initLiquidStakerAtomBal) + require.EqualValues(t, int64(0), initLiquidityPoolerAtomBal) print("\n ticking...\n") cmd = []string{"neutrond", "tx", "wasm", "execute", address, @@ -515,17 +555,44 @@ func TestICS(t *testing.T) { err = testutil.WaitForBlocks(ctx, 10, atom, neutron) require.NoError(t, err, "failed to wait for blocks") - depositorAtomBal, err := neutron.GetBalance(ctx, address, "uatom") + depositorAtomBal, err := neutron.GetBalance(ctx, address, atom.Config().Denom) require.NoError(t, err, "failed to query depositor atom balance") - require.Equal(t, 0, depositorAtomBal) + require.Equal(t, int64(0), depositorAtomBal) // query respective accounts and validate they received the funds - liquidStakerAtomBal, err := cosmosNeutron.GetBalance(ctx, lsAddress, "uatom") + liquidStakerAtomBal, err := cosmosNeutron.GetBalance(ctx, lsAddress, atom.Config().Denom) require.NoError(t, err, "failed to get LSer balance") - liquidityPoolerAtomBal, err := cosmosNeutron.GetBalance(ctx, lpAddress, "uatom") + liquidityPoolerAtomBal, err := cosmosNeutron.GetBalance(ctx, lpAddress, atom.Config().Denom) require.NoError(t, err, "failed to get LPer balance") - require.EqualValues(t, liquidStakerAtomBal, 10, "LS did not receive atom") - require.EqualValues(t, liquidityPoolerAtomBal, 10, "LP did not receive atom") + require.EqualValues(t, int64(10), liquidStakerAtomBal, "LS did not receive atom") + require.EqualValues(t, int64(10), liquidityPoolerAtomBal, "LP did not receive atom") + }) + + t.Run("subsequent ticks do nothing", func(t *testing.T) { + cmd = []string{"neutrond", "tx", "wasm", "execute", address, + `{"tick":{}}`, + "--from", neutronUser.KeyName, + "--gas-prices", "0.0untrn", + "--gas-adjustment", `1.5`, + "--output", "json", + "--home", "/var/cosmos-chain/neutron-2", + "--node", neutron.GetRPCAddress(), + "--home", neutron.HomeDir(), + "--chain-id", neutron.Config().ChainID, + "--from", "faucet", + "--gas", "50000.0untrn", + "--keyring-backend", keyring.BackendTest, + "-y", + } + + _, _, err = neutron.Exec(ctx, cmd, nil) + require.NoError(t, err) + + // Wait a bit for the ICA packet to get relayed. This takes a + // long time as the relayer has to do an entire IBC handshake + // because ICA creates a channel per account. + err = testutil.WaitForBlocks(ctx, 10, atom, neutron) + require.NoError(t, err, "failed to wait for blocks") }) }) From e8fb4ee55e7eb5972b823ff2fea69bc82af5d0e3 Mon Sep 17 00:00:00 2001 From: bekauz Date: Mon, 12 Jun 2023 22:41:04 +0200 Subject: [PATCH 14/20] wip: ibc ica transfer --- .../packages/depositor/src/contract.rs | 157 +++++++----------- .../packages/depositor/src/state.rs | 6 +- .../tests/interchaintest/ics_test.go | 55 +++++- 3 files changed, 115 insertions(+), 103 deletions(-) diff --git a/stride-covenant/packages/depositor/src/contract.rs b/stride-covenant/packages/depositor/src/contract.rs index ffc0f599..18d65275 100644 --- a/stride-covenant/packages/depositor/src/contract.rs +++ b/stride-covenant/packages/depositor/src/contract.rs @@ -1,10 +1,10 @@ -use cosmos_sdk_proto::cosmos; use cosmos_sdk_proto::cosmos::base::v1beta1::Coin; use cosmos_sdk_proto::cosmos::staking::v1beta1::{ MsgDelegateResponse, MsgUndelegateResponse, }; use cosmos_sdk_proto::ibc::applications::transfer::v1::MsgTransfer; + #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ @@ -14,6 +14,9 @@ use cosmwasm_std::{ use cw2::set_contract_version; use neutron_sdk::bindings::types::ProtobufAny; use neutron_sdk::interchain_queries::v045::new_register_transfers_query_msg; + + +use neutron_sdk::sudo::msg::RequestPacketTimeoutHeight; use prost::Message; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -35,7 +38,7 @@ use neutron_sdk::{ use crate::state::{ add_error_to_queue, read_errors_from_queue, read_reply_payload, read_sudo_payload, save_sudo_payload, AcknowledgementResult, - ACKNOWLEDGEMENT_RESULTS, INTERCHAIN_ACCOUNTS, SUDO_PAYLOAD_REPLY_ID, CLOCK_ADDRESS, STRIDE_ATOM_RECEIVER, NATIVE_ATOM_RECEIVER, ICS_PORT_ID, ICA_ADDRESS, SudoPayload, save_reply_payload, CONTRACT_STATE, ContractState, + ACKNOWLEDGEMENT_RESULTS, INTERCHAIN_ACCOUNTS, SUDO_PAYLOAD_REPLY_ID, CLOCK_ADDRESS, STRIDE_ATOM_RECEIVER, NATIVE_ATOM_RECEIVER, IBC_PORT_ID, ICA_ADDRESS, SudoPayload, save_reply_payload, CONTRACT_STATE, ContractState, }; // Default timeout for SubmitTX is two weeks @@ -90,7 +93,7 @@ pub fn instantiate( NATIVE_ATOM_RECEIVER.save(deps.storage, &msg.atom_receiver)?; CLOCK_ADDRESS.save(deps.storage, &Addr::unchecked(msg.clock_address))?; CONTRACT_STATE.save(deps.storage, &ContractState::INSTANTIATED)?; - + Ok(Response::default()) } @@ -148,62 +151,54 @@ fn try_receive_atom_from_ica( amount: Uint128::new(1000u128) }], }; + let port_id = IBC_PORT_ID.load(deps.storage)?; - let (ica, connection_id) = get_ica(deps.as_ref(), &env, &INTERCHAIN_ACCOUNT_ID)?; - - let coin = Coin { - denom: ATOM_DENOM.to_string(), - amount: Uint128::new(20).to_string(), - }; - - let msg = MsgTransfer { - source_port: TRANSFER_PORT.to_string(), - source_channel: GAIA_NEUTRON_IBC_CHANNEL_ID.to_string(), - token: Some(coin), - sender: ica.clone(), - receiver: env.contract.address.to_string(), - timeout_height: None, - timeout_timestamp: 0, - }; - - // Serialize the Transfer message - let mut buf = Vec::new(); - buf.reserve(msg.encoded_len()); - if let Err(e) = msg.encode(&mut buf) { - return Err(StdError::generic_err(format!("Encode error: {}", e)).into()); - } - - let protobuf = ProtobufAny { - type_url: "/ibc.applications.transfer.v1.MsgTransfer".to_string(), - value: Binary::from(buf), - }; + let interchain_account = INTERCHAIN_ACCOUNTS.load(deps.storage, port_id.clone())?; + + match interchain_account { + Some((address, controller_conn_id)) => { + let coin = Coin { + denom: ATOM_DENOM.to_string(), + amount: Uint128::new(20).to_string(), + }; - let cosmos_msg = NeutronMsg::submit_tx( - connection_id.clone(), - INTERCHAIN_ACCOUNT_ID.to_string(), - vec![protobuf], - "ica transaction memo".to_string(), - DEFAULT_TIMEOUT_SECONDS, - fee.clone() - ); + let msg = MsgTransfer { + source_port: "transfer".to_string(), + source_channel: "channel-0".to_string(), + token: Some(coin), + sender: address, + receiver: env.contract.address.to_string(), + timeout_height: None, + timeout_timestamp: 0, + }; + + // Serialize the Transfer message + let mut buf = Vec::new(); + buf.reserve(msg.encoded_len()); + if let Err(e) = msg.encode(&mut buf) { + return Err(StdError::generic_err(format!("Encode error: {}", e)).into()); + } + + let protobuf = ProtobufAny { + type_url: "/ibc.applications.transfer.v1.MsgTransfer".to_string(), + value: Binary::from(buf), + }; - let submsg = msg_with_sudo_callback( - deps.branch(), - cosmos_msg, - SudoPayload { - port_id: get_port_id( - env.contract.address.to_string(), - "test".to_string(), - ), - message: "ica transfer".to_string(), + let submit_msg = NeutronMsg::submit_tx( + controller_conn_id, + INTERCHAIN_ACCOUNT_ID.to_string(), + vec![protobuf], + "ibc transfer memo".to_string(), + 100000, + fee + ); + + Ok(Response::default() + .add_submessage(SubMsg::new(submit_msg)) + ) }, - )?.with_gas_limit(252814); - - Ok(Response::default() - .add_attribute("ica address: ", ica) - .add_attribute("connection_id: ", connection_id) - .add_submessage(submsg) - ) + None => return Err(NeutronError::Std(StdError::NotFound { kind: "no ica found".to_string() })), + } } fn try_register_gaia_ica( @@ -218,12 +213,12 @@ fn try_register_gaia_ica( gaia_acc_id.clone() ); let key = get_port_id(env.contract.address.as_str(), &gaia_acc_id); - ICS_PORT_ID.save(deps.storage, &key)?; + IBC_PORT_ID.save(deps.storage, &key)?; // we are saving empty data here because we handle response of registering ICA in sudo_open_ack method - INTERCHAIN_ACCOUNTS.save(deps.storage, key, &None)?; + // INTERCHAIN_ACCOUNTS.save(deps.storage, key, &None)?; - CONTRACT_STATE.save(deps.storage, &ContractState::ICA_CREATED)?; + // CONTRACT_STATE.save(deps.storage, &ContractState::ICA_CREATED)?; Ok(Response::new().add_message(register)) } @@ -387,15 +382,6 @@ fn msg_with_sudo_callback>, T>( Ok(SubMsg::reply_on_success(msg, SUDO_PAYLOAD_REPLY_ID)) } -// fn msg_with_sudo_callback>, T>( -// deps: DepsMut, -// msg: C, -// payload: SudoPayload, -// ) -> StdResult> { -// let id = save_reply_payload(deps.storage, payload)?; -// Ok(SubMsg::reply_on_success(msg, id)) -// } - pub fn register_transfers_query( connection_id: String, recipient: String, @@ -410,7 +396,7 @@ pub fn register_transfers_query( fn try_handle_received() -> NeutronResult> { - Ok(Response::default()) + Ok(Response::default().add_attribute("try_handle_received", "received msg`")) } #[cfg_attr(not(feature = "library"), entry_point)] @@ -579,6 +565,7 @@ fn sudo_open_ack( )), )?; ICA_ADDRESS.save(deps.storage, &parsed_version.address)?; + CONTRACT_STATE.save(deps.storage, &ContractState::ICA_CREATED)?; return Ok(Response::default()); } Err(StdError::generic_err("Can't parse counterparty_version")) @@ -641,35 +628,11 @@ fn sudo_response(deps: DepsMut, request: RequestPacket, data: Binary) -> StdResu let item_type = item.msg_type.as_str(); item_types.push(item_type.to_string()); match item_type { - "/cosmos.staking.v1beta1.MsgUndelegate" => { - // WARNING: RETURNING THIS ERROR CLOSES THE CHANNEL. - // AN ALTERNATIVE IS TO MAINTAIN AN ERRORS QUEUE AND PUT THE FAILED REQUEST THERE - // FOR LATER INSPECTION. - // In this particular case, a mismatch between the string message type and the - // serialised data layout looks like a fatal error that has to be investigated. - let out: MsgUndelegateResponse = decode_message_response(&item.data)?; - - // NOTE: NO ERROR IS RETURNED HERE. THE CHANNEL LIVES ON. - // In this particular case, we demonstrate that minor errors should not - // close the channel, and should be treated in a forgiving manner. - let completion_time = out.completion_time.or_else(|| { - let error_msg = "WASMDEBUG: sudo_response: Recoverable error. Failed to get completion time"; - deps.api - .debug(error_msg); - add_error_to_queue(deps.storage, error_msg.to_string()); - Some(prost_types::Timestamp::default()) - }); - deps.api - .debug(format!("Undelegation completion time: {:?}", completion_time).as_str()); - } - "/cosmos.staking.v1beta1.MsgDelegate" => { - // WARNING: RETURNING THIS ERROR CLOSES THE CHANNEL. - // AN ALTERNATIVE IS TO MAINTAIN AN ERRORS QUEUE AND PUT THE FAILED REQUEST THERE - // FOR LATER INSPECTION. - // In this particular case, a mismatch between the string message type and the - // serialised data layout looks like a fatal error that has to be investigated. - let _out: MsgDelegateResponse = decode_message_response(&item.data)?; - } + "/ibc.applications.transfer.v1.MsgTransfer" => { + deps.api.debug( + format!("MsgTransfer response: {:?}", item.data).as_str() + ); + }, _ => { deps.api.debug( format!( diff --git a/stride-covenant/packages/depositor/src/state.rs b/stride-covenant/packages/depositor/src/state.rs index f7607a07..095c943a 100644 --- a/stride-covenant/packages/depositor/src/state.rs +++ b/stride-covenant/packages/depositor/src/state.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{from_binary, to_vec, Binary, Order, StdResult, Storage, Addr}; +use cosmwasm_std::{from_binary, to_vec, Addr, Binary, Order, StdResult, Storage}; use cw_storage_plus::{Item, Map}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -18,7 +18,7 @@ pub const ICA_ADDRESS: Item = Item::new("ica_address"); // ICA pub const INTERCHAIN_ACCOUNTS: Map> = Map::new("interchain_accounts"); -pub const ICS_PORT_ID: Item = Item::new("ics_port_id"); +pub const IBC_PORT_ID: Item = Item::new("ibc_port_id"); #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] @@ -105,4 +105,4 @@ pub fn save_sudo_payload( payload: SudoPayload, ) -> StdResult<()> { SUDO_PAYLOAD.save(store, (channel_id, seq_id), &to_vec(&payload)?) -} \ No newline at end of file +} diff --git a/stride-covenant/tests/interchaintest/ics_test.go b/stride-covenant/tests/interchaintest/ics_test.go index 9d450abe..38e934a1 100644 --- a/stride-covenant/tests/interchaintest/ics_test.go +++ b/stride-covenant/tests/interchaintest/ics_test.go @@ -472,6 +472,31 @@ func TestICS(t *testing.T) { require.EqualValues(t, 20, atomBal) }) + t.Run("multisig test ibc transfer to neutron user", func(t *testing.T) { + tx, err := atom.SendIBCTransfer( + ctx, + "channel-0", + gaiaUser.KeyName, + ibc.WalletAmount{ + Address: neutronUser.Address, + Amount: 20, + Denom: atom.Config().Denom, + }, + ibc.TransferOptions{ + Timeout: &ibc.IBCTimeout{ + NanoSeconds: 999999, + Height: 999999, + }, + Memo: "hi", + }) + require.NoError(t, err, "failed to ibc transfer from gaia to neutron") + print(string(tx.Packet.Data)) + + neutronBal, err := neutron.GetBalance(ctx, address, atom.Config().Denom) + require.NoError(t, err, "failed to ibc transfer to neutron") + require.EqualValues(t, 20, neutronBal) + }) + t.Run("fund depositor contract with some neutron", func(t *testing.T) { err := neutron.SendFunds(ctx, neutronUser.KeyName, ibc.WalletAmount{ Address: address, @@ -505,11 +530,12 @@ func TestICS(t *testing.T) { "-y", } - stdout, _, err := neutron.Exec(ctx, cmd, nil) + stdout, stderr, err := neutron.Exec(ctx, cmd, nil) require.NoError(t, err) - print("\n ", string(stdout)) + print("\n stdout: ", string(stdout)) + print("\n stderr: ", string(stderr), "\n") - err = testutil.WaitForBlocks(ctx, 20, atom, neutron) + err = testutil.WaitForBlocks(ctx, 100000, atom, neutron) require.NoError(t, err, "failed to wait for blocks") atomICABal, err := atom.GetBalance(ctx, icaAccountAddress, atom.Config().Denom) @@ -521,6 +547,29 @@ func TestICS(t *testing.T) { require.Equal(t, int64(20), neutronAtomBal) }) + t.Run("reading errors queue", func(t *testing.T) { + cmd = []string{"neutrond", "query", "wasm", "contract-state", "smart", address, + "--from", neutronUser.KeyName, + "--gas-prices", "0.0untrn", + "--gas-adjustment", `1.5`, + "--output", "json", + "--home", "/var/cosmos-chain/neutron-2", + "--node", neutron.GetRPCAddress(), + "--home", neutron.HomeDir(), + "--chain-id", neutron.Config().ChainID, + "--from", "faucet", + "--gas", "50000.0untrn", + "--keyring-backend", keyring.BackendTest, + "-y", + } + + stdout, stderr, err := neutron.Exec(ctx, cmd, nil) + require.NoError(t, err) + print("\n errors queue: \n") + print("\n stdout: ", string(stdout)) + print("\n stderr: ", string(stderr), "\n") + }) + t.Run("third tick transfers to LS and LP modules", func(t *testing.T) { initLiquidStakerAtomBal, err := neutron.GetBalance(ctx, lsAddress, atom.Config().Denom) require.NoError(t, err, "failed to get LSer balance") From 4bd4e0f5a93039a98c63924d4ed3b9a2c49d6a13 Mon Sep 17 00:00:00 2001 From: bekauz Date: Tue, 13 Jun 2023 16:59:42 +0200 Subject: [PATCH 15/20] wip: passing channel-id during depositor instantiation --- .../packages/depositor/src/contract.rs | 15 +- stride-covenant/packages/depositor/src/msg.rs | 1 + .../packages/depositor/src/state.rs | 3 + .../packages/depositor/src/tests/suite.rs | 2 + .../tests/interchaintest/ics_test.go | 155 +++++++++++------- 5 files changed, 115 insertions(+), 61 deletions(-) diff --git a/stride-covenant/packages/depositor/src/contract.rs b/stride-covenant/packages/depositor/src/contract.rs index 18d65275..9cf6e301 100644 --- a/stride-covenant/packages/depositor/src/contract.rs +++ b/stride-covenant/packages/depositor/src/contract.rs @@ -38,7 +38,7 @@ use neutron_sdk::{ use crate::state::{ add_error_to_queue, read_errors_from_queue, read_reply_payload, read_sudo_payload, save_sudo_payload, AcknowledgementResult, - ACKNOWLEDGEMENT_RESULTS, INTERCHAIN_ACCOUNTS, SUDO_PAYLOAD_REPLY_ID, CLOCK_ADDRESS, STRIDE_ATOM_RECEIVER, NATIVE_ATOM_RECEIVER, IBC_PORT_ID, ICA_ADDRESS, SudoPayload, save_reply_payload, CONTRACT_STATE, ContractState, + ACKNOWLEDGEMENT_RESULTS, INTERCHAIN_ACCOUNTS, SUDO_PAYLOAD_REPLY_ID, CLOCK_ADDRESS, STRIDE_ATOM_RECEIVER, NATIVE_ATOM_RECEIVER, IBC_PORT_ID, ICA_ADDRESS, SudoPayload, save_reply_payload, CONTRACT_STATE, ContractState, GAIA_NEUTRON_IBC_TRANSFER_CHANNEL_ID, }; // Default timeout for SubmitTX is two weeks @@ -50,14 +50,14 @@ const IBC_CONNECTION: &str = "connection-0"; const ICS_CONNECTION_ID: &str = "connection-1"; const INTERCHAIN_ACCOUNT_ID: &str = "test"; const TRANSFER_PORT: &str = "transfer"; -const GAIA_NEUTRON_IBC_CHANNEL_ID: &str = "channel-0"; +// const GAIA_NEUTRON_IBC_CHANNEL_ID: &str = "channel-0"; const CONTRACT_NAME: &str = concat!("crates.io:neutron-sdk__", env!("CARGO_PKG_NAME")); const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] -struct OpenAckVersion { +struct OpenAckVersion { version: String, controller_connection_id: String, host_connection_id: String, @@ -93,6 +93,7 @@ pub fn instantiate( NATIVE_ATOM_RECEIVER.save(deps.storage, &msg.atom_receiver)?; CLOCK_ADDRESS.save(deps.storage, &Addr::unchecked(msg.clock_address))?; CONTRACT_STATE.save(deps.storage, &ContractState::INSTANTIATED)?; + GAIA_NEUTRON_IBC_TRANSFER_CHANNEL_ID.save(deps.storage, &msg.gaia_neutron_ibc_transfer_channel_id)?; Ok(Response::default()) } @@ -157,6 +158,8 @@ fn try_receive_atom_from_ica( match interchain_account { Some((address, controller_conn_id)) => { + let source_channel = GAIA_NEUTRON_IBC_TRANSFER_CHANNEL_ID.load(deps.storage)?; + let coin = Coin { denom: ATOM_DENOM.to_string(), amount: Uint128::new(20).to_string(), @@ -164,9 +167,9 @@ fn try_receive_atom_from_ica( let msg = MsgTransfer { source_port: "transfer".to_string(), - source_channel: "channel-0".to_string(), + source_channel: source_channel, token: Some(coin), - sender: address, + sender: address.clone(), receiver: env.contract.address.to_string(), timeout_height: None, timeout_timestamp: 0, @@ -188,7 +191,7 @@ fn try_receive_atom_from_ica( controller_conn_id, INTERCHAIN_ACCOUNT_ID.to_string(), vec![protobuf], - "ibc transfer memo".to_string(), + address, 100000, fee ); diff --git a/stride-covenant/packages/depositor/src/msg.rs b/stride-covenant/packages/depositor/src/msg.rs index 85261cac..9711cb29 100644 --- a/stride-covenant/packages/depositor/src/msg.rs +++ b/stride-covenant/packages/depositor/src/msg.rs @@ -7,6 +7,7 @@ pub struct InstantiateMsg { pub st_atom_receiver: WeightedReceiver, pub atom_receiver: WeightedReceiver, pub clock_address: String, + pub gaia_neutron_ibc_transfer_channel_id: String, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] diff --git a/stride-covenant/packages/depositor/src/state.rs b/stride-covenant/packages/depositor/src/state.rs index 095c943a..937c97cc 100644 --- a/stride-covenant/packages/depositor/src/state.rs +++ b/stride-covenant/packages/depositor/src/state.rs @@ -14,6 +14,9 @@ pub const NATIVE_ATOM_RECEIVER: Item = Item::new("native_atom_ // store the clock address to verify calls pub const CLOCK_ADDRESS: Item = Item::new("clock_address"); +// the ibc transfer channel +pub const GAIA_NEUTRON_IBC_TRANSFER_CHANNEL_ID: Item = Item::new("gn_ibc_chann_id"); + pub const ICA_ADDRESS: Item = Item::new("ica_address"); // ICA pub const INTERCHAIN_ACCOUNTS: Map> = diff --git a/stride-covenant/packages/depositor/src/tests/suite.rs b/stride-covenant/packages/depositor/src/tests/suite.rs index 4017308f..43eb96c0 100644 --- a/stride-covenant/packages/depositor/src/tests/suite.rs +++ b/stride-covenant/packages/depositor/src/tests/suite.rs @@ -45,6 +45,8 @@ impl Default for SuiteBuilder { address: NATIVE_ATOM_DENOM.to_string(), }, clock_address: "default-clock".to_string(), + gaia_neutron_ibc_transfer_channel_id: "channel-3".to_string(), + }, } } diff --git a/stride-covenant/tests/interchaintest/ics_test.go b/stride-covenant/tests/interchaintest/ics_test.go index 38e934a1..c82f2553 100644 --- a/stride-covenant/tests/interchaintest/ics_test.go +++ b/stride-covenant/tests/interchaintest/ics_test.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/types" + transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" "github.com/icza/dyno" ibctest "github.com/strangelove-ventures/interchaintest/v3" "github.com/strangelove-ventures/interchaintest/v3/chain/cosmos" @@ -23,9 +24,10 @@ import ( ) type InstantiateMsg struct { - StAtomReceiver WeightedReceiver `json:"st_atom_receiver"` - AtomReceiver WeightedReceiver `json:"atom_receiver"` - ClockAddress string `json:"clock_address,string"` + StAtomReceiver WeightedReceiver `json:"st_atom_receiver"` + AtomReceiver WeightedReceiver `json:"atom_receiver"` + ClockAddress string `json:"clock_address,string"` + GaiaNeutronIBCTransferChannelId string `json:"gaia_neutron_ibc_transfer_channel_id"` } type WeightedReceiver struct { @@ -335,6 +337,9 @@ func TestICS(t *testing.T) { neutron.CreateKey(ctx, "lper") neutron.CreateKey(ctx, "lser") + neutronAddress := neutronUser.Bech32Address(neutron.Config().Bech32Prefix) + atomAddress := gaiaUser.Bech32Address(atom.Config().Bech32Prefix) + lpAddressBytes, _ := neutron.GetAddress(ctx, "lper") lsAddressBytes, _ := neutron.GetAddress(ctx, "lser") @@ -348,6 +353,25 @@ func TestICS(t *testing.T) { require.NoError(t, err, "failed to fund neutron user") require.EqualValues(t, int64(100_000_000), neutronUserBal) + neutronChannelInfo, _ := r.GetChannels(ctx, eRep, neutron.Config().ChainID) + var neutronGaiaIBCChannel ibc.ChannelOutput + for _, s := range neutronChannelInfo { + neutronJson, _ := json.Marshal(s) + print("\n neutron_channel: ", string(neutronJson)) + if s.State == "STATE_OPEN" && s.Ordering == "ORDER_UNORDERED" && s.PortID == "transfer" { + if len(s.Counterparty.ChannelID) > 5 && s.Counterparty.PortID == "transfer" { + neutronGaiaIBCChannel = s + break + } + } + } + gaiaNeutronIBCChannel := neutronGaiaIBCChannel.Counterparty + neutronGaiaIBCChannelId := neutronGaiaIBCChannel.ChannelID + gaiaNeutronIBCChannelId := gaiaNeutronIBCChannel.ChannelID + + print("\nneutronGaiaIBCChannelId = ", neutronGaiaIBCChannelId) + print("\ngaiaNeutronIBCChannelId = ", gaiaNeutronIBCChannelId, "\n") + t.Run("instantiate depositor", func(t *testing.T) { // Store and instantiate the Neutron ICA example contract. The // wasm file is placed in `wasms/` by the `just test` command. @@ -363,9 +387,10 @@ func TestICS(t *testing.T) { } msg := InstantiateMsg{ - StAtomReceiver: stAtomWeightedReceiver, - AtomReceiver: atomWeightedReceiver, - ClockAddress: clockContractAddress, + StAtomReceiver: stAtomWeightedReceiver, + AtomReceiver: atomWeightedReceiver, + ClockAddress: clockContractAddress, + GaiaNeutronIBCTransferChannelId: gaiaNeutronIBCChannelId, } str, err := json.Marshal(msg) @@ -440,7 +465,7 @@ func TestICS(t *testing.T) { require.NoError(t, err, "failed to query ICA account address") require.NotEmpty(t, response.Data.InterchainAccountAddress) icaAccountAddress = response.Data.InterchainAccountAddress - + print("\n icaAccountAddress: ", icaAccountAddress, "\n") err = cosmosNeutron.QueryContract(ctx, address, DepositorICAAddressQuery{ DepositorInterchainAccountAddress: DepositorInterchainAccountAddressQuery{}, }, &addrResponse) @@ -472,30 +497,12 @@ func TestICS(t *testing.T) { require.EqualValues(t, 20, atomBal) }) - t.Run("multisig test ibc transfer to neutron user", func(t *testing.T) { - tx, err := atom.SendIBCTransfer( - ctx, - "channel-0", - gaiaUser.KeyName, - ibc.WalletAmount{ - Address: neutronUser.Address, - Amount: 20, - Denom: atom.Config().Denom, - }, - ibc.TransferOptions{ - Timeout: &ibc.IBCTimeout{ - NanoSeconds: 999999, - Height: 999999, - }, - Memo: "hi", - }) - require.NoError(t, err, "failed to ibc transfer from gaia to neutron") - print(string(tx.Packet.Data)) - - neutronBal, err := neutron.GetBalance(ctx, address, atom.Config().Denom) - require.NoError(t, err, "failed to ibc transfer to neutron") - require.EqualValues(t, 20, neutronBal) - }) + neutronSrcDenomTrace := transfertypes.ParseDenomTrace( + transfertypes.GetPrefixedDenom("transfer", + neutronGaiaIBCChannelId, + atom.Config().Denom)) + neutronDstIbcDenom := neutronSrcDenomTrace.IBCDenom() + amountToSend := int64(5_000) t.Run("fund depositor contract with some neutron", func(t *testing.T) { err := neutron.SendFunds(ctx, neutronUser.KeyName, ibc.WalletAmount{ @@ -514,6 +521,10 @@ func TestICS(t *testing.T) { }) t.Run("second tick ibc transfers atom from ICA account to neutron", func(t *testing.T) { + atomBal, err := atom.GetBalance(ctx, icaAccountAddress, atom.Config().Denom) + require.NoError(t, err, "failed to get ICA balance") + require.EqualValues(t, 20, atomBal) + cmd = []string{"neutrond", "tx", "wasm", "execute", address, `{"tick":{}}`, "--from", neutronUser.KeyName, @@ -535,39 +546,73 @@ func TestICS(t *testing.T) { print("\n stdout: ", string(stdout)) print("\n stderr: ", string(stderr), "\n") - err = testutil.WaitForBlocks(ctx, 100000, atom, neutron) + require.NoError(t, r.FlushPackets(ctx, eRep, gaiaNeutronIBCPath, neutronGaiaIBCChannelId)) + require.NoError(t, r.FlushAcknowledgements(ctx, eRep, gaiaNeutronIBCPath, gaiaNeutronIBCChannelId)) + + err = testutil.WaitForBlocks(ctx, 10, atom, neutron) require.NoError(t, err, "failed to wait for blocks") - atomICABal, err := atom.GetBalance(ctx, icaAccountAddress, atom.Config().Denom) + neutronUserBalNew, err := neutron.GetBalance( + ctx, + neutronAddress, + neutronDstIbcDenom) + require.NoError(t, err, "failed to query neutron atom balance") + require.Equal(t, int64(20), neutronUserBalNew) + + atomICABal, err := atom.GetBalance( + ctx, + icaAccountAddress, + atom.Config().Denom) require.NoError(t, err, "failed to query ICA balance") require.Equal(t, int64(0), atomICABal) - - neutronAtomBal, err := neutron.GetBalance(ctx, address, atom.Config().Denom) - require.NoError(t, err, "failed to query neutron atom balance") - require.Equal(t, int64(20), neutronAtomBal) }) - t.Run("reading errors queue", func(t *testing.T) { - cmd = []string{"neutrond", "query", "wasm", "contract-state", "smart", address, - "--from", neutronUser.KeyName, - "--gas-prices", "0.0untrn", - "--gas-adjustment", `1.5`, - "--output", "json", - "--home", "/var/cosmos-chain/neutron-2", - "--node", neutron.GetRPCAddress(), - "--home", neutron.HomeDir(), - "--chain-id", neutron.Config().ChainID, - "--from", "faucet", - "--gas", "50000.0untrn", - "--keyring-backend", keyring.BackendTest, - "-y", + t.Run("multisig test ibc transfer to neutron user", func(t *testing.T) { + + gaiaUserBalInitial, err := atom.GetBalance( + ctx, + atomAddress, + atom.Config().Denom) + require.NoError(t, err) + transferAtom := ibc.WalletAmount{ + Address: neutronAddress, + Denom: atom.Config().Denom, + Amount: amountToSend, } - stdout, stderr, err := neutron.Exec(ctx, cmd, nil) + atomTx, err := atom.SendIBCTransfer( + ctx, + gaiaNeutronIBCChannel.ChannelID, + gaiaUser.GetKeyName(), + transferAtom, + ibc.TransferOptions{}) require.NoError(t, err) - print("\n errors queue: \n") - print("\n stdout: ", string(stdout)) - print("\n stderr: ", string(stderr), "\n") + require.NoError(t, atomTx.Validate()) + + // relay IBC packets and acks + require.NoError(t, r.FlushPackets(ctx, eRep, gaiaNeutronIBCPath, neutronGaiaIBCChannelId)) + require.NoError(t, r.FlushAcknowledgements(ctx, eRep, gaiaNeutronIBCPath, gaiaNeutronIBCChannelId)) + + // relay ics packets and acks + // require.NoError(t, r.FlushPackets(ctx, eRep, gaiaNeutronICSPath, neutronGaiaICSChannelID)) + // require.NoError(t, r.FlushAcknowledgements(ctx, eRep, gaiaNeutronICSPath, gaiaNeutronICSChannel.ChannelID)) + + // test source wallet has decreased funds + expectedBal := gaiaUserBalInitial - amountToSend + gaiaUserBalNew, err := atom.GetBalance( + ctx, + atomAddress, + atom.Config().Denom) + require.NoError(t, err) + require.Equal(t, expectedBal, gaiaUserBalNew) + + // Test destination wallets have increased funds + neutronUserBalNew, err := neutron.GetBalance( + ctx, + neutronAddress, + neutronDstIbcDenom) + require.NoError(t, err) + require.Equal(t, amountToSend, neutronUserBalNew) }) t.Run("third tick transfers to LS and LP modules", func(t *testing.T) { From e2e6277238c2e004884037f36dd1d6a76609e7d2 Mon Sep 17 00:00:00 2001 From: bekauz Date: Tue, 13 Jun 2023 18:31:16 +0200 Subject: [PATCH 16/20] modifying gaia genesis to allow interchainaccount messages --- .../tests/interchaintest/ics_test.go | 46 ++++++++++++++++--- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/stride-covenant/tests/interchaintest/ics_test.go b/stride-covenant/tests/interchaintest/ics_test.go index c82f2553..ba1a6c4e 100644 --- a/stride-covenant/tests/interchaintest/ics_test.go +++ b/stride-covenant/tests/interchaintest/ics_test.go @@ -143,6 +143,38 @@ func setupNeutronGenesis( } } +func setupGaiaGenesis() func(ibc.ChainConfig, []byte) ([]byte, error) { + return func(chainConfig ibc.ChainConfig, genbz []byte) ([]byte, error) { + g := make(map[string]interface{}) + if err := json.Unmarshal(genbz, &g); err != nil { + return nil, fmt.Errorf("failed to unmarshal genesis file: %w", err) + } + + arr := []string{ + "/cosmos.bank.v1beta1.MsgSend", + "/cosmos.bank.v1beta1.MsgMultiSend", + "/cosmos.staking.v1beta1.MsgDelegate", + "/cosmos.staking.v1beta1.MsgUndelegate", + "/cosmos.staking.v1beta1.MsgBeginRedelegate", + "/cosmos.staking.v1beta1.MsgRedeemTokensforShares", + "/cosmos.staking.v1beta1.MsgTokenizeShares", + "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward", + "/cosmos.distribution.v1beta1.MsgSetWithdrawAddress", + "/ibc.applications.transfer.v1.MsgTransfer", + } + + if err := dyno.Set(g, arr, "app_state", "interchainaccounts", "host_genesis_state", "params", "allow_messages"); err != nil { + return nil, fmt.Errorf("failed to set allow_messages for interchainaccount host in genesis json: %w", err) + } + + out, err := json.Marshal(g) + if err != nil { + return nil, fmt.Errorf("failed to marshal genesis bytes to json: %w", err) + } + return out, nil + } +} + // This tests Cosmos Interchain Security, spinning up gaia, neutron, and stride func TestICS(t *testing.T) { if testing.Short() { @@ -158,6 +190,7 @@ func TestICS(t *testing.T) { {Name: "gaia", Version: "v9.1.0", ChainConfig: ibc.ChainConfig{ GasAdjustment: 1.3, GasPrices: "0.0atom", + ModifyGenesis: setupGaiaGenesis(), }}, { ChainConfig: ibc.ChainConfig{ @@ -552,6 +585,13 @@ func TestICS(t *testing.T) { err = testutil.WaitForBlocks(ctx, 10, atom, neutron) require.NoError(t, err, "failed to wait for blocks") + atomICABal, err := atom.GetBalance( + ctx, + icaAccountAddress, + atom.Config().Denom) + require.NoError(t, err, "failed to query ICA balance") + require.Equal(t, int64(0), atomICABal) + neutronUserBalNew, err := neutron.GetBalance( ctx, neutronAddress, @@ -559,12 +599,6 @@ func TestICS(t *testing.T) { require.NoError(t, err, "failed to query neutron atom balance") require.Equal(t, int64(20), neutronUserBalNew) - atomICABal, err := atom.GetBalance( - ctx, - icaAccountAddress, - atom.Config().Denom) - require.NoError(t, err, "failed to query ICA balance") - require.Equal(t, int64(0), atomICABal) }) t.Run("multisig test ibc transfer to neutron user", func(t *testing.T) { From d84e001305073c0f759fb21ed0156a8e32cfe723 Mon Sep 17 00:00:00 2001 From: bekauz Date: Wed, 14 Jun 2023 13:26:50 +0200 Subject: [PATCH 17/20] second tick withdraws atom to depositor --- .../packages/depositor/src/contract.rs | 9 ++- .../tests/interchaintest/ics_test.go | 69 ++++--------------- 2 files changed, 20 insertions(+), 58 deletions(-) diff --git a/stride-covenant/packages/depositor/src/contract.rs b/stride-covenant/packages/depositor/src/contract.rs index 9cf6e301..4a2e3978 100644 --- a/stride-covenant/packages/depositor/src/contract.rs +++ b/stride-covenant/packages/depositor/src/contract.rs @@ -5,6 +5,7 @@ use cosmos_sdk_proto::cosmos::staking::v1beta1::{ }; use cosmos_sdk_proto::ibc::applications::transfer::v1::MsgTransfer; +use cosmos_sdk_proto::ibc::core::client::v1::Height; #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ @@ -162,7 +163,7 @@ fn try_receive_atom_from_ica( let coin = Coin { denom: ATOM_DENOM.to_string(), - amount: Uint128::new(20).to_string(), + amount: "20".to_string(), }; let msg = MsgTransfer { @@ -171,7 +172,11 @@ fn try_receive_atom_from_ica( token: Some(coin), sender: address.clone(), receiver: env.contract.address.to_string(), - timeout_height: None, + // TODO: look into what the timeout_height should be + timeout_height: Some(Height { + revision_number: 2, + revision_height: 123, + }), timeout_timestamp: 0, }; diff --git a/stride-covenant/tests/interchaintest/ics_test.go b/stride-covenant/tests/interchaintest/ics_test.go index ba1a6c4e..d96bc4ef 100644 --- a/stride-covenant/tests/interchaintest/ics_test.go +++ b/stride-covenant/tests/interchaintest/ics_test.go @@ -370,8 +370,8 @@ func TestICS(t *testing.T) { neutron.CreateKey(ctx, "lper") neutron.CreateKey(ctx, "lser") - neutronAddress := neutronUser.Bech32Address(neutron.Config().Bech32Prefix) - atomAddress := gaiaUser.Bech32Address(atom.Config().Bech32Prefix) + // neutronAddress := neutronUser.Bech32Address(neutron.Config().Bech32Prefix) + // atomAddress := gaiaUser.Bech32Address(atom.Config().Bech32Prefix) lpAddressBytes, _ := neutron.GetAddress(ctx, "lper") lsAddressBytes, _ := neutron.GetAddress(ctx, "lser") @@ -388,20 +388,23 @@ func TestICS(t *testing.T) { neutronChannelInfo, _ := r.GetChannels(ctx, eRep, neutron.Config().ChainID) var neutronGaiaIBCChannel ibc.ChannelOutput + var neutronGaiaICSChannel ibc.ChannelOutput for _, s := range neutronChannelInfo { neutronJson, _ := json.Marshal(s) print("\n neutron_channel: ", string(neutronJson)) if s.State == "STATE_OPEN" && s.Ordering == "ORDER_UNORDERED" && s.PortID == "transfer" { if len(s.Counterparty.ChannelID) > 5 && s.Counterparty.PortID == "transfer" { neutronGaiaIBCChannel = s - break } + } else if s.Ordering == "ORDER_ORDERED" { + neutronGaiaICSChannel = s } } gaiaNeutronIBCChannel := neutronGaiaIBCChannel.Counterparty neutronGaiaIBCChannelId := neutronGaiaIBCChannel.ChannelID gaiaNeutronIBCChannelId := gaiaNeutronIBCChannel.ChannelID - + gaiaNeutronICSChannelId := neutronGaiaICSChannel.Counterparty.ChannelID + neutronGaiaICSChannelId := neutronGaiaICSChannel.ChannelID print("\nneutronGaiaIBCChannelId = ", neutronGaiaIBCChannelId) print("\ngaiaNeutronIBCChannelId = ", gaiaNeutronIBCChannelId, "\n") @@ -535,7 +538,6 @@ func TestICS(t *testing.T) { neutronGaiaIBCChannelId, atom.Config().Denom)) neutronDstIbcDenom := neutronSrcDenomTrace.IBCDenom() - amountToSend := int64(5_000) t.Run("fund depositor contract with some neutron", func(t *testing.T) { err := neutron.SendFunds(ctx, neutronUser.KeyName, ibc.WalletAmount{ @@ -561,7 +563,6 @@ func TestICS(t *testing.T) { cmd = []string{"neutrond", "tx", "wasm", "execute", address, `{"tick":{}}`, "--from", neutronUser.KeyName, - // "--gas-prices", "0.0025untrn", "--gas-adjustment", `1.3`, "--output", "json", "--home", "/var/cosmos-chain/neutron-2", @@ -582,6 +583,10 @@ func TestICS(t *testing.T) { require.NoError(t, r.FlushPackets(ctx, eRep, gaiaNeutronIBCPath, neutronGaiaIBCChannelId)) require.NoError(t, r.FlushAcknowledgements(ctx, eRep, gaiaNeutronIBCPath, gaiaNeutronIBCChannelId)) + // relay ics packets and acks + require.NoError(t, r.FlushPackets(ctx, eRep, gaiaNeutronICSPath, neutronGaiaICSChannelId)) + require.NoError(t, r.FlushAcknowledgements(ctx, eRep, gaiaNeutronICSPath, gaiaNeutronICSChannelId)) + err = testutil.WaitForBlocks(ctx, 10, atom, neutron) require.NoError(t, err, "failed to wait for blocks") @@ -594,61 +599,13 @@ func TestICS(t *testing.T) { neutronUserBalNew, err := neutron.GetBalance( ctx, - neutronAddress, + address, neutronDstIbcDenom) - require.NoError(t, err, "failed to query neutron atom balance") + require.NoError(t, err, "failed to query depositor contract atom balance") require.Equal(t, int64(20), neutronUserBalNew) }) - t.Run("multisig test ibc transfer to neutron user", func(t *testing.T) { - - gaiaUserBalInitial, err := atom.GetBalance( - ctx, - atomAddress, - atom.Config().Denom) - require.NoError(t, err) - transferAtom := ibc.WalletAmount{ - Address: neutronAddress, - Denom: atom.Config().Denom, - Amount: amountToSend, - } - - atomTx, err := atom.SendIBCTransfer( - ctx, - gaiaNeutronIBCChannel.ChannelID, - gaiaUser.GetKeyName(), - transferAtom, - ibc.TransferOptions{}) - require.NoError(t, err) - require.NoError(t, atomTx.Validate()) - - // relay IBC packets and acks - require.NoError(t, r.FlushPackets(ctx, eRep, gaiaNeutronIBCPath, neutronGaiaIBCChannelId)) - require.NoError(t, r.FlushAcknowledgements(ctx, eRep, gaiaNeutronIBCPath, gaiaNeutronIBCChannelId)) - - // relay ics packets and acks - // require.NoError(t, r.FlushPackets(ctx, eRep, gaiaNeutronICSPath, neutronGaiaICSChannelID)) - // require.NoError(t, r.FlushAcknowledgements(ctx, eRep, gaiaNeutronICSPath, gaiaNeutronICSChannel.ChannelID)) - - // test source wallet has decreased funds - expectedBal := gaiaUserBalInitial - amountToSend - gaiaUserBalNew, err := atom.GetBalance( - ctx, - atomAddress, - atom.Config().Denom) - require.NoError(t, err) - require.Equal(t, expectedBal, gaiaUserBalNew) - - // Test destination wallets have increased funds - neutronUserBalNew, err := neutron.GetBalance( - ctx, - neutronAddress, - neutronDstIbcDenom) - require.NoError(t, err) - require.Equal(t, amountToSend, neutronUserBalNew) - }) - t.Run("third tick transfers to LS and LP modules", func(t *testing.T) { initLiquidStakerAtomBal, err := neutron.GetBalance(ctx, lsAddress, atom.Config().Denom) require.NoError(t, err, "failed to get LSer balance") From 705da273f89e005cfc72c8707d88b706bec7160e Mon Sep 17 00:00:00 2001 From: bekauz Date: Thu, 15 Jun 2023 15:56:50 +0200 Subject: [PATCH 18/20] storing LP address in depositor; cleanup --- .../packages/depositor/src/contract.rs | 33 ++-- stride-covenant/packages/depositor/src/msg.rs | 2 +- .../packages/depositor/src/state.rs | 1 + .../packages/depositor/src/tests/suite.rs | 1 - .../tests/interchaintest/ics_test.go | 169 +++++------------- 5 files changed, 60 insertions(+), 146 deletions(-) diff --git a/stride-covenant/packages/depositor/src/contract.rs b/stride-covenant/packages/depositor/src/contract.rs index 4a2e3978..cfbe79d9 100644 --- a/stride-covenant/packages/depositor/src/contract.rs +++ b/stride-covenant/packages/depositor/src/contract.rs @@ -1,8 +1,6 @@ -use cosmos_sdk_proto::cosmos::base::v1beta1::Coin; +use std::str::FromStr; -use cosmos_sdk_proto::cosmos::staking::v1beta1::{ - MsgDelegateResponse, MsgUndelegateResponse, -}; +use cosmos_sdk_proto::cosmos::base::v1beta1::Coin; use cosmos_sdk_proto::ibc::applications::transfer::v1::MsgTransfer; use cosmos_sdk_proto::ibc::core::client::v1::Height; @@ -16,8 +14,6 @@ use cw2::set_contract_version; use neutron_sdk::bindings::types::ProtobufAny; use neutron_sdk::interchain_queries::v045::new_register_transfers_query_msg; - -use neutron_sdk::sudo::msg::RequestPacketTimeoutHeight; use prost::Message; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -30,7 +26,7 @@ use neutron_sdk::{ query::{NeutronQuery, QueryInterchainAccountAddressResponse}, }, interchain_txs::helpers::{ - decode_acknowledgement_response, decode_message_response, get_port_id, + decode_acknowledgement_response, get_port_id, }, sudo::msg::{RequestPacket, SudoMsg}, NeutronError, NeutronResult, @@ -51,7 +47,6 @@ const IBC_CONNECTION: &str = "connection-0"; const ICS_CONNECTION_ID: &str = "connection-1"; const INTERCHAIN_ACCOUNT_ID: &str = "test"; const TRANSFER_PORT: &str = "transfer"; -// const GAIA_NEUTRON_IBC_CHANNEL_ID: &str = "channel-0"; const CONTRACT_NAME: &str = concat!("crates.io:neutron-sdk__", env!("CARGO_PKG_NAME")); const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -77,17 +72,7 @@ pub fn instantiate( deps.api.debug("WASMDEBUG: instantiate"); set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; - // can we do better with validation here? - // deps.api.addr_validate(&msg.st_atom_receiver.address)?; - // deps.api.addr_validate(&msg.atom_receiver.address)?; - // let clock_address = deps.api.addr_validate(&msg.clock_address)?; - - // avoid zero deposit configurations - // if msg.st_atom_receiver.amount == 0 || msg.atom_receiver.amount == 0 { - // return Err(NeutronError::Std( - // StdError::GenericErr { msg: "Zero deposit config".to_string() }) - // ) - // } + // TODO: validations // minations and amounts STRIDE_ATOM_RECEIVER.save(deps.storage, &msg.st_atom_receiver)?; @@ -160,17 +145,21 @@ fn try_receive_atom_from_ica( match interchain_account { Some((address, controller_conn_id)) => { let source_channel = GAIA_NEUTRON_IBC_TRANSFER_CHANNEL_ID.load(deps.storage)?; - + // let lp_receiver = NATIVE_ATOM_RECEIVER.load(deps.storage)?; + + // we should parse the amount from WeightedReceiver here. + // parsing it to string does not work so temporarily hardcoded. + // see: docs.rs/cosmos-sdk-proto/latest/cosmos_sdk_proto/cosmos/base/v1beta1/struct.Coin.html let coin = Coin { denom: ATOM_DENOM.to_string(), - amount: "20".to_string(), + amount: "10".to_string(), }; let msg = MsgTransfer { source_port: "transfer".to_string(), source_channel: source_channel, token: Some(coin), - sender: address.clone(), + sender: address.clone().to_string(), receiver: env.contract.address.to_string(), // TODO: look into what the timeout_height should be timeout_height: Some(Height { diff --git a/stride-covenant/packages/depositor/src/msg.rs b/stride-covenant/packages/depositor/src/msg.rs index 9711cb29..2388e690 100644 --- a/stride-covenant/packages/depositor/src/msg.rs +++ b/stride-covenant/packages/depositor/src/msg.rs @@ -12,7 +12,7 @@ pub struct InstantiateMsg { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct WeightedReceiver { - pub amount: u128, + pub amount: i64, pub address: String, } diff --git a/stride-covenant/packages/depositor/src/state.rs b/stride-covenant/packages/depositor/src/state.rs index 937c97cc..42a156a7 100644 --- a/stride-covenant/packages/depositor/src/state.rs +++ b/stride-covenant/packages/depositor/src/state.rs @@ -14,6 +14,7 @@ pub const NATIVE_ATOM_RECEIVER: Item = Item::new("native_atom_ // store the clock address to verify calls pub const CLOCK_ADDRESS: Item = Item::new("clock_address"); +pub const LP_ADDRESS: Item = Item::new("lp_address"); // the ibc transfer channel pub const GAIA_NEUTRON_IBC_TRANSFER_CHANNEL_ID: Item = Item::new("gn_ibc_chann_id"); diff --git a/stride-covenant/packages/depositor/src/tests/suite.rs b/stride-covenant/packages/depositor/src/tests/suite.rs index 43eb96c0..75c80dcf 100644 --- a/stride-covenant/packages/depositor/src/tests/suite.rs +++ b/stride-covenant/packages/depositor/src/tests/suite.rs @@ -46,7 +46,6 @@ impl Default for SuiteBuilder { }, clock_address: "default-clock".to_string(), gaia_neutron_ibc_transfer_channel_id: "channel-3".to_string(), - }, } } diff --git a/stride-covenant/tests/interchaintest/ics_test.go b/stride-covenant/tests/interchaintest/ics_test.go index d96bc4ef..9ddcc25d 100644 --- a/stride-covenant/tests/interchaintest/ics_test.go +++ b/stride-covenant/tests/interchaintest/ics_test.go @@ -8,7 +8,6 @@ import ( "time" "github.com/cosmos/cosmos-sdk/crypto/keyring" - "github.com/cosmos/cosmos-sdk/types" transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" "github.com/icza/dyno" ibctest "github.com/strangelove-ventures/interchaintest/v3" @@ -31,7 +30,7 @@ type InstantiateMsg struct { } type WeightedReceiver struct { - Amount uint64 `json:"amount,string"` + Amount int64 `json:"amount"` Address string `json:"address,string"` } @@ -143,27 +142,17 @@ func setupNeutronGenesis( } } -func setupGaiaGenesis() func(ibc.ChainConfig, []byte) ([]byte, error) { +// Sets custom fields for the Gaia genesis file that interchaintest isn't aware of by default. +// +// allowed_messages - explicitly allowed messages to be accepted by the the interchainaccounts section +func setupGaiaGenesis(allowed_messages []string) func(ibc.ChainConfig, []byte) ([]byte, error) { return func(chainConfig ibc.ChainConfig, genbz []byte) ([]byte, error) { g := make(map[string]interface{}) if err := json.Unmarshal(genbz, &g); err != nil { return nil, fmt.Errorf("failed to unmarshal genesis file: %w", err) } - arr := []string{ - "/cosmos.bank.v1beta1.MsgSend", - "/cosmos.bank.v1beta1.MsgMultiSend", - "/cosmos.staking.v1beta1.MsgDelegate", - "/cosmos.staking.v1beta1.MsgUndelegate", - "/cosmos.staking.v1beta1.MsgBeginRedelegate", - "/cosmos.staking.v1beta1.MsgRedeemTokensforShares", - "/cosmos.staking.v1beta1.MsgTokenizeShares", - "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward", - "/cosmos.distribution.v1beta1.MsgSetWithdrawAddress", - "/ibc.applications.transfer.v1.MsgTransfer", - } - - if err := dyno.Set(g, arr, "app_state", "interchainaccounts", "host_genesis_state", "params", "allow_messages"); err != nil { + if err := dyno.Set(g, allowed_messages, "app_state", "interchainaccounts", "host_genesis_state", "params", "allow_messages"); err != nil { return nil, fmt.Errorf("failed to set allow_messages for interchainaccount host in genesis json: %w", err) } @@ -190,7 +179,18 @@ func TestICS(t *testing.T) { {Name: "gaia", Version: "v9.1.0", ChainConfig: ibc.ChainConfig{ GasAdjustment: 1.3, GasPrices: "0.0atom", - ModifyGenesis: setupGaiaGenesis(), + ModifyGenesis: setupGaiaGenesis([]string{ + "/cosmos.bank.v1beta1.MsgSend", + "/cosmos.bank.v1beta1.MsgMultiSend", + "/cosmos.staking.v1beta1.MsgDelegate", + "/cosmos.staking.v1beta1.MsgUndelegate", + "/cosmos.staking.v1beta1.MsgBeginRedelegate", + "/cosmos.staking.v1beta1.MsgRedeemTokensforShares", + "/cosmos.staking.v1beta1.MsgTokenizeShares", + "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward", + "/cosmos.distribution.v1beta1.MsgSetWithdrawAddress", + "/ibc.applications.transfer.v1.MsgTransfer", + }), }}, { ChainConfig: ibc.ChainConfig{ @@ -222,7 +222,7 @@ func TestICS(t *testing.T) { Images: []ibc.DockerImage{ { Repository: "ghcr.io/strangelove-ventures/heighliner/stride", - Version: "v9.1.1", + Version: "v9.2.1", UidGid: "1025:1025", }, }, @@ -261,6 +261,7 @@ func TestICS(t *testing.T) { const gaiaNeutronICSPath = "gn-ics-path" const gaiaNeutronIBCPath = "gn-ibc-path" const gaiaStrideIBCPath = "gs-ibc-path" + ic := ibctest.NewInterchain(). AddChain(atom). AddChain(neutron). @@ -367,17 +368,6 @@ func TestICS(t *testing.T) { users := ibctest.GetAndFundTestUsers(t, ctx, "default", int64(100_000_000), atom, neutron, stride) gaiaUser, neutronUser, strideUser := users[0], users[1], users[2] _, _ = gaiaUser, strideUser - neutron.CreateKey(ctx, "lper") - neutron.CreateKey(ctx, "lser") - - // neutronAddress := neutronUser.Bech32Address(neutron.Config().Bech32Prefix) - // atomAddress := gaiaUser.Bech32Address(atom.Config().Bech32Prefix) - - lpAddressBytes, _ := neutron.GetAddress(ctx, "lper") - lsAddressBytes, _ := neutron.GetAddress(ctx, "lser") - - lpAddress, err := types.Bech32ifyAddressBytes(neutron.Config().Bech32Prefix, lpAddressBytes) - lsAddress, err := types.Bech32ifyAddressBytes(neutron.Config().Bech32Prefix, lsAddressBytes) neutronUserBal, err := neutron.GetBalance( ctx, @@ -389,15 +379,19 @@ func TestICS(t *testing.T) { neutronChannelInfo, _ := r.GetChannels(ctx, eRep, neutron.Config().ChainID) var neutronGaiaIBCChannel ibc.ChannelOutput var neutronGaiaICSChannel ibc.ChannelOutput + // find the ics channel + for _, s := range neutronChannelInfo { + if s.Ordering == "ORDER_ORDERED" { + neutronGaiaICSChannel = s + break + } + } + // find the ibc transfer channel to gaia (same connection hops) for _, s := range neutronChannelInfo { - neutronJson, _ := json.Marshal(s) - print("\n neutron_channel: ", string(neutronJson)) if s.State == "STATE_OPEN" && s.Ordering == "ORDER_UNORDERED" && s.PortID == "transfer" { - if len(s.Counterparty.ChannelID) > 5 && s.Counterparty.PortID == "transfer" { + if len(s.Counterparty.ChannelID) > 5 && s.Counterparty.PortID == "transfer" && s.ConnectionHops[0] == neutronGaiaICSChannel.ConnectionHops[0] { neutronGaiaIBCChannel = s } - } else if s.Ordering == "ORDER_ORDERED" { - neutronGaiaICSChannel = s } } gaiaNeutronIBCChannel := neutronGaiaIBCChannel.Counterparty @@ -405,23 +399,22 @@ func TestICS(t *testing.T) { gaiaNeutronIBCChannelId := gaiaNeutronIBCChannel.ChannelID gaiaNeutronICSChannelId := neutronGaiaICSChannel.Counterparty.ChannelID neutronGaiaICSChannelId := neutronGaiaICSChannel.ChannelID - print("\nneutronGaiaIBCChannelId = ", neutronGaiaIBCChannelId) - print("\ngaiaNeutronIBCChannelId = ", gaiaNeutronIBCChannelId, "\n") + _, _ = gaiaNeutronICSChannelId, neutronGaiaICSChannelId t.Run("instantiate depositor", func(t *testing.T) { // Store and instantiate the Neutron ICA example contract. The // wasm file is placed in `wasms/` by the `just test` command. codeId, err := cosmosNeutron.StoreContract(ctx, neutronUser.KeyName, "wasms/stride_depositor.wasm") require.NoError(t, err, "failed to store neutron ICA contract") + stAtomWeightedReceiver := WeightedReceiver{ - Amount: 10, + Amount: int64(10), Address: "neutron1ud6resqzgewt92njs826m5st98n9r6kkjnurup", } atomWeightedReceiver := WeightedReceiver{ - Amount: 10, - Address: "neutron1q0z62s0q29ecay5x7vc3lj6yq7md4lmyafqs5p", + Amount: int64(10), + Address: "neutron1ud6resqzgewt92njs826m5st98n9r6kkjnurup", } - msg := InstantiateMsg{ StAtomReceiver: stAtomWeightedReceiver, AtomReceiver: atomWeightedReceiver, @@ -435,6 +428,12 @@ func TestICS(t *testing.T) { address, err := cosmosNeutron.InstantiateContract(ctx, neutronUser.KeyName, codeId, string(str), true) require.NoError(t, err, "failed to instantiate depositor contract: ", err) + neutronSrcDenomTrace := transfertypes.ParseDenomTrace( + transfertypes.GetPrefixedDenom("transfer", + neutronGaiaIBCChannelId, + atom.Config().Denom)) + neutronDstIbcDenom := neutronSrcDenomTrace.IBCDenom() + t.Run("query instantiated clock", func(t *testing.T) { var response ClockQueryResponse err = cosmosNeutron.QueryContract(ctx, address, DepositorContractQuery{ @@ -458,7 +457,8 @@ func TestICS(t *testing.T) { AtomReceiver: AtomReceiverQuery{}, }, &atomReceiver) require.NoError(t, err, "failed to query atom weighted receiver") - require.Equal(t, atomWeightedReceiver, atomReceiver.Data) + require.Equal(t, int64(10), atomReceiver.Data.Amount) + require.Equal(t, "neutron1ud6resqzgewt92njs826m5st98n9r6kkjnurup", atomReceiver.Data.Address) }) var addrResponse QueryResponse @@ -483,14 +483,9 @@ func TestICS(t *testing.T) { _, _, err = neutron.Exec(ctx, cmd, nil) require.NoError(t, err) - // Wait a bit for the ICA packet to get relayed. This takes a - // long time as the relayer has to do an entire IBC handshake - // because ICA creates a channel per account. err = testutil.WaitForBlocks(ctx, 10, atom, neutron) require.NoError(t, err, "failed to wait for blocks") - // Finally, we query the contract for the address of the - // account on Atom. var response QueryResponse err = cosmosNeutron.QueryContract(ctx, address, IcaExampleContractQuery{ InterchainAccountAddress: InterchainAccountAddressQuery{ @@ -501,7 +496,6 @@ func TestICS(t *testing.T) { require.NoError(t, err, "failed to query ICA account address") require.NotEmpty(t, response.Data.InterchainAccountAddress) icaAccountAddress = response.Data.InterchainAccountAddress - print("\n icaAccountAddress: ", icaAccountAddress, "\n") err = cosmosNeutron.QueryContract(ctx, address, DepositorICAAddressQuery{ DepositorInterchainAccountAddress: DepositorInterchainAccountAddressQuery{}, }, &addrResponse) @@ -533,12 +527,6 @@ func TestICS(t *testing.T) { require.EqualValues(t, 20, atomBal) }) - neutronSrcDenomTrace := transfertypes.ParseDenomTrace( - transfertypes.GetPrefixedDenom("transfer", - neutronGaiaIBCChannelId, - atom.Config().Denom)) - neutronDstIbcDenom := neutronSrcDenomTrace.IBCDenom() - t.Run("fund depositor contract with some neutron", func(t *testing.T) { err := neutron.SendFunds(ctx, neutronUser.KeyName, ibc.WalletAmount{ Address: address, @@ -575,82 +563,22 @@ func TestICS(t *testing.T) { "-y", } - stdout, stderr, err := neutron.Exec(ctx, cmd, nil) + _, _, err = neutron.Exec(ctx, cmd, nil) require.NoError(t, err) - print("\n stdout: ", string(stdout)) - print("\n stderr: ", string(stderr), "\n") - - require.NoError(t, r.FlushPackets(ctx, eRep, gaiaNeutronIBCPath, neutronGaiaIBCChannelId)) - require.NoError(t, r.FlushAcknowledgements(ctx, eRep, gaiaNeutronIBCPath, gaiaNeutronIBCChannelId)) - - // relay ics packets and acks - require.NoError(t, r.FlushPackets(ctx, eRep, gaiaNeutronICSPath, neutronGaiaICSChannelId)) - require.NoError(t, r.FlushAcknowledgements(ctx, eRep, gaiaNeutronICSPath, gaiaNeutronICSChannelId)) - err = testutil.WaitForBlocks(ctx, 10, atom, neutron) + err = testutil.WaitForBlocks(ctx, 20, atom, neutron) require.NoError(t, err, "failed to wait for blocks") - atomICABal, err := atom.GetBalance( - ctx, - icaAccountAddress, - atom.Config().Denom) + atomICABal, err := atom.GetBalance(ctx, icaAccountAddress, atom.Config().Denom) require.NoError(t, err, "failed to query ICA balance") - require.Equal(t, int64(0), atomICABal) + require.Equal(t, int64(10), atomICABal) neutronUserBalNew, err := neutron.GetBalance( ctx, address, neutronDstIbcDenom) require.NoError(t, err, "failed to query depositor contract atom balance") - require.Equal(t, int64(20), neutronUserBalNew) - - }) - - t.Run("third tick transfers to LS and LP modules", func(t *testing.T) { - initLiquidStakerAtomBal, err := neutron.GetBalance(ctx, lsAddress, atom.Config().Denom) - require.NoError(t, err, "failed to get LSer balance") - initLiquidityPoolerAtomBal, err := neutron.GetBalance(ctx, lpAddress, atom.Config().Denom) - require.NoError(t, err, "failed to get LPer balance") - require.EqualValues(t, int64(0), initLiquidStakerAtomBal) - require.EqualValues(t, int64(0), initLiquidityPoolerAtomBal) - - print("\n ticking...\n") - cmd = []string{"neutrond", "tx", "wasm", "execute", address, - `{"tick":{}}`, - "--from", neutronUser.KeyName, - "--gas-prices", "0.0untrn", - "--gas-adjustment", `1.5`, - "--output", "json", - "--home", "/var/cosmos-chain/neutron-2", - "--node", neutron.GetRPCAddress(), - "--home", neutron.HomeDir(), - "--chain-id", neutron.Config().ChainID, - "--from", "faucet", - "--gas", "50000.0untrn", - "--keyring-backend", keyring.BackendTest, - "-y", - } - - _, _, err = neutron.Exec(ctx, cmd, nil) - require.NoError(t, err) - - // Wait a bit for the ICA packet to get relayed. This takes a - // long time as the relayer has to do an entire IBC handshake - // because ICA creates a channel per account. - err = testutil.WaitForBlocks(ctx, 10, atom, neutron) - require.NoError(t, err, "failed to wait for blocks") - - depositorAtomBal, err := neutron.GetBalance(ctx, address, atom.Config().Denom) - require.NoError(t, err, "failed to query depositor atom balance") - require.Equal(t, int64(0), depositorAtomBal) - - // query respective accounts and validate they received the funds - liquidStakerAtomBal, err := cosmosNeutron.GetBalance(ctx, lsAddress, atom.Config().Denom) - require.NoError(t, err, "failed to get LSer balance") - liquidityPoolerAtomBal, err := cosmosNeutron.GetBalance(ctx, lpAddress, atom.Config().Denom) - require.NoError(t, err, "failed to get LPer balance") - require.EqualValues(t, int64(10), liquidStakerAtomBal, "LS did not receive atom") - require.EqualValues(t, int64(10), liquidityPoolerAtomBal, "LP did not receive atom") + require.Equal(t, int64(10), neutronUserBalNew) }) t.Run("subsequent ticks do nothing", func(t *testing.T) { @@ -673,9 +601,6 @@ func TestICS(t *testing.T) { _, _, err = neutron.Exec(ctx, cmd, nil) require.NoError(t, err) - // Wait a bit for the ICA packet to get relayed. This takes a - // long time as the relayer has to do an entire IBC handshake - // because ICA creates a channel per account. err = testutil.WaitForBlocks(ctx, 10, atom, neutron) require.NoError(t, err, "failed to wait for blocks") }) From 8099bace5aa01a2525ea1aedc1f5a9ca138db1b4 Mon Sep 17 00:00:00 2001 From: bekauz Date: Thu, 15 Jun 2023 18:04:39 +0200 Subject: [PATCH 19/20] removing hardcoded values from contract --- .../packages/depositor/src/contract.rs | 34 ++++--------------- .../tests/interchaintest/ics_test.go | 4 +-- 2 files changed, 9 insertions(+), 29 deletions(-) diff --git a/stride-covenant/packages/depositor/src/contract.rs b/stride-covenant/packages/depositor/src/contract.rs index cfbe79d9..cfce0b32 100644 --- a/stride-covenant/packages/depositor/src/contract.rs +++ b/stride-covenant/packages/depositor/src/contract.rs @@ -145,14 +145,13 @@ fn try_receive_atom_from_ica( match interchain_account { Some((address, controller_conn_id)) => { let source_channel = GAIA_NEUTRON_IBC_TRANSFER_CHANNEL_ID.load(deps.storage)?; - // let lp_receiver = NATIVE_ATOM_RECEIVER.load(deps.storage)?; - - // we should parse the amount from WeightedReceiver here. - // parsing it to string does not work so temporarily hardcoded. - // see: docs.rs/cosmos-sdk-proto/latest/cosmos_sdk_proto/cosmos/base/v1beta1/struct.Coin.html + let lp_receiver = NATIVE_ATOM_RECEIVER.load(deps.storage)?; + let amount = String::from(lp_receiver.amount.to_string()); + let receiver = String::from(lp_receiver.address.to_string()); + let coin = Coin { denom: ATOM_DENOM.to_string(), - amount: "10".to_string(), + amount, }; let msg = MsgTransfer { @@ -160,7 +159,7 @@ fn try_receive_atom_from_ica( source_channel: source_channel, token: Some(coin), sender: address.clone().to_string(), - receiver: env.contract.address.to_string(), + receiver, // TODO: look into what the timeout_height should be timeout_height: Some(Height { revision_number: 2, @@ -212,24 +211,9 @@ fn try_register_gaia_ica( let key = get_port_id(env.contract.address.as_str(), &gaia_acc_id); IBC_PORT_ID.save(deps.storage, &key)?; - // we are saving empty data here because we handle response of registering ICA in sudo_open_ack method - // INTERCHAIN_ACCOUNTS.save(deps.storage, key, &None)?; - - // CONTRACT_STATE.save(deps.storage, &ContractState::ICA_CREATED)?; - Ok(Response::new().add_message(register)) -} - -fn execute_register_ica( - deps: DepsMut, - env: Env, - connection_id: String, - interchain_account_id: String, -) -> NeutronResult> { - let register = - NeutronMsg::register_interchain_account(connection_id, interchain_account_id.clone()); - let key = get_port_id(env.contract.address.as_str(), &interchain_account_id); // we are saving empty data here because we handle response of registering ICA in sudo_open_ack method INTERCHAIN_ACCOUNTS.save(deps.storage, key, &None)?; + Ok(Response::new().add_message(register)) } @@ -364,10 +348,6 @@ fn try_execute_transfers( Ok(Response::default() .add_submessages(vec![ls_submsg, lp_submsg]) ) - // }, - // Err(_) => return Err(NeutronError::from(StdError::generic_err("failed to query atom balance on depositor"))), - // } - } fn msg_with_sudo_callback>, T>( diff --git a/stride-covenant/tests/interchaintest/ics_test.go b/stride-covenant/tests/interchaintest/ics_test.go index 9ddcc25d..e190cfb9 100644 --- a/stride-covenant/tests/interchaintest/ics_test.go +++ b/stride-covenant/tests/interchaintest/ics_test.go @@ -249,7 +249,7 @@ func TestICS(t *testing.T) { client, network := ibctest.DockerSetup(t) r := ibctest.NewBuiltinRelayerFactory( ibc.CosmosRly, - zaptest.NewLogger(t, zaptest.Level(zap.DebugLevel)), + zaptest.NewLogger(t), relayer.CustomDockerImage("ghcr.io/cosmos/relayer", "v2.3.1", rly.RlyDefaultUidGid), relayer.RelayerOptionExtraStartFlags{Flags: []string{"-d", "--log-format", "console"}}, ).Build(t, client, network) @@ -566,7 +566,7 @@ func TestICS(t *testing.T) { _, _, err = neutron.Exec(ctx, cmd, nil) require.NoError(t, err) - err = testutil.WaitForBlocks(ctx, 20, atom, neutron) + err = testutil.WaitForBlocks(ctx, 50, atom, neutron) require.NoError(t, err, "failed to wait for blocks") atomICABal, err := atom.GetBalance(ctx, icaAccountAddress, atom.Config().Denom) From 93b5d38bb8743f2a64778b771fef631779658b08 Mon Sep 17 00:00:00 2001 From: bekauz Date: Wed, 21 Jun 2023 15:53:57 +0200 Subject: [PATCH 20/20] downgrading rust to 1.66; moving depositor to contracts/ --- Cargo.toml | 3 +- .../depositor/.cargo/config | 0 .../depositor/Cargo.toml | 0 .../packages => contracts}/depositor/LICENSE | 0 .../depositor/README.md | 0 .../depositor/examples/schema.rs | 0 .../depositor/schema/execute_msg.json | 0 .../depositor/schema/instantiate_msg.json | 0 ...y_interchain_account_address_response.json | 0 .../depositor/schema/query_msg.json | 0 .../depositor/schema/sudo_msg.json | 0 .../depositor/src/contract.rs | 66 +++++++------------ .../depositor/src/error.rs | 0 .../depositor/src/lib.rs | 0 .../depositor/src/msg.rs | 6 +- .../depositor/src/state.rs | 10 +-- .../depositor/src/tests/mod.rs | 0 .../depositor/src/tests/suite.rs | 0 .../depositor/src/tests/tests.rs | 0 stride-covenant/justfile | 29 ++++++-- stride-covenant/optimize.sh | 16 +++++ 21 files changed, 69 insertions(+), 61 deletions(-) rename {stride-covenant/packages => contracts}/depositor/.cargo/config (100%) rename {stride-covenant/packages => contracts}/depositor/Cargo.toml (100%) rename {stride-covenant/packages => contracts}/depositor/LICENSE (100%) rename {stride-covenant/packages => contracts}/depositor/README.md (100%) rename {stride-covenant/packages => contracts}/depositor/examples/schema.rs (100%) rename {stride-covenant/packages => contracts}/depositor/schema/execute_msg.json (100%) rename {stride-covenant/packages => contracts}/depositor/schema/instantiate_msg.json (100%) rename {stride-covenant/packages => contracts}/depositor/schema/query_interchain_account_address_response.json (100%) rename {stride-covenant/packages => contracts}/depositor/schema/query_msg.json (100%) rename {stride-covenant/packages => contracts}/depositor/schema/sudo_msg.json (100%) rename {stride-covenant/packages => contracts}/depositor/src/contract.rs (94%) rename {stride-covenant/packages => contracts}/depositor/src/error.rs (100%) rename {stride-covenant/packages => contracts}/depositor/src/lib.rs (100%) rename {stride-covenant/packages => contracts}/depositor/src/msg.rs (93%) rename {stride-covenant/packages => contracts}/depositor/src/state.rs (98%) rename {stride-covenant/packages => contracts}/depositor/src/tests/mod.rs (100%) rename {stride-covenant/packages => contracts}/depositor/src/tests/suite.rs (100%) rename {stride-covenant/packages => contracts}/depositor/src/tests/tests.rs (100%) create mode 100755 stride-covenant/optimize.sh diff --git a/Cargo.toml b/Cargo.toml index 9cc145cf..6d3cb373 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ members = [ [workspace.package] edition = "2021" license = "BSD-3" -rust-version = "1.67" +rust-version = "1.66" version = "0.1.0" [profile.release] @@ -42,6 +42,7 @@ cw-fifo = { path = "packages/cw-fifo" } covenant-clock = { path = "contracts/clock" } covenant-clock-tester = { path = "contracts/clock-tester" } +covenant-depositor = { path = "contracts/depositor" } # dev-dependencies cw-multi-test = "0.16" diff --git a/stride-covenant/packages/depositor/.cargo/config b/contracts/depositor/.cargo/config similarity index 100% rename from stride-covenant/packages/depositor/.cargo/config rename to contracts/depositor/.cargo/config diff --git a/stride-covenant/packages/depositor/Cargo.toml b/contracts/depositor/Cargo.toml similarity index 100% rename from stride-covenant/packages/depositor/Cargo.toml rename to contracts/depositor/Cargo.toml diff --git a/stride-covenant/packages/depositor/LICENSE b/contracts/depositor/LICENSE similarity index 100% rename from stride-covenant/packages/depositor/LICENSE rename to contracts/depositor/LICENSE diff --git a/stride-covenant/packages/depositor/README.md b/contracts/depositor/README.md similarity index 100% rename from stride-covenant/packages/depositor/README.md rename to contracts/depositor/README.md diff --git a/stride-covenant/packages/depositor/examples/schema.rs b/contracts/depositor/examples/schema.rs similarity index 100% rename from stride-covenant/packages/depositor/examples/schema.rs rename to contracts/depositor/examples/schema.rs diff --git a/stride-covenant/packages/depositor/schema/execute_msg.json b/contracts/depositor/schema/execute_msg.json similarity index 100% rename from stride-covenant/packages/depositor/schema/execute_msg.json rename to contracts/depositor/schema/execute_msg.json diff --git a/stride-covenant/packages/depositor/schema/instantiate_msg.json b/contracts/depositor/schema/instantiate_msg.json similarity index 100% rename from stride-covenant/packages/depositor/schema/instantiate_msg.json rename to contracts/depositor/schema/instantiate_msg.json diff --git a/stride-covenant/packages/depositor/schema/query_interchain_account_address_response.json b/contracts/depositor/schema/query_interchain_account_address_response.json similarity index 100% rename from stride-covenant/packages/depositor/schema/query_interchain_account_address_response.json rename to contracts/depositor/schema/query_interchain_account_address_response.json diff --git a/stride-covenant/packages/depositor/schema/query_msg.json b/contracts/depositor/schema/query_msg.json similarity index 100% rename from stride-covenant/packages/depositor/schema/query_msg.json rename to contracts/depositor/schema/query_msg.json diff --git a/stride-covenant/packages/depositor/schema/sudo_msg.json b/contracts/depositor/schema/sudo_msg.json similarity index 100% rename from stride-covenant/packages/depositor/schema/sudo_msg.json rename to contracts/depositor/schema/sudo_msg.json diff --git a/stride-covenant/packages/depositor/src/contract.rs b/contracts/depositor/src/contract.rs similarity index 94% rename from stride-covenant/packages/depositor/src/contract.rs rename to contracts/depositor/src/contract.rs index cfce0b32..5da9ecf2 100644 --- a/stride-covenant/packages/depositor/src/contract.rs +++ b/contracts/depositor/src/contract.rs @@ -1,5 +1,3 @@ -use std::str::FromStr; - use cosmos_sdk_proto::cosmos::base::v1beta1::Coin; use cosmos_sdk_proto::ibc::applications::transfer::v1::MsgTransfer; @@ -40,7 +38,7 @@ use crate::state::{ // Default timeout for SubmitTX is two weeks const DEFAULT_TIMEOUT_SECONDS: u64 = 60 * 60 * 24 * 7 * 2; -const DEFAULT_TIMEOUT_HEIGHT: u64 = 10000000; +// const DEFAULT_TIMEOUT_HEIGHT: u64 = 10000000; const NEUTRON_DENOM: &str = "untrn"; const ATOM_DENOM: &str = "uatom"; const IBC_CONNECTION: &str = "connection-0"; @@ -48,7 +46,7 @@ const ICS_CONNECTION_ID: &str = "connection-1"; const INTERCHAIN_ACCOUNT_ID: &str = "test"; const TRANSFER_PORT: &str = "transfer"; -const CONTRACT_NAME: &str = concat!("crates.io:neutron-sdk__", env!("CARGO_PKG_NAME")); +const CONTRACT_NAME: &str = "crates.io:stride-depositor"; const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -78,7 +76,7 @@ pub fn instantiate( STRIDE_ATOM_RECEIVER.save(deps.storage, &msg.st_atom_receiver)?; NATIVE_ATOM_RECEIVER.save(deps.storage, &msg.atom_receiver)?; CLOCK_ADDRESS.save(deps.storage, &Addr::unchecked(msg.clock_address))?; - CONTRACT_STATE.save(deps.storage, &ContractState::INSTANTIATED)?; + CONTRACT_STATE.save(deps.storage, &ContractState::Instantiated)?; GAIA_NEUTRON_IBC_TRANSFER_CHANNEL_ID.save(deps.storage, &msg.gaia_neutron_ibc_transfer_channel_id)?; Ok(Response::default()) @@ -86,7 +84,7 @@ pub fn instantiate( #[entry_point] pub fn execute( - mut deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, @@ -96,15 +94,11 @@ pub fn execute( match msg { ExecuteMsg::Tick { } => try_tick(deps, env, info), ExecuteMsg::Received { } => try_handle_received(), - ExecuteMsg::Register { - connection_id, - interchain_account_id, - } => execute_register_ica(deps, env, connection_id, interchain_account_id), } } -fn try_tick(mut deps: DepsMut, env: Env, info: MessageInfo) -> NeutronResult> { +fn try_tick(deps: DepsMut, env: Env, info: MessageInfo) -> NeutronResult> { let current_state = CONTRACT_STATE.load(deps.storage)?; let ica_address: Result = ICA_ADDRESS.load(deps.storage); let gaia_account_address = match ica_address { @@ -114,18 +108,18 @@ fn try_tick(mut deps: DepsMut, env: Env, info: MessageInfo) -> NeutronResult try_register_gaia_ica(deps, env), - ContractState::ICA_CREATED => try_receive_atom_from_ica(deps, env, info, gaia_account_address), - ContractState::RECEIVED_FUNDS => try_execute_transfers(deps, env, info, gaia_account_address), - ContractState::COMPLETE => Ok(Response::default()), + ContractState::Instantiated => try_register_gaia_ica(deps, env), + ContractState::ICACreated => try_receive_atom_from_ica(deps, env, info, gaia_account_address), + ContractState::ReceivedFunds => try_execute_transfers(deps, env, info, gaia_account_address), + ContractState::Complete => Ok(Response::default()), } } fn try_receive_atom_from_ica( - mut deps: DepsMut, + deps: DepsMut, env: Env, - info: MessageInfo, - gaia_account_address: String + _info: MessageInfo, + _gaia_account_address: String ) -> NeutronResult> { let fee = IbcFee { recv_fee: vec![], // must be empty @@ -147,7 +141,7 @@ fn try_receive_atom_from_ica( let source_channel = GAIA_NEUTRON_IBC_TRANSFER_CHANNEL_ID.load(deps.storage)?; let lp_receiver = NATIVE_ATOM_RECEIVER.load(deps.storage)?; let amount = String::from(lp_receiver.amount.to_string()); - let receiver = String::from(lp_receiver.address.to_string()); + // let receiver = String::from(lp_receiver.address.to_string()); let coin = Coin { denom: ATOM_DENOM.to_string(), @@ -158,12 +152,13 @@ fn try_receive_atom_from_ica( source_port: "transfer".to_string(), source_channel: source_channel, token: Some(coin), - sender: address.clone().to_string(), - receiver, + sender: address.clone(), + // receiver: String::from(lp_receiver.address.to_string()), + receiver: env.contract.address.to_string(), // TODO: look into what the timeout_height should be timeout_height: Some(Height { revision_number: 2, - revision_height: 123, + revision_height: 500, }), timeout_timestamp: 0, }; @@ -198,7 +193,7 @@ fn try_receive_atom_from_ica( } fn try_register_gaia_ica( - mut deps: DepsMut, + deps: DepsMut, env: Env, ) -> NeutronResult> { let gaia_acc_id = INTERCHAIN_ACCOUNT_ID.to_string(); @@ -220,7 +215,7 @@ fn try_register_gaia_ica( fn try_execute_transfers( mut deps: DepsMut, env: Env, - info: MessageInfo, + _info: MessageInfo, gaia_account_address: String ) -> NeutronResult> { // validate that tick was triggered by the authorized clock @@ -237,7 +232,7 @@ fn try_execute_transfers( // 2. transfer 1/2 of atoms from ICA to liquidity-pooler module // let fee = min_ntrn_ibc_fee(query_min_ibc_fee(deps.as_ref())?.min_fee); - let neutron_coin = Coin { + let _neutron_coin = Coin { denom: NEUTRON_DENOM.to_string(), amount: 1000u128.to_string(), }; @@ -406,7 +401,7 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> NeutronResult pub fn query_depositor_interchain_address( deps: Deps, - env: Env, + _env: Env, ) -> NeutronResult { let addr = ICA_ADDRESS.load(deps.storage); @@ -542,7 +537,7 @@ fn sudo_open_ack( )), )?; ICA_ADDRESS.save(deps.storage, &parsed_version.address)?; - CONTRACT_STATE.save(deps.storage, &ContractState::ICA_CREATED)?; + CONTRACT_STATE.save(deps.storage, &ContractState::ICACreated)?; return Ok(Response::default()); } Err(StdError::generic_err("Can't parse counterparty_version")) @@ -785,19 +780,4 @@ pub fn reply(deps: DepsMut, env: Env, msg: Reply) -> StdResult { ))), } } - -fn min_ntrn_ibc_fee(fee: IbcFee) -> IbcFee { - IbcFee { - recv_fee: fee.recv_fee, - ack_fee: fee - .ack_fee - .into_iter() - .filter(|a| a.denom == NEUTRON_DENOM) - .collect(), - timeout_fee: fee - .timeout_fee - .into_iter() - .filter(|a| a.denom == NEUTRON_DENOM) - .collect(), - } -} \ No newline at end of file + \ No newline at end of file diff --git a/stride-covenant/packages/depositor/src/error.rs b/contracts/depositor/src/error.rs similarity index 100% rename from stride-covenant/packages/depositor/src/error.rs rename to contracts/depositor/src/error.rs diff --git a/stride-covenant/packages/depositor/src/lib.rs b/contracts/depositor/src/lib.rs similarity index 100% rename from stride-covenant/packages/depositor/src/lib.rs rename to contracts/depositor/src/lib.rs diff --git a/stride-covenant/packages/depositor/src/msg.rs b/contracts/depositor/src/msg.rs similarity index 93% rename from stride-covenant/packages/depositor/src/msg.rs rename to contracts/depositor/src/msg.rs index 2388e690..9d659d03 100644 --- a/stride-covenant/packages/depositor/src/msg.rs +++ b/contracts/depositor/src/msg.rs @@ -21,10 +21,6 @@ pub struct WeightedReceiver { pub enum ExecuteMsg { Tick {}, Received {}, - Register { - connection_id: String, - interchain_account_id: String, - }, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] @@ -53,4 +49,4 @@ pub enum QueryMsg { } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] -pub struct MigrateMsg {} +pub struct MigrateMsg {} \ No newline at end of file diff --git a/stride-covenant/packages/depositor/src/state.rs b/contracts/depositor/src/state.rs similarity index 98% rename from stride-covenant/packages/depositor/src/state.rs rename to contracts/depositor/src/state.rs index 42a156a7..74bfdff0 100644 --- a/stride-covenant/packages/depositor/src/state.rs +++ b/contracts/depositor/src/state.rs @@ -27,10 +27,10 @@ pub const IBC_PORT_ID: Item = Item::new("ibc_port_id"); #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum ContractState { - INSTANTIATED, - ICA_CREATED, - RECEIVED_FUNDS, - COMPLETE, + Instantiated, + ICACreated, + ReceivedFunds, + Complete, } pub const CONTRACT_STATE: Item = Item::new("contract_state"); @@ -109,4 +109,4 @@ pub fn save_sudo_payload( payload: SudoPayload, ) -> StdResult<()> { SUDO_PAYLOAD.save(store, (channel_id, seq_id), &to_vec(&payload)?) -} +} \ No newline at end of file diff --git a/stride-covenant/packages/depositor/src/tests/mod.rs b/contracts/depositor/src/tests/mod.rs similarity index 100% rename from stride-covenant/packages/depositor/src/tests/mod.rs rename to contracts/depositor/src/tests/mod.rs diff --git a/stride-covenant/packages/depositor/src/tests/suite.rs b/contracts/depositor/src/tests/suite.rs similarity index 100% rename from stride-covenant/packages/depositor/src/tests/suite.rs rename to contracts/depositor/src/tests/suite.rs diff --git a/stride-covenant/packages/depositor/src/tests/tests.rs b/contracts/depositor/src/tests/tests.rs similarity index 100% rename from stride-covenant/packages/depositor/src/tests/tests.rs rename to contracts/depositor/src/tests/tests.rs diff --git a/stride-covenant/justfile b/stride-covenant/justfile index ca13756c..8c671ef9 100644 --- a/stride-covenant/justfile +++ b/stride-covenant/justfile @@ -1,13 +1,28 @@ build: cargo build +gen: build gen-schema + +gen-schema: + START_DIR=$(pwd); \ + for f in ./packages/*; do \ + echo "generating schema"; \ + cd "$f"; \ + CMD="cargo run --example schema"; \ + eval ${CMD} > /dev/null; \ + rm -rf ./schema/raw; \ + cd "$START_DIR"; \ + done + +test: + cargo test + optimize: - cd packages/* && docker run --platform linux/amd64 --rm -v "$(pwd)":/code \ - --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ - --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.13 + ./optimize.sh -test: optimize +simtest: optimize mkdir -p tests/interchaintest/wasms - cp packages/*/artifacts/*.wasm tests/interchaintest/wasms - cd tests/interchaintest && go test -v ./... \ No newline at end of file + + cp -R ./../artifacts/*.wasm tests/interchaintest/wasms + go clean -testcache + cd tests/interchaintest/ && go test -v ./... \ No newline at end of file diff --git a/stride-covenant/optimize.sh b/stride-covenant/optimize.sh new file mode 100755 index 00000000..0d2ed785 --- /dev/null +++ b/stride-covenant/optimize.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +cd .. +if [[ $(uname -m) =~ "arm64" ]]; then \ + docker run --rm -v "$(pwd)":/code \ + --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ + --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ + cosmwasm/workspace-optimizer-arm64:0.12.11 + +else + docker run --rm -v "$(pwd)":/code \ + --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ + --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ + --platform linux/amd64 \ + cosmwasm/workspace-optimizer:0.12.13 +fi