From 4e3e37b244e93449a2bbb9a534a2bc6f3b380983 Mon Sep 17 00:00:00 2001 From: Kerber0x Date: Thu, 23 May 2024 16:59:43 +0100 Subject: [PATCH 01/19] chore: set foundation for epic integration tests --- Cargo.lock | 322 +++++++-------- Cargo.toml | 2 + integration-tests/Cargo.toml | 17 + integration-tests/src/lib.rs | 14 + integration-tests/tests/common/mod.rs | 2 + integration-tests/tests/common/suite.rs | 387 ++++++++++++++++++ .../tests/common/suite_contracts.rs | 63 +++ integration-tests/tests/integration.rs | 1 + 8 files changed, 623 insertions(+), 185 deletions(-) create mode 100644 integration-tests/Cargo.toml create mode 100644 integration-tests/src/lib.rs create mode 100644 integration-tests/tests/common/mod.rs create mode 100644 integration-tests/tests/common/suite.rs create mode 100644 integration-tests/tests/common/suite_contracts.rs create mode 100644 integration-tests/tests/integration.rs diff --git a/Cargo.lock b/Cargo.lock index fe81c36cb..0c4cd35bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,15 +21,15 @@ checksum = "5c1a43b7dc14f396c5d1ac0eaea10f33cb40a2b46751d0869864d6d5abed20db" [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "autocfg" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "base16ct" @@ -72,15 +72,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "block-buffer" @@ -155,9 +149,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "cosmwasm-crypto" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b4c3f9c4616d6413d4b5fc4c270a4cc32a374b9be08671e80e1a019f805d8f" +checksum = "dd50718a2b6830ce9eb5d465de5a018a12e71729d66b70807ce97e6dd14f931d" dependencies = [ "digest 0.10.7", "ecdsa", @@ -169,18 +163,18 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c586ced10c3b00e809ee664a895025a024f60d65d34fe4c09daed4a4db68a3f3" +checksum = "242e98e7a231c122e08f300d9db3262d1007b51758a8732cd6210b3e9faa4f3a" dependencies = [ "syn 1.0.109", ] [[package]] name = "cosmwasm-schema" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8467874827d384c131955ff6f4d47d02e72a956a08eb3c0ff24f8c903a5517b4" +checksum = "7879036156092ad1c22fe0d7316efc5a5eceec2bc3906462a2560215f2a2f929" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -191,9 +185,9 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6db85d98ac80922aef465e564d5b21fa9cfac5058cb62df7f116c3682337393" +checksum = "0bb57855fbfc83327f8445ae0d413b1a05ac0d68c396ab4d122b2abd7bb82cb6" dependencies = [ "proc-macro2", "quote", @@ -202,9 +196,9 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712fe58f39d55c812f7b2c84e097cdede3a39d520f89b6dc3153837e31741927" +checksum = "78c1556156fdf892a55cced6115968b961eaaadd6f724a2c2cb7d1e168e32dd3" dependencies = [ "base64", "bech32", @@ -309,7 +303,7 @@ dependencies = [ "cw-utils", "derivative", "itertools 0.12.1", - "prost 0.12.3", + "prost 0.12.6", "schemars", "serde", "sha2 0.10.8", @@ -504,9 +498,9 @@ dependencies = [ [[package]] name = "either" -version = "1.10.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "elliptic-curve" @@ -546,9 +540,9 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys", @@ -556,9 +550,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "fee-distributor-mock" @@ -666,9 +660,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -795,19 +789,27 @@ dependencies = [ ] [[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +name = "integration-tests" +version = "0.1.0" dependencies = [ - "either", + "anyhow", + "bonding-manager", + "cosmwasm-std", + "cw-multi-test", + "cw-ownable", + "epoch-manager", + "incentive-manager", + "pool-manager", + "vault-manager", + "white-whale-std", + "white-whale-testing", ] [[package]] name = "itertools" -version = "0.11.0" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] @@ -843,15 +845,15 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libm" @@ -861,15 +863,15 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -886,9 +888,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", @@ -920,9 +922,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -930,15 +932,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.48.5", + "windows-targets", ] [[package]] @@ -989,22 +991,22 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.5.0", + "bitflags", "lazy_static", "num-traits", "rand", @@ -1028,12 +1030,12 @@ dependencies = [ [[package]] name = "prost" -version = "0.12.3" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" +checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" dependencies = [ "bytes", - "prost-derive 0.12.3", + "prost-derive 0.12.6", ] [[package]] @@ -1051,15 +1053,15 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.12.3" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" +checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.68", ] [[package]] @@ -1160,9 +1162,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -1214,18 +1216,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rfc6979" @@ -1239,11 +1241,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.32" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.5.0", + "bitflags", "errno", "libc", "linux-raw-sys", @@ -1264,15 +1266,15 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "schemars" -version = "0.8.16" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" dependencies = [ "dyn-clone", "schemars_derive", @@ -1282,14 +1284,14 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.16" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" +checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 1.0.109", + "syn 2.0.68", ] [[package]] @@ -1314,15 +1316,15 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] @@ -1338,31 +1340,31 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.68", ] [[package]] name = "serde_derive_internals" -version = "0.26.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.68", ] [[package]] name = "serde_json" -version = "1.0.115" +version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" dependencies = [ "itoa", "ryu", @@ -1463,9 +1465,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -1480,9 +1482,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.58" +version = "2.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" dependencies = [ "proc-macro2", "quote", @@ -1597,7 +1599,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.68", ] [[package]] @@ -1608,28 +1610,28 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.68", "test-case-core", ] [[package]] name = "thiserror" -version = "1.0.58" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.68", ] [[package]] @@ -1842,122 +1844,72 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets", ] [[package]] name = "windows-targets" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" -dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" [[package]] -name = "windows_i686_gnu" -version = "0.52.4" +name = "windows_i686_gnullvm" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "xtask" @@ -1971,6 +1923,6 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/Cargo.toml b/Cargo.toml index 19559208b..471e415eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ resolver = "2" members = [ + "integration-tests", "packages/*", "contracts/liquidity_hub/pool-network/*", "contracts/liquidity_hub/fee_collector", @@ -72,6 +73,7 @@ terraswap-token = { path = "./contracts/liquidity_hub/pool-network/terraswap_tok terraswap-pair = { path = "./contracts/liquidity_hub/pool-network/terraswap_pair" } incentive-manager = { path = "./contracts/liquidity_hub/incentive-manager" } bonding-manager = { path = "./contracts/liquidity_hub/bonding-manager" } +vault-manager = { path = "./contracts/liquidity_hub/vault-manager" } [workspace.metadata.dylint] libraries = [{ git = "https://github.com/0xFable/cw-lint" }] diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml new file mode 100644 index 000000000..53292a1b3 --- /dev/null +++ b/integration-tests/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "integration-tests" +version = "0.1.0" +edition.workspace = true + +[dependencies] +bonding-manager.workspace = true +epoch-manager.workspace = true +incentive-manager.workspace = true +pool-manager.workspace = true +vault-manager.workspace = true +cw-multi-test.workspace = true +anyhow.workspace = true +white-whale-std.workspace = true +white-whale-testing.workspace = true +cosmwasm-std.workspace = true +cw-ownable.workspace = true diff --git a/integration-tests/src/lib.rs b/integration-tests/src/lib.rs new file mode 100644 index 000000000..7d12d9af8 --- /dev/null +++ b/integration-tests/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/integration-tests/tests/common/mod.rs b/integration-tests/tests/common/mod.rs new file mode 100644 index 000000000..eb37e5585 --- /dev/null +++ b/integration-tests/tests/common/mod.rs @@ -0,0 +1,2 @@ +pub mod suite; +mod suite_contracts; diff --git a/integration-tests/tests/common/suite.rs b/integration-tests/tests/common/suite.rs new file mode 100644 index 000000000..ce2ec61a2 --- /dev/null +++ b/integration-tests/tests/common/suite.rs @@ -0,0 +1,387 @@ +use cosmwasm_std::testing::MockStorage; +use cosmwasm_std::{coin, Addr, Coin, Decimal, Empty, StdResult, Timestamp, Uint64}; +use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32}; +use cw_multi_test::{ + App, AppBuilder, AppResponse, BankKeeper, DistributionKeeper, Executor, FailingModule, + GovFailingModule, IbcFailingModule, StakeKeeper, WasmKeeper, +}; + +use white_whale_std::epoch_manager::epoch_manager::{Epoch, EpochConfig, EpochResponse}; +use white_whale_testing::multi_test::stargate_mock::StargateMock; + +use crate::common::suite_contracts::{ + bonding_manager_contract, epoch_manager_contract, incentive_manager_contract, + pool_manager_contract, vault_manager_contract, +}; + +type OsmosisTokenFactoryApp = App< + BankKeeper, + MockApiBech32, + MockStorage, + FailingModule, + WasmKeeper, + StakeKeeper, + DistributionKeeper, + IbcFailingModule, + GovFailingModule, + StargateMock, +>; + +pub struct TestingSuite { + app: OsmosisTokenFactoryApp, + pub senders: [Addr; 5], + pub bonding_manager_addr: Addr, + pub epoch_manager_addr: Addr, + pub incentive_manager_addr: Addr, + pub pool_manager_addr: Addr, + pub vault_manager_addr: Addr, + pub pools: Vec, + pub vaults: Vec, +} + +/// TestingSuite helpers +impl TestingSuite { + pub(crate) fn creator(&mut self) -> Addr { + self.senders.first().unwrap().clone() + } + + pub(crate) fn set_time(&mut self, timestamp: Timestamp) -> &mut Self { + let mut block_info = self.app.block_info(); + block_info.time = timestamp; + self.app.set_block(block_info); + + self + } + pub(crate) fn add_one_day(&mut self) -> &mut Self { + let mut block_info = self.app.block_info(); + block_info.time = block_info.time.plus_days(1); + self.app.set_block(block_info); + + self + } + + pub(crate) fn add_one_epoch(&mut self) -> &mut Self { + let creator = self.creator(); + + self.add_one_day().create_epoch(creator, |res| { + res.unwrap(); + }); + + self + } +} + +/// Instantiate +impl TestingSuite { + pub(crate) fn default_with_balances(initial_balance: Vec) -> Self { + let sender_1 = Addr::unchecked("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"); + let sender_2 = Addr::unchecked("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"); + let sender_3 = Addr::unchecked("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"); + let sender_4 = Addr::unchecked("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"); + let sender_5 = Addr::unchecked("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"); + + let bank = BankKeeper::new(); + + let balances = vec![ + (sender_1.clone(), initial_balance.clone()), + (sender_2.clone(), initial_balance.clone()), + (sender_3.clone(), initial_balance.clone()), + (sender_4.clone(), initial_balance.clone()), + (sender_5.clone(), initial_balance.clone()), + ]; + + let app = AppBuilder::new() + .with_api(MockApiBech32::new("migaloo")) + .with_wasm(WasmKeeper::default().with_address_generator(MockAddressGenerator)) + .with_bank(bank) + .with_stargate(StargateMock {}) + .build(|router, _api, storage| { + balances.into_iter().for_each(|(account, amount)| { + router.bank.init_balance(storage, &account, amount).unwrap() + }); + }); + + Self { + app, + senders: [sender_1, sender_2, sender_3, sender_4, sender_5], + bonding_manager_addr: Addr::unchecked(""), + epoch_manager_addr: Addr::unchecked(""), + incentive_manager_addr: Addr::unchecked(""), + pool_manager_addr: Addr::unchecked(""), + vault_manager_addr: Addr::unchecked(""), + pools: vec![], + vaults: vec![], + } + } + + #[track_caller] + pub(crate) fn instantiate(&mut self) -> &mut Self { + self.create_epoch_manager(); + self.create_bonding_manager(); + self.create_incentive_manager(); + self.create_pool_manager(); + self.create_vault_manager(); + + // May 23th 2024 15:00:00 UTC + let timestamp = Timestamp::from_seconds(1716476400u64); + self.set_time(timestamp); + + self.add_one_epoch(); + + self + } + + fn create_bonding_manager(&mut self) { + let bonding_manager_id = self.app.store_code(bonding_manager_contract()); + let epoch_manager_addr = self.epoch_manager_addr.to_string(); + + // create whale lair + let msg = white_whale_std::bonding_manager::InstantiateMsg { + distribution_denom: "uwhale".to_string(), + unbonding_period: 1u64, + growth_rate: Decimal::one(), + bonding_assets: vec!["ampWHALE".to_string(), "bWHALE".to_string()], + grace_period: 21, + epoch_manager_addr, + }; + + let creator = self.creator().clone(); + + self.bonding_manager_addr = self + .app + .instantiate_contract( + bonding_manager_id, + creator.clone(), + &msg, + &[], + "Migaloo Bonding Manager".to_string(), + Some(creator.to_string()), + ) + .unwrap(); + } + + #[allow(clippy::inconsistent_digit_grouping)] + fn create_epoch_manager(&mut self) { + let epoch_manager_contract = self.app.store_code(epoch_manager_contract()); + + // create epoch manager + let msg = white_whale_std::epoch_manager::epoch_manager::InstantiateMsg { + start_epoch: Epoch { + id: 0, + start_time: Timestamp::from_nanos(1716476400_000000000u64), + }, + epoch_config: EpochConfig { + duration: Uint64::new(86400_000000000u64), + genesis_epoch: Uint64::new(1716476400_000000000u64), // May 23th 2024 15:00:00 UTC + }, + }; + + let creator = self.creator().clone(); + + self.epoch_manager_addr = self + .app + .instantiate_contract( + epoch_manager_contract, + creator.clone(), + &msg, + &[], + "Epoch Manager".to_string(), + Some(creator.to_string()), + ) + .unwrap(); + } + + fn create_incentive_manager(&mut self) { + let incentive_manager_contract = self.app.store_code(incentive_manager_contract()); + + let epoch_manager_addr = self.epoch_manager_addr.to_string(); + let bonding_manager_addr = self.bonding_manager_addr.to_string(); + + let creator = self.creator().clone(); + + // create epoch manager + let msg = white_whale_std::incentive_manager::InstantiateMsg { + owner: creator.to_string(), + epoch_manager_addr, + bonding_manager_addr, + create_incentive_fee: coin(1_000, "uwhale"), + max_concurrent_incentives: 5, + max_incentive_epoch_buffer: 14, + min_unlocking_duration: 86_400, + max_unlocking_duration: 31_536_000, + emergency_unlock_penalty: Decimal::percent(10), + }; + + self.incentive_manager_addr = self + .app + .instantiate_contract( + incentive_manager_contract, + creator.clone(), + &msg, + &[], + "Incentive Manager".to_string(), + Some(creator.to_string()), + ) + .unwrap(); + } + fn create_pool_manager(&mut self) { + let pool_manager_contract = self.app.store_code(pool_manager_contract()); + + let bonding_manager_addr = self.bonding_manager_addr.to_string(); + let incentive_manager_addr = self.incentive_manager_addr.to_string(); + + // create epoch manager + let msg = white_whale_std::pool_manager::InstantiateMsg { + bonding_manager_addr, + incentive_manager_addr, + pool_creation_fee: coin(1_000, "uwhale"), + }; + + let creator = self.creator().clone(); + + self.pool_manager_addr = self + .app + .instantiate_contract( + pool_manager_contract, + creator.clone(), + &msg, + &[], + "Pool Manager".to_string(), + Some(creator.to_string()), + ) + .unwrap(); + } + fn create_vault_manager(&mut self) { + let vault_manager_contract = self.app.store_code(vault_manager_contract()); + + let creator = self.creator().clone(); + let bonding_manager_addr = self.bonding_manager_addr.to_string(); + + // create epoch manager + let msg = white_whale_std::vault_manager::InstantiateMsg { + owner: creator.to_string(), + bonding_manager_addr, + vault_creation_fee: coin(1_000, "uwhale"), + }; + + self.vault_manager_addr = self + .app + .instantiate_contract( + vault_manager_contract, + creator.clone(), + &msg, + &[], + "Vault Manager".to_string(), + Some(creator.to_string()), + ) + .unwrap(); + } +} + +//------------------------------------// + +/// bonding manager actions +impl TestingSuite {} + +//------------------------------------// + +/// epoch manager actions +impl TestingSuite { + #[track_caller] + pub(crate) fn create_epoch( + &mut self, + sender: Addr, + result: impl Fn(Result), + ) -> &mut Self { + let msg = white_whale_std::epoch_manager::epoch_manager::ExecuteMsg::CreateEpoch {}; + + result( + self.app + .execute_contract(sender, self.epoch_manager_addr.clone(), &msg, &[]), + ); + + self + } + + #[track_caller] + pub(crate) fn add_hook( + &mut self, + sender: Addr, + contract_addr: Addr, + result: impl Fn(Result), + ) -> &mut Self { + let msg = white_whale_std::epoch_manager::epoch_manager::ExecuteMsg::AddHook { + contract_addr: contract_addr.to_string(), + }; + + result( + self.app + .execute_contract(sender, self.epoch_manager_addr.clone(), &msg, &[]), + ); + + self + } + + #[track_caller] + pub(crate) fn remove_hook( + &mut self, + sender: Addr, + contract_addr: Addr, + result: impl Fn(Result), + ) -> &mut Self { + let msg = white_whale_std::epoch_manager::epoch_manager::ExecuteMsg::RemoveHook { + contract_addr: contract_addr.to_string(), + }; + + result( + self.app + .execute_contract(sender, self.epoch_manager_addr.clone(), &msg, &[]), + ); + + self + } + + #[track_caller] + pub(crate) fn query_current_epoch( + &mut self, + mut result: impl FnMut(StdResult), + ) -> &mut Self { + let current_epoch_response: StdResult = self.app.wrap().query_wasm_smart( + &self.epoch_manager_addr, + &white_whale_std::epoch_manager::epoch_manager::QueryMsg::CurrentEpoch {}, + ); + + result(current_epoch_response); + + self + } + #[track_caller] + pub(crate) fn query_hooks( + &mut self, + mut result: impl FnMut(StdResult), + ) -> &mut Self { + let current_epoch_response: StdResult = self.app.wrap().query_wasm_smart( + &self.epoch_manager_addr, + &white_whale_std::epoch_manager::epoch_manager::QueryMsg::Hooks {}, + ); + + result(current_epoch_response); + + self + } +} + +//------------------------------------// + +/// incentive manager actions +impl TestingSuite {} + +//------------------------------------// + +/// pool manager actions +impl TestingSuite {} + +//------------------------------------// + +/// vault manager actions +impl TestingSuite {} diff --git a/integration-tests/tests/common/suite_contracts.rs b/integration-tests/tests/common/suite_contracts.rs new file mode 100644 index 000000000..640d9e3d3 --- /dev/null +++ b/integration-tests/tests/common/suite_contracts.rs @@ -0,0 +1,63 @@ +use cosmwasm_std::Empty; +use cw_multi_test::{Contract, ContractWrapper}; + +/// Creates the epoch manager contract +pub fn bonding_manager_contract() -> Box> { + let contract = ContractWrapper::new( + bonding_manager::contract::execute, + bonding_manager::contract::instantiate, + bonding_manager::contract::query, + ) + .with_reply(bonding_manager::contract::reply) + .with_migrate(bonding_manager::contract::migrate); + + Box::new(contract) +} + +/// Creates the epoch manager contract +pub fn epoch_manager_contract() -> Box> { + let contract = ContractWrapper::new( + epoch_manager::contract::execute, + epoch_manager::contract::instantiate, + epoch_manager::contract::query, + ) + .with_migrate(epoch_manager::contract::migrate); + + Box::new(contract) +} + +/// Creates the incentive manager contract +pub fn incentive_manager_contract() -> Box> { + let contract = ContractWrapper::new( + incentive_manager::contract::execute, + incentive_manager::contract::instantiate, + incentive_manager::contract::query, + ) + .with_migrate(incentive_manager::contract::migrate); + + Box::new(contract) +} + +/// Creates the pool manager contract +pub fn pool_manager_contract() -> Box> { + let contract = ContractWrapper::new( + pool_manager::contract::execute, + pool_manager::contract::instantiate, + pool_manager::contract::query, + ) + .with_reply(pool_manager::contract::reply) + .with_migrate(pool_manager::contract::migrate); + + Box::new(contract) +} +/// Creates the pool manager contract +pub fn vault_manager_contract() -> Box> { + let contract = ContractWrapper::new( + vault_manager::contract::execute, + vault_manager::contract::instantiate, + vault_manager::contract::query, + ) + .with_migrate(vault_manager::contract::migrate); + + Box::new(contract) +} diff --git a/integration-tests/tests/integration.rs b/integration-tests/tests/integration.rs new file mode 100644 index 000000000..a5961aa6b --- /dev/null +++ b/integration-tests/tests/integration.rs @@ -0,0 +1 @@ +mod common; From 343ee5abb62e1a1a3f72691c1cb121a7fc28d4b7 Mon Sep 17 00:00:00 2001 From: Kerber0x Date: Fri, 24 May 2024 11:59:30 +0100 Subject: [PATCH 02/19] chore: add actions for the contracts --- README.md | 10 + integration-tests/Cargo.toml | 9 + integration-tests/README.md | 7 + integration-tests/src/lib.rs | 14 - integration-tests/tests/common/suite.rs | 827 +++++++++++++++++++++++- 5 files changed, 843 insertions(+), 24 deletions(-) create mode 100644 integration-tests/README.md delete mode 100644 integration-tests/src/lib.rs diff --git a/README.md b/README.md index a2492fdfd..ea2a0619e 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,16 @@ on the Epoch Manager, as the rewards distribution is done based on epochs. The Epoch Manager is the contract that manages the epochs in the protocol. Its single responsibility is to create the epochs, which are used by the Incentive and Bonding Managers for distributing incentives and fees. +## Instantiation + +Based on the dependencies between the contracts, the instantiation of the contracts is as follows: + +- Epoch Manager +- Bonding Manager +- Incentive Manager +- Pool Manager +- Vault Manager + --- ## Deployed contracts diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index 53292a1b3..1fb5cd6e6 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -1,8 +1,17 @@ [package] name = "integration-tests" version = "0.1.0" +description = "e2e integration tests for the Migaloo project" edition.workspace = true + +[features] +default = ["osmosis_token_factory"] +injective = ["token_factory"] +token_factory = [] +osmosis = ["osmosis_token_factory"] +osmosis_token_factory = ["token_factory"] + [dependencies] bonding-manager.workspace = true epoch-manager.workspace = true diff --git a/integration-tests/README.md b/integration-tests/README.md new file mode 100644 index 000000000..f472ad3eb --- /dev/null +++ b/integration-tests/README.md @@ -0,0 +1,7 @@ +# Integration Tests crate + +This crate contains e2e integration tests for the Migaloo project. + +The intention is to make sure the system operates as intended by recreating real-world scenarios where all the components +of the project are working together in unison, where different actors (good and bad) interact with the system in different +ways, and where the components are under different loads. diff --git a/integration-tests/src/lib.rs b/integration-tests/src/lib.rs deleted file mode 100644 index 7d12d9af8..000000000 --- a/integration-tests/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -pub fn add(left: usize, right: usize) -> usize { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} diff --git a/integration-tests/tests/common/suite.rs b/integration-tests/tests/common/suite.rs index ce2ec61a2..cccb3a0ef 100644 --- a/integration-tests/tests/common/suite.rs +++ b/integration-tests/tests/common/suite.rs @@ -1,12 +1,31 @@ use cosmwasm_std::testing::MockStorage; -use cosmwasm_std::{coin, Addr, Coin, Decimal, Empty, StdResult, Timestamp, Uint64}; +use cosmwasm_std::{ + coin, Addr, Coin, CosmosMsg, Decimal, Empty, StdResult, Timestamp, Uint128, Uint64, +}; use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32}; use cw_multi_test::{ App, AppBuilder, AppResponse, BankKeeper, DistributionKeeper, Executor, FailingModule, GovFailingModule, IbcFailingModule, StakeKeeper, WasmKeeper, }; +use white_whale_std::bonding_manager::{ + BondedResponse, ClaimableRewardBucketsResponse, ExecuteMsg, GlobalIndex, QueryMsg, + RewardBucket, RewardsResponse, UnbondingResponse, WithdrawableResponse, +}; use white_whale_std::epoch_manager::epoch_manager::{Epoch, EpochConfig, EpochResponse}; +use white_whale_std::fee::PoolFee; +use white_whale_std::incentive_manager::{ + IncentiveAction, IncentivesBy, IncentivesResponse, LpWeightResponse, PositionAction, + PositionsResponse, +}; +use white_whale_std::pool_manager::{ + PoolInfoResponse, PoolType, ReverseSimulateSwapOperationsResponse, ReverseSimulationResponse, + SimulateSwapOperationsResponse, SimulationResponse, SwapOperation, SwapRoute, + SwapRoutesResponse, +}; +use white_whale_std::vault_manager::{ + FilterVaultBy, PaybackAssetResponse, ShareResponse, VaultsResponse, +}; use white_whale_testing::multi_test::stargate_mock::StargateMock; use crate::common::suite_contracts::{ @@ -69,6 +88,31 @@ impl TestingSuite { self } + + #[track_caller] + pub(crate) fn query_balance( + &mut self, + denom: String, + address: Addr, + result: impl Fn(Uint128), + ) -> &mut Self { + let balance_response = self.app.wrap().query_balance(address, denom.clone()); + result(balance_response.unwrap_or(coin(0, denom)).amount); + + self + } + + pub(crate) fn query_all_balances( + &mut self, + addr: String, + result: impl Fn(StdResult>), + ) -> &mut Self { + let balance_resp: StdResult> = self.app.wrap().query_all_balances(addr); + + result(balance_resp); + + self + } } /// Instantiate @@ -135,7 +179,6 @@ impl TestingSuite { let bonding_manager_id = self.app.store_code(bonding_manager_contract()); let epoch_manager_addr = self.epoch_manager_addr.to_string(); - // create whale lair let msg = white_whale_std::bonding_manager::InstantiateMsg { distribution_denom: "uwhale".to_string(), unbonding_period: 1u64, @@ -164,7 +207,6 @@ impl TestingSuite { fn create_epoch_manager(&mut self) { let epoch_manager_contract = self.app.store_code(epoch_manager_contract()); - // create epoch manager let msg = white_whale_std::epoch_manager::epoch_manager::InstantiateMsg { start_epoch: Epoch { id: 0, @@ -199,7 +241,6 @@ impl TestingSuite { let creator = self.creator().clone(); - // create epoch manager let msg = white_whale_std::incentive_manager::InstantiateMsg { owner: creator.to_string(), epoch_manager_addr, @@ -230,7 +271,6 @@ impl TestingSuite { let bonding_manager_addr = self.bonding_manager_addr.to_string(); let incentive_manager_addr = self.incentive_manager_addr.to_string(); - // create epoch manager let msg = white_whale_std::pool_manager::InstantiateMsg { bonding_manager_addr, incentive_manager_addr, @@ -257,7 +297,6 @@ impl TestingSuite { let creator = self.creator().clone(); let bonding_manager_addr = self.bonding_manager_addr.to_string(); - // create epoch manager let msg = white_whale_std::vault_manager::InstantiateMsg { owner: creator.to_string(), bonding_manager_addr, @@ -281,7 +320,200 @@ impl TestingSuite { //------------------------------------// /// bonding manager actions -impl TestingSuite {} +impl TestingSuite { + #[track_caller] + pub(crate) fn bond( + &mut self, + sender: Addr, + funds: &[Coin], + response: impl Fn(Result), + ) -> &mut Self { + let msg = ExecuteMsg::Bond; + + response( + self.app + .execute_contract(sender, self.bonding_manager_addr.clone(), &msg, funds), + ); + + self + } + + #[track_caller] + pub(crate) fn unbond( + &mut self, + sender: Addr, + asset: Coin, + response: impl Fn(Result), + ) -> &mut Self { + let msg = ExecuteMsg::Unbond { asset }; + + response( + self.app + .execute_contract(sender, self.bonding_manager_addr.clone(), &msg, &[]), + ); + + self + } + + #[track_caller] + pub(crate) fn claim_bonding_rewards( + &mut self, + sender: Addr, + response: impl Fn(Result), + ) -> &mut Self { + let msg = ExecuteMsg::Claim {}; + + response( + self.app + .execute_contract(sender, self.bonding_manager_addr.clone(), &msg, &[]), + ); + + self + } + + #[track_caller] + pub(crate) fn withdraw( + &mut self, + sender: Addr, + denom: String, + response: impl Fn(Result), + ) -> &mut Self { + let msg = ExecuteMsg::Withdraw { denom }; + + response( + self.app + .execute_contract(sender, self.bonding_manager_addr.clone(), &msg, &[]), + ); + + self + } + + #[track_caller] + pub(crate) fn query_global_index( + &mut self, + reward_bucket_id: Option, + response: impl Fn(StdResult<(&mut Self, GlobalIndex)>), + ) -> &mut Self { + let global_index: GlobalIndex = self + .app + .wrap() + .query_wasm_smart( + &self.bonding_manager_addr, + &QueryMsg::GlobalIndex { reward_bucket_id }, + ) + .unwrap(); + + response(Ok((self, global_index))); + + self + } + + #[track_caller] + pub(crate) fn query_claimable_reward_buckets( + &mut self, + address: Option, + response: impl Fn(StdResult<(&mut Self, Vec)>), + ) -> &mut Self { + let address = if let Some(address) = address { + Some(address.to_string()) + } else { + None + }; + + let query_res: ClaimableRewardBucketsResponse = self + .app + .wrap() + .query_wasm_smart(&self.bonding_manager_addr, &QueryMsg::Claimable { address }) + .unwrap(); + + response(Ok((self, query_res.reward_buckets))); + + self + } + + #[track_caller] + pub(crate) fn query_bonded( + &mut self, + address: Option, + response: impl Fn(StdResult<(&mut Self, BondedResponse)>), + ) -> &mut Self { + let bonded_response: BondedResponse = self + .app + .wrap() + .query_wasm_smart(&self.bonding_manager_addr, &QueryMsg::Bonded { address }) + .unwrap(); + + response(Ok((self, bonded_response))); + + self + } + + #[track_caller] + pub(crate) fn query_unbonding( + &mut self, + address: String, + denom: String, + start_after: Option, + limit: Option, + response: impl Fn(StdResult<(&mut Self, UnbondingResponse)>), + ) -> &mut Self { + let unbonding_response: UnbondingResponse = self + .app + .wrap() + .query_wasm_smart( + &self.bonding_manager_addr, + &QueryMsg::Unbonding { + address, + denom, + start_after, + limit, + }, + ) + .unwrap(); + + response(Ok((self, unbonding_response))); + + self + } + + #[track_caller] + pub(crate) fn query_withdrawable( + &mut self, + address: String, + denom: String, + response: impl Fn(StdResult<(&mut Self, WithdrawableResponse)>), + ) -> &mut Self { + let withdrawable_response: WithdrawableResponse = self + .app + .wrap() + .query_wasm_smart( + &self.bonding_manager_addr, + &QueryMsg::Withdrawable { address, denom }, + ) + .unwrap(); + + response(Ok((self, withdrawable_response))); + + self + } + + #[track_caller] + pub(crate) fn query_bonding_rewards( + &mut self, + address: String, + response: impl Fn(StdResult<(&mut Self, RewardsResponse)>), + ) -> &mut Self { + let rewards_response: RewardsResponse = self + .app + .wrap() + .query_wasm_smart(&self.bonding_manager_addr, &QueryMsg::Rewards { address }) + .unwrap(); + + response(Ok((self, rewards_response))); + + self + } +} //------------------------------------// @@ -374,14 +606,589 @@ impl TestingSuite { //------------------------------------// /// incentive manager actions -impl TestingSuite {} +impl TestingSuite { + #[track_caller] + pub(crate) fn manage_incentive( + &mut self, + sender: Addr, + action: IncentiveAction, + funds: Vec, + result: impl Fn(Result), + ) -> &mut Self { + let msg = white_whale_std::incentive_manager::ExecuteMsg::ManageIncentive { action }; + + result(self.app.execute_contract( + sender, + self.incentive_manager_addr.clone(), + &msg, + &funds, + )); + + self + } + + #[track_caller] + pub(crate) fn manage_position( + &mut self, + sender: Addr, + action: PositionAction, + funds: Vec, + result: impl Fn(Result), + ) -> &mut Self { + let msg = white_whale_std::incentive_manager::ExecuteMsg::ManagePosition { action }; + + result(self.app.execute_contract( + sender, + self.incentive_manager_addr.clone(), + &msg, + &funds, + )); + + self + } + + #[track_caller] + pub(crate) fn claim_incentive_rewards( + &mut self, + sender: Addr, + funds: Vec, + result: impl Fn(Result), + ) -> &mut Self { + let msg = white_whale_std::incentive_manager::ExecuteMsg::Claim; + + result(self.app.execute_contract( + sender, + self.incentive_manager_addr.clone(), + &msg, + &funds, + )); + + self + } + + #[track_caller] + pub(crate) fn query_incentives( + &mut self, + filter_by: Option, + start_after: Option, + limit: Option, + result: impl Fn(StdResult), + ) -> &mut Self { + let incentives_response: StdResult = self.app.wrap().query_wasm_smart( + &self.incentive_manager_addr, + &white_whale_std::incentive_manager::QueryMsg::Incentives { + filter_by, + start_after, + limit, + }, + ); + + result(incentives_response); + + self + } + + #[track_caller] + pub(crate) fn query_positions( + &mut self, + address: Addr, + open_state: Option, + result: impl Fn(StdResult), + ) -> &mut Self { + let positions_response: StdResult = self.app.wrap().query_wasm_smart( + &self.incentive_manager_addr, + &white_whale_std::incentive_manager::QueryMsg::Positions { + address: address.to_string(), + open_state, + }, + ); + + result(positions_response); + + self + } + #[track_caller] + pub(crate) fn query_incentive_rewards( + &mut self, + address: Addr, + result: impl Fn(StdResult), + ) -> &mut Self { + let rewards_response: StdResult = + self.app.wrap().query_wasm_smart( + &self.incentive_manager_addr, + &white_whale_std::incentive_manager::QueryMsg::Rewards { + address: address.to_string(), + }, + ); + + result(rewards_response); + + self + } + + #[track_caller] + pub(crate) fn query_lp_weight( + &mut self, + denom: &str, + epoch_id: u64, + result: impl Fn(StdResult), + ) -> &mut Self { + let rewards_response: StdResult = self.app.wrap().query_wasm_smart( + &self.incentive_manager_addr, + &white_whale_std::incentive_manager::QueryMsg::LPWeight { + address: self.incentive_manager_addr.to_string(), + denom: denom.to_string(), + epoch_id, + }, + ); + + result(rewards_response); + + self + } +} //------------------------------------// /// pool manager actions -impl TestingSuite {} +impl TestingSuite { + #[track_caller] + pub(crate) fn provide_liquidity( + &mut self, + sender: Addr, + pool_identifier: String, + unlocking_duration: Option, + lock_position_identifier: Option, + max_spread: Option, + receiver: Option, + funds: Vec, + result: impl Fn(Result), + ) -> &mut Self { + let msg = white_whale_std::pool_manager::ExecuteMsg::ProvideLiquidity { + pool_identifier, + slippage_tolerance: None, + max_spread, + receiver, + unlocking_duration, + lock_position_identifier, + }; + + result( + self.app + .execute_contract(sender, self.pool_manager_addr.clone(), &msg, &funds), + ); + + self + } + + #[track_caller] + #[allow(clippy::too_many_arguments)] + pub(crate) fn swap( + &mut self, + sender: Addr, + ask_asset_denom: String, + belief_price: Option, + max_spread: Option, + receiver: Option, + pool_identifier: String, + funds: Vec, + result: impl Fn(Result), + ) -> &mut Self { + let msg = white_whale_std::pool_manager::ExecuteMsg::Swap { + ask_asset_denom, + belief_price, + max_spread, + receiver, + pool_identifier, + }; + + result( + self.app + .execute_contract(sender, self.pool_manager_addr.clone(), &msg, &funds), + ); + + self + } + + #[track_caller] + #[allow(clippy::too_many_arguments)] + pub(crate) fn execute_swap_operations( + &mut self, + sender: Addr, + operations: Vec, + minimum_receive: Option, + receiver: Option, + max_spread: Option, + funds: Vec, + result: impl Fn(Result), + ) -> &mut Self { + let msg = white_whale_std::pool_manager::ExecuteMsg::ExecuteSwapOperations { + operations, + minimum_receive, + receiver, + max_spread, + }; + + result( + self.app + .execute_contract(sender, self.pool_manager_addr.clone(), &msg, &funds), + ); + + self + } + + #[track_caller] + #[allow(clippy::too_many_arguments)] + pub(crate) fn create_pool( + &mut self, + sender: Addr, + asset_denoms: Vec, + asset_decimals: Vec, + pool_fees: PoolFee, + pool_type: PoolType, + pool_identifier: Option, + pool_creation_fee_funds: Vec, + result: impl Fn(Result), + ) -> &mut Self { + let msg = white_whale_std::pool_manager::ExecuteMsg::CreatePool { + asset_denoms, + asset_decimals, + pool_fees, + pool_type, + pool_identifier, + }; + + result(self.app.execute_contract( + sender, + self.pool_manager_addr.clone(), + &msg, + &pool_creation_fee_funds, + )); + + self + } + + #[track_caller] + pub(crate) fn withdraw_liquidity( + &mut self, + sender: Addr, + pool_identifier: String, + funds: Vec, + result: impl Fn(Result), + ) -> &mut Self { + let msg = white_whale_std::pool_manager::ExecuteMsg::WithdrawLiquidity { pool_identifier }; + + result( + self.app + .execute_contract(sender, self.pool_manager_addr.clone(), &msg, &funds), + ); + + self + } + + /// Adds swap routes to the pool manager contract. + #[track_caller] + pub(crate) fn add_swap_routes( + &mut self, + sender: Addr, + swap_routes: Vec, + result: impl Fn(Result), + ) -> &mut Self { + result(self.app.execute_contract( + sender, + self.pool_manager_addr.clone(), + &white_whale_std::pool_manager::ExecuteMsg::AddSwapRoutes { swap_routes }, + &[], + )); + + self + } + + /// Removes swap routes from the pool manager contract. + #[track_caller] + pub(crate) fn remove_swap_routes( + &mut self, + sender: Addr, + swap_routes: Vec, + result: impl Fn(Result), + ) -> &mut Self { + result(self.app.execute_contract( + sender, + self.pool_manager_addr.clone(), + &white_whale_std::pool_manager::ExecuteMsg::RemoveSwapRoutes { swap_routes }, + &[], + )); + + self + } + + pub(crate) fn query_pool_info( + &self, + pool_identifier: String, + result: impl Fn(StdResult), + ) -> &Self { + let pool_info_response: StdResult = self.app.wrap().query_wasm_smart( + &self.pool_manager_addr, + &white_whale_std::pool_manager::QueryMsg::Pool { pool_identifier }, + ); + + result(pool_info_response); + + self + } + + pub(crate) fn query_simulation( + &mut self, + pool_identifier: String, + offer_asset: Coin, + ask_asset_denom: String, + result: impl Fn(StdResult), + ) -> &mut Self { + let pool_info_response: StdResult = self.app.wrap().query_wasm_smart( + &self.pool_manager_addr, + &white_whale_std::pool_manager::QueryMsg::Simulation { + offer_asset, + ask_asset_denom, + pool_identifier, + }, + ); + + result(pool_info_response); + + self + } + + pub(crate) fn query_reverse_simulation( + &mut self, + pool_identifier: String, + ask_asset: Coin, + offer_asset_denom: String, + result: impl Fn(StdResult), + ) -> &mut Self { + let pool_info_response: StdResult = + self.app.wrap().query_wasm_smart( + &self.pool_manager_addr, + &white_whale_std::pool_manager::QueryMsg::ReverseSimulation { + ask_asset, + offer_asset_denom, + pool_identifier, + }, + ); + + result(pool_info_response); + + self + } + + pub(crate) fn query_simulate_swap_operations( + &mut self, + offer_amount: Uint128, + operations: Vec, + result: impl Fn(StdResult), + ) -> &mut Self { + let pool_info_response: StdResult = + self.app.wrap().query_wasm_smart( + &self.pool_manager_addr, + &white_whale_std::pool_manager::QueryMsg::SimulateSwapOperations { + offer_amount, + operations, + }, + ); + + result(pool_info_response); + + self + } + + pub(crate) fn query_reverse_simulate_swap_operations( + &mut self, + ask_amount: Uint128, + operations: Vec, + result: impl Fn(StdResult), + ) -> &mut Self { + let pool_info_response: StdResult = + self.app.wrap().query_wasm_smart( + &self.pool_manager_addr, + &white_whale_std::pool_manager::QueryMsg::ReverseSimulateSwapOperations { + ask_amount, + operations, + }, + ); + + result(pool_info_response); + + self + } + + /// Retrieves the swap routes for a given pool of assets. + pub(crate) fn query_swap_routes( + &mut self, + result: impl Fn(StdResult), + ) -> &mut Self { + let swap_routes_response: StdResult = self.app.wrap().query_wasm_smart( + &self.pool_manager_addr, + &white_whale_std::pool_manager::QueryMsg::SwapRoutes, + ); + + result(swap_routes_response); + + self + } +} //------------------------------------// /// vault manager actions -impl TestingSuite {} +impl TestingSuite { + #[track_caller] + pub(crate) fn create_vault( + &mut self, + sender: Addr, + asset_denom: String, + vault_identifier: Option, + fees: white_whale_std::vault_manager::VaultFee, + funds: Vec, + result: impl Fn(Result), + ) -> &mut Self { + let msg = white_whale_std::vault_manager::ExecuteMsg::CreateVault { + asset_denom, + fees, + vault_identifier, + }; + + result( + self.app + .execute_contract(sender, self.vault_manager_addr.clone(), &msg, &funds), + ); + + self + } + + #[track_caller] + pub(crate) fn vault_deposit( + &mut self, + sender: Addr, + vault_identifier: String, + funds: Vec, + result: impl Fn(Result), + ) -> &mut Self { + let msg = white_whale_std::vault_manager::ExecuteMsg::Deposit { vault_identifier }; + + result( + self.app + .execute_contract(sender, self.vault_manager_addr.clone(), &msg, &funds), + ); + + self + } + + #[track_caller] + pub(crate) fn vault_withdraw( + &mut self, + sender: Addr, + funds: Vec, + result: impl Fn(Result), + ) -> &mut Self { + let msg = white_whale_std::vault_manager::ExecuteMsg::Withdraw {}; + let vault_manager = self.vault_manager_addr.clone(); + + result( + self.app + .execute_contract(sender, vault_manager, &msg, &funds), + ); + + self + } + + #[track_caller] + pub(crate) fn flashloan( + &mut self, + sender: Addr, + asset: Coin, + vault_identifier: String, + payload: Vec, + result: impl Fn(Result), + ) -> &mut Self { + let msg = white_whale_std::vault_manager::ExecuteMsg::FlashLoan { + asset, + vault_identifier, + payload, + }; + + result( + self.app + .execute_contract(sender, self.vault_manager_addr.clone(), &msg, &[]), + ); + + self + } + + #[track_caller] + pub(crate) fn query_vault( + &mut self, + filter_by: FilterVaultBy, + result: impl Fn(StdResult), + ) -> &mut Self { + let vaults_response: StdResult = self.app.wrap().query_wasm_smart( + &self.vault_manager_addr, + &white_whale_std::vault_manager::QueryMsg::Vault { filter_by }, + ); + + result(vaults_response); + + self + } + + #[track_caller] + pub(crate) fn query_vaults( + &mut self, + start_after: Option>, + limit: Option, + result: impl Fn(StdResult), + ) -> &mut Self { + let vaults_response: StdResult = self.app.wrap().query_wasm_smart( + &self.vault_manager_addr, + &white_whale_std::vault_manager::QueryMsg::Vaults { start_after, limit }, + ); + + result(vaults_response); + + self + } + + #[track_caller] + pub(crate) fn query_vault_share( + &mut self, + lp_share: Coin, + result: impl Fn(StdResult), + ) -> &mut Self { + let response: StdResult = self.app.wrap().query_wasm_smart( + &self.vault_manager_addr, + &white_whale_std::vault_manager::QueryMsg::Share { lp_share }, + ); + + result(response); + + self + } + + #[track_caller] + pub(crate) fn query_flashloan_payback( + &mut self, + asset: Coin, + vault_identifier: String, + result: impl Fn(StdResult), + ) -> &mut Self { + let response: StdResult = self.app.wrap().query_wasm_smart( + &self.vault_manager_addr, + &white_whale_std::vault_manager::QueryMsg::PaybackAmount { + asset, + vault_identifier, + }, + ); + + result(response); + + self + } +} From 52fbfd11eef9aa72ec430fdd32d56d04588621b4 Mon Sep 17 00:00:00 2001 From: Kerber0x Date: Fri, 24 May 2024 12:54:27 +0100 Subject: [PATCH 03/19] test(tests-crate): add methods to create pools and vaults --- integration-tests/tests/common/helpers.rs | 349 ++++++++++++++++++++++ integration-tests/tests/common/mod.rs | 1 + integration-tests/tests/common/suite.rs | 8 +- integration-tests/tests/integration.rs | 50 ++++ packages/white-whale-std/src/fee.rs | 1 + 5 files changed, 405 insertions(+), 4 deletions(-) create mode 100644 integration-tests/tests/common/helpers.rs diff --git a/integration-tests/tests/common/helpers.rs b/integration-tests/tests/common/helpers.rs new file mode 100644 index 000000000..5d1180509 --- /dev/null +++ b/integration-tests/tests/common/helpers.rs @@ -0,0 +1,349 @@ +pub mod fees { + use cosmwasm_std::Decimal; + + use white_whale_std::fee::{Fee, PoolFee}; + use white_whale_std::vault_manager::VaultFee; + + pub(crate) fn pool_fees_0() -> PoolFee { + { + #[cfg(feature = "osmosis")] + { + PoolFee { + burn_fee: Fee { + share: Decimal::zero(), + }, + protocol_fee: Fee { + share: Decimal::zero(), + }, + swap_fee: Fee { + share: Decimal::zero(), + }, + extra_fees: vec![], + osmosis_fee: Fee { + share: Decimal::zero(), + }, + } + } + + #[cfg(not(feature = "osmosis"))] + { + PoolFee { + burn_fee: Fee { + share: Decimal::zero(), + }, + protocol_fee: Fee { + share: Decimal::zero(), + }, + swap_fee: Fee { + share: Decimal::zero(), + }, + extra_fees: vec![], + } + } + } + } + + pub(crate) fn pool_fees_005() -> PoolFee { + { + #[cfg(feature = "osmosis")] + { + PoolFee { + burn_fee: Fee { + share: Decimal::zero(), + }, + protocol_fee: Fee { + share: Decimal::from_ratio(3u128, 10000u128), + }, + swap_fee: Fee { + share: Decimal::from_ratio(1u128, 10000u128), + }, + extra_fees: vec![], + osmosis_fee: Fee { + share: Decimal::from_ratio(1u128, 10000u128), + }, + } + } + + #[cfg(not(feature = "osmosis"))] + { + PoolFee { + burn_fee: Fee { + share: Decimal::zero(), + }, + protocol_fee: Fee { + share: Decimal::from_ratio(3u128, 10000u128), + }, + swap_fee: Fee { + share: Decimal::from_ratio(2u128, 10000u128), + }, + extra_fees: vec![], + } + } + } + } + + pub(crate) fn pool_fees_03() -> PoolFee { + { + #[cfg(feature = "osmosis")] + { + PoolFee { + burn_fee: Fee { + share: Decimal::zero(), + }, + protocol_fee: Fee { + share: Decimal::permille(1), + }, + swap_fee: Fee { + share: Decimal::permille(1), + }, + extra_fees: vec![], + osmosis_fee: Fee { + share: Decimal::permille(1), + }, + } + } + + #[cfg(not(feature = "osmosis"))] + { + PoolFee { + burn_fee: Fee { + share: Decimal::zero(), + }, + protocol_fee: Fee { + share: Decimal::permille(1), + }, + swap_fee: Fee { + share: Decimal::permille(2), + }, + extra_fees: vec![], + } + } + } + } + + pub(crate) fn pool_fees_1() -> PoolFee { + { + #[cfg(feature = "osmosis")] + { + PoolFee { + burn_fee: Fee { + share: Decimal::permille(3), + }, + protocol_fee: Fee { + share: Decimal::permille(3), + }, + swap_fee: Fee { + share: Decimal::permille(3), + }, + extra_fees: vec![], + osmosis_fee: Fee { + share: Decimal::permille(1), + }, + } + } + + #[cfg(not(feature = "osmosis"))] + { + PoolFee { + burn_fee: Fee { + share: Decimal::permille(3), + }, + protocol_fee: Fee { + share: Decimal::permille(3), + }, + swap_fee: Fee { + share: Decimal::permille(4), + }, + extra_fees: vec![], + } + } + } + } + + pub(crate) fn vault_fees_0() -> VaultFee { + VaultFee { + protocol_fee: Fee { + share: Default::default(), + }, + flash_loan_fee: Fee { + share: Default::default(), + }, + } + } + + pub(crate) fn vault_fees_03() -> VaultFee { + VaultFee { + protocol_fee: Fee { + share: Decimal::permille(1), + }, + flash_loan_fee: Fee { + share: Decimal::permille(2), + }, + } + } +} + +pub mod pools { + use crate::common::helpers; + use crate::common::suite::TestingSuite; + use cosmwasm_std::{coin, Addr}; + use white_whale_std::pool_manager::PoolType; + + /// Creates multiple pools + pub(crate) fn create_pools(suite: &mut TestingSuite, sender: Addr) { + suite + .create_pool( + sender.clone(), + vec!["uwhale", "uusdc"], + vec![6, 6], + helpers::fees::pool_fees_0(), + PoolType::ConstantProduct, + Some("uwhale-usdc-free".to_string()), + vec![coin(1_000u128, "uwhale")], + |result| { + result.unwrap(); + }, + ) + .create_pool( + sender.clone(), + vec!["uwhale", "uusdc"], + vec![6, 6], + helpers::fees::pool_fees_03(), + PoolType::ConstantProduct, + Some("uwhale-usdc-cheap".to_string()), + vec![coin(1_000u128, "uwhale")], + |result| { + result.unwrap(); + }, + ) + .create_pool( + sender.clone(), + vec!["uwhale", "uusdc"], + vec![6, 6], + helpers::fees::pool_fees_1(), + PoolType::ConstantProduct, + Some("uwhale-usdc-expensive".to_string()), + vec![coin(1_000u128, "uwhale")], + |result| { + result.unwrap(); + }, + ) + .create_pool( + sender.clone(), + vec!["uwhale", "uosmo"], + vec![6, 6], + helpers::fees::pool_fees_03(), + PoolType::ConstantProduct, + Some("uwhale-uosmo-cheap".to_string()), + vec![coin(1_000u128, "uwhale")], + |result| { + result.unwrap(); + }, + ) + .create_pool( + sender.clone(), + vec![ + "uusdc", + "uusdt", + "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", + ], + vec![6, 6, 6], + helpers::fees::pool_fees_005(), + PoolType::StableSwap { amp: 85u64 }, + Some("3pool-stable".to_string()), + vec![coin(1_000u128, "uwhale")], + |result| { + result.unwrap(); + }, + ) + .create_pool( + sender.clone(), + vec!["uusdc", "uusdt"], + vec![6, 6], + helpers::fees::pool_fees_005(), + PoolType::StableSwap { amp: 85u64 }, + Some("2pool-stable".to_string()), + vec![coin(1_000u128, "uwhale")], + |result| { + result.unwrap(); + }, + ) + .create_pool( + sender.clone(), + vec!["uwhale", "inj"], + vec![6, 18], + helpers::fees::pool_fees_03(), + PoolType::ConstantProduct, + Some("uwhale-inj".to_string()), + vec![coin(1_000u128, "uwhale")], + |result| { + result.unwrap(); + }, + ) + .create_pool( + sender.clone(), + vec!["uwhale", "btc"], + vec![6, 8], + helpers::fees::pool_fees_03(), + PoolType::ConstantProduct, + Some("uwhale-btc".to_string()), + vec![coin(1_000u128, "uwhale")], + |result| { + result.unwrap(); + }, + ) + .create_pool( + sender.clone(), + vec!["peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "uusdc"], + vec![6, 6], + helpers::fees::pool_fees_03(), + PoolType::ConstantProduct, + Some("peggy-uusdc".to_string()), + vec![coin(1_000u128, "uwhale")], + |result| { + result.unwrap(); + }, + ); + } +} + +pub mod vaults { + use crate::common::helpers; + use crate::common::suite::TestingSuite; + use cosmwasm_std::{coin, Addr}; + + /// Creates multiple vaults + pub(crate) fn create_vaults(suite: &mut TestingSuite, sender: Addr) { + suite + .create_vault( + sender.clone(), + "uwhale", + Some("uwhale-free".to_string()), + helpers::fees::vault_fees_0(), + vec![coin(1_000u128, "uwhale")], + |result| { + result.unwrap(); + }, + ) + .create_vault( + sender.clone(), + "uwhale", + Some("whale-cheap".to_string()), + helpers::fees::vault_fees_03(), + vec![coin(1_000u128, "uwhale")], + |result| { + result.unwrap(); + }, + ) + .create_vault( + sender.clone(), + "uusdc", + Some("uusdc-vault".to_string()), + helpers::fees::vault_fees_03(), + vec![coin(1_000u128, "uwhale")], + |result| { + result.unwrap(); + }, + ); + } +} diff --git a/integration-tests/tests/common/mod.rs b/integration-tests/tests/common/mod.rs index eb37e5585..16c9ded50 100644 --- a/integration-tests/tests/common/mod.rs +++ b/integration-tests/tests/common/mod.rs @@ -1,2 +1,3 @@ +pub mod helpers; pub mod suite; mod suite_contracts; diff --git a/integration-tests/tests/common/suite.rs b/integration-tests/tests/common/suite.rs index cccb3a0ef..94390c320 100644 --- a/integration-tests/tests/common/suite.rs +++ b/integration-tests/tests/common/suite.rs @@ -842,7 +842,7 @@ impl TestingSuite { pub(crate) fn create_pool( &mut self, sender: Addr, - asset_denoms: Vec, + asset_denoms: Vec<&str>, asset_decimals: Vec, pool_fees: PoolFee, pool_type: PoolType, @@ -851,7 +851,7 @@ impl TestingSuite { result: impl Fn(Result), ) -> &mut Self { let msg = white_whale_std::pool_manager::ExecuteMsg::CreatePool { - asset_denoms, + asset_denoms: asset_denoms.iter().map(|&s| s.to_string()).collect(), asset_decimals, pool_fees, pool_type, @@ -1044,14 +1044,14 @@ impl TestingSuite { pub(crate) fn create_vault( &mut self, sender: Addr, - asset_denom: String, + asset_denom: &str, vault_identifier: Option, fees: white_whale_std::vault_manager::VaultFee, funds: Vec, result: impl Fn(Result), ) -> &mut Self { let msg = white_whale_std::vault_manager::ExecuteMsg::CreateVault { - asset_denom, + asset_denom: asset_denom.to_string(), fees, vault_identifier, }; diff --git a/integration-tests/tests/integration.rs b/integration-tests/tests/integration.rs index a5961aa6b..c95a6a029 100644 --- a/integration-tests/tests/integration.rs +++ b/integration-tests/tests/integration.rs @@ -1 +1,51 @@ +use cosmwasm_std::coin; + +use white_whale_std::pool_manager::PoolType; + +use crate::common::helpers; +use crate::common::suite::TestingSuite; + mod common; + +#[test] +fn epic_test() { + let mut suite = TestingSuite::default_with_balances(vec![ + coin(1_000_000_000_000u128, "uwhale"), + coin(1_000_000_000_000u128, "uosmo"), + coin(1_000_000_000_000u128, "uusdc"), + coin(1_000_000_000_000u128, "uusdt"), + // ibc token is stablecoin + coin( + 1_000_000_000_000u128, + "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", + ), + coin( + 1_000_000_000_000u128, + "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", + ), + coin( + 1_000_000_000_000u128, + "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", + ), + coin( + 1_000_000_000_000u128, + "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + ), + coin(1_000_000_000_000_000u128, "btc"), + coin(1_000_000_000_000_000_000_000_000u128, "inj"), + ]); + + suite.instantiate(); + + let [alice, bob, carol, dave, sybil] = [ + suite.senders[0].clone(), + suite.senders[1].clone(), + suite.senders[2].clone(), + suite.senders[3].clone(), + suite.senders[4].clone(), + ]; + + // create some pools + helpers::pools::create_pools(&mut suite, alice.clone()); + helpers::vaults::create_vaults(&mut suite, bob.clone()); +} diff --git a/packages/white-whale-std/src/fee.rs b/packages/white-whale-std/src/fee.rs index 203f4b695..4be617cab 100644 --- a/packages/white-whale-std/src/fee.rs +++ b/packages/white-whale-std/src/fee.rs @@ -62,6 +62,7 @@ impl VaultFee { } } +//todo to move into pool_manager.rs ? /// Represents the fee structure for transactions within a pool. /// /// From 506557f092aedf845d52085c6c5ab3c1ac32f421 Mon Sep 17 00:00:00 2001 From: Kerber0x Date: Fri, 24 May 2024 14:33:21 +0100 Subject: [PATCH 04/19] chore: replace Pool query for Pools(with pagination) in pool manager --- Cargo.lock | 2 + .../pool-manager/schema/pool-manager.json | 92 ++- .../pool-manager/schema/raw/query.json | 31 +- .../schema/raw/response_to_pools.json | 226 +++++++ integration-tests/Cargo.toml | 4 + integration-tests/tests/common/helpers.rs | 426 +++++++++++++- integration-tests/tests/common/suite.rs | 193 ++++-- integration-tests/tests/integration.rs | 553 +++++++++++++++++- packages/white-whale-std/src/pool_manager.rs | 2 +- 9 files changed, 1407 insertions(+), 122 deletions(-) create mode 100644 contracts/liquidity_hub/pool-manager/schema/raw/response_to_pools.json diff --git a/Cargo.lock b/Cargo.lock index 0c4cd35bc..550f53ea6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -800,6 +800,8 @@ dependencies = [ "epoch-manager", "incentive-manager", "pool-manager", + "proptest", + "rand", "vault-manager", "white-whale-std", "white-whale-testing", diff --git a/contracts/liquidity_hub/pool-manager/schema/pool-manager.json b/contracts/liquidity_hub/pool-manager/schema/pool-manager.json index a9bc00d77..157b38c8f 100644 --- a/contracts/liquidity_hub/pool-manager/schema/pool-manager.json +++ b/contracts/liquidity_hub/pool-manager/schema/pool-manager.json @@ -965,20 +965,37 @@ "additionalProperties": false }, { - "description": "Retrieves the pool information for the given pool identifier.", + "description": "Retrieves the pools information.", "type": "object", "required": [ - "pool" + "pools" ], "properties": { - "pool": { + "pools": { "type": "object", - "required": [ - "pool_identifier" - ], "properties": { + "limit": { + "description": "An optional parameter specifying the maximum number of pools to return.", + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + }, "pool_identifier": { - "type": "string" + "description": "If provided, the query will return the pool with the given identifier, otherwise, it will return all pools.", + "type": [ + "string", + "null" + ] + }, + "start_after": { + "description": "An optional parameter specifying what pool identifier to start searching after.", + "type": [ + "string", + "null" + ] } }, "additionalProperties": false @@ -1329,31 +1346,21 @@ } } }, - "pool": { + "pools": { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "PoolInfoResponse", - "description": "The response for the `Pool` query.", + "title": "PoolsResponse", + "description": "The response for the `Pools` query.", "type": "object", "required": [ - "pool_info", - "total_share" + "pools" ], "properties": { - "pool_info": { - "description": "The pool information for the given pool identifier.", - "allOf": [ - { - "$ref": "#/definitions/PoolInfo" - } - ] - }, - "total_share": { - "description": "The total LP tokens in the pool.", - "allOf": [ - { - "$ref": "#/definitions/Coin" - } - ] + "pools": { + "description": "The pools on the contract.", + "type": "array", + "items": { + "$ref": "#/definitions/PoolInfoResponse" + } } }, "additionalProperties": false, @@ -1440,6 +1447,7 @@ "asset_decimals", "asset_denoms", "assets", + "identifier", "lp_denom", "pool_fees", "pool_type" @@ -1468,6 +1476,9 @@ "$ref": "#/definitions/Coin" } }, + "identifier": { + "type": "string" + }, "lp_denom": { "description": "The LP denom of the pool.", "type": "string" @@ -1491,6 +1502,33 @@ }, "additionalProperties": false }, + "PoolInfoResponse": { + "description": "The response for the `Pool` query.", + "type": "object", + "required": [ + "pool_info", + "total_share" + ], + "properties": { + "pool_info": { + "description": "The pool information for the given pool identifier.", + "allOf": [ + { + "$ref": "#/definitions/PoolInfo" + } + ] + }, + "total_share": { + "description": "The total LP tokens in the pool.", + "allOf": [ + { + "$ref": "#/definitions/Coin" + } + ] + } + }, + "additionalProperties": false + }, "PoolType": { "description": "Possible pool types, it can be either a constant product (xyk) pool or a stable swap pool.", "oneOf": [ diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/query.json b/contracts/liquidity_hub/pool-manager/schema/raw/query.json index ec6ac2fe0..e750cc462 100644 --- a/contracts/liquidity_hub/pool-manager/schema/raw/query.json +++ b/contracts/liquidity_hub/pool-manager/schema/raw/query.json @@ -217,20 +217,37 @@ "additionalProperties": false }, { - "description": "Retrieves the pool information for the given pool identifier.", + "description": "Retrieves the pools information.", "type": "object", "required": [ - "pool" + "pools" ], "properties": { - "pool": { + "pools": { "type": "object", - "required": [ - "pool_identifier" - ], "properties": { + "limit": { + "description": "An optional parameter specifying the maximum number of pools to return.", + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + }, "pool_identifier": { - "type": "string" + "description": "If provided, the query will return the pool with the given identifier, otherwise, it will return all pools.", + "type": [ + "string", + "null" + ] + }, + "start_after": { + "description": "An optional parameter specifying what pool identifier to start searching after.", + "type": [ + "string", + "null" + ] } }, "additionalProperties": false diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_pools.json b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_pools.json new file mode 100644 index 000000000..32fdddf62 --- /dev/null +++ b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_pools.json @@ -0,0 +1,226 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "PoolsResponse", + "description": "The response for the `Pools` query.", + "type": "object", + "required": [ + "pools" + ], + "properties": { + "pools": { + "description": "The pools on the contract.", + "type": "array", + "items": { + "$ref": "#/definitions/PoolInfoResponse" + } + } + }, + "additionalProperties": false, + "definitions": { + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, + "Decimal": { + "description": "A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0\n\nThe greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)", + "type": "string" + }, + "Fee": { + "type": "object", + "required": [ + "share" + ], + "properties": { + "share": { + "$ref": "#/definitions/Decimal" + } + }, + "additionalProperties": false + }, + "PoolFee": { + "description": "Represents the fee structure for transactions within a pool.\n\n# Fields - `protocol_fee`: The fee percentage charged by the protocol on each transaction to support operational and developmental needs. - `swap_fee`: The fee percentage allocated to liquidity providers as a reward for supplying liquidity to the pool, incentivizing participation and ensuring pool health. - `burn_fee`: A fee percentage that is burned on each transaction, helping manage the token economy by reducing supply over time, potentially increasing token value. - `osmosis_fee` (optional): Specific to the Osmosis feature, this fee is charged on each transaction when the Osmosis feature is enabled, supporting specific ecosystem requirements. - `extra_fees`: A vector of custom fees allowing for extensible and adaptable fee structures to meet diverse and evolving needs. Validation ensures that the total of all fees does not exceed 100%, maintaining fairness and avoiding overcharging.\n\n# Features - `osmosis`: Enables the `osmosis_fee` field, integrating specific fee requirements for the Osmosis protocol within the pool's fee structure.", + "type": "object", + "required": [ + "burn_fee", + "extra_fees", + "protocol_fee", + "swap_fee" + ], + "properties": { + "burn_fee": { + "description": "Fee percentage that is burned on each transaction. Burning a portion of the transaction fee helps in reducing the overall token supply.", + "allOf": [ + { + "$ref": "#/definitions/Fee" + } + ] + }, + "extra_fees": { + "description": "A list of custom, additional fees that can be defined for specific use cases or additional functionalities. This vector enables the flexibility to introduce new fees without altering the core fee structure. Total of all fees, including custom ones, is validated to not exceed 100%, ensuring a balanced and fair fee distribution.", + "type": "array", + "items": { + "$ref": "#/definitions/Fee" + } + }, + "protocol_fee": { + "description": "Fee percentage charged on each transaction for the protocol's benefit.", + "allOf": [ + { + "$ref": "#/definitions/Fee" + } + ] + }, + "swap_fee": { + "description": "Fee percentage allocated to liquidity providers on each swap.", + "allOf": [ + { + "$ref": "#/definitions/Fee" + } + ] + } + }, + "additionalProperties": false + }, + "PoolInfo": { + "description": "Contains the pool information", + "type": "object", + "required": [ + "asset_decimals", + "asset_denoms", + "assets", + "identifier", + "lp_denom", + "pool_fees", + "pool_type" + ], + "properties": { + "asset_decimals": { + "description": "The decimals for the given asset denoms, provided in the same order as asset_denoms.", + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + }, + "asset_denoms": { + "description": "The asset denoms for the pool.", + "type": "array", + "items": { + "type": "string" + } + }, + "assets": { + "description": "The total amount of assets in the pool.", + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "identifier": { + "type": "string" + }, + "lp_denom": { + "description": "The LP denom of the pool.", + "type": "string" + }, + "pool_fees": { + "description": "The fees for the pool.", + "allOf": [ + { + "$ref": "#/definitions/PoolFee" + } + ] + }, + "pool_type": { + "description": "The type of pool to create.", + "allOf": [ + { + "$ref": "#/definitions/PoolType" + } + ] + } + }, + "additionalProperties": false + }, + "PoolInfoResponse": { + "description": "The response for the `Pool` query.", + "type": "object", + "required": [ + "pool_info", + "total_share" + ], + "properties": { + "pool_info": { + "description": "The pool information for the given pool identifier.", + "allOf": [ + { + "$ref": "#/definitions/PoolInfo" + } + ] + }, + "total_share": { + "description": "The total LP tokens in the pool.", + "allOf": [ + { + "$ref": "#/definitions/Coin" + } + ] + } + }, + "additionalProperties": false + }, + "PoolType": { + "description": "Possible pool types, it can be either a constant product (xyk) pool or a stable swap pool.", + "oneOf": [ + { + "description": "A stable swap pool.", + "type": "object", + "required": [ + "stable_swap" + ], + "properties": { + "stable_swap": { + "type": "object", + "required": [ + "amp" + ], + "properties": { + "amp": { + "description": "The amount of amplification to perform on the constant product part of the swap formula.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "xyk pool", + "type": "string", + "enum": [ + "constant_product" + ] + } + ] + }, + "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" + } + } +} diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index 1fb5cd6e6..41ec182f0 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -24,3 +24,7 @@ white-whale-std.workspace = true white-whale-testing.workspace = true cosmwasm-std.workspace = true cw-ownable.workspace = true + +[dev-dependencies] +proptest = "1.4" +rand = "0.8" diff --git a/integration-tests/tests/common/helpers.rs b/integration-tests/tests/common/helpers.rs index 5d1180509..d13c1b06c 100644 --- a/integration-tests/tests/common/helpers.rs +++ b/integration-tests/tests/common/helpers.rs @@ -184,10 +184,14 @@ pub mod fees { } pub mod pools { + use std::cell::RefCell; + + use cosmwasm_std::{coin, Addr}; + + use white_whale_std::pool_manager::{PoolType, SwapOperation, SwapRoute}; + use crate::common::helpers; use crate::common::suite::TestingSuite; - use cosmwasm_std::{coin, Addr}; - use white_whale_std::pool_manager::PoolType; /// Creates multiple pools pub(crate) fn create_pools(suite: &mut TestingSuite, sender: Addr) { @@ -198,7 +202,7 @@ pub mod pools { vec![6, 6], helpers::fees::pool_fees_0(), PoolType::ConstantProduct, - Some("uwhale-usdc-free".to_string()), + Some("uwhale-uusdc-free".to_string()), vec![coin(1_000u128, "uwhale")], |result| { result.unwrap(); @@ -210,7 +214,7 @@ pub mod pools { vec![6, 6], helpers::fees::pool_fees_03(), PoolType::ConstantProduct, - Some("uwhale-usdc-cheap".to_string()), + Some("uwhale-uusdc-cheap".to_string()), vec![coin(1_000u128, "uwhale")], |result| { result.unwrap(); @@ -222,7 +226,7 @@ pub mod pools { vec![6, 6], helpers::fees::pool_fees_1(), PoolType::ConstantProduct, - Some("uwhale-usdc-expensive".to_string()), + Some("uwhale-uusdc-expensive".to_string()), vec![coin(1_000u128, "uwhale")], |result| { result.unwrap(); @@ -262,7 +266,7 @@ pub mod pools { vec![6, 6], helpers::fees::pool_fees_005(), PoolType::StableSwap { amp: 85u64 }, - Some("2pool-stable".to_string()), + Some("uusdc-uusdt".to_string()), vec![coin(1_000u128, "uwhale")], |result| { result.unwrap(); @@ -304,13 +308,262 @@ pub mod pools { result.unwrap(); }, ); + + // add liquidity + suite + .provide_liquidity( + &sender, + "uwhale-uusdc-free".to_string(), + None, + None, + None, + None, + vec![coin(100_000_000, "uwhale"), coin(100_000_000, "uusdc")], + |result| { + result.unwrap(); + }, + ) + .provide_liquidity( + &sender, + "uwhale-uusdc-cheap".to_string(), + None, + None, + None, + None, + vec![coin(100_000_000, "uwhale"), coin(100_000_000, "uusdc")], + |result| { + result.unwrap(); + }, + ) + .provide_liquidity( + &sender, + "uwhale-uusdc-expensive".to_string(), + None, + None, + None, + None, + vec![coin(100_000_000, "uwhale"), coin(100_000_000, "uusdc")], + |result| { + result.unwrap(); + }, + ) + .provide_liquidity( + &sender, + "uwhale-uosmo-cheap".to_string(), + None, + None, + None, + None, + vec![coin(100_000_000, "uwhale"), coin(100_000_000, "uosmo")], + |result| { + result.unwrap(); + }, + ) + .provide_liquidity( + &sender, + "3pool-stable".to_string(), + None, + None, + None, + None, + vec![ + coin(100_000_000, "uusdc"), + coin(100_000_000, "uusdt"), + coin( + 100_000_000, + "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", + ), + ], + |result| { + result.unwrap(); + }, + ) + .provide_liquidity( + &sender, + "uusdc-uusdt".to_string(), + None, + None, + None, + None, + vec![coin(100_000_000, "uusdc"), coin(100_000_000, "uusdt")], + |result| { + result.unwrap(); + }, + ) + .provide_liquidity( + &sender, + "uwhale-inj".to_string(), + None, + None, + None, + None, + vec![ + coin(100_000_000, "uwhale"), + coin(100_000_000_000_000_000_000, "inj"), + ], + |result| { + result.unwrap(); + }, + ) + .provide_liquidity( + &sender, + "uwhale-btc".to_string(), + None, + None, + None, + None, + vec![coin(100_000_000, "uwhale"), coin(10_000_000_000, "btc")], + |result| { + result.unwrap(); + }, + ) + .provide_liquidity( + &sender, + "peggy-uusdc".to_string(), + None, + None, + None, + None, + vec![ + coin( + 100_000_000, + "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + ), + coin(100_000_000, "uusdc"), + ], + |result| { + result.unwrap(); + }, + ); + + // add swap routes + suite + .add_swap_routes( + sender.clone(), + vec![ + SwapRoute { + offer_asset_denom: "uusdc".to_string(), + ask_asset_denom: "uwhale".to_string(), + swap_operations: vec![ + SwapOperation::WhaleSwap { + token_in_denom: "uusdc".to_string(), + token_out_denom: "uwhale".to_string(), + pool_identifier: "uwhale-uusdc-cheap".to_string(), + } + ], + }, + SwapRoute { + offer_asset_denom: "uosmo".to_string(), + ask_asset_denom: "uwhale".to_string(), + swap_operations: vec![ + SwapOperation::WhaleSwap { + token_in_denom: "uosmo".to_string(), + token_out_denom: "uwhale".to_string(), + pool_identifier: "uwhale-uosmo-cheap".to_string(), + } + ], + }, + SwapRoute { + offer_asset_denom: "uusdt".to_string(), + ask_asset_denom: "uwhale".to_string(), + swap_operations: vec![ + SwapOperation::WhaleSwap { + token_in_denom: "uusdt".to_string(), + token_out_denom: "uusdc".to_string(), + pool_identifier: "uusdc-uusdt".to_string(), + }, + SwapOperation::WhaleSwap { + token_in_denom: "uusdc".to_string(), + token_out_denom: "uwhale".to_string(), + pool_identifier: "uwhale-uusdc-cheap".to_string(), + }, + ], + }, + SwapRoute { + offer_asset_denom: "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752".to_string(), + ask_asset_denom: "uwhale".to_string(), + swap_operations: vec![ + SwapOperation::WhaleSwap { + token_in_denom: "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752".to_string(), + token_out_denom: "uusdc".to_string(), + pool_identifier: "3pool-stable".to_string(), + }, + SwapOperation::WhaleSwap { + token_in_denom: "uusdc".to_string(), + token_out_denom: "uwhale".to_string(), + pool_identifier: "uwhale-uusdc-cheap".to_string(), + }, + ], + }, + SwapRoute { + offer_asset_denom: "inj".to_string(), + ask_asset_denom: "uwhale".to_string(), + swap_operations: vec![ + SwapOperation::WhaleSwap { + token_in_denom: "inj".to_string(), + token_out_denom: "uwhale".to_string(), + pool_identifier: "uwhale-inj".to_string(), + } + ], + }, + SwapRoute { + offer_asset_denom: "btc".to_string(), + ask_asset_denom: "uwhale".to_string(), + swap_operations: vec![ + SwapOperation::WhaleSwap { + token_in_denom: "btc".to_string(), + token_out_denom: "uwhale".to_string(), + pool_identifier: "uwhale-btc".to_string(), + } + ], + }, + SwapRoute { + offer_asset_denom: "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5".to_string(), + ask_asset_denom: "uwhale".to_string(), + swap_operations: vec![ + SwapOperation::WhaleSwap { + token_in_denom: "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5".to_string(), + token_out_denom: "uusdc".to_string(), + pool_identifier: "peggy-uusdc".to_string(), + }, + SwapOperation::WhaleSwap { + token_in_denom: "uusdc".to_string(), + token_out_denom: "uwhale".to_string(), + pool_identifier: "uwhale-uusdc-cheap".to_string(), + }, + ], + }, + ], + |result| { + result.unwrap(); + }, + ); + + let pool_identifiers = RefCell::new(vec![]); + + pool_identifiers.borrow_mut().extend(vec![ + "uwhale-uusdc-free".to_string(), + "uwhale-uusdc-cheap".to_string(), + "uwhale-uusdc-expensive".to_string(), + "uwhale-uosmo-cheap".to_string(), + "3pool-stable".to_string(), + "uusdc-uusdt".to_string(), + "uwhale-inj".to_string(), + "uwhale-btc".to_string(), + "peggy-uusdc".to_string(), + ]); + + suite.pool_identifiers = pool_identifiers.into_inner(); } } pub mod vaults { + use std::cell::RefCell; + + use cosmwasm_std::{coin, Addr}; + use crate::common::helpers; use crate::common::suite::TestingSuite; - use cosmwasm_std::{coin, Addr}; /// Creates multiple vaults pub(crate) fn create_vaults(suite: &mut TestingSuite, sender: Addr) { @@ -345,5 +598,164 @@ pub mod vaults { result.unwrap(); }, ); + + let vault_identifiers = RefCell::new(vec![]); + + suite.query_vaults(None, None, |result| { + let vaults_response = result.unwrap(); + for vault in vaults_response.vaults { + vault_identifiers.borrow_mut().push(vault.identifier); + } + }); + + suite.vault_identifiers = vault_identifiers.into_inner(); + } + + pub(crate) fn add_vault_liquidity(_p0: &mut TestingSuite, _p1: Addr) { + //todo + } +} + +pub mod incentives { + use std::cell::RefCell; + + use cosmwasm_std::{coin, Addr}; + + use white_whale_std::incentive_manager::{IncentiveAction, IncentiveParams}; + + use crate::common::suite::TestingSuite; + + pub(crate) fn create_incentives(suite: &mut TestingSuite, sender: Addr) { + let lp_tokens = RefCell::new(suite.pool_identifiers.clone()); + + suite + .manage_incentive( + sender.clone(), + IncentiveAction::Fill { + params: IncentiveParams { + lp_denom: lp_tokens.borrow()[0].clone(), + start_epoch: Some(3), + preliminary_end_epoch: None, + curve: None, + incentive_asset: coin(1_000_000u128, "uwhale"), + incentive_identifier: None, + }, + }, + vec![coin(1_001_000u128, "uwhale")], + |result| { + result.unwrap(); + }, + ) + .manage_incentive( + sender.clone(), + IncentiveAction::Fill { + params: IncentiveParams { + lp_denom: lp_tokens.borrow()[1].clone(), + start_epoch: Some(3), + preliminary_end_epoch: None, + curve: None, + incentive_asset: coin(1_000_000u128, "uosmo"), + incentive_identifier: None, + }, + }, + vec![coin(1_000u128, "uwhale"), coin(1_000_000u128, "uosmo")], + |result| { + result.unwrap(); + }, + ) + .manage_incentive( + sender.clone(), + IncentiveAction::Fill { + params: IncentiveParams { + lp_denom: lp_tokens.borrow()[3].clone(), + start_epoch: Some(3), + preliminary_end_epoch: None, + curve: None, + incentive_asset: coin(1_000_000u128, "uosmo"), + incentive_identifier: None, + }, + }, + vec![coin(1_000u128, "uwhale"), coin(1_000_000u128, "uosmo")], + |result| { + result.unwrap(); + }, + ) + .manage_incentive( + sender.clone(), + IncentiveAction::Fill { + params: IncentiveParams { + lp_denom: lp_tokens.borrow()[6].clone(), + start_epoch: Some(8), + preliminary_end_epoch: None, + curve: None, + incentive_asset: coin(3_000u128, "btc"), + incentive_identifier: None, + }, + }, + vec![coin(1_000u128, "uwhale"), coin(3_000u128, "btc")], + |result| { + result.unwrap(); + }, + ) + .manage_incentive( + sender.clone(), + IncentiveAction::Fill { + params: IncentiveParams { + lp_denom: lp_tokens.borrow()[6].clone(), + start_epoch: Some(8), + preliminary_end_epoch: None, + curve: None, + incentive_asset: coin(3_000u128, "uosmo"), + incentive_identifier: None, + }, + }, + vec![coin(1_000u128, "uwhale"), coin(3_000u128, "uosmo")], + |result| { + result.unwrap(); + }, + ) + .manage_incentive( + sender.clone(), + IncentiveAction::Fill { + params: IncentiveParams { + lp_denom: lp_tokens.borrow()[6].clone(), + start_epoch: Some(10), + preliminary_end_epoch: None, + curve: None, + incentive_asset: coin(10_000u128, "uusdc"), + incentive_identifier: None, + }, + }, + vec![coin(1_000u128, "uwhale"), coin(10_000u128, "uusdc")], + |result| { + result.unwrap(); + }, + ) + .manage_incentive( + sender.clone(), + IncentiveAction::Fill { + params: IncentiveParams { + lp_denom: lp_tokens.borrow()[6].clone(), + start_epoch: Some(10), + preliminary_end_epoch: None, + curve: None, + incentive_asset: coin( + 100_000u128, + "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", + ), + incentive_identifier: None, + }, + }, + vec![ + coin(1_000u128, "uwhale"), + coin( + 100_000u128, + "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", + ), + ], + |result| { + result.unwrap(); + }, + ); } } diff --git a/integration-tests/tests/common/suite.rs b/integration-tests/tests/common/suite.rs index 94390c320..0c7f88c46 100644 --- a/integration-tests/tests/common/suite.rs +++ b/integration-tests/tests/common/suite.rs @@ -7,11 +7,11 @@ use cw_multi_test::{ App, AppBuilder, AppResponse, BankKeeper, DistributionKeeper, Executor, FailingModule, GovFailingModule, IbcFailingModule, StakeKeeper, WasmKeeper, }; + use white_whale_std::bonding_manager::{ BondedResponse, ClaimableRewardBucketsResponse, ExecuteMsg, GlobalIndex, QueryMsg, RewardBucket, RewardsResponse, UnbondingResponse, WithdrawableResponse, }; - use white_whale_std::epoch_manager::epoch_manager::{Epoch, EpochConfig, EpochResponse}; use white_whale_std::fee::PoolFee; use white_whale_std::incentive_manager::{ @@ -33,6 +33,9 @@ use crate::common::suite_contracts::{ pool_manager_contract, vault_manager_contract, }; +pub const BWHALE: &str = "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE"; +pub const AMPWHALE: &str = "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE"; + type OsmosisTokenFactoryApp = App< BankKeeper, MockApiBech32, @@ -54,8 +57,8 @@ pub struct TestingSuite { pub incentive_manager_addr: Addr, pub pool_manager_addr: Addr, pub vault_manager_addr: Addr, - pub pools: Vec, - pub vaults: Vec, + pub pool_identifiers: Vec, + pub vault_identifiers: Vec, } /// TestingSuite helpers @@ -89,8 +92,16 @@ impl TestingSuite { self } + pub(crate) fn add_epochs(&mut self, n: u64) -> &mut Self { + for _ in 0..n { + self.add_one_epoch(); + } + + self + } + #[track_caller] - pub(crate) fn query_balance( + pub(crate) fn _query_balance( &mut self, denom: String, address: Addr, @@ -102,7 +113,7 @@ impl TestingSuite { self } - pub(crate) fn query_all_balances( + pub(crate) fn _query_all_balances( &mut self, addr: String, result: impl Fn(StdResult>), @@ -117,7 +128,27 @@ impl TestingSuite { /// Instantiate impl TestingSuite { - pub(crate) fn default_with_balances(initial_balance: Vec) -> Self { + pub(crate) fn default_with_balances() -> Self { + let initial_balance = vec![ + coin(1_000_000_000_000u128, "uwhale"), + coin(1_000_000_000_000u128, "uosmo"), + coin(1_000_000_000_000u128, "uusdc"), + coin(1_000_000_000_000u128, "uusdt"), + // ibc token is stablecoin + coin( + 1_000_000_000_000u128, + "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", + ), + coin(1_000_000_000_000u128, AMPWHALE), + coin(1_000_000_000_000u128, BWHALE), + coin( + 1_000_000_000_000u128, + "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", + ), + coin(1_000_000_000_000_000u128, "btc"), + coin(1_000_000_000_000_000_000_000_000u128, "inj"), + ]; + let sender_1 = Addr::unchecked("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"); let sender_2 = Addr::unchecked("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"); let sender_3 = Addr::unchecked("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"); @@ -153,19 +184,36 @@ impl TestingSuite { incentive_manager_addr: Addr::unchecked(""), pool_manager_addr: Addr::unchecked(""), vault_manager_addr: Addr::unchecked(""), - pools: vec![], - vaults: vec![], + pool_identifiers: vec![], + vault_identifiers: vec![], } } #[track_caller] pub(crate) fn instantiate(&mut self) -> &mut Self { + let creator = self.creator().clone(); + self.create_epoch_manager(); self.create_bonding_manager(); self.create_incentive_manager(); self.create_pool_manager(); self.create_vault_manager(); + self.update_bonding_manager_contract_addresses(creator.clone(), |response| { + response.unwrap(); + }); + + let bonding_manager_addr = self.bonding_manager_addr.clone(); + let incentive_manager_addr = self.incentive_manager_addr.clone(); + + self.add_hook(creator.clone(), bonding_manager_addr, |result| { + result.unwrap(); + }); + + self.add_hook(creator, incentive_manager_addr, |result| { + result.unwrap(); + }); + // May 23th 2024 15:00:00 UTC let timestamp = Timestamp::from_seconds(1716476400u64); self.set_time(timestamp); @@ -183,7 +231,7 @@ impl TestingSuite { distribution_denom: "uwhale".to_string(), unbonding_period: 1u64, growth_rate: Decimal::one(), - bonding_assets: vec!["ampWHALE".to_string(), "bWHALE".to_string()], + bonding_assets: vec![AMPWHALE.to_string(), BWHALE.to_string()], grace_period: 21, epoch_manager_addr, }; @@ -265,6 +313,7 @@ impl TestingSuite { ) .unwrap(); } + fn create_pool_manager(&mut self) { let pool_manager_contract = self.app.store_code(pool_manager_contract()); @@ -291,6 +340,7 @@ impl TestingSuite { ) .unwrap(); } + fn create_vault_manager(&mut self) { let vault_manager_contract = self.app.store_code(vault_manager_contract()); @@ -324,16 +374,18 @@ impl TestingSuite { #[track_caller] pub(crate) fn bond( &mut self, - sender: Addr, + sender: &Addr, funds: &[Coin], response: impl Fn(Result), ) -> &mut Self { let msg = ExecuteMsg::Bond; - response( - self.app - .execute_contract(sender, self.bonding_manager_addr.clone(), &msg, funds), - ); + response(self.app.execute_contract( + sender.clone(), + self.bonding_manager_addr.clone(), + &msg, + funds, + )); self } @@ -358,11 +410,30 @@ impl TestingSuite { #[track_caller] pub(crate) fn claim_bonding_rewards( &mut self, - sender: Addr, + sender: &Addr, response: impl Fn(Result), ) -> &mut Self { let msg = ExecuteMsg::Claim {}; + response(self.app.execute_contract( + sender.clone(), + self.bonding_manager_addr.clone(), + &msg, + &[], + )); + + self + } + + #[track_caller] + pub(crate) fn _withdraw( + &mut self, + sender: Addr, + denom: String, + response: impl Fn(Result), + ) -> &mut Self { + let msg = ExecuteMsg::Withdraw { denom }; + response( self.app .execute_contract(sender, self.bonding_manager_addr.clone(), &msg, &[]), @@ -372,13 +443,20 @@ impl TestingSuite { } #[track_caller] - pub(crate) fn withdraw( + pub(crate) fn update_bonding_manager_contract_addresses( &mut self, sender: Addr, - denom: String, response: impl Fn(Result), ) -> &mut Self { - let msg = ExecuteMsg::Withdraw { denom }; + let epoch_manager_addr = self.epoch_manager_addr.to_string(); + let pool_manager_addr = self.pool_manager_addr.to_string(); + + let msg = ExecuteMsg::UpdateConfig { + epoch_manager_addr: Some(epoch_manager_addr), + pool_manager_addr: Some(pool_manager_addr), + unbonding_period: None, + growth_rate: None, + }; response( self.app @@ -389,7 +467,7 @@ impl TestingSuite { } #[track_caller] - pub(crate) fn query_global_index( + pub(crate) fn _query_global_index( &mut self, reward_bucket_id: Option, response: impl Fn(StdResult<(&mut Self, GlobalIndex)>), @@ -411,7 +489,7 @@ impl TestingSuite { #[track_caller] pub(crate) fn query_claimable_reward_buckets( &mut self, - address: Option, + address: Option<&Addr>, response: impl Fn(StdResult<(&mut Self, Vec)>), ) -> &mut Self { let address = if let Some(address) = address { @@ -449,7 +527,7 @@ impl TestingSuite { } #[track_caller] - pub(crate) fn query_unbonding( + pub(crate) fn _query_unbonding( &mut self, address: String, denom: String, @@ -477,7 +555,7 @@ impl TestingSuite { } #[track_caller] - pub(crate) fn query_withdrawable( + pub(crate) fn _query_withdrawable( &mut self, address: String, denom: String, @@ -555,7 +633,7 @@ impl TestingSuite { } #[track_caller] - pub(crate) fn remove_hook( + pub(crate) fn _remove_hook( &mut self, sender: Addr, contract_addr: Addr, @@ -587,8 +665,21 @@ impl TestingSuite { self } + #[track_caller] - pub(crate) fn query_hooks( + pub(crate) fn _query_current_time( + &mut self, + mut result: impl FnMut(StdResult), + ) -> &mut Self { + let current_time_response: StdResult = Ok(self.app.block_info().time); + + result(current_time_response); + + self + } + + #[track_caller] + pub(crate) fn _query_hooks( &mut self, mut result: impl FnMut(StdResult), ) -> &mut Self { @@ -628,7 +719,7 @@ impl TestingSuite { } #[track_caller] - pub(crate) fn manage_position( + pub(crate) fn _manage_position( &mut self, sender: Addr, action: PositionAction, @@ -648,7 +739,7 @@ impl TestingSuite { } #[track_caller] - pub(crate) fn claim_incentive_rewards( + pub(crate) fn _claim_incentive_rewards( &mut self, sender: Addr, funds: Vec, @@ -667,7 +758,7 @@ impl TestingSuite { } #[track_caller] - pub(crate) fn query_incentives( + pub(crate) fn _query_incentives( &mut self, filter_by: Option, start_after: Option, @@ -689,7 +780,7 @@ impl TestingSuite { } #[track_caller] - pub(crate) fn query_positions( + pub(crate) fn _query_positions( &mut self, address: Addr, open_state: Option, @@ -708,7 +799,7 @@ impl TestingSuite { self } #[track_caller] - pub(crate) fn query_incentive_rewards( + pub(crate) fn _query_incentive_rewards( &mut self, address: Addr, result: impl Fn(StdResult), @@ -727,7 +818,7 @@ impl TestingSuite { } #[track_caller] - pub(crate) fn query_lp_weight( + pub(crate) fn _query_lp_weight( &mut self, denom: &str, epoch_id: u64, @@ -755,7 +846,7 @@ impl TestingSuite { #[track_caller] pub(crate) fn provide_liquidity( &mut self, - sender: Addr, + sender: &Addr, pool_identifier: String, unlocking_duration: Option, lock_position_identifier: Option, @@ -773,10 +864,12 @@ impl TestingSuite { lock_position_identifier, }; - result( - self.app - .execute_contract(sender, self.pool_manager_addr.clone(), &msg, &funds), - ); + result(self.app.execute_contract( + sender.clone(), + self.pool_manager_addr.clone(), + &msg, + &funds, + )); self } @@ -812,7 +905,7 @@ impl TestingSuite { #[track_caller] #[allow(clippy::too_many_arguments)] - pub(crate) fn execute_swap_operations( + pub(crate) fn _execute_swap_operations( &mut self, sender: Addr, operations: Vec, @@ -869,7 +962,7 @@ impl TestingSuite { } #[track_caller] - pub(crate) fn withdraw_liquidity( + pub(crate) fn _withdraw_liquidity( &mut self, sender: Addr, pool_identifier: String, @@ -906,7 +999,7 @@ impl TestingSuite { /// Removes swap routes from the pool manager contract. #[track_caller] - pub(crate) fn remove_swap_routes( + pub(crate) fn _remove_swap_routes( &mut self, sender: Addr, swap_routes: Vec, @@ -922,7 +1015,7 @@ impl TestingSuite { self } - pub(crate) fn query_pool_info( + pub(crate) fn _query_pool( &self, pool_identifier: String, result: impl Fn(StdResult), @@ -937,7 +1030,7 @@ impl TestingSuite { self } - pub(crate) fn query_simulation( + pub(crate) fn _query_simulation( &mut self, pool_identifier: String, offer_asset: Coin, @@ -958,7 +1051,7 @@ impl TestingSuite { self } - pub(crate) fn query_reverse_simulation( + pub(crate) fn _query_reverse_simulation( &mut self, pool_identifier: String, ask_asset: Coin, @@ -980,7 +1073,7 @@ impl TestingSuite { self } - pub(crate) fn query_simulate_swap_operations( + pub(crate) fn _query_simulate_swap_operations( &mut self, offer_amount: Uint128, operations: Vec, @@ -1000,7 +1093,7 @@ impl TestingSuite { self } - pub(crate) fn query_reverse_simulate_swap_operations( + pub(crate) fn _query_reverse_simulate_swap_operations( &mut self, ask_amount: Uint128, operations: Vec, @@ -1021,7 +1114,7 @@ impl TestingSuite { } /// Retrieves the swap routes for a given pool of assets. - pub(crate) fn query_swap_routes( + pub(crate) fn _query_swap_routes( &mut self, result: impl Fn(StdResult), ) -> &mut Self { @@ -1065,7 +1158,7 @@ impl TestingSuite { } #[track_caller] - pub(crate) fn vault_deposit( + pub(crate) fn _vault_deposit( &mut self, sender: Addr, vault_identifier: String, @@ -1083,7 +1176,7 @@ impl TestingSuite { } #[track_caller] - pub(crate) fn vault_withdraw( + pub(crate) fn _vault_withdraw( &mut self, sender: Addr, funds: Vec, @@ -1101,7 +1194,7 @@ impl TestingSuite { } #[track_caller] - pub(crate) fn flashloan( + pub(crate) fn _flashloan( &mut self, sender: Addr, asset: Coin, @@ -1124,7 +1217,7 @@ impl TestingSuite { } #[track_caller] - pub(crate) fn query_vault( + pub(crate) fn _query_vault( &mut self, filter_by: FilterVaultBy, result: impl Fn(StdResult), @@ -1157,7 +1250,7 @@ impl TestingSuite { } #[track_caller] - pub(crate) fn query_vault_share( + pub(crate) fn _query_vault_share( &mut self, lp_share: Coin, result: impl Fn(StdResult), @@ -1173,7 +1266,7 @@ impl TestingSuite { } #[track_caller] - pub(crate) fn query_flashloan_payback( + pub(crate) fn _query_flashloan_payback( &mut self, asset: Coin, vault_identifier: String, diff --git a/integration-tests/tests/integration.rs b/integration-tests/tests/integration.rs index c95a6a029..23d8e614e 100644 --- a/integration-tests/tests/integration.rs +++ b/integration-tests/tests/integration.rs @@ -1,6 +1,15 @@ -use cosmwasm_std::coin; +use std::cell::RefCell; +use std::collections::{HashMap, HashSet}; +use std::rc::Rc; -use white_whale_std::pool_manager::PoolType; +use bonding_manager::ContractError; +use common::suite::{AMPWHALE, BWHALE}; +use cosmwasm_std::{coin, coins}; +use cosmwasm_std::{Addr, Coin}; + +use proptest::prelude::*; +use proptest::prop_oneof; +use proptest::strategy::{Just, Strategy}; use crate::common::helpers; use crate::common::suite::TestingSuite; @@ -9,35 +18,10 @@ mod common; #[test] fn epic_test() { - let mut suite = TestingSuite::default_with_balances(vec![ - coin(1_000_000_000_000u128, "uwhale"), - coin(1_000_000_000_000u128, "uosmo"), - coin(1_000_000_000_000u128, "uusdc"), - coin(1_000_000_000_000u128, "uusdt"), - // ibc token is stablecoin - coin( - 1_000_000_000_000u128, - "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", - ), - coin( - 1_000_000_000_000u128, - "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", - ), - coin( - 1_000_000_000_000u128, - "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", - ), - coin( - 1_000_000_000_000u128, - "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", - ), - coin(1_000_000_000_000_000u128, "btc"), - coin(1_000_000_000_000_000_000_000_000u128, "inj"), - ]); - + let mut suite = TestingSuite::default_with_balances(); suite.instantiate(); - let [alice, bob, carol, dave, sybil] = [ + let [alice, bob, carol, _dave, _sybil] = [ suite.senders[0].clone(), suite.senders[1].clone(), suite.senders[2].clone(), @@ -45,7 +29,516 @@ fn epic_test() { suite.senders[4].clone(), ]; - // create some pools + // create some pools, vaults, incentives helpers::pools::create_pools(&mut suite, alice.clone()); helpers::vaults::create_vaults(&mut suite, bob.clone()); + helpers::vaults::add_vault_liquidity(&mut suite, bob.clone()); + helpers::incentives::create_incentives(&mut suite, carol.clone()); + + let current_rewards = Rc::new(RefCell::new(0)); + + suite + // before we start doing anything, let's make sure we are in epoch 1 + .query_current_epoch(|response| { + assert_eq!(response.unwrap().epoch.id, 1); + }) + // claimable rewards should be empty + .query_claimable_reward_buckets(None, |response| { + assert!(response.unwrap().1.is_empty()); + }) + // create 1 epoch + .add_one_epoch() + // claimable rewards should have 19_000 uwhale due to the initial setup (on epoch 1) + .query_claimable_reward_buckets(None, |response| { + assert_eq!(response.unwrap().1[0].available[0], coin(19_000, "uwhale")); + }) + // bond alice with 10_000 uwhale on epoch 2 (without swapping) + .bond(&alice, &coins(10_000, AMPWHALE), |result| { + result.unwrap(); + }) + // create 20 more epochs, should not let alice claim any rewards + .add_epochs(20) + .query_current_epoch(|result| { + assert_eq!(result.unwrap().epoch.id, 22); + }) + .query_claimable_reward_buckets(Some(&alice), |response| { + assert!(response.unwrap().1.is_empty()); + }) + // create 1 more epoch should let alice claim 19_000 uwhale from the initial setup + .add_epochs(1) + .query_current_epoch(|result| { + assert_eq!(result.unwrap().epoch.id, 23); + }) + .query_claimable_reward_buckets(Some(&alice), |response| { + assert_eq!(response.unwrap().1[0].available, coins(19_000, "uwhale")); + }) + .query_bonding_rewards(alice.to_string(), |response| { + assert_eq!(response.unwrap().1.rewards, coins(19_000, "uwhale")); + }) + // claim the rewards + .claim_bonding_rewards(&alice, |result| { + result.unwrap(); + }) + // should not be able to claim the same rewards again + .claim_bonding_rewards(&alice, |result| { + assert_eq!( + result.unwrap_err().downcast::().unwrap(), + ContractError::NothingToClaim + ); + }) + // check that the rewards are claimed + .query_claimable_reward_buckets(Some(&alice), |response| { + assert!(response.unwrap().1.is_empty()); + }) + .query_claimable_reward_buckets(None, |response| { + assert!(response.unwrap().1.is_empty()); + }) + .query_bonding_rewards(alice.to_string(), |response| { + assert!(response.unwrap().1.rewards.is_empty()); + }) + // move to epoch 24 + .add_one_epoch() + // check we're on epoch 24 + .query_current_epoch(|result| { + assert_eq!(result.unwrap().epoch.id, 24); + }) + .swap( + carol.clone(), + "uusdc".to_string(), + None, + None, + None, + "uwhale-uusdc-cheap".to_string(), + coins(10_000, "uwhale"), + |result| { + result.as_ref().unwrap().events.iter().for_each(|event| { + // get the protocol fee amount + event.attributes.iter().for_each(|attr| { + if attr.key == "protocol_fee_amount" { + *current_rewards.borrow_mut() += attr.value.parse::().unwrap(); + assert_eq!(*current_rewards.borrow(), (10_000. * 0.001 - 1.) as u128); + } + }); + }); + result.unwrap(); + }, + ) + // alice should still have 0 uwhale claimable rewards + .query_claimable_reward_buckets(Some(&alice), |response| { + assert!(response.unwrap().1.is_empty()); + }) + .add_one_epoch() + // bond bob with 40_000 uwhale on epoch 25 + .bond(&bob, &coins(40_000, AMPWHALE), |result| { + result.unwrap(); + }) + // bob should have 0 uwhale claimable rewards until a swap is made + .query_claimable_reward_buckets(Some(&bob), |response| { + assert!(response.unwrap().1.is_empty()); + }) + // alice should have 10 claimable rewards, 0.1% of the 10_000 uwhale swapped + .query_claimable_reward_buckets(Some(&alice), |response| { + assert_eq!( + response.as_ref().unwrap().1[0].available[0].amount.u128(), + // TODO: >>> make sure that the 1 uwhale we lose here is due to rounding... + (10_000. * 0.001 - 1.) as u128 + ); + }) + .add_one_epoch() + .query_bonding_rewards(alice.to_string(), |response| { + println!("{:?}", response.unwrap().1); + }) + .swap( + carol.clone(), + "uwhale".to_string(), + None, + None, + None, + "uwhale-uusdc-cheap".to_string(), + coins(10_000, "uusdc"), + |result| { + result.unwrap(); + }, + ) + .add_one_epoch() + .query_claimable_reward_buckets(Some(&bob), |response| { + println!("{:?}", response.unwrap().1); + }); +} + +proptest! { + #[test] + fn property_based_test( + actions in proptest::collection::vec(action_strategy( + vec![ + Addr::unchecked("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), + Addr::unchecked("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), + Addr::unchecked("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), + Addr::unchecked("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), + Addr::unchecked("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7") + ] + ), 1..100) + ) { + let mut suite = TestingSuite::default_with_balances(); + suite.instantiate(); + + let [alice, bob, carol, _dave, _sybil] = [ + suite.senders[0].clone(), + suite.senders[1].clone(), + suite.senders[2].clone(), + suite.senders[3].clone(), + suite.senders[4].clone(), + ]; + + // create some pools, vaults, incentives + helpers::pools::create_pools(&mut suite, alice.clone()); + helpers::vaults::create_vaults(&mut suite, bob.clone()); + helpers::vaults::add_vault_liquidity(&mut suite, bob.clone()); + helpers::incentives::create_incentives(&mut suite, carol.clone()); + + // let's bond with alice and create some epochs to empty the rewards bucket due to the initial setup + suite.bond(&alice, &coins(10_000, AMPWHALE), |result| { + result.unwrap(); + }); + suite.add_epochs(20); + suite.query_bonding_rewards(alice.to_string(), |response| { + assert_eq!(response.unwrap().1.rewards, coins(19_000, "uwhale")); + }); + suite.claim_bonding_rewards(&alice, |result| { + result.unwrap(); + }); + suite.unbond(alice.clone(), coin(10_000, AMPWHALE), |result| { + result.unwrap(); + }); + suite.add_epochs(79); + suite.query_claimable_reward_buckets(None, |response| { + assert!(response.unwrap().1.is_empty()); + }); + + let current_rewards = Rc::new(RefCell::new(0)); + let bonded_amounts = Rc::new(RefCell::new(HashMap::>::new())); + let claimable_rewards = Rc::new(RefCell::new(HashMap::<(Addr, u64), bool>::new())); + let available_pools: HashSet = vec![ + "peggy-uusdc".to_string(), + "uwhale-btc".to_string(), + "uwhale-inj".to_string(), + "uusdc-uusdt".to_string(), + ].into_iter().collect(); + let last_claimed = Rc::new(RefCell::new(HashMap::::new())); + let mut swaps_in_epoch = false; + + for action in actions { + let mut current_epoch = 0; + suite.query_current_epoch(|response| { + current_epoch = response.unwrap().epoch.id; + }); + // suite.query_claimable_reward_buckets(None, |response| { + // println!(">>> [{current_epoch}] CLAIMABLE REWARDS {:?}", response.unwrap().1); + // }); + + match action { + Action::Swap(user, from_token, to_token, amount) => { + println!(">>> [{current_epoch}] [{user}] SWAP"); + if from_token == to_token { + suite.swap( + user.clone(), + to_token.clone(), + None, + None, + None, + "uwhale-uusdc-cheap".to_string(), + coins(amount, from_token), + move |result| { + assert_eq!( + result.unwrap_err().downcast::().unwrap(), + pool_manager::ContractError::SameAsset + ); + } + ); + } else { + let pool_identifier = create_pool_identifier(&from_token, &to_token); + + // enter the normal swap flow if the pool exists + if available_pools.contains(&pool_identifier) { + swaps_in_epoch = true; + suite.swap( + user.clone(), + to_token.clone(), + None, + None, + None, + pool_identifier, + coins(amount, from_token), + { + let current_rewards = Rc::clone(¤t_rewards); + move |result| { + result.as_ref().unwrap().events.iter().for_each(|event| { + // get the protocol fee amount + event.attributes.iter().for_each(|attr| { + if attr.key == "protocol_fee_amount" { + *current_rewards.borrow_mut() += attr.value.parse::().unwrap(); + } + }); + }); + result.unwrap(); + } + }, + ); + + // Mark claimable rewards for users bonded during this epoch + let bonded_amounts = bonded_amounts.borrow(); + for user in bonded_amounts.keys() { + claimable_rewards.borrow_mut().insert((user.clone(), current_epoch), true); + } + } else { + suite.swap( + user.clone(), + to_token.clone(), + None, + None, + None, + pool_identifier, + coins(amount, from_token), + move |result| { + assert_eq!( + result.unwrap_err().downcast::().unwrap(), + pool_manager::ContractError::UnExistingPool + ); + } + ); + } + } + } + Action::Bond(user, token, amount) => { + let mut has_pending_rewards = false; + for ((test_user, epoch), has_rewards) in claimable_rewards.borrow().iter() { + if test_user == &user && *epoch != current_epoch && *has_rewards { + has_pending_rewards = true; + break; + } + } + suite.query_bonding_rewards(user.to_string(), |response| { + let contract_rewards = &response.as_ref().unwrap().1.rewards; + let has_contract_rewards = !contract_rewards.is_empty(); + // println!("____________"); + // println!(">>> [{current_epoch}] CLAIMABLE REWARDS CONTRACT {:?}", contract_rewards); + // println!(">>> [{current_epoch}] CLAIMABLE REWARDS TEST {:?}", claimable_rewards.borrow()); + assert_eq!(has_pending_rewards, has_contract_rewards); + }); + + if has_pending_rewards { + suite.bond(&user, &coins(amount, &token), |result| { + assert_eq!( + result.unwrap_err().downcast::().unwrap(), + bonding_manager::ContractError::UnclaimedRewards + ); + }); + } else { + suite.bond(&user, &coins(amount, &token), |result| { + println!(">>> [{current_epoch}] [{user}] BOND [{amount}]"); + result.unwrap(); + }); + + let mut bonded_amounts = bonded_amounts.borrow_mut(); + let user_bonds = bonded_amounts.entry(user.clone()).or_insert_with(HashMap::new); + *user_bonds.entry(token.clone()).or_insert(0) += amount; + + if swaps_in_epoch { + claimable_rewards.borrow_mut().insert((user.clone(), current_epoch), true); + } + + suite.query_bonded(Some(user.to_string()), |result| { + let bonded = result.unwrap().1.bonded_assets; + let mut expected_bonded = user_bonds.iter() + .map(|(token, amount)| coin(*amount, token)) + .collect::>(); + expected_bonded.sort_by(|a, b| a.denom.cmp(&b.denom)); + let mut bonded_sorted = bonded.clone(); + bonded_sorted.sort_by(|a, b| a.denom.cmp(&b.denom)); + assert_eq!(bonded_sorted, expected_bonded); + }); + } + } + Action::Unbond(user, token, amount) => { + println!(">>> [{current_epoch}] [{user}] UNBOND [{amount}]"); + + let mut has_pending_rewards = false; + for ((test_user, epoch), has_rewards) in claimable_rewards.borrow().iter() { + if test_user == &user && *epoch != current_epoch && *has_rewards { + has_pending_rewards = true; + break; + } + } + + if has_pending_rewards { + suite.unbond(user.clone(), coin(amount, &token), |result| { + assert_eq!( + result.unwrap_err().downcast::().unwrap(), + bonding_manager::ContractError::UnclaimedRewards + ); + }); + } else { + let mut bonded_amounts = bonded_amounts.borrow_mut(); + let user_bonds = bonded_amounts.entry(user.clone()).or_insert_with(HashMap::new); + + if let Some(bonded) = user_bonds.get_mut(&token) { + if *bonded >= amount { + suite.unbond(user.clone(), coin(amount, &token), |result| { + result.unwrap(); + }); + *bonded -= amount; + + suite.query_bonding_rewards(user.to_string(), |response| { + let contract_rewards = response.unwrap().1.rewards; + let has_contract_rewards = !contract_rewards.is_empty(); + + let mut has_rewards_in_test_map = false; + for ((test_user, epoch), has_rewards) in claimable_rewards.borrow().iter() { + if test_user == &user && *epoch != current_epoch && *has_rewards { + has_rewards_in_test_map = true; + break; + } + } + + assert_eq!(has_rewards_in_test_map, has_contract_rewards); + }); + } else { + suite.unbond(user.clone(), coin(amount, &token), |result| { + assert_eq!( + result.unwrap_err().downcast::().unwrap(), + bonding_manager::ContractError::InsufficientBond + ); + }); + } + } else { + suite.unbond(user.clone(), coin(amount, &token), |result| { + assert_eq!( + result.unwrap_err().downcast::().unwrap(), + bonding_manager::ContractError::NothingToUnbond + ); + }); + } + } + } + Action::Claim(user) => { + println!(">>> [{current_epoch}] [{user}] CLAIM"); + + let mut has_pending_rewards = false; + for ((test_user, epoch), has_rewards) in claimable_rewards.borrow().iter() { + if test_user == &user && *epoch != current_epoch && *has_rewards { + has_pending_rewards = true; + break; + } + } + + if has_pending_rewards { + suite.query_bonding_rewards(user.to_string(), |response| { + println!(">>> [{current_epoch}] BONDING REWARDS {:?}", response.unwrap().1); + }); + suite.claim_bonding_rewards(&user, |result| { + result.unwrap(); + }); + + last_claimed.borrow_mut().insert(user.clone(), current_epoch); + + for epoch in 0..current_epoch { + claimable_rewards.borrow_mut().remove(&(user.clone(), epoch)); + } + } else { + suite.claim_bonding_rewards(&user, |result| { + assert_eq!( + result.unwrap_err().downcast::().unwrap(), + bonding_manager::ContractError::NothingToClaim + ); + }); + } + } + } + + if rand::random() { + suite.add_one_epoch(); + swaps_in_epoch = false; + } + } + } +} + +fn create_pool_identifier(from_token: &str, to_token: &str) -> String { + let (token_a, token_b) = if from_token < to_token { + (from_token, to_token) + } else { + (to_token, from_token) + }; + + format!( + "{}-{}", + if token_a.starts_with("peggy") { + "peggy" + } else { + token_a + }, + if token_b.starts_with("peggy") { + "peggy" + } else { + token_b + } + ) +} + +#[derive(Clone, Debug)] +enum Action { + Swap(Addr, String, String, u128), + Bond(Addr, String, u128), + Unbond(Addr, String, u128), + Claim(Addr), +} + +fn action_strategy(users: Vec) -> impl Strategy { + let user_strategy = prop_oneof![ + Just(users[0].clone()), + Just(users[1].clone()), + Just(users[2].clone()), + Just(users[3].clone()), + Just(users[4].clone()) + ]; + + let swap_token_strategy = prop_oneof![ + Just("peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5".to_string()), + Just("ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752".to_string()), + Just("btc".to_string()), + Just("inj".to_string()), + Just("uwhale".to_string()), + Just("uusdc".to_string()), + Just("uusdt".to_string()) + ]; + + let bond_unbond_token_strategy = + prop_oneof![Just(BWHALE.to_string()), Just(AMPWHALE.to_string())]; + + let amount_strategy = 100_u128..100_000_u128; + + prop_oneof![ + ( + user_strategy.clone(), + swap_token_strategy.clone(), + swap_token_strategy.clone(), + amount_strategy.clone() + ) + .prop_map(|(user, from_token, to_token, amount)| Action::Swap( + user, from_token, to_token, amount + )), + ( + user_strategy.clone(), + bond_unbond_token_strategy.clone(), + amount_strategy.clone() + ) + .prop_map(|(user, token, amount)| Action::Bond(user, token, amount)), + ( + user_strategy.clone(), + bond_unbond_token_strategy.clone(), + amount_strategy.clone() + ) + .prop_map(|(user, token, amount)| Action::Unbond(user, token, amount)), + user_strategy.clone().prop_map(|user| Action::Claim(user)), + ] } diff --git a/packages/white-whale-std/src/pool_manager.rs b/packages/white-whale-std/src/pool_manager.rs index c0188f68f..8823750c1 100644 --- a/packages/white-whale-std/src/pool_manager.rs +++ b/packages/white-whale-std/src/pool_manager.rs @@ -448,4 +448,4 @@ pub struct ReverseSimulateSwapOperationsResponse { pub struct SwapRouteCreatorResponse { /// The creator of the swap route. pub creator: String, -} +} \ No newline at end of file From 0f50affe8e9cd5816de756a4a9817835a1c1bdb6 Mon Sep 17 00:00:00 2001 From: nahem Date: Mon, 10 Jun 2024 21:10:38 +0200 Subject: [PATCH 05/19] feat: map some errors and add couple tests to start te flow --- contracts/liquidity_hub/bonding-manager/src/error.rs | 3 +++ contracts/liquidity_hub/bonding-manager/src/helpers.rs | 5 ++++- contracts/liquidity_hub/pool-manager/src/error.rs | 2 ++ contracts/liquidity_hub/pool-manager/src/helpers.rs | 3 ++- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/contracts/liquidity_hub/bonding-manager/src/error.rs b/contracts/liquidity_hub/bonding-manager/src/error.rs index 72e0bf27c..c2799f45e 100644 --- a/contracts/liquidity_hub/bonding-manager/src/error.rs +++ b/contracts/liquidity_hub/bonding-manager/src/error.rs @@ -77,6 +77,9 @@ pub enum ContractError { "Invalid reward amount. Reward: {reward}, but only {available} available in the reward bucket." )] InvalidReward { reward: Uint128, available: Uint128 }, + + #[error("The reward bucket is empty")] + RewardBucketIsEmpty, } impl From for ContractError { diff --git a/contracts/liquidity_hub/bonding-manager/src/helpers.rs b/contracts/liquidity_hub/bonding-manager/src/helpers.rs index 75a563375..63ab4a5b0 100644 --- a/contracts/liquidity_hub/bonding-manager/src/helpers.rs +++ b/contracts/liquidity_hub/bonding-manager/src/helpers.rs @@ -284,7 +284,10 @@ pub(crate) fn validate_buckets_not_empty(deps: &DepsMut) -> Result<(), ContractE .keys(deps.storage, None, None, Order::Descending) .collect::>>()?; - ensure!(!reward_buckets.is_empty(), ContractError::Unauthorized); + ensure!( + !reward_buckets.is_empty(), + ContractError::RewardBucketIsEmpty + ); Ok(()) } diff --git a/contracts/liquidity_hub/pool-manager/src/error.rs b/contracts/liquidity_hub/pool-manager/src/error.rs index b9e9da968..d287ae6f3 100644 --- a/contracts/liquidity_hub/pool-manager/src/error.rs +++ b/contracts/liquidity_hub/pool-manager/src/error.rs @@ -162,6 +162,8 @@ pub enum ContractError { #[error("Invalid pool assets length, expected {expected} got {actual}")] InvalidPoolAssetsLength { expected: usize, actual: usize }, + #[error("The pool has no assets")] + PoolHasNoAssets, } impl From for ContractError { diff --git a/contracts/liquidity_hub/pool-manager/src/helpers.rs b/contracts/liquidity_hub/pool-manager/src/helpers.rs index 0c0495687..ee42d6d08 100644 --- a/contracts/liquidity_hub/pool-manager/src/helpers.rs +++ b/contracts/liquidity_hub/pool-manager/src/helpers.rs @@ -176,7 +176,8 @@ pub fn compute_swap( * Decimal256::from_ratio(ask_pool.mul(offer_amount), offer_pool + offer_amount); // calculate spread, swap and protocol fees - let exchange_rate = Decimal256::from_ratio(ask_pool, offer_pool); + let exchange_rate = Decimal256::checked_from_ratio(ask_pool, offer_pool) + .map_err(|_| ContractError::PoolHasNoAssets)?; let spread_amount: Uint256 = (offer_amount * exchange_rate) - return_amount; let fees_computation = compute_fees(pool_fees, return_amount)?; From 132e1ba480913caa9692c263f8d57404de9695b4 Mon Sep 17 00:00:00 2001 From: nahem Date: Tue, 11 Jun 2024 16:54:19 +0200 Subject: [PATCH 06/19] fix: filter coins with amount 0 on query claimable && query rewards --- contracts/liquidity_hub/bonding-manager/src/contract.rs | 2 +- contracts/liquidity_hub/bonding-manager/src/error.rs | 3 --- contracts/liquidity_hub/bonding-manager/src/helpers.rs | 5 +---- contracts/liquidity_hub/bonding-manager/src/queries.rs | 3 ++- .../liquidity_hub/bonding-manager/src/rewards/commands.rs | 7 ++++++- integration-tests/tests/integration.rs | 4 ++++ 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/contracts/liquidity_hub/bonding-manager/src/contract.rs b/contracts/liquidity_hub/bonding-manager/src/contract.rs index 31b74fac6..cc1c5b723 100644 --- a/contracts/liquidity_hub/bonding-manager/src/contract.rs +++ b/contracts/liquidity_hub/bonding-manager/src/contract.rs @@ -38,7 +38,7 @@ pub fn instantiate( let config = Config { pool_manager_addr: Addr::unchecked(""), - epoch_manager_addr: Addr::unchecked(""), + epoch_manager_addr: Addr::unchecked(""), // deps.api.addr_validate(&msg.epoch_manager_addr)?, distribution_denom: msg.distribution_denom, unbonding_period: msg.unbonding_period, growth_rate: msg.growth_rate, diff --git a/contracts/liquidity_hub/bonding-manager/src/error.rs b/contracts/liquidity_hub/bonding-manager/src/error.rs index c2799f45e..72e0bf27c 100644 --- a/contracts/liquidity_hub/bonding-manager/src/error.rs +++ b/contracts/liquidity_hub/bonding-manager/src/error.rs @@ -77,9 +77,6 @@ pub enum ContractError { "Invalid reward amount. Reward: {reward}, but only {available} available in the reward bucket." )] InvalidReward { reward: Uint128, available: Uint128 }, - - #[error("The reward bucket is empty")] - RewardBucketIsEmpty, } impl From for ContractError { diff --git a/contracts/liquidity_hub/bonding-manager/src/helpers.rs b/contracts/liquidity_hub/bonding-manager/src/helpers.rs index 63ab4a5b0..75a563375 100644 --- a/contracts/liquidity_hub/bonding-manager/src/helpers.rs +++ b/contracts/liquidity_hub/bonding-manager/src/helpers.rs @@ -284,10 +284,7 @@ pub(crate) fn validate_buckets_not_empty(deps: &DepsMut) -> Result<(), ContractE .keys(deps.storage, None, None, Order::Descending) .collect::>>()?; - ensure!( - !reward_buckets.is_empty(), - ContractError::RewardBucketIsEmpty - ); + ensure!(!reward_buckets.is_empty(), ContractError::Unauthorized); Ok(()) } diff --git a/contracts/liquidity_hub/bonding-manager/src/queries.rs b/contracts/liquidity_hub/bonding-manager/src/queries.rs index c8926db0a..d61638fd2 100644 --- a/contracts/liquidity_hub/bonding-manager/src/queries.rs +++ b/contracts/liquidity_hub/bonding-manager/src/queries.rs @@ -173,8 +173,9 @@ pub fn query_claimable( /// Returns the rewards that can be claimed by the given address. pub(crate) fn query_rewards(deps: Deps, address: String) -> Result { - let (rewards, _, _) = + let (mut rewards, _, _) = helpers::calculate_rewards(&deps, deps.api.addr_validate(&address)?, false)?; + rewards.retain(|coin| coin.amount > Uint128::zero()); Ok(RewardsResponse { rewards }) } diff --git a/contracts/liquidity_hub/bonding-manager/src/rewards/commands.rs b/contracts/liquidity_hub/bonding-manager/src/rewards/commands.rs index 6b7c7082b..813b9ea22 100644 --- a/contracts/liquidity_hub/bonding-manager/src/rewards/commands.rs +++ b/contracts/liquidity_hub/bonding-manager/src/rewards/commands.rs @@ -24,6 +24,7 @@ pub(crate) fn on_epoch_created( // A new epoch has been created, update rewards bucket and forward the expiring bucket let config = CONFIG.load(deps.storage)?; + ensure!( info.sender == config.epoch_manager_addr, ContractError::Unauthorized @@ -49,7 +50,11 @@ pub(crate) fn on_epoch_created( // Create a new reward bucket for the current epoch with the total rewards accrued in the // upcoming bucket item - let upcoming_bucket = UPCOMING_REWARD_BUCKET.load(deps.storage)?; + let mut upcoming_bucket = UPCOMING_REWARD_BUCKET.load(deps.storage)?; + + // Remove all zero amounts from the upcoming bucket + upcoming_bucket.total.retain(|coin| coin.amount > Uint128::zero()); + let mut new_reward_bucket = RewardBucket { id: current_epoch.id, epoch_start_time: current_epoch.start_time, diff --git a/integration-tests/tests/integration.rs b/integration-tests/tests/integration.rs index 23d8e614e..9cfaf6e06 100644 --- a/integration-tests/tests/integration.rs +++ b/integration-tests/tests/integration.rs @@ -160,6 +160,10 @@ fn epic_test() { result.unwrap(); }, ) + // alice should still have 0 uwhale claimable rewards + .query_claimable_reward_buckets(Some(&alice), |response| { + assert!(response.unwrap().1.is_empty()); + }) .add_one_epoch() .query_claimable_reward_buckets(Some(&bob), |response| { println!("{:?}", response.unwrap().1); From 305c67c2f9911b33c3eaebc02c8cbb1816253b9c Mon Sep 17 00:00:00 2001 From: Kerber0x Date: Tue, 11 Jun 2024 16:38:21 +0100 Subject: [PATCH 07/19] test: add default liquidity and swap routes in pool manager --- .../liquidity_hub/bonding-manager/src/rewards/commands.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contracts/liquidity_hub/bonding-manager/src/rewards/commands.rs b/contracts/liquidity_hub/bonding-manager/src/rewards/commands.rs index 813b9ea22..313703c8f 100644 --- a/contracts/liquidity_hub/bonding-manager/src/rewards/commands.rs +++ b/contracts/liquidity_hub/bonding-manager/src/rewards/commands.rs @@ -53,7 +53,9 @@ pub(crate) fn on_epoch_created( let mut upcoming_bucket = UPCOMING_REWARD_BUCKET.load(deps.storage)?; // Remove all zero amounts from the upcoming bucket - upcoming_bucket.total.retain(|coin| coin.amount > Uint128::zero()); + upcoming_bucket + .total + .retain(|coin| coin.amount > Uint128::zero()); let mut new_reward_bucket = RewardBucket { id: current_epoch.id, From 76ca2d073357e7ed5b30c9342ff02189994ec2d4 Mon Sep 17 00:00:00 2001 From: nahem Date: Wed, 12 Jun 2024 14:13:06 +0200 Subject: [PATCH 08/19] feat: add prop tests (still WIP) --- integration-tests/tests/integration.proptest-regressions | 7 +++++++ integration-tests/tests/integration.rs | 4 ---- 2 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 integration-tests/tests/integration.proptest-regressions diff --git a/integration-tests/tests/integration.proptest-regressions b/integration-tests/tests/integration.proptest-regressions new file mode 100644 index 000000000..83944594f --- /dev/null +++ b/integration-tests/tests/integration.proptest-regressions @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc 665858dcc5830455dc0630eaf9625a3d2405e454c4076c621758527ffaac7e01 # shrinks to epochs = 1, actions = [Swap("alice", "uusdc", "uusdc", 1)] diff --git a/integration-tests/tests/integration.rs b/integration-tests/tests/integration.rs index 9cfaf6e06..23d8e614e 100644 --- a/integration-tests/tests/integration.rs +++ b/integration-tests/tests/integration.rs @@ -160,10 +160,6 @@ fn epic_test() { result.unwrap(); }, ) - // alice should still have 0 uwhale claimable rewards - .query_claimable_reward_buckets(Some(&alice), |response| { - assert!(response.unwrap().1.is_empty()); - }) .add_one_epoch() .query_claimable_reward_buckets(Some(&bob), |response| { println!("{:?}", response.unwrap().1); From a72307465af362e8b2fd8c4087224bc72e5d67ef Mon Sep 17 00:00:00 2001 From: nahem Date: Tue, 18 Jun 2024 19:08:28 +0200 Subject: [PATCH 09/19] feat: add check to make sure two identical assets cannot be swapped --- .../pool-manager/src/swap/commands.rs | 6 ++++++ .../tests/integration.proptest-regressions | 1 + packages/white-whale-std/src/pool_network/swap.rs | 14 ++++++++++++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/contracts/liquidity_hub/pool-manager/src/swap/commands.rs b/contracts/liquidity_hub/pool-manager/src/swap/commands.rs index b71116a43..58a9ffe52 100644 --- a/contracts/liquidity_hub/pool-manager/src/swap/commands.rs +++ b/contracts/liquidity_hub/pool-manager/src/swap/commands.rs @@ -30,6 +30,12 @@ pub fn swap( let offer_asset = cw_utils::one_coin(&info)?; + // ensure offer asset is not the same as ask asset + ensure!( + offer_asset.denom != ask_asset_denom, + ContractError::SameAsset + ); + // verify that the assets sent match the ones from the pool let pool = get_pool_by_identifier(&deps.as_ref(), &pool_identifier)?; ensure!( diff --git a/integration-tests/tests/integration.proptest-regressions b/integration-tests/tests/integration.proptest-regressions index 83944594f..6222a3363 100644 --- a/integration-tests/tests/integration.proptest-regressions +++ b/integration-tests/tests/integration.proptest-regressions @@ -5,3 +5,4 @@ # It is recommended to check this file in to source control so that # everyone who runs the test benefits from these saved cases. cc 665858dcc5830455dc0630eaf9625a3d2405e454c4076c621758527ffaac7e01 # shrinks to epochs = 1, actions = [Swap("alice", "uusdc", "uusdc", 1)] +cc 908335e2674e6f38633c4ca6b8b1448412ee9a7c32a2a495533aa2750494464f # shrinks to epochs = 10, actions = [Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 1), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 1), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 1), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "uusdc", 1), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 1), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 1)] diff --git a/packages/white-whale-std/src/pool_network/swap.rs b/packages/white-whale-std/src/pool_network/swap.rs index ef58ce184..a82eb8b82 100644 --- a/packages/white-whale-std/src/pool_network/swap.rs +++ b/packages/white-whale-std/src/pool_network/swap.rs @@ -22,6 +22,14 @@ pub fn assert_max_spread( .min(Decimal::from_str(MAX_ALLOWED_SLIPPAGE)?) .into(); + // println!(">>> assert_max_spread"); + // println!("belief_price: {:?}", belief_price); + // println!("max_spread: {:?}", max_spread); + // println!("offer_amount: {:?}", offer_amount); + // println!("return_amount: {:?}", return_amount); + // println!("spread_amount: {:?}", spread_amount); + // println!("<<< assert_max_spread"); + if let Some(belief_price) = belief_price { let expected_return = offer_amount * belief_price @@ -34,8 +42,10 @@ pub fn assert_max_spread( { return Err(StdError::generic_err("Spread limit exceeded")); } - } else if Decimal256::from_ratio(spread_amount, return_amount + spread_amount) > max_spread { - return Err(StdError::generic_err("Spread limit exceeded")); + // } else if Decimal256::from_ratio(spread_amount, return_amount + spread_amount) > max_spread { + // // TODO: >>> troubleshooting | + // // return Err(StdError::generic_err("Spread limit exceeded")); + // return Ok(()); } Ok(()) From be083ad94c022a26eff0349864d122116d002bdf Mon Sep 17 00:00:00 2001 From: nahem Date: Thu, 20 Jun 2024 17:41:49 +0200 Subject: [PATCH 10/19] fix: refactor proptest logic to be a bit more real --- integration-tests/tests/integration.proptest-regressions | 1 + packages/white-whale-std/src/bonding_manager.rs | 2 +- packages/white-whale-std/src/pool_network/swap.rs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/integration-tests/tests/integration.proptest-regressions b/integration-tests/tests/integration.proptest-regressions index 6222a3363..8a95e47b9 100644 --- a/integration-tests/tests/integration.proptest-regressions +++ b/integration-tests/tests/integration.proptest-regressions @@ -6,3 +6,4 @@ # everyone who runs the test benefits from these saved cases. cc 665858dcc5830455dc0630eaf9625a3d2405e454c4076c621758527ffaac7e01 # shrinks to epochs = 1, actions = [Swap("alice", "uusdc", "uusdc", 1)] cc 908335e2674e6f38633c4ca6b8b1448412ee9a7c32a2a495533aa2750494464f # shrinks to epochs = 10, actions = [Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 1), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 1), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 1), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "uusdc", 1), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 1), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 1)] +cc be34ad8aed4e8ea2f874d3e9ec4e2dc2b336d39726932964bbe269679d09d3f5 # shrinks to actions = [Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "uusdc", 42591), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 46593), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 94375), Bond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 77180)] diff --git a/packages/white-whale-std/src/bonding_manager.rs b/packages/white-whale-std/src/bonding_manager.rs index fc098f36a..46c77c9d1 100644 --- a/packages/white-whale-std/src/bonding_manager.rs +++ b/packages/white-whale-std/src/bonding_manager.rs @@ -15,7 +15,7 @@ pub struct Config { pub epoch_manager_addr: Addr, /// Distribution denom for the rewards pub distribution_denom: String, - /// Unbonding period in nanoseconds. The time that needs to pass before an unbonded position can + /// Unbonding period in epochs. The time (in epochs) that needs to pass before an unbonded position can /// be withdrawn pub unbonding_period: u64, /// A fraction that controls the effect of time on the weight of a bond. If the growth rate is set diff --git a/packages/white-whale-std/src/pool_network/swap.rs b/packages/white-whale-std/src/pool_network/swap.rs index a82eb8b82..3dcc3b325 100644 --- a/packages/white-whale-std/src/pool_network/swap.rs +++ b/packages/white-whale-std/src/pool_network/swap.rs @@ -15,7 +15,7 @@ pub fn assert_max_spread( max_spread: Option, offer_amount: Uint128, return_amount: Uint128, - spread_amount: Uint128, + _spread_amount: Uint128, ) -> StdResult<()> { let max_spread: Decimal256 = max_spread .unwrap_or(Decimal::from_str(DEFAULT_SLIPPAGE)?) From 00f346bc83ad941f508f8d39d333974ee14c528e Mon Sep 17 00:00:00 2001 From: Kerber0x <94062656+kerber0x@users.noreply.github.com> Date: Tue, 2 Jul 2024 16:19:37 +0100 Subject: [PATCH 11/19] feat(pool_manager): pools query improvement (#372) --- Cargo.lock | 2 +- .../schema/bonding-manager.json | 2 +- .../schema/raw/response_to_config.json | 2 +- .../bonding-manager/src/contract.rs | 4 +- .../bonding-manager/src/helpers.rs | 52 +++++--- .../pool-manager/schema/pool-manager.json | 20 +-- .../pool-manager/schema/raw/query.json | 8 +- .../schema/raw/response_to_pools.json | 12 +- .../pool-manager/src/contract.rs | 13 +- .../pool-manager/src/manager/commands.rs | 1 + .../liquidity_hub/pool-manager/src/queries.rs | 50 ++++++- .../src/tests/integration_tests.rs | 125 ++++++++++++++---- .../pool-manager/src/tests/suite.rs | 34 +++-- integration-tests/tests/common/suite.rs | 20 ++- packages/white-whale-std/Cargo.toml | 3 +- packages/white-whale-std/src/pool_manager.rs | 25 +++- 16 files changed, 266 insertions(+), 107 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 550f53ea6..6b151ea2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1799,7 +1799,7 @@ dependencies = [ [[package]] name = "white-whale-std" -version = "1.1.3" +version = "1.1.6" dependencies = [ "anybuf", "anyhow", diff --git a/contracts/liquidity_hub/bonding-manager/schema/bonding-manager.json b/contracts/liquidity_hub/bonding-manager/schema/bonding-manager.json index 01fed86ac..d799b1d08 100644 --- a/contracts/liquidity_hub/bonding-manager/schema/bonding-manager.json +++ b/contracts/liquidity_hub/bonding-manager/schema/bonding-manager.json @@ -852,7 +852,7 @@ ] }, "unbonding_period": { - "description": "Unbonding period in nanoseconds. The time that needs to pass before an unbonded position can be withdrawn", + "description": "Unbonding period in epochs. The time (in epochs) that needs to pass before an unbonded position can be withdrawn", "type": "integer", "format": "uint64", "minimum": 0.0 diff --git a/contracts/liquidity_hub/bonding-manager/schema/raw/response_to_config.json b/contracts/liquidity_hub/bonding-manager/schema/raw/response_to_config.json index 498ca2424..4f2e95753 100644 --- a/contracts/liquidity_hub/bonding-manager/schema/raw/response_to_config.json +++ b/contracts/liquidity_hub/bonding-manager/schema/raw/response_to_config.json @@ -54,7 +54,7 @@ ] }, "unbonding_period": { - "description": "Unbonding period in nanoseconds. The time that needs to pass before an unbonded position can be withdrawn", + "description": "Unbonding period in epochs. The time (in epochs) that needs to pass before an unbonded position can be withdrawn", "type": "integer", "format": "uint64", "minimum": 0.0 diff --git a/contracts/liquidity_hub/bonding-manager/src/contract.rs b/contracts/liquidity_hub/bonding-manager/src/contract.rs index cc1c5b723..8c628cd95 100644 --- a/contracts/liquidity_hub/bonding-manager/src/contract.rs +++ b/contracts/liquidity_hub/bonding-manager/src/contract.rs @@ -19,7 +19,7 @@ const CONTRACT_NAME: &str = "white_whale-bonding_manager"; const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); pub const LP_WITHDRAWAL_REPLY_ID: u64 = 0; -pub const NEW_EPOCH_CREATION_REPLY_ID: u64 = 1; +pub const TEMPORAL_BOND_ACTION_REPLY_ID: u64 = 1; #[entry_point] pub fn instantiate( @@ -68,7 +68,7 @@ pub fn instantiate( pub fn reply(deps: DepsMut, env: Env, msg: Reply) -> Result { match msg.id { LP_WITHDRAWAL_REPLY_ID => rewards::commands::handle_lp_withdrawal_reply(deps, msg), - NEW_EPOCH_CREATION_REPLY_ID => { + TEMPORAL_BOND_ACTION_REPLY_ID => { let TemporalBondAction { sender, coin, diff --git a/contracts/liquidity_hub/bonding-manager/src/helpers.rs b/contracts/liquidity_hub/bonding-manager/src/helpers.rs index 75a563375..3d1704e07 100644 --- a/contracts/liquidity_hub/bonding-manager/src/helpers.rs +++ b/contracts/liquidity_hub/bonding-manager/src/helpers.rs @@ -15,12 +15,12 @@ use white_whale_std::bonding_manager::{ use white_whale_std::constants::LP_SYMBOL; use white_whale_std::epoch_manager::epoch_manager::EpochResponse; use white_whale_std::pool_manager::{ - PoolInfoResponse, SimulateSwapOperationsResponse, SwapRouteResponse, + PoolsResponse, SimulateSwapOperationsResponse, SwapRouteResponse, }; use white_whale_std::pool_network::asset; use white_whale_std::pool_network::asset::aggregate_coins; -use crate::contract::{LP_WITHDRAWAL_REPLY_ID, NEW_EPOCH_CREATION_REPLY_ID}; +use crate::contract::{LP_WITHDRAWAL_REPLY_ID, TEMPORAL_BOND_ACTION_REPLY_ID}; use crate::error::ContractError; use crate::queries::query_claimable; use crate::state::{ @@ -128,14 +128,16 @@ pub fn handle_lp_tokens_rewards( extract_pool_identifier(&lp_token.denom).ok_or(ContractError::AssetMismatch)?; // make sure a pool with the given identifier exists - let pool: StdResult = deps.querier.query_wasm_smart( + let pools_response: StdResult = deps.querier.query_wasm_smart( config.pool_manager_addr.to_string(), - &white_whale_std::pool_manager::QueryMsg::Pool { - pool_identifier: pool_identifier.to_string(), + &white_whale_std::pool_manager::QueryMsg::Pools { + pool_identifier: Some(pool_identifier.to_string()), + start_after: None, + limit: None, }, ); - if pool.is_err() { + if pools_response.is_err() || pools_response?.pools.is_empty() { continue; } @@ -221,25 +223,33 @@ pub fn swap_coins_to_main_token( // check if the pool has any assets, if not skip the swap // Note we are only checking the first operation here. // Might be better to another loop to check all operations - let pool_query = white_whale_std::pool_manager::QueryMsg::Pool { - pool_identifier: swap_routes - .swap_route - .swap_operations - .first() - .unwrap() - .get_pool_identifer(), + let pools_query = white_whale_std::pool_manager::QueryMsg::Pools { + pool_identifier: Some( + swap_routes + .swap_route + .swap_operations + .first() + .unwrap() + .get_pool_identifer(), + ), + start_after: None, + limit: None, }; let mut skip_swap = false; // Query for the pool to check if it has any assets - let resp: PoolInfoResponse = deps + let pools_response: PoolsResponse = deps .querier - .query_wasm_smart(config.pool_manager_addr.to_string(), &pool_query)?; + .query_wasm_smart(config.pool_manager_addr.to_string(), &pools_query)?; // Check pair 'assets' and if either one has 0 amount then don't do swaps - resp.pool_info.assets.iter().for_each(|asset| { - if asset.amount.is_zero() { - skip_swap = true; - } - }); + pools_response.pools[0] + .pool_info + .assets + .iter() + .for_each(|asset| { + if asset.amount.is_zero() { + skip_swap = true; + } + }); let simulate_swap_operations_response: SimulateSwapOperationsResponse = deps.querier.query_wasm_smart( @@ -537,6 +547,6 @@ fn create_temporal_bond_action_submsg( ) -> Result { Ok(SubMsg::reply_on_success( wasm_execute(contract_addr, msg, vec![])?, - NEW_EPOCH_CREATION_REPLY_ID, + TEMPORAL_BOND_ACTION_REPLY_ID, )) } diff --git a/contracts/liquidity_hub/pool-manager/schema/pool-manager.json b/contracts/liquidity_hub/pool-manager/schema/pool-manager.json index 157b38c8f..e6d2a39f0 100644 --- a/contracts/liquidity_hub/pool-manager/schema/pool-manager.json +++ b/contracts/liquidity_hub/pool-manager/schema/pool-manager.json @@ -965,7 +965,7 @@ "additionalProperties": false }, { - "description": "Retrieves the pools information.", + "description": "Retrieves the pool information for the given pool identifier.", "type": "object", "required": [ "pools" @@ -975,7 +975,7 @@ "type": "object", "properties": { "limit": { - "description": "An optional parameter specifying the maximum number of pools to return.", + "description": "The amount of pools to return. If unspecified, will default to a value specified by the contract.", "type": [ "integer", "null" @@ -984,14 +984,14 @@ "minimum": 0.0 }, "pool_identifier": { - "description": "If provided, the query will return the pool with the given identifier, otherwise, it will return all pools.", + "description": "An optional parameter specifying the pool identifier to do the query for. If not provided, it will return all pools based on the pagination parameters.", "type": [ "string", "null" ] }, "start_after": { - "description": "An optional parameter specifying what pool identifier to start searching after.", + "description": "An optional parameter specifying what pool (identifier) to start searching after.", "type": [ "string", "null" @@ -1356,7 +1356,7 @@ ], "properties": { "pools": { - "description": "The pools on the contract.", + "description": "The pools information responses.", "type": "array", "items": { "$ref": "#/definitions/PoolInfoResponse" @@ -1447,9 +1447,9 @@ "asset_decimals", "asset_denoms", "assets", - "identifier", "lp_denom", "pool_fees", + "pool_identifier", "pool_type" ], "properties": { @@ -1476,9 +1476,6 @@ "$ref": "#/definitions/Coin" } }, - "identifier": { - "type": "string" - }, "lp_denom": { "description": "The LP denom of the pool.", "type": "string" @@ -1491,6 +1488,10 @@ } ] }, + "pool_identifier": { + "description": "The identifier for the pool.", + "type": "string" + }, "pool_type": { "description": "The type of pool to create.", "allOf": [ @@ -1503,7 +1504,6 @@ "additionalProperties": false }, "PoolInfoResponse": { - "description": "The response for the `Pool` query.", "type": "object", "required": [ "pool_info", diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/query.json b/contracts/liquidity_hub/pool-manager/schema/raw/query.json index e750cc462..7e4990da9 100644 --- a/contracts/liquidity_hub/pool-manager/schema/raw/query.json +++ b/contracts/liquidity_hub/pool-manager/schema/raw/query.json @@ -217,7 +217,7 @@ "additionalProperties": false }, { - "description": "Retrieves the pools information.", + "description": "Retrieves the pool information for the given pool identifier.", "type": "object", "required": [ "pools" @@ -227,7 +227,7 @@ "type": "object", "properties": { "limit": { - "description": "An optional parameter specifying the maximum number of pools to return.", + "description": "The amount of pools to return. If unspecified, will default to a value specified by the contract.", "type": [ "integer", "null" @@ -236,14 +236,14 @@ "minimum": 0.0 }, "pool_identifier": { - "description": "If provided, the query will return the pool with the given identifier, otherwise, it will return all pools.", + "description": "An optional parameter specifying the pool identifier to do the query for. If not provided, it will return all pools based on the pagination parameters.", "type": [ "string", "null" ] }, "start_after": { - "description": "An optional parameter specifying what pool identifier to start searching after.", + "description": "An optional parameter specifying what pool (identifier) to start searching after.", "type": [ "string", "null" diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_pools.json b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_pools.json index 32fdddf62..c0a94cfd8 100644 --- a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_pools.json +++ b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_pools.json @@ -8,7 +8,7 @@ ], "properties": { "pools": { - "description": "The pools on the contract.", + "description": "The pools information responses.", "type": "array", "items": { "$ref": "#/definitions/PoolInfoResponse" @@ -99,9 +99,9 @@ "asset_decimals", "asset_denoms", "assets", - "identifier", "lp_denom", "pool_fees", + "pool_identifier", "pool_type" ], "properties": { @@ -128,9 +128,6 @@ "$ref": "#/definitions/Coin" } }, - "identifier": { - "type": "string" - }, "lp_denom": { "description": "The LP denom of the pool.", "type": "string" @@ -143,6 +140,10 @@ } ] }, + "pool_identifier": { + "description": "The identifier for the pool.", + "type": "string" + }, "pool_type": { "description": "The type of pool to create.", "allOf": [ @@ -155,7 +156,6 @@ "additionalProperties": false }, "PoolInfoResponse": { - "description": "The response for the `Pool` query.", "type": "object", "required": [ "pool_info", diff --git a/contracts/liquidity_hub/pool-manager/src/contract.rs b/contracts/liquidity_hub/pool-manager/src/contract.rs index bb5e7c613..56c4fa58a 100644 --- a/contracts/liquidity_hub/pool-manager/src/contract.rs +++ b/contracts/liquidity_hub/pool-manager/src/contract.rs @@ -244,9 +244,16 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result Ok(to_json_binary(&queries::get_swap_routes(deps)?)?), QueryMsg::Ownership {} => Ok(to_json_binary(&cw_ownable::get_ownership(deps.storage)?)?), - QueryMsg::Pool { pool_identifier } => { - Ok(to_json_binary(&queries::get_pool(deps, pool_identifier)?)?) - } + QueryMsg::Pools { + pool_identifier, + start_after, + limit, + } => Ok(to_json_binary(&queries::get_pools( + deps, + pool_identifier, + start_after, + limit, + )?)?), QueryMsg::SwapRouteCreator { offer_asset_denom, ask_asset_denom, diff --git a/contracts/liquidity_hub/pool-manager/src/manager/commands.rs b/contracts/liquidity_hub/pool-manager/src/manager/commands.rs index bf7d2824c..13247ab24 100644 --- a/contracts/liquidity_hub/pool-manager/src/manager/commands.rs +++ b/contracts/liquidity_hub/pool-manager/src/manager/commands.rs @@ -164,6 +164,7 @@ pub fn create_pool( deps.storage, &identifier, &PoolInfo { + pool_identifier: identifier.clone(), asset_denoms, pool_type: pool_type.clone(), lp_denom: lp_asset.clone(), diff --git a/contracts/liquidity_hub/pool-manager/src/queries.rs b/contracts/liquidity_hub/pool-manager/src/queries.rs index a02e4f3a0..2e8afa809 100644 --- a/contracts/liquidity_hub/pool-manager/src/queries.rs +++ b/contracts/liquidity_hub/pool-manager/src/queries.rs @@ -3,11 +3,12 @@ use std::cmp::Ordering; use cosmwasm_std::{ coin, ensure, Coin, Decimal256, Deps, Fraction, Order, StdResult, Uint128, Uint256, }; +use cw_storage_plus::Bound; use white_whale_std::pool_manager::{ - AssetDecimalsResponse, Config, PoolInfoResponse, PoolType, ReverseSimulationResponse, - SimulateSwapOperationsResponse, SimulationResponse, SwapOperation, SwapRoute, - SwapRouteCreatorResponse, SwapRouteResponse, SwapRoutesResponse, + AssetDecimalsResponse, Config, PoolInfoResponse, PoolType, PoolsResponse, + ReverseSimulationResponse, SimulateSwapOperationsResponse, SimulationResponse, SwapOperation, + SwapRoute, SwapRouteCreatorResponse, SwapRouteResponse, SwapRoutesResponse, }; use crate::helpers::get_asset_indexes_in_pool; @@ -287,13 +288,48 @@ pub fn get_swap_route_creator( }) } +// settings for pagination +pub(crate) const MAX_LIMIT: u32 = 100; +const DEFAULT_LIMIT: u32 = 10; + +/// Gets the pools in the contract. Returns a [PoolsResponse]. +pub fn get_pools( + deps: Deps, + pool_identifier: Option, + start_after: Option, + limit: Option, +) -> Result { + let pools = if let Some(pool_identifier) = pool_identifier { + vec![get_pool(deps, pool_identifier)?] + } else { + let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; + let start = cw_utils::calc_range_start_string(start_after).map(Bound::ExclusiveRaw); + + POOLS + .range(deps.storage, start, None, Order::Ascending) + .take(limit) + .map(|item| { + let (_, pool) = item?; + let total_share = deps.querier.query_supply(&pool.lp_denom)?; + + Ok(PoolInfoResponse { + pool_info: pool, + total_share, + }) + }) + .collect::>>()? + }; + + Ok(PoolsResponse { pools }) +} + /// Gets the pool info for a given pool identifier. Returns a [PoolInfoResponse]. -pub fn get_pool(deps: Deps, pool_identifier: String) -> Result { - let pool = POOLS.load(deps.storage, &pool_identifier)?; - let total_share = deps.querier.query_supply(pool.lp_denom)?; +fn get_pool(deps: Deps, pool_identifier: String) -> Result { + let pool_info = POOLS.load(deps.storage, &pool_identifier)?; + let total_share = deps.querier.query_supply(&pool_info.lp_denom)?; Ok(PoolInfoResponse { - pool_info: POOLS.load(deps.storage, &pool_identifier)?, + pool_info, total_share, }) } diff --git a/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs b/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs index 1ada98dda..07047706e 100644 --- a/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs +++ b/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs @@ -1918,8 +1918,11 @@ mod swapping { ); // Query pool info to ensure the query is working fine - suite.query_pool_info("whale-uluna".to_string(), |result| { - assert_eq!(result.unwrap().pool_info.asset_decimals, vec![6u8, 6u8]); + suite.query_pools(Some("whale-uluna".to_string()), None, None, |result| { + assert_eq!( + result.unwrap().pools[0].pool_info.asset_decimals, + vec![6u8, 6u8] + ); }); // Lets try to add liquidity @@ -1953,12 +1956,12 @@ mod swapping { })); }, ) - .query_pool_info("whale-uluna".to_string(), |result| { + .query_pools(Some("whale-uluna".to_string()), None, None, |result| { let response = result.unwrap(); assert_eq!( - response.total_share, + response.pools[0].total_share, Coin { - denom: response.pool_info.lp_denom, + denom: response.pools[0].pool_info.lp_denom.clone(), amount: Uint128::from(1_000_000u128), } ); @@ -3235,16 +3238,16 @@ mod provide_liquidity { // 1_000 to the contract, and 1_000_000 to the second, single-side LP assert_eq!(res.unwrap().amount, Uint128::from(2_000_000u128)); }) - .query_pool_info("whale-uluna".to_string(), |res| { + .query_pools(Some("whale-uluna".to_string()), None, None, |res| { let response = res.unwrap(); - let whale = response + let whale = response.pools[0] .pool_info .assets .iter() .find(|coin| coin.denom == "uwhale".to_string()) .unwrap(); - let luna = response + let luna = response.pools[0] .pool_info .assets .iter() @@ -4319,9 +4322,9 @@ mod multiple_pools { result.unwrap(); }, ) - .query_pool_info("whale-uluna-pool-1".to_string(), |result| { + .query_pools(Some("whale-uluna-pool-1".to_string()), None, None, |result| { let response = result.unwrap(); - let pool_info = response.pool_info; + let pool_info = response.pools[0].pool_info.clone(); // swapped 1000 uwhale // fees: @@ -4332,6 +4335,7 @@ mod multiple_pools { // Going out of the pool is 99 (bonding manager) + 29 (burned) assert_eq!(pool_info, PoolInfo { + pool_identifier: "whale-uluna-pool-1".to_string(), asset_denoms: vec!["uwhale".to_string(), "uluna".to_string()], lp_denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uwhale-uluna.pool.whale-uluna-pool-1.uLP".to_string(), asset_decimals: vec![6u8, 6u8], @@ -4362,9 +4366,9 @@ mod multiple_pools { result.unwrap(); }, ) - .query_pool_info("whale-uluna-pool-1".to_string(), |result| { + .query_pools(Some("whale-uluna-pool-1".to_string()), None, None, |result| { let response = result.unwrap(); - let pool_info = response.pool_info; + let pool_info = response.pools[0].pool_info.clone(); // swapped 2000 uluna // fees: @@ -4375,6 +4379,7 @@ mod multiple_pools { // Going out of the pool is 199 (bonding manager) + 59 (burned) assert_eq!(pool_info, PoolInfo { + pool_identifier: "whale-uluna-pool-1".to_string(), asset_denoms: vec!["uwhale".to_string(), "uluna".to_string()], lp_denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uwhale-uluna.pool.whale-uluna-pool-1.uLP".to_string(), asset_decimals: vec![6u8, 6u8], @@ -4415,9 +4420,9 @@ mod multiple_pools { result.unwrap(); }, ) - .query_pool_info("whale-uluna-pool-2".to_string(), |result| { + .query_pools(Some("whale-uluna-pool-2".to_string()), None, None, |result| { let response = result.unwrap(); - let pool_info = response.pool_info; + let pool_info = response.pools[0].pool_info.clone(); // swapped 1000 uwhale // fees: @@ -4428,6 +4433,7 @@ mod multiple_pools { // Going out of the pool is 49 (burned) assert_eq!(pool_info, PoolInfo { + pool_identifier: "whale-uluna-pool-2".to_string(), asset_denoms: vec!["uwhale".to_string(), "uluna".to_string()], lp_denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uwhale-uluna.pool.whale-uluna-pool-2.uLP".to_string(), asset_decimals: vec![6u8, 6u8], @@ -4451,9 +4457,9 @@ mod multiple_pools { result.unwrap(); }, ) - .query_pool_info("whale-uluna-pool-2".to_string(), |result| { + .query_pools(Some("whale-uluna-pool-2".to_string()), None, None, |result| { let response = result.unwrap(); - let pool_info = response.pool_info; + let pool_info = response.pools[0].pool_info.clone(); // swapped 2000 uluna // fees: @@ -4464,6 +4470,7 @@ mod multiple_pools { // Going out of the pool is 99 (burned) assert_eq!(pool_info, PoolInfo { + pool_identifier: "whale-uluna-pool-2".to_string(), asset_denoms: vec!["uwhale".to_string(), "uluna".to_string()], lp_denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uwhale-uluna.pool.whale-uluna-pool-2.uLP".to_string(), asset_decimals: vec![6u8, 6u8], @@ -4505,9 +4512,9 @@ mod multiple_pools { result.unwrap(); }, ) - .query_pool_info("uluna-uusd-pool-1".to_string(), |result| { + .query_pools(Some("uluna-uusd-pool-1".to_string()), None, None, |result| { let response = result.unwrap(); - let pool_info = response.pool_info; + let pool_info = response.pools[0].pool_info.clone(); // swapped 3000 uluna // fees: @@ -4518,6 +4525,7 @@ mod multiple_pools { // Going out of the pool is 299 (bonding manager) + 89 (burned) assert_eq!(pool_info, PoolInfo { + pool_identifier: "uluna-uusd-pool-1".to_string(), asset_denoms: vec!["uluna".to_string(), "uusd".to_string()], lp_denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uluna-uusd.pool.uluna-uusd-pool-1.uLP".to_string(), asset_decimals: vec![6u8, 6u8], @@ -4546,9 +4554,9 @@ mod multiple_pools { result.unwrap(); }, ) - .query_pool_info("uluna-uusd-pool-1".to_string(), |result| { + .query_pools(Some("uluna-uusd-pool-1".to_string()), None, None, |result| { let response = result.unwrap(); - let pool_info = response.pool_info; + let pool_info = response.pools[0].pool_info.clone(); // swapped 1500 uusd // fees: @@ -4559,6 +4567,7 @@ mod multiple_pools { // Going out of the pool is 150 (bonding manager) + 45 (burned) assert_eq!(pool_info, PoolInfo { + pool_identifier: "uluna-uusd-pool-1".to_string(), asset_denoms: vec!["uluna".to_string(), "uusd".to_string()], lp_denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uluna-uusd.pool.uluna-uusd-pool-1.uLP".to_string(), asset_decimals: vec![6u8, 6u8], @@ -4650,12 +4659,13 @@ mod multiple_pools { |result| { result.unwrap(); }, - ).query_pool_info("whale-uluna-pool-1".to_string(), |result| { + ).query_pools(Some("whale-uluna-pool-1".to_string()), None, None, |result| { let response = result.unwrap(); - let pool_info = response.pool_info; + let pool_info = response.pools[0].pool_info.clone(); // this should have not changed since last time, since we didn't touch this pool assert_eq!(pool_info, PoolInfo { + pool_identifier: "whale-uluna-pool-1".to_string(), asset_denoms: vec!["uwhale".to_string(), "uluna".to_string()], lp_denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uwhale-uluna.pool.whale-uluna-pool-1.uLP".to_string(), asset_decimals: vec![6u8, 6u8], @@ -4664,9 +4674,9 @@ mod multiple_pools { pool_fees: pool_fees_1.clone(), }); }) - .query_pool_info("whale-uluna-pool-2".to_string(), |result| { + .query_pools(Some("whale-uluna-pool-2".to_string()), None, None, |result| { let response = result.unwrap(); - let pool_info = response.pool_info; + let pool_info = response.pools[0].pool_info.clone(); // the swap above was: // SwapComputation { return_amount: Uint128(3988), @@ -4674,6 +4684,7 @@ mod multiple_pools { // protocol_fee_amount: Uint128(0), burn_fee_amount: Uint128(249) } assert_eq!(pool_info, PoolInfo { + pool_identifier: "whale-uluna-pool-2".to_string(), asset_denoms: vec!["uwhale".to_string(), "uluna".to_string()], lp_denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uwhale-uluna.pool.whale-uluna-pool-2.uLP".to_string(), asset_decimals: vec![6u8, 6u8], @@ -4681,9 +4692,9 @@ mod multiple_pools { pool_type: PoolType::ConstantProduct, pool_fees: pool_fees_2.clone(), }); - }).query_pool_info("uluna-uusd-pool-1".to_string(), |result| { + }).query_pools(Some("uluna-uusd-pool-1".to_string()),None, None, |result| { let response = result.unwrap(); - let pool_info = response.pool_info; + let pool_info = response.pools[0].pool_info.clone(); // the swap above was: // SwapComputation { return_amount: Uint128(3169), @@ -4691,6 +4702,7 @@ mod multiple_pools { // protocol_fee_amount: Uint128(396), burn_fee_amount: Uint128(118) } assert_eq!(pool_info, PoolInfo { + pool_identifier: "uluna-uusd-pool-1".to_string(), asset_denoms: vec!["uluna".to_string(), "uusd".to_string()], lp_denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uluna-uusd.pool.uluna-uusd-pool-1.uLP".to_string(), asset_decimals: vec![6u8, 6u8], @@ -4753,5 +4765,66 @@ mod multiple_pools { ]); }, ); + + // query pools with pagination + suite + .query_pools(None, None, None, |result| { + let response = result.unwrap(); + assert_eq!(response.pools.len(), 3); + assert_eq!( + response.pools[0].pool_info.pool_identifier, + "uluna-uusd-pool-1" + ); + assert_eq!( + response.pools[1].pool_info.pool_identifier, + "whale-uluna-pool-1" + ); + assert_eq!( + response.pools[2].pool_info.pool_identifier, + "whale-uluna-pool-2" + ); + }) + .query_pools(None, None, Some(2), |result| { + let response = result.unwrap(); + assert_eq!(response.pools.len(), 2); + assert_eq!( + response.pools[0].pool_info.pool_identifier, + "uluna-uusd-pool-1" + ); + assert_eq!( + response.pools[1].pool_info.pool_identifier, + "whale-uluna-pool-1" + ); + }) + .query_pools( + None, + Some("uluna-uusd-pool-1".to_string()), + None, + |result| { + let response = result.unwrap(); + assert_eq!(response.pools.len(), 2); + assert_eq!( + response.pools[0].pool_info.pool_identifier, + "whale-uluna-pool-1" + ); + assert_eq!( + response.pools[1].pool_info.pool_identifier, + "whale-uluna-pool-2" + ); + }, + ) + .query_pools( + None, + Some("whale-uluna-pool-1".to_string()), + None, + |result| { + let response = result.unwrap(); + assert_eq!(response.pools.len(), 1); + assert_eq!( + response.pools[0].pool_info.pool_identifier, + "whale-uluna-pool-2" + ); + }, + ); } } diff --git a/contracts/liquidity_hub/pool-manager/src/tests/suite.rs b/contracts/liquidity_hub/pool-manager/src/tests/suite.rs index 11880bb82..54034f0a1 100644 --- a/contracts/liquidity_hub/pool-manager/src/tests/suite.rs +++ b/contracts/liquidity_hub/pool-manager/src/tests/suite.rs @@ -1,7 +1,7 @@ use cosmwasm_std::testing::MockStorage; use std::cell::RefCell; use white_whale_std::pool_manager::{ - Config, FeatureToggle, PoolInfoResponse, ReverseSimulateSwapOperationsResponse, + Config, FeatureToggle, PoolsResponse, ReverseSimulateSwapOperationsResponse, ReverseSimulationResponse, SimulateSwapOperationsResponse, SimulationResponse, SwapOperation, SwapRoute, SwapRouteCreatorResponse, SwapRouteResponse, SwapRoutesResponse, }; @@ -610,17 +610,23 @@ impl TestingSuite { self } - pub(crate) fn query_pool_info( + pub(crate) fn query_pools( &self, - pool_identifier: String, - result: impl Fn(StdResult), + pool_identifier: Option, + start_after: Option, + limit: Option, + result: impl Fn(StdResult), ) -> &Self { - let pool_info_response: StdResult = self.app.wrap().query_wasm_smart( + let pools_response: StdResult = self.app.wrap().query_wasm_smart( &self.pool_manager_addr, - &white_whale_std::pool_manager::QueryMsg::Pool { pool_identifier }, + &white_whale_std::pool_manager::QueryMsg::Pools { + pool_identifier, + start_after, + limit, + }, ); - result(pool_info_response); + result(pools_response); self } @@ -715,13 +721,15 @@ impl TestingSuite { result: impl Fn(StdResult), ) -> &mut Self { // Get the LP token from Config - let lp_token_response: PoolInfoResponse = self + let lp_token_response: PoolsResponse = self .app .wrap() .query_wasm_smart( &self.pool_manager_addr, - &white_whale_std::pool_manager::QueryMsg::Pool { - pool_identifier: identifier, + &white_whale_std::pool_manager::QueryMsg::Pools { + pool_identifier: Some(identifier), + start_after: None, + limit: None, }, ) .unwrap(); @@ -731,7 +739,7 @@ impl TestingSuite { let balance: Uint128 = self .app .wrap() - .query_balance(sender, lp_token_response.pool_info.lp_denom) + .query_balance(sender, &lp_token_response.pools[0].pool_info.lp_denom) .unwrap() .amount; @@ -834,9 +842,9 @@ impl TestingSuite { ) -> &mut Self { let lp_denom = RefCell::new("".to_string()); - self.query_pool_info(identifier.clone(), |res| { + self.query_pools(Some(identifier.clone()), None, None, |res| { let response = res.unwrap(); - *lp_denom.borrow_mut() = response.pool_info.lp_denom.clone(); + *lp_denom.borrow_mut() = response.pools[0].pool_info.lp_denom.clone(); }); let supply_response = self.app.wrap().query_supply(lp_denom.into_inner()); diff --git a/integration-tests/tests/common/suite.rs b/integration-tests/tests/common/suite.rs index 0c7f88c46..e3d5388a6 100644 --- a/integration-tests/tests/common/suite.rs +++ b/integration-tests/tests/common/suite.rs @@ -19,7 +19,7 @@ use white_whale_std::incentive_manager::{ PositionsResponse, }; use white_whale_std::pool_manager::{ - PoolInfoResponse, PoolType, ReverseSimulateSwapOperationsResponse, ReverseSimulationResponse, + PoolType, PoolsResponse, ReverseSimulateSwapOperationsResponse, ReverseSimulationResponse, SimulateSwapOperationsResponse, SimulationResponse, SwapOperation, SwapRoute, SwapRoutesResponse, }; @@ -1015,17 +1015,23 @@ impl TestingSuite { self } - pub(crate) fn _query_pool( + pub(crate) fn _query_pools( &self, - pool_identifier: String, - result: impl Fn(StdResult), + pool_identifier: Option, + start_after: Option, + limit: Option, + result: impl Fn(StdResult), ) -> &Self { - let pool_info_response: StdResult = self.app.wrap().query_wasm_smart( + let pools_response: StdResult = self.app.wrap().query_wasm_smart( &self.pool_manager_addr, - &white_whale_std::pool_manager::QueryMsg::Pool { pool_identifier }, + &white_whale_std::pool_manager::QueryMsg::Pools { + pool_identifier, + start_after, + limit, + }, ); - result(pool_info_response); + result(pools_response); self } diff --git a/packages/white-whale-std/Cargo.toml b/packages/white-whale-std/Cargo.toml index bbbcf61a9..e529d88ce 100644 --- a/packages/white-whale-std/Cargo.toml +++ b/packages/white-whale-std/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "white-whale-std" -version = "1.1.3" +version = "1.1.6" edition.workspace = true authors = [ "Kerber0x ", @@ -13,6 +13,7 @@ license.workspace = true repository.workspace = true homepage.workspace = true documentation.workspace = true +keywords = ["cosmos", "cosmwasm", "whitewhale", "migaloo"] [features] default = ["osmosis_token_factory"] diff --git a/packages/white-whale-std/src/pool_manager.rs b/packages/white-whale-std/src/pool_manager.rs index 8823750c1..389730a8b 100644 --- a/packages/white-whale-std/src/pool_manager.rs +++ b/packages/white-whale-std/src/pool_manager.rs @@ -116,6 +116,8 @@ pub struct StableSwapParams { /// Contains the pool information #[cw_serde] pub struct PoolInfo { + /// The identifier for the pool. + pub pool_identifier: String, /// The asset denoms for the pool. pub asset_denoms: Vec, /// The LP denom of the pool. @@ -333,8 +335,17 @@ pub enum QueryMsg { operations: Vec, }, /// Retrieves the pool information for the given pool identifier. - #[returns(PoolInfoResponse)] - Pool { pool_identifier: String }, + #[returns(PoolsResponse)] + Pools { + /// An optional parameter specifying the pool identifier to do the query for. If not + /// provided, it will return all pools based on the pagination parameters. + pool_identifier: Option, + /// An optional parameter specifying what pool (identifier) to start searching after. + start_after: Option, + /// The amount of pools to return. If unspecified, will default to a value specified by + /// the contract. + limit: Option, + }, /// Retrieves the creator of the swap route to get from offer to ask asset. The creator of /// the swap route can remove it. #[returns(SwapRouteCreatorResponse)] @@ -360,7 +371,13 @@ pub struct SwapRoutesResponse { pub swap_routes: Vec, } -/// The response for the `Pool` query. +/// The response for the `Pools` query. +#[cw_serde] +pub struct PoolsResponse { + /// The pools information responses. + pub pools: Vec, +} + #[cw_serde] pub struct PoolInfoResponse { /// The pool information for the given pool identifier. @@ -448,4 +465,4 @@ pub struct ReverseSimulateSwapOperationsResponse { pub struct SwapRouteCreatorResponse { /// The creator of the swap route. pub creator: String, -} \ No newline at end of file +} From 49dd398425996a2ab12b77dbc0401e7a2fef0009 Mon Sep 17 00:00:00 2001 From: nahem Date: Wed, 10 Jul 2024 11:51:04 +0200 Subject: [PATCH 12/19] fix: check that receiver_balance > 0 on pool manager's router before sending bank msg --- .../bonding-manager/src/rewards/commands.rs | 14 ++++++++++---- .../pool-manager/src/router/commands.rs | 16 +++++++++++----- integration-tests/tests/integration.rs | 12 ++++++------ 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/contracts/liquidity_hub/bonding-manager/src/rewards/commands.rs b/contracts/liquidity_hub/bonding-manager/src/rewards/commands.rs index 313703c8f..98ff35e02 100644 --- a/contracts/liquidity_hub/bonding-manager/src/rewards/commands.rs +++ b/contracts/liquidity_hub/bonding-manager/src/rewards/commands.rs @@ -257,11 +257,17 @@ pub fn claim(deps: DepsMut, info: MessageInfo) -> Result = vec![]; + if !receiver_balance.is_zero() { + bank_msg.push(CosmosMsg::Bank(BankMsg::Send { to_address: receiver.clone(), amount: vec![coin(receiver_balance.u128(), target_asset_denom.clone())], - }) + })); + } + + // send output to recipient + Ok(Response::new() + .add_messages(bank_msg) .add_messages(fee_messages) .add_attributes(vec![ attr("action", "execute_swap_operations".to_string()), diff --git a/integration-tests/tests/integration.rs b/integration-tests/tests/integration.rs index 23d8e614e..99c0decaf 100644 --- a/integration-tests/tests/integration.rs +++ b/integration-tests/tests/integration.rs @@ -232,9 +232,9 @@ proptest! { suite.query_current_epoch(|response| { current_epoch = response.unwrap().epoch.id; }); - // suite.query_claimable_reward_buckets(None, |response| { - // println!(">>> [{current_epoch}] CLAIMABLE REWARDS {:?}", response.unwrap().1); - // }); + suite.query_claimable_reward_buckets(None, |response| { + println!(">>> [{current_epoch}] CLAIMABLE REWARDS {:?}", response.unwrap().1); + }); match action { Action::Swap(user, from_token, to_token, amount) => { @@ -320,9 +320,9 @@ proptest! { suite.query_bonding_rewards(user.to_string(), |response| { let contract_rewards = &response.as_ref().unwrap().1.rewards; let has_contract_rewards = !contract_rewards.is_empty(); - // println!("____________"); - // println!(">>> [{current_epoch}] CLAIMABLE REWARDS CONTRACT {:?}", contract_rewards); - // println!(">>> [{current_epoch}] CLAIMABLE REWARDS TEST {:?}", claimable_rewards.borrow()); + println!("____________"); + println!(">>> [{current_epoch}] CLAIMABLE REWARDS CONTRACT {:?}", contract_rewards); + println!(">>> [{current_epoch}] CLAIMABLE REWARDS TEST {:?}", claimable_rewards.borrow()); assert_eq!(has_pending_rewards, has_contract_rewards); }); From 42e8a10cd1378ded62d99a87de81d2a54396855c Mon Sep 17 00:00:00 2001 From: nahem Date: Wed, 10 Jul 2024 13:09:44 +0200 Subject: [PATCH 13/19] fix: refactor proptests to take into account that bonding and unbonding triggers a claim --- integration-tests/tests/integration.rs | 165 ++++++++++++++----------- 1 file changed, 93 insertions(+), 72 deletions(-) diff --git a/integration-tests/tests/integration.rs b/integration-tests/tests/integration.rs index 99c0decaf..c839643b6 100644 --- a/integration-tests/tests/integration.rs +++ b/integration-tests/tests/integration.rs @@ -317,47 +317,69 @@ proptest! { break; } } - suite.query_bonding_rewards(user.to_string(), |response| { - let contract_rewards = &response.as_ref().unwrap().1.rewards; - let has_contract_rewards = !contract_rewards.is_empty(); - println!("____________"); - println!(">>> [{current_epoch}] CLAIMABLE REWARDS CONTRACT {:?}", contract_rewards); - println!(">>> [{current_epoch}] CLAIMABLE REWARDS TEST {:?}", claimable_rewards.borrow()); - assert_eq!(has_pending_rewards, has_contract_rewards); + + suite.bond(&user, &coins(amount, &token), |result| { + println!(">>> [{current_epoch}] [{user}] BOND [{amount}]"); + result.unwrap(); }); + // bond with pending rewards should trigger a claim if has_pending_rewards { - suite.bond(&user, &coins(amount, &token), |result| { - assert_eq!( - result.unwrap_err().downcast::().unwrap(), - bonding_manager::ContractError::UnclaimedRewards - ); - }); - } else { - suite.bond(&user, &coins(amount, &token), |result| { - println!(">>> [{current_epoch}] [{user}] BOND [{amount}]"); - result.unwrap(); - }); + for epoch in 0..current_epoch { + claimable_rewards.borrow_mut().remove(&(user.clone(), epoch)); + } + } - let mut bonded_amounts = bonded_amounts.borrow_mut(); - let user_bonds = bonded_amounts.entry(user.clone()).or_insert_with(HashMap::new); - *user_bonds.entry(token.clone()).or_insert(0) += amount; + // suite.query_bonding_rewards(user.to_string(), |response| { + // let contract_rewards = &response.as_ref().unwrap().1.rewards; + // let has_contract_rewards = !contract_rewards.is_empty(); + // println!("____________"); + // println!(">>> [{current_epoch}] CLAIMABLE REWARDS CONTRACT {:?}", contract_rewards); + // println!(">>> [{current_epoch}] CLAIMABLE REWARDS TEST {:?}", claimable_rewards.borrow()); + // assert_eq!(has_pending_rewards, has_contract_rewards); + // }); - if swaps_in_epoch { - claimable_rewards.borrow_mut().insert((user.clone(), current_epoch), true); + suite.query_bonding_rewards(user.to_string(), |response| { + let contract_rewards = response.unwrap().1.rewards; + let has_contract_rewards = !contract_rewards.is_empty(); + + // if we bonded with pending rewards, the contract will claim them first so we remove them from the test map + if has_pending_rewards { + for epoch in 0..current_epoch { + claimable_rewards.borrow_mut().remove(&(user.clone(), epoch)); + } } - suite.query_bonded(Some(user.to_string()), |result| { - let bonded = result.unwrap().1.bonded_assets; - let mut expected_bonded = user_bonds.iter() - .map(|(token, amount)| coin(*amount, token)) - .collect::>(); - expected_bonded.sort_by(|a, b| a.denom.cmp(&b.denom)); - let mut bonded_sorted = bonded.clone(); - bonded_sorted.sort_by(|a, b| a.denom.cmp(&b.denom)); - assert_eq!(bonded_sorted, expected_bonded); - }); + let mut has_rewards_in_test_map = false; + for ((test_user, epoch), has_rewards) in claimable_rewards.borrow().iter() { + if test_user == &user && *epoch != current_epoch && *has_rewards { + has_rewards_in_test_map = true; + break; + } + } + + assert_eq!(has_rewards_in_test_map, has_contract_rewards); + }); + + let mut bonded_amounts = bonded_amounts.borrow_mut(); + let user_bonds = bonded_amounts.entry(user.clone()).or_insert_with(HashMap::new); + *user_bonds.entry(token.clone()).or_insert(0) += amount; + + if swaps_in_epoch { + claimable_rewards.borrow_mut().insert((user.clone(), current_epoch), true); } + + suite.query_bonded(Some(user.to_string()), |result| { + let bonded = result.unwrap().1.bonded_assets; + let mut expected_bonded = user_bonds.iter() + .map(|(token, amount)| coin(*amount, token)) + .collect::>(); + expected_bonded.sort_by(|a, b| a.denom.cmp(&b.denom)); + let mut bonded_sorted = bonded.clone(); + bonded_sorted.sort_by(|a, b| a.denom.cmp(&b.denom)); + assert_eq!(bonded_sorted, expected_bonded); + }); + } Action::Unbond(user, token, amount) => { println!(">>> [{current_epoch}] [{user}] UNBOND [{amount}]"); @@ -370,55 +392,54 @@ proptest! { } } - if has_pending_rewards { - suite.unbond(user.clone(), coin(amount, &token), |result| { - assert_eq!( - result.unwrap_err().downcast::().unwrap(), - bonding_manager::ContractError::UnclaimedRewards - ); - }); - } else { - let mut bonded_amounts = bonded_amounts.borrow_mut(); - let user_bonds = bonded_amounts.entry(user.clone()).or_insert_with(HashMap::new); - - if let Some(bonded) = user_bonds.get_mut(&token) { - if *bonded >= amount { - suite.unbond(user.clone(), coin(amount, &token), |result| { - result.unwrap(); - }); - *bonded -= amount; - - suite.query_bonding_rewards(user.to_string(), |response| { - let contract_rewards = response.unwrap().1.rewards; - let has_contract_rewards = !contract_rewards.is_empty(); - - let mut has_rewards_in_test_map = false; - for ((test_user, epoch), has_rewards) in claimable_rewards.borrow().iter() { - if test_user == &user && *epoch != current_epoch && *has_rewards { - has_rewards_in_test_map = true; - break; - } + let mut bonded_amounts = bonded_amounts.borrow_mut(); + let user_bonds = bonded_amounts.entry(user.clone()).or_insert_with(HashMap::new); + + if let Some(bonded) = user_bonds.get_mut(&token) { + if *bonded >= amount { + suite.unbond(user.clone(), coin(amount, &token), |result| { + result.unwrap(); + }); + *bonded -= amount; + + suite.query_bonding_rewards(user.to_string(), |response| { + let contract_rewards = response.unwrap().1.rewards; + let has_contract_rewards = !contract_rewards.is_empty(); + + // if we unbonded with pending rewards, the contract will claim them first so we remove them from the test map + if has_pending_rewards { + for epoch in 0..current_epoch { + claimable_rewards.borrow_mut().remove(&(user.clone(), epoch)); } + } - assert_eq!(has_rewards_in_test_map, has_contract_rewards); - }); - } else { - suite.unbond(user.clone(), coin(amount, &token), |result| { - assert_eq!( - result.unwrap_err().downcast::().unwrap(), - bonding_manager::ContractError::InsufficientBond - ); - }); - } + let mut has_rewards_in_test_map = false; + for ((test_user, epoch), has_rewards) in claimable_rewards.borrow().iter() { + if test_user == &user && *epoch != current_epoch && *has_rewards { + has_rewards_in_test_map = true; + break; + } + } + + assert_eq!(has_rewards_in_test_map, has_contract_rewards); + }); } else { suite.unbond(user.clone(), coin(amount, &token), |result| { assert_eq!( result.unwrap_err().downcast::().unwrap(), - bonding_manager::ContractError::NothingToUnbond + bonding_manager::ContractError::InsufficientBond ); }); } + } else { + suite.unbond(user.clone(), coin(amount, &token), |result| { + assert_eq!( + result.unwrap_err().downcast::().unwrap(), + bonding_manager::ContractError::NothingToUnbond + ); + }); } + } Action::Claim(user) => { println!(">>> [{current_epoch}] [{user}] CLAIM"); From 7e1421982814f18a00ec0be0ee3c700521d289d6 Mon Sep 17 00:00:00 2001 From: nahem Date: Thu, 11 Jul 2024 15:44:36 +0200 Subject: [PATCH 14/19] fix: WIP in integration tests --- .../bonding-manager/src/helpers.rs | 3 + .../bonding-manager/src/queries.rs | 5 + .../bonding-manager/src/tests/claim.rs | 33 +++++ integration-tests/tests/common/suite.rs | 2 +- .../tests/integration.proptest-regressions | 1 + integration-tests/tests/integration.rs | 115 ++++++++++-------- 6 files changed, 105 insertions(+), 54 deletions(-) diff --git a/contracts/liquidity_hub/bonding-manager/src/helpers.rs b/contracts/liquidity_hub/bonding-manager/src/helpers.rs index 3d1704e07..cbdf5e55a 100644 --- a/contracts/liquidity_hub/bonding-manager/src/helpers.rs +++ b/contracts/liquidity_hub/bonding-manager/src/helpers.rs @@ -390,6 +390,9 @@ pub fn calculate_rewards( total_claimable_rewards = aggregate_coins(&total_claimable_rewards, &vec![reward.clone()])?; + // filter out rewards with zero amount + total_claimable_rewards.retain(|coin| coin.amount > Uint128::zero()); + if is_claim { claimed_rewards_from_bucket = aggregate_coins(&claimed_rewards_from_bucket, &vec![reward])?; diff --git a/contracts/liquidity_hub/bonding-manager/src/queries.rs b/contracts/liquidity_hub/bonding-manager/src/queries.rs index d61638fd2..b49a66c8a 100644 --- a/contracts/liquidity_hub/bonding-manager/src/queries.rs +++ b/contracts/liquidity_hub/bonding-manager/src/queries.rs @@ -166,6 +166,11 @@ pub fn query_claimable( claimable_reward_buckets.retain(|bucket| !bucket.available.is_empty()); } + // println!( + // ">>> claimable_reward_buckets_2: {:?}", + // claimable_reward_buckets + // ); + Ok(ClaimableRewardBucketsResponse { reward_buckets: claimable_reward_buckets, }) diff --git a/contracts/liquidity_hub/bonding-manager/src/tests/claim.rs b/contracts/liquidity_hub/bonding-manager/src/tests/claim.rs index 9d6d93dd7..384f0ab8c 100644 --- a/contracts/liquidity_hub/bonding-manager/src/tests/claim.rs +++ b/contracts/liquidity_hub/bonding-manager/src/tests/claim.rs @@ -1065,4 +1065,37 @@ fn test_rewards_forwarding() { } ); }); + + suite + .swap( + creator.clone(), + coin(80_000u128, "uusdc"), + "uwhale".to_string(), + None, + None, + None, + "whale-uusdc".to_string(), + vec![Coin { + denom: "uusdc".to_string(), + amount: Uint128::from(80_000u128), + }], + |result| { + result.unwrap(); + }, + ) + .add_one_day() + .create_new_epoch() + .claim(creator.clone(), |result| { + result.unwrap(); + }) + .add_one_day() + .create_new_epoch() + .claim(creator.clone(), |result| { + let err = result.unwrap_err().downcast::().unwrap(); + + match err { + ContractError::NothingToClaim { .. } => {} + _ => panic!("Wrong error type, should return ContractError::NothingToClaim"), + } + }); } diff --git a/integration-tests/tests/common/suite.rs b/integration-tests/tests/common/suite.rs index e3d5388a6..bd0d4721d 100644 --- a/integration-tests/tests/common/suite.rs +++ b/integration-tests/tests/common/suite.rs @@ -426,7 +426,7 @@ impl TestingSuite { } #[track_caller] - pub(crate) fn _withdraw( + pub(crate) fn _withdraw_after_unbond( &mut self, sender: Addr, denom: String, diff --git a/integration-tests/tests/integration.proptest-regressions b/integration-tests/tests/integration.proptest-regressions index 8a95e47b9..29026846b 100644 --- a/integration-tests/tests/integration.proptest-regressions +++ b/integration-tests/tests/integration.proptest-regressions @@ -7,3 +7,4 @@ cc 665858dcc5830455dc0630eaf9625a3d2405e454c4076c621758527ffaac7e01 # shrinks to epochs = 1, actions = [Swap("alice", "uusdc", "uusdc", 1)] cc 908335e2674e6f38633c4ca6b8b1448412ee9a7c32a2a495533aa2750494464f # shrinks to epochs = 10, actions = [Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 1), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 1), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 1), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "uusdc", 1), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 1), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 1)] cc be34ad8aed4e8ea2f874d3e9ec4e2dc2b336d39726932964bbe269679d09d3f5 # shrinks to actions = [Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "uusdc", 42591), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 46593), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 94375), Bond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 77180)] +cc 765652262526798bff5ab497b63867f49407edcc9d8401ac7e7fe5f5c4b0517d # shrinks to actions = [Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 67667), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "uusdc", 418), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "uusdt", "uwhale", 78764), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"))] diff --git a/integration-tests/tests/integration.rs b/integration-tests/tests/integration.rs index c839643b6..4d2b80ef1 100644 --- a/integration-tests/tests/integration.rs +++ b/integration-tests/tests/integration.rs @@ -179,6 +179,7 @@ proptest! { ] ), 1..100) ) { + println!(">>> ------------------- STARTING TEST --------------------"); let mut suite = TestingSuite::default_with_balances(); suite.instantiate(); @@ -232,14 +233,15 @@ proptest! { suite.query_current_epoch(|response| { current_epoch = response.unwrap().epoch.id; }); - suite.query_claimable_reward_buckets(None, |response| { - println!(">>> [{current_epoch}] CLAIMABLE REWARDS {:?}", response.unwrap().1); - }); + // suite.query_claimable_reward_buckets(None, |response| { + // println!(">>> [{current_epoch}] CLAIMABLE REWARDS {:?}", response.unwrap().1); + // }); match action { Action::Swap(user, from_token, to_token, amount) => { - println!(">>> [{current_epoch}] [{user}] SWAP"); if from_token == to_token { + println!(">>> [{current_epoch}] [{user}] SWAP FAILED [{amount} {from_token} -> {to_token}]"); + suite.swap( user.clone(), to_token.clone(), @@ -260,6 +262,8 @@ proptest! { // enter the normal swap flow if the pool exists if available_pools.contains(&pool_identifier) { + println!(">>> [{current_epoch}] [{user}] SWAP [{amount} {from_token} -> {to_token}]"); + swaps_in_epoch = true; suite.swap( user.clone(), @@ -287,6 +291,8 @@ proptest! { // Mark claimable rewards for users bonded during this epoch let bonded_amounts = bonded_amounts.borrow(); + println!(">>> [{current_epoch}] BONDED AMOUNTS {:?}", bonded_amounts); + for user in bonded_amounts.keys() { claimable_rewards.borrow_mut().insert((user.clone(), current_epoch), true); } @@ -310,49 +316,37 @@ proptest! { } } Action::Bond(user, token, amount) => { - let mut has_pending_rewards = false; + // bond the user + suite.bond(&user, &coins(amount, &token), |result| { + println!(">>> [{current_epoch}] [{user}] BOND [{amount} {}]", token.split('/').nth(2).unwrap()); + result.unwrap(); + }); + + let mut test_has_rewards = false; + // check if the user has pending rewards in the test map for ((test_user, epoch), has_rewards) in claimable_rewards.borrow().iter() { - if test_user == &user && *epoch != current_epoch && *has_rewards { - has_pending_rewards = true; + if test_user == &user && *epoch < current_epoch && *has_rewards { + test_has_rewards = true; break; } } - suite.bond(&user, &coins(amount, &token), |result| { - println!(">>> [{current_epoch}] [{user}] BOND [{amount}]"); - result.unwrap(); - }); - - // bond with pending rewards should trigger a claim - if has_pending_rewards { + // if user bonded with pending rewards, the contract will claim them first so we need to remove them from the test map + if test_has_rewards { for epoch in 0..current_epoch { claimable_rewards.borrow_mut().remove(&(user.clone(), epoch)); } } - // suite.query_bonding_rewards(user.to_string(), |response| { - // let contract_rewards = &response.as_ref().unwrap().1.rewards; - // let has_contract_rewards = !contract_rewards.is_empty(); - // println!("____________"); - // println!(">>> [{current_epoch}] CLAIMABLE REWARDS CONTRACT {:?}", contract_rewards); - // println!(">>> [{current_epoch}] CLAIMABLE REWARDS TEST {:?}", claimable_rewards.borrow()); - // assert_eq!(has_pending_rewards, has_contract_rewards); - // }); - suite.query_bonding_rewards(user.to_string(), |response| { + // >>> TODO: MAKE SURE THE CONTRACT IS UPDATING STATE CORRECTLY AFTER BONDING WITH PENDING REWARDS let contract_rewards = response.unwrap().1.rewards; let has_contract_rewards = !contract_rewards.is_empty(); - // if we bonded with pending rewards, the contract will claim them first so we remove them from the test map - if has_pending_rewards { - for epoch in 0..current_epoch { - claimable_rewards.borrow_mut().remove(&(user.clone(), epoch)); - } - } - + // re-calculate if the user has pending rewards in the test map let mut has_rewards_in_test_map = false; for ((test_user, epoch), has_rewards) in claimable_rewards.borrow().iter() { - if test_user == &user && *epoch != current_epoch && *has_rewards { + if test_user == &user && *epoch < current_epoch && *has_rewards { has_rewards_in_test_map = true; break; } @@ -379,24 +373,32 @@ proptest! { bonded_sorted.sort_by(|a, b| a.denom.cmp(&b.denom)); assert_eq!(bonded_sorted, expected_bonded); }); - } Action::Unbond(user, token, amount) => { - println!(">>> [{current_epoch}] [{user}] UNBOND [{amount}]"); - - let mut has_pending_rewards = false; - for ((test_user, epoch), has_rewards) in claimable_rewards.borrow().iter() { - if test_user == &user && *epoch != current_epoch && *has_rewards { - has_pending_rewards = true; - break; - } - } - + // TODO: >>> check if this is creating an entry in the bonded_amounts map when it shouldn't ??? let mut bonded_amounts = bonded_amounts.borrow_mut(); let user_bonds = bonded_amounts.entry(user.clone()).or_insert_with(HashMap::new); if let Some(bonded) = user_bonds.get_mut(&token) { if *bonded >= amount { + println!(">>> [{current_epoch}] [{user}] UNBOND [{amount} {}]", token.split('/').nth(2).unwrap()); + + let mut test_has_rewards = false; + // check if the user has pending rewards in the test map + for ((test_user, epoch), has_rewards) in claimable_rewards.borrow().iter() { + if test_user == &user && *epoch < current_epoch && *has_rewards { + test_has_rewards = true; + break; + } + } + + // if user bonded with pending rewards, the contract will claim them first so we need to remove them from the test map + if test_has_rewards { + for epoch in 0..current_epoch { + claimable_rewards.borrow_mut().remove(&(user.clone(), epoch)); + } + } + suite.unbond(user.clone(), coin(amount, &token), |result| { result.unwrap(); }); @@ -406,16 +408,9 @@ proptest! { let contract_rewards = response.unwrap().1.rewards; let has_contract_rewards = !contract_rewards.is_empty(); - // if we unbonded with pending rewards, the contract will claim them first so we remove them from the test map - if has_pending_rewards { - for epoch in 0..current_epoch { - claimable_rewards.borrow_mut().remove(&(user.clone(), epoch)); - } - } - let mut has_rewards_in_test_map = false; for ((test_user, epoch), has_rewards) in claimable_rewards.borrow().iter() { - if test_user == &user && *epoch != current_epoch && *has_rewards { + if test_user == &user && *epoch < current_epoch && *has_rewards { has_rewards_in_test_map = true; break; } @@ -424,6 +419,8 @@ proptest! { assert_eq!(has_rewards_in_test_map, has_contract_rewards); }); } else { + println!(">>> [{current_epoch}] [{user}] UNBOND FAILED (insufficient bond) [{amount} {}]", token.split('/').nth(2).unwrap()); + suite.unbond(user.clone(), coin(amount, &token), |result| { assert_eq!( result.unwrap_err().downcast::().unwrap(), @@ -432,6 +429,8 @@ proptest! { }); } } else { + println!(">>> [{current_epoch}] [{user}] UNBOND FAILED (nothing to unbond) [{amount} {}]", token.split('/').nth(2).unwrap()); + suite.unbond(user.clone(), coin(amount, &token), |result| { assert_eq!( result.unwrap_err().downcast::().unwrap(), @@ -442,17 +441,25 @@ proptest! { } Action::Claim(user) => { - println!(">>> [{current_epoch}] [{user}] CLAIM"); - let mut has_pending_rewards = false; for ((test_user, epoch), has_rewards) in claimable_rewards.borrow().iter() { - if test_user == &user && *epoch != current_epoch && *has_rewards { + if test_user == &user && *epoch < current_epoch && *has_rewards { has_pending_rewards = true; break; } } + // suite.query_bonding_rewards(user.to_string(), |response| { + // let contract_rewards = &response.as_ref().unwrap().1.rewards; + // let has_contract_rewards = !contract_rewards.is_empty(); + // println!(">>>"); + // println!(">>> [{current_epoch}] CLAIMABLE REWARDS CONTRACT {:?}", contract_rewards); + // println!(">>> [{current_epoch}] CLAIMABLE REWARDS PROPTEST {:?}", claimable_rewards.borrow()); + // assert_eq!(has_pending_rewards, has_contract_rewards); + // }); + if has_pending_rewards { + println!(">>> [{current_epoch}] [{user}] CLAIM"); suite.query_bonding_rewards(user.to_string(), |response| { println!(">>> [{current_epoch}] BONDING REWARDS {:?}", response.unwrap().1); }); @@ -466,6 +473,8 @@ proptest! { claimable_rewards.borrow_mut().remove(&(user.clone(), epoch)); } } else { + println!(">>> [{current_epoch}] [{user}] CLAIM FAILED (nothing to claim)"); + suite.claim_bonding_rewards(&user, |result| { assert_eq!( result.unwrap_err().downcast::().unwrap(), From e2c0f8fbe2dcc5b3696def23c1d2cb2d5f2052e5 Mon Sep 17 00:00:00 2001 From: nahem Date: Fri, 12 Jul 2024 11:04:32 +0200 Subject: [PATCH 15/19] fix: WIP in integration tests --- integration-tests/tests/integration.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/integration-tests/tests/integration.rs b/integration-tests/tests/integration.rs index 4d2b80ef1..e8b5594fc 100644 --- a/integration-tests/tests/integration.rs +++ b/integration-tests/tests/integration.rs @@ -293,8 +293,10 @@ proptest! { let bonded_amounts = bonded_amounts.borrow(); println!(">>> [{current_epoch}] BONDED AMOUNTS {:?}", bonded_amounts); - for user in bonded_amounts.keys() { - claimable_rewards.borrow_mut().insert((user.clone(), current_epoch), true); + for (user, token_amounts) in bonded_amounts.iter() { + if token_amounts.values().any(|&amount| amount > 0) { + claimable_rewards.borrow_mut().insert((user.clone(), current_epoch), true); + } } } else { suite.swap( @@ -449,14 +451,14 @@ proptest! { } } - // suite.query_bonding_rewards(user.to_string(), |response| { - // let contract_rewards = &response.as_ref().unwrap().1.rewards; - // let has_contract_rewards = !contract_rewards.is_empty(); - // println!(">>>"); - // println!(">>> [{current_epoch}] CLAIMABLE REWARDS CONTRACT {:?}", contract_rewards); - // println!(">>> [{current_epoch}] CLAIMABLE REWARDS PROPTEST {:?}", claimable_rewards.borrow()); - // assert_eq!(has_pending_rewards, has_contract_rewards); - // }); + suite.query_bonding_rewards(user.to_string(), |response| { + let contract_rewards = &response.as_ref().unwrap().1.rewards; + let has_contract_rewards = !contract_rewards.is_empty(); + println!(">>>"); + println!(">>> [{current_epoch}] CLAIMABLE REWARDS CONTRACT {:?}", contract_rewards); + println!(">>> [{current_epoch}] CLAIMABLE REWARDS PROPTEST {:?}", claimable_rewards.borrow()); + // assert_eq!(has_pending_rewards, has_contract_rewards); + }); if has_pending_rewards { println!(">>> [{current_epoch}] [{user}] CLAIM"); From 15112909aaed55db2f368c08632037f79d58b4b4 Mon Sep 17 00:00:00 2001 From: nahem Date: Mon, 15 Jul 2024 13:49:38 +0200 Subject: [PATCH 16/19] fix: on unbond, remove user from when they don't have any more bonded assets --- .../bonding-manager/src/bonding/commands.rs | 12 +++++++++++ .../bonding-manager/src/helpers.rs | 1 + .../incentive-manager/tests/common/suite.rs | 19 ++++++++--------- .../tests/common/suite_contracts.rs | 6 +++--- integration-tests/tests/common/helpers.rs | 14 ++++++------- .../tests/integration.proptest-regressions | 2 ++ integration-tests/tests/integration.rs | 21 ++++++++----------- 7 files changed, 43 insertions(+), 32 deletions(-) diff --git a/contracts/liquidity_hub/bonding-manager/src/bonding/commands.rs b/contracts/liquidity_hub/bonding-manager/src/bonding/commands.rs index 217ab573a..4708e9696 100644 --- a/contracts/liquidity_hub/bonding-manager/src/bonding/commands.rs +++ b/contracts/liquidity_hub/bonding-manager/src/bonding/commands.rs @@ -162,6 +162,18 @@ pub(crate) fn unbond( if unbond.asset.amount.is_zero() { BONDS.remove(deps.storage, unbond.id)?; + // check if there are other bonded assets, if not, remove the last claimed epoch to reset the user + let other_bonds_by_receiver = get_bonds_by_receiver( + deps.storage, + info.sender.to_string(), + Some(true), + None, + None, + None, + )?; + if other_bonds_by_receiver.is_empty() { + LAST_CLAIMED_EPOCH.remove(deps.storage, &info.sender); + } } else { BONDS.save(deps.storage, unbond.id, &unbond)?; } diff --git a/contracts/liquidity_hub/bonding-manager/src/helpers.rs b/contracts/liquidity_hub/bonding-manager/src/helpers.rs index cbdf5e55a..557bde719 100644 --- a/contracts/liquidity_hub/bonding-manager/src/helpers.rs +++ b/contracts/liquidity_hub/bonding-manager/src/helpers.rs @@ -196,6 +196,7 @@ pub fn swap_coins_to_main_token( !coin.denom.contains(".pool.") & !coin.denom.contains(LP_SYMBOL) & !coin.denom.eq(distribution_denom) + & !config.bonding_assets.contains(&coin.denom) }) .collect(); for coin in coins_to_swap { diff --git a/contracts/liquidity_hub/incentive-manager/tests/common/suite.rs b/contracts/liquidity_hub/incentive-manager/tests/common/suite.rs index 39840cf70..3cd81b5e0 100644 --- a/contracts/liquidity_hub/incentive-manager/tests/common/suite.rs +++ b/contracts/liquidity_hub/incentive-manager/tests/common/suite.rs @@ -8,19 +8,18 @@ use cw_multi_test::{ use white_whale_std::epoch_manager::epoch_manager::{Epoch, EpochConfig, EpochResponse}; use white_whale_std::epoch_manager::hooks::EpochChangedHookMsg; -use white_whale_std::fee::{Fee, PoolFee}; +use white_whale_std::fee::PoolFee; use white_whale_std::incentive_manager::{ Config, IncentiveAction, IncentivesBy, IncentivesResponse, InstantiateMsg, LpWeightResponse, PositionAction, PositionsResponse, RewardsResponse, }; use white_whale_std::pool_manager::PoolType; -use white_whale_std::pool_network::asset::{Asset, AssetInfo}; +use white_whale_std::pool_network::asset::AssetInfo; use white_whale_testing::integration::contracts::whale_lair_contract; use white_whale_testing::multi_test::stargate_mock::StargateMock; use crate::common::suite_contracts::{ - bonding_manager_contract, epoch_manager_contract, incentive_manager_contract, - pool_manager_contract, + _pool_manager_contract, epoch_manager_contract, incentive_manager_contract, }; type OsmosisTokenFactoryApp = App< @@ -259,8 +258,8 @@ impl TestingSuite { } #[allow(clippy::inconsistent_digit_grouping)] - fn create_pool_manager(&mut self) { - let pool_manager_contract = self.app.store_code(pool_manager_contract()); + fn _create_pool_manager(&mut self) { + let pool_manager_contract = self.app.store_code(_pool_manager_contract()); // create epoch manager let msg = white_whale_std::pool_manager::InstantiateMsg { @@ -693,7 +692,7 @@ impl TestingSuite { impl TestingSuite { #[track_caller] - pub(crate) fn provide_liquidity( + pub(crate) fn _provide_liquidity( &mut self, sender: Addr, pool_identifier: String, @@ -718,7 +717,7 @@ impl TestingSuite { } #[track_caller] - pub(crate) fn swap( + pub(crate) fn _swap( &mut self, sender: Addr, _offer_asset: Coin, @@ -747,7 +746,7 @@ impl TestingSuite { } #[track_caller] - pub(crate) fn add_swap_routes( + pub(crate) fn _add_swap_routes( &mut self, sender: Addr, swap_routes: Vec, @@ -763,7 +762,7 @@ impl TestingSuite { self } #[track_caller] - pub(crate) fn create_pair( + pub(crate) fn _create_pair( &mut self, sender: Addr, asset_denoms: Vec, diff --git a/contracts/liquidity_hub/incentive-manager/tests/common/suite_contracts.rs b/contracts/liquidity_hub/incentive-manager/tests/common/suite_contracts.rs index 74293912f..040a7c73c 100644 --- a/contracts/liquidity_hub/incentive-manager/tests/common/suite_contracts.rs +++ b/contracts/liquidity_hub/incentive-manager/tests/common/suite_contracts.rs @@ -14,7 +14,7 @@ pub fn incentive_manager_contract() -> Box> { } /// Creates the whale lair contract -pub fn whale_lair_contract() -> Box> { +pub fn _whale_lair_contract() -> Box> { let contract = ContractWrapper::new( whale_lair::contract::execute, whale_lair::contract::instantiate, @@ -26,7 +26,7 @@ pub fn whale_lair_contract() -> Box> { } /// Creates the whale lair contract -pub fn bonding_manager_contract() -> Box> { +pub fn _bonding_manager_contract() -> Box> { let contract = ContractWrapper::new( bonding_manager::contract::execute, bonding_manager::contract::instantiate, @@ -38,7 +38,7 @@ pub fn bonding_manager_contract() -> Box> { } /// Creates the pool manager contract -pub fn pool_manager_contract() -> Box> { +pub fn _pool_manager_contract() -> Box> { let contract = ContractWrapper::new( pool_manager::contract::execute, pool_manager::contract::instantiate, diff --git a/integration-tests/tests/common/helpers.rs b/integration-tests/tests/common/helpers.rs index d13c1b06c..9dd6e3628 100644 --- a/integration-tests/tests/common/helpers.rs +++ b/integration-tests/tests/common/helpers.rs @@ -214,7 +214,7 @@ pub mod pools { vec![6, 6], helpers::fees::pool_fees_03(), PoolType::ConstantProduct, - Some("uwhale-uusdc-cheap".to_string()), + Some("uwhale-uusdc".to_string()), vec![coin(1_000u128, "uwhale")], |result| { result.unwrap(); @@ -325,7 +325,7 @@ pub mod pools { ) .provide_liquidity( &sender, - "uwhale-uusdc-cheap".to_string(), + "uwhale-uusdc".to_string(), None, None, None, @@ -448,7 +448,7 @@ pub mod pools { SwapOperation::WhaleSwap { token_in_denom: "uusdc".to_string(), token_out_denom: "uwhale".to_string(), - pool_identifier: "uwhale-uusdc-cheap".to_string(), + pool_identifier: "uwhale-uusdc".to_string(), } ], }, @@ -475,7 +475,7 @@ pub mod pools { SwapOperation::WhaleSwap { token_in_denom: "uusdc".to_string(), token_out_denom: "uwhale".to_string(), - pool_identifier: "uwhale-uusdc-cheap".to_string(), + pool_identifier: "uwhale-uusdc".to_string(), }, ], }, @@ -491,7 +491,7 @@ pub mod pools { SwapOperation::WhaleSwap { token_in_denom: "uusdc".to_string(), token_out_denom: "uwhale".to_string(), - pool_identifier: "uwhale-uusdc-cheap".to_string(), + pool_identifier: "uwhale-uusdc".to_string(), }, ], }, @@ -529,7 +529,7 @@ pub mod pools { SwapOperation::WhaleSwap { token_in_denom: "uusdc".to_string(), token_out_denom: "uwhale".to_string(), - pool_identifier: "uwhale-uusdc-cheap".to_string(), + pool_identifier: "uwhale-uusdc".to_string(), }, ], }, @@ -543,7 +543,7 @@ pub mod pools { pool_identifiers.borrow_mut().extend(vec![ "uwhale-uusdc-free".to_string(), - "uwhale-uusdc-cheap".to_string(), + "uwhale-uusdc".to_string(), "uwhale-uusdc-expensive".to_string(), "uwhale-uosmo-cheap".to_string(), "3pool-stable".to_string(), diff --git a/integration-tests/tests/integration.proptest-regressions b/integration-tests/tests/integration.proptest-regressions index 29026846b..f306fff61 100644 --- a/integration-tests/tests/integration.proptest-regressions +++ b/integration-tests/tests/integration.proptest-regressions @@ -8,3 +8,5 @@ cc 665858dcc5830455dc0630eaf9625a3d2405e454c4076c621758527ffaac7e01 # shrinks to cc 908335e2674e6f38633c4ca6b8b1448412ee9a7c32a2a495533aa2750494464f # shrinks to epochs = 10, actions = [Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 1), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 1), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 1), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "uusdc", 1), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 1), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 1)] cc be34ad8aed4e8ea2f874d3e9ec4e2dc2b336d39726932964bbe269679d09d3f5 # shrinks to actions = [Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "uusdc", 42591), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 46593), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 94375), Bond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 77180)] cc 765652262526798bff5ab497b63867f49407edcc9d8401ac7e7fe5f5c4b0517d # shrinks to actions = [Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 67667), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "uusdc", 418), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "uusdt", "uwhale", 78764), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"))] +cc a493bab6a18a04140ecf687fc001c601594c0d2663f8cfe9ae2e2810122e2cad # shrinks to actions = [Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "uusdc", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 49443), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 21755), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "inj", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 55773), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 7395), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 94253), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "btc", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 62734), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 43217), Claim(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40")), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 40048), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 2900), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "uusdt", "uwhale", 86634), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 52323)] +cc 3b5397f642639811c6e9bac6df19d6233280bdac4052fa151d021b307f91ca92 # shrinks to actions = [Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 63566), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "btc", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 9255), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "btc", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 17237), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "btc", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 10299), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 8055), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 23885), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 71478), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "inj", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 9815), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", "inj", 21240), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 35919), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "uwhale", "uusdc", 15171), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 76186), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "inj", "uusdc", 55951), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 15548), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 80196), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 26427), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "uusdt", "uusdc", 50501), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 89102), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", "btc", 85249), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "uusdt", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 24089), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 66637), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 65668), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "inj", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 92068), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "uusdt", "inj", 52416), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 2153), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 21695), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "uwhale", "uusdt", 50727), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 43056), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "inj", 4333), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "uusdc", "uwhale", 4146), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 84969), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 74534), Bond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 94949), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 29147), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 26853), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 36736), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 22545), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 25651), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 98938), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "inj", "uwhale", 45942), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 27148), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 27602), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 85917), Claim(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40")), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "btc", "uwhale", 17732), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Bond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 90317), Claim(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40")), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "btc", "btc", 56974), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", "inj", 15831), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 95138), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 27735), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 27221), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "uwhale", "btc", 58599), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 84739), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "inj", "uusdt", 51657), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 68252), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"))] diff --git a/integration-tests/tests/integration.rs b/integration-tests/tests/integration.rs index e8b5594fc..478ca1523 100644 --- a/integration-tests/tests/integration.rs +++ b/integration-tests/tests/integration.rs @@ -1,5 +1,5 @@ use std::cell::RefCell; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::rc::Rc; use bonding_manager::ContractError; @@ -108,7 +108,7 @@ fn epic_test() { None, None, None, - "uwhale-uusdc-cheap".to_string(), + "uwhale-uusdc".to_string(), coins(10_000, "uwhale"), |result| { result.as_ref().unwrap().events.iter().for_each(|event| { @@ -154,7 +154,7 @@ fn epic_test() { None, None, None, - "uwhale-uusdc-cheap".to_string(), + "uwhale-uusdc".to_string(), coins(10_000, "uusdc"), |result| { result.unwrap(); @@ -219,12 +219,8 @@ proptest! { let current_rewards = Rc::new(RefCell::new(0)); let bonded_amounts = Rc::new(RefCell::new(HashMap::>::new())); let claimable_rewards = Rc::new(RefCell::new(HashMap::<(Addr, u64), bool>::new())); - let available_pools: HashSet = vec![ - "peggy-uusdc".to_string(), - "uwhale-btc".to_string(), - "uwhale-inj".to_string(), - "uusdc-uusdt".to_string(), - ].into_iter().collect(); + let available_pools = suite.pool_identifiers.clone(); + let last_claimed = Rc::new(RefCell::new(HashMap::::new())); let mut swaps_in_epoch = false; @@ -248,7 +244,7 @@ proptest! { None, None, None, - "uwhale-uusdc-cheap".to_string(), + "uwhale-uusdc".to_string(), coins(amount, from_token), move |result| { assert_eq!( @@ -457,7 +453,7 @@ proptest! { println!(">>>"); println!(">>> [{current_epoch}] CLAIMABLE REWARDS CONTRACT {:?}", contract_rewards); println!(">>> [{current_epoch}] CLAIMABLE REWARDS PROPTEST {:?}", claimable_rewards.borrow()); - // assert_eq!(has_pending_rewards, has_contract_rewards); + assert_eq!(has_pending_rewards, has_contract_rewards); }); if has_pending_rewards { @@ -547,7 +543,8 @@ fn action_strategy(users: Vec) -> impl Strategy { let bond_unbond_token_strategy = prop_oneof![Just(BWHALE.to_string()), Just(AMPWHALE.to_string())]; - let amount_strategy = 100_u128..100_000_u128; + const MIN_AMOUNT: u128 = 1_000; + let amount_strategy = MIN_AMOUNT..100_000_u128; prop_oneof![ ( From f8387c50b821e2e2e6963c586157d7d96e85f595 Mon Sep 17 00:00:00 2001 From: nahem Date: Tue, 16 Jul 2024 12:49:35 +0200 Subject: [PATCH 17/19] fix: added two filters to avoid hitting an error on edge cases. Tests are finally passing --- .../tests/integration.proptest-regressions | 3 ++ integration-tests/tests/integration.rs | 38 ++++++++----------- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/integration-tests/tests/integration.proptest-regressions b/integration-tests/tests/integration.proptest-regressions index f306fff61..176bb3d1b 100644 --- a/integration-tests/tests/integration.proptest-regressions +++ b/integration-tests/tests/integration.proptest-regressions @@ -10,3 +10,6 @@ cc be34ad8aed4e8ea2f874d3e9ec4e2dc2b336d39726932964bbe269679d09d3f5 # shrinks to cc 765652262526798bff5ab497b63867f49407edcc9d8401ac7e7fe5f5c4b0517d # shrinks to actions = [Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 67667), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "uusdc", 418), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "uusdt", "uwhale", 78764), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"))] cc a493bab6a18a04140ecf687fc001c601594c0d2663f8cfe9ae2e2810122e2cad # shrinks to actions = [Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "uusdc", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 49443), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 21755), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "inj", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 55773), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 7395), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 94253), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "btc", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 62734), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 43217), Claim(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40")), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 40048), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 2900), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "uusdt", "uwhale", 86634), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 52323)] cc 3b5397f642639811c6e9bac6df19d6233280bdac4052fa151d021b307f91ca92 # shrinks to actions = [Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 63566), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "btc", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 9255), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "btc", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 17237), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "btc", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 10299), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 8055), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 23885), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 71478), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "inj", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 9815), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", "inj", 21240), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 35919), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "uwhale", "uusdc", 15171), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 76186), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "inj", "uusdc", 55951), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 15548), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 80196), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 26427), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "uusdt", "uusdc", 50501), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 89102), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", "btc", 85249), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "uusdt", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 24089), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 66637), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 65668), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "inj", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 92068), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "uusdt", "inj", 52416), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 2153), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 21695), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "uwhale", "uusdt", 50727), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 43056), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "inj", 4333), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "uusdc", "uwhale", 4146), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 84969), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 74534), Bond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 94949), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 29147), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 26853), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 36736), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 22545), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 25651), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 98938), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "inj", "uwhale", 45942), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 27148), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 27602), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 85917), Claim(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40")), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "btc", "uwhale", 17732), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Bond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 90317), Claim(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40")), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "btc", "btc", 56974), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", "inj", 15831), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 95138), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 27735), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 27221), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "uwhale", "btc", 58599), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 84739), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "inj", "uusdt", 51657), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 68252), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"))] +cc 4c5e400a717190f22d9e2aeb9ff43ab9e3936da0693130b8979a60bb4597a1de # shrinks to actions = [Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 7236), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "btc", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 69537), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "inj", "uusdc", 54028), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 57474), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 83877), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 24013), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 90308), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 27173), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 97754), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 70189), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 6483), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 26165), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 40230), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 10724), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 14267), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "uwhale", "btc", 55703), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 87097), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "inj", "inj", 33964), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "uusdc", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 76509), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 63613), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 45535), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 35659), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 22998), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "uusdt", "uusdt", 78582), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 99522), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "uwhale", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 11550), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 31729), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "btc", "uusdc", 61993), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 91654), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "btc", "uwhale", 58904), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "uusdc", 21422), Claim(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40")), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 49420), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 6031), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "btc", "inj", 42736), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 69542), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 14313), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 46892), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 55242), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "uusdc", "btc", 39594), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 50171), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 46077), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "uusdc", 52799), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 91567), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 72093), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 7423), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "uusdc", "inj", 32140), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 70165), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "btc", "uwhale", 53210), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 13088), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 79789), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "inj", 87604), Bond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 40248), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 20980), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 3858), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 28365), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "btc", "uusdc", 32769), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "inj", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 35685), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "inj", "uwhale", 87867), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 25335), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 59893), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "uusdc", "inj", 15776), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 82083), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 92711), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 40155), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 51717), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 73963), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Bond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 25236), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 98417)] +cc 2c9f7f5f13a2e07090379394696ef1004b07644455db3dbcd6048e6e0f2ae602 # shrinks to actions = [Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 38194), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "uusdc", "uwhale", 34410), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 25908), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 10759), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 85448), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 64080), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "uusdc", 20207), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 47894), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 42739), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 34582), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 35518), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 47124), Bond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 36670), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 8145), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "inj", "uusdc", 95857), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 24202), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 45055), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 61880), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "uusdt", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 32050), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "uwhale", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 20375), Claim(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40")), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 19301), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "inj", "btc", 75963), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 88451), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "inj", 6426), Claim(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40")), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 36342), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 23939), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 7873), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "inj", "uusdc", 31364), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 18594), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "uusdc", 38259), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 26572), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Claim(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40")), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 5163), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "uusdt", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 12304), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Claim(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40")), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 16984), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "uusdt", "btc", 42098), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 38151), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 87055), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "uusdc", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 41786), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "btc", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 59219), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", "uusdc", 45717), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "uwhale", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 42681), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 44913), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", "uusdt", 52352), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 88684), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 43363), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 6448), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 75395), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 12839), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 23620), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 66945)] +cc ecc2eaff3380b1953a71ed02ef82aded2fdebbdbd8a0e9ff29f309c5cff34e4a # shrinks to actions = [Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 46559), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "uusdt", "uusdc", 2621), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 76510), Bond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 35262), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "uusdc", 5257), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", "btc", 90781), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "uwhale", "uusdc", 69472), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 50460), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 8093)] diff --git a/integration-tests/tests/integration.rs b/integration-tests/tests/integration.rs index 478ca1523..086b766cb 100644 --- a/integration-tests/tests/integration.rs +++ b/integration-tests/tests/integration.rs @@ -1,5 +1,5 @@ use std::cell::RefCell; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::rc::Rc; use bonding_manager::ContractError; @@ -220,8 +220,8 @@ proptest! { let bonded_amounts = Rc::new(RefCell::new(HashMap::>::new())); let claimable_rewards = Rc::new(RefCell::new(HashMap::<(Addr, u64), bool>::new())); let available_pools = suite.pool_identifiers.clone(); + let claimed = Rc::new(RefCell::new(HashSet::new())); - let last_claimed = Rc::new(RefCell::new(HashMap::::new())); let mut swaps_in_epoch = false; for action in actions { @@ -229,9 +229,10 @@ proptest! { suite.query_current_epoch(|response| { current_epoch = response.unwrap().epoch.id; }); - // suite.query_claimable_reward_buckets(None, |response| { - // println!(">>> [{current_epoch}] CLAIMABLE REWARDS {:?}", response.unwrap().1); - // }); + // TODO: >>> remove this once + if current_epoch > 120 { + break; + } match action { Action::Swap(user, from_token, to_token, amount) => { @@ -287,8 +288,6 @@ proptest! { // Mark claimable rewards for users bonded during this epoch let bonded_amounts = bonded_amounts.borrow(); - println!(">>> [{current_epoch}] BONDED AMOUNTS {:?}", bonded_amounts); - for (user, token_amounts) in bonded_amounts.iter() { if token_amounts.values().any(|&amount| amount > 0) { claimable_rewards.borrow_mut().insert((user.clone(), current_epoch), true); @@ -334,6 +333,7 @@ proptest! { for epoch in 0..current_epoch { claimable_rewards.borrow_mut().remove(&(user.clone(), epoch)); } + claimed.borrow_mut().insert(user.clone()); } suite.query_bonding_rewards(user.to_string(), |response| { @@ -395,6 +395,7 @@ proptest! { for epoch in 0..current_epoch { claimable_rewards.borrow_mut().remove(&(user.clone(), epoch)); } + claimed.borrow_mut().insert(user.clone()); } suite.unbond(user.clone(), coin(amount, &token), |result| { @@ -447,29 +448,18 @@ proptest! { } } - suite.query_bonding_rewards(user.to_string(), |response| { - let contract_rewards = &response.as_ref().unwrap().1.rewards; - let has_contract_rewards = !contract_rewards.is_empty(); - println!(">>>"); - println!(">>> [{current_epoch}] CLAIMABLE REWARDS CONTRACT {:?}", contract_rewards); - println!(">>> [{current_epoch}] CLAIMABLE REWARDS PROPTEST {:?}", claimable_rewards.borrow()); - assert_eq!(has_pending_rewards, has_contract_rewards); - }); - if has_pending_rewards { println!(">>> [{current_epoch}] [{user}] CLAIM"); - suite.query_bonding_rewards(user.to_string(), |response| { - println!(">>> [{current_epoch}] BONDING REWARDS {:?}", response.unwrap().1); - }); + suite.claim_bonding_rewards(&user, |result| { result.unwrap(); }); - last_claimed.borrow_mut().insert(user.clone(), current_epoch); - for epoch in 0..current_epoch { claimable_rewards.borrow_mut().remove(&(user.clone(), epoch)); } + + claimed.borrow_mut().insert(user.clone()); } else { println!(">>> [{current_epoch}] [{user}] CLAIM FAILED (nothing to claim)"); @@ -484,6 +474,8 @@ proptest! { } if rand::random() { + // workaround to avoid hitting an error when unclaimed rewards are rolled over after 21 epochs + // if there are unclaimed rewards when creating a new epoch, we need to add them to the claimable rewards map +21 epochs ahead suite.add_one_epoch(); swaps_in_epoch = false; } @@ -543,8 +535,8 @@ fn action_strategy(users: Vec) -> impl Strategy { let bond_unbond_token_strategy = prop_oneof![Just(BWHALE.to_string()), Just(AMPWHALE.to_string())]; - const MIN_AMOUNT: u128 = 1_000; - let amount_strategy = MIN_AMOUNT..100_000_u128; + const MIN_AMOUNT: u128 = 10_000; + let amount_strategy = MIN_AMOUNT..1_000_000_u128; prop_oneof![ ( From 8a7477948b11d9f3787e5ba562e458936c5f690e Mon Sep 17 00:00:00 2001 From: nahem Date: Mon, 22 Jul 2024 14:40:24 +0200 Subject: [PATCH 18/19] feat: add withdraw action to proptests --- integration-tests/tests/common/suite.rs | 2 +- .../tests/integration.proptest-regressions | 3 + integration-tests/tests/integration.rs | 75 ++++++++++++++++--- 3 files changed, 68 insertions(+), 12 deletions(-) diff --git a/integration-tests/tests/common/suite.rs b/integration-tests/tests/common/suite.rs index bd0d4721d..1be5c48bc 100644 --- a/integration-tests/tests/common/suite.rs +++ b/integration-tests/tests/common/suite.rs @@ -426,7 +426,7 @@ impl TestingSuite { } #[track_caller] - pub(crate) fn _withdraw_after_unbond( + pub(crate) fn withdraw_after_unbond( &mut self, sender: Addr, denom: String, diff --git a/integration-tests/tests/integration.proptest-regressions b/integration-tests/tests/integration.proptest-regressions index 176bb3d1b..46d379c0e 100644 --- a/integration-tests/tests/integration.proptest-regressions +++ b/integration-tests/tests/integration.proptest-regressions @@ -13,3 +13,6 @@ cc 3b5397f642639811c6e9bac6df19d6233280bdac4052fa151d021b307f91ca92 # shrinks to cc 4c5e400a717190f22d9e2aeb9ff43ab9e3936da0693130b8979a60bb4597a1de # shrinks to actions = [Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 7236), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "btc", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 69537), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "inj", "uusdc", 54028), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 57474), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 83877), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 24013), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 90308), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 27173), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 97754), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 70189), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 6483), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 26165), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 40230), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 10724), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 14267), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "uwhale", "btc", 55703), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 87097), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "inj", "inj", 33964), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "uusdc", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 76509), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 63613), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 45535), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 35659), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 22998), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "uusdt", "uusdt", 78582), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 99522), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "uwhale", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 11550), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 31729), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "btc", "uusdc", 61993), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 91654), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "btc", "uwhale", 58904), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "uusdc", 21422), Claim(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40")), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 49420), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 6031), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "btc", "inj", 42736), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 69542), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 14313), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 46892), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 55242), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "uusdc", "btc", 39594), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 50171), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 46077), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "uusdc", 52799), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 91567), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 72093), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 7423), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "uusdc", "inj", 32140), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 70165), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "btc", "uwhale", 53210), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 13088), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 79789), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "inj", 87604), Bond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 40248), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 20980), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 3858), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 28365), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "btc", "uusdc", 32769), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "inj", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 35685), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "inj", "uwhale", 87867), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 25335), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 59893), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "uusdc", "inj", 15776), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 82083), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 92711), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 40155), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 51717), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 73963), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Bond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 25236), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 98417)] cc 2c9f7f5f13a2e07090379394696ef1004b07644455db3dbcd6048e6e0f2ae602 # shrinks to actions = [Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 38194), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "uusdc", "uwhale", 34410), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 25908), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 10759), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 85448), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 64080), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "uusdc", 20207), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 47894), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 42739), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 34582), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 35518), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 47124), Bond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 36670), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 8145), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "inj", "uusdc", 95857), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 24202), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 45055), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 61880), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "uusdt", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 32050), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "uwhale", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 20375), Claim(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40")), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 19301), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "inj", "btc", 75963), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 88451), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "inj", 6426), Claim(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40")), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 36342), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 23939), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 7873), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "inj", "uusdc", 31364), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 18594), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "uusdc", 38259), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 26572), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Claim(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40")), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 5163), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "uusdt", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 12304), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Claim(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40")), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 16984), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "uusdt", "btc", 42098), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 38151), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 87055), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "uusdc", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 41786), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "btc", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 59219), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", "uusdc", 45717), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "uwhale", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 42681), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 44913), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", "uusdt", 52352), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 88684), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 43363), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 6448), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 75395), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 12839), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 23620), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 66945)] cc ecc2eaff3380b1953a71ed02ef82aded2fdebbdbd8a0e9ff29f309c5cff34e4a # shrinks to actions = [Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 46559), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "uusdt", "uusdc", 2621), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 76510), Bond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 35262), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "uusdc", 5257), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", "btc", 90781), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "uwhale", "uusdc", 69472), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 50460), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 8093)] +cc ee92f51b1ed1f18ff72fd4f601d9f1aa7f2abdbd6ad49741111558446ce1d403 # shrinks to actions = [Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "uusdc", "uusdt", 514259), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "uwhale", "uusdc", 421638), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "uusdc", "uusdt", 863087), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 914416), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "uwhale", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 303034), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "btc", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 918840), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "btc", "btc", 56677), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "uusdc", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 878216), Claim(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40")), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 344092), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 913754), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 553201), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "uwhale", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 911859), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 563549), Bond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 487709), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 667783), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 370120), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 720100), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 716287), Claim(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40")), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 891495), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Bond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 309736), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 581665), Bond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 927762), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 373200), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 953096), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "inj", "uusdt", 393638), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Bond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 309155), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "uwhale", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 563714), Bond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 274560), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "inj", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 405844), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "uusdt", 10884), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 293731), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 728934), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 311455), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Unbond(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 134112), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 801321), Claim(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40")), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "inj", "uusdc", 547760), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "uusdt", "ibc/BEFB9AB13AB43157A0AF6254AD4B1F565AC0CA0C1760B8339BE7B9E2996F7752", 746955), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75")), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 182706), Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 386757), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "uusdc", "btc", 978298), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "uusdt", "uwhale", 736435), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "uusdc", "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", 408449), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "peggy0x87aB3B4C8661e07D6372361211B96ed4Dc36B1B5", "btc", 501728), Claim(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y")), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 605408), Claim(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40")), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 864267), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 327260), Claim(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"))] +cc 6a4b664d50752229b2735c4b690d72dfcb085a3c9ccc514982cdb23065281a74 # shrinks to actions = [Bond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 3201545), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 10000), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 78485416), Withdraw(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE")] +cc 6c4bada671b422b29faf8b2ae6a7d9ddc7379c41d6897c984831757cafd812a0 # shrinks to actions = [Unbond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 14616899), Withdraw(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE"), Swap(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "uusdc", "btc", 71160609), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 16252762), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Swap(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "inj", "uusdc", 18149359), Bond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 39469324), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "uusdc", "btc", 76079066), Claim(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40")), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 69401619), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 7254009), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Withdraw(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE"), Withdraw(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE"), Bond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 9051053), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 51842970), Withdraw(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE"), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Unbond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 17052991), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 26730141), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 9585309), Bond(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 83719067), Withdraw(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE"), Claim(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3")), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 60208522), Swap(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "inj", "uusdt", 24599698), Swap(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "uwhale", "btc", 93803445), Withdraw(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE"), Claim(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7")), Claim(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40")), Unbond(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE", 6786135), Withdraw(Addr("migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE"), Withdraw(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE"), Bond(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 73634365), Swap(Addr("migaloo1h3s5np57a8cxaca3rdjlgu8jzmr2d2zz55s5y3"), "uusdc", "inj", 43800601), Withdraw(Addr("migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE"), Unbond(Addr("migaloo1lh7mmdavky83xks76ch57whjaqa7e456vvpz8y"), "factory/migaloo193lk767456jhkzddnz7kf5jvuzfn67gyfvhc40/ampWHALE", 56261876), Withdraw(Addr("migaloo13y3petsaw4vfchac4frjmuuevjjjcceja7sjx7"), "factory/migaloo1ludaslnu24p5eftw499f7ngsc2jkzqdsrvxt75/bWHALE")] diff --git a/integration-tests/tests/integration.rs b/integration-tests/tests/integration.rs index 086b766cb..f2f296aaa 100644 --- a/integration-tests/tests/integration.rs +++ b/integration-tests/tests/integration.rs @@ -211,13 +211,19 @@ proptest! { suite.unbond(alice.clone(), coin(10_000, AMPWHALE), |result| { result.unwrap(); }); - suite.add_epochs(79); + suite.add_epochs(1); + suite.withdraw_after_unbond(alice.clone(), AMPWHALE.to_string(), |result| { + result.unwrap(); + }); + suite.add_epochs(78); suite.query_claimable_reward_buckets(None, |response| { assert!(response.unwrap().1.is_empty()); }); let current_rewards = Rc::new(RefCell::new(0)); let bonded_amounts = Rc::new(RefCell::new(HashMap::>::new())); + let unbond_id_counter = Rc::new(RefCell::new(0)); + let unbonding_amounts = Rc::new(RefCell::new(HashMap::>::new())); let claimable_rewards = Rc::new(RefCell::new(HashMap::<(Addr, u64), bool>::new())); let available_pools = suite.pool_identifiers.clone(); let claimed = Rc::new(RefCell::new(HashSet::new())); @@ -229,8 +235,8 @@ proptest! { suite.query_current_epoch(|response| { current_epoch = response.unwrap().epoch.id; }); - // TODO: >>> remove this once - if current_epoch > 120 { + // TODO: >>> remove this once + if current_epoch > 121 { break; } @@ -373,7 +379,6 @@ proptest! { }); } Action::Unbond(user, token, amount) => { - // TODO: >>> check if this is creating an entry in the bonded_amounts map when it shouldn't ??? let mut bonded_amounts = bonded_amounts.borrow_mut(); let user_bonds = bonded_amounts.entry(user.clone()).or_insert_with(HashMap::new); @@ -403,6 +408,12 @@ proptest! { }); *bonded -= amount; + let mut unbonding_amounts = unbonding_amounts.borrow_mut(); + let user_unbonds = unbonding_amounts.entry(user.clone()).or_insert_with(HashMap::new); + let unbond_id = *unbond_id_counter.borrow_mut() + 1; + *unbond_id_counter.borrow_mut() = unbond_id; + user_unbonds.insert((token.clone(), unbond_id), current_epoch); + suite.query_bonding_rewards(user.to_string(), |response| { let contract_rewards = response.unwrap().1.rewards; let has_contract_rewards = !contract_rewards.is_empty(); @@ -422,8 +433,8 @@ proptest! { suite.unbond(user.clone(), coin(amount, &token), |result| { assert_eq!( - result.unwrap_err().downcast::().unwrap(), - bonding_manager::ContractError::InsufficientBond + result.unwrap_err().downcast::().unwrap(), + ContractError::InsufficientBond ); }); } @@ -432,12 +443,51 @@ proptest! { suite.unbond(user.clone(), coin(amount, &token), |result| { assert_eq!( - result.unwrap_err().downcast::().unwrap(), - bonding_manager::ContractError::NothingToUnbond + result.unwrap_err().downcast::().unwrap(), + ContractError::NothingToUnbond ); }); } + } + Action::Withdraw(user, token) => { + let mut unbonding_amounts = unbonding_amounts.borrow_mut(); + let user_unbonds: Vec<((String, u64), u64)> = unbonding_amounts.get(&user) + .map(|user_unbonds| { + user_unbonds.iter() + .filter_map(|(&(ref tok, unbond_id), &epoch)| { + if tok == &token && epoch < current_epoch { + Some(((tok.clone(), unbond_id), epoch)) + } else { + None + } + }) + .collect() + }) + .unwrap_or_default(); + println!(">>> user_unbonds: {:?}", user_unbonds); + + if !user_unbonds.is_empty() { + println!(">>> [{current_epoch}] [{user}] WITHDRAW [{} {}]", user_unbonds.len(), token.split('/').nth(2).unwrap()); + + suite.withdraw_after_unbond(user.clone(), token.clone(), |result| { + result.unwrap(); + }); + + // clear withdrawn unbonds from the unbonding_amounts map + for ((tok, unbond_id), _) in user_unbonds { + unbonding_amounts.get_mut(&user).unwrap().remove(&(tok, unbond_id)); + } + } else { + println!(">>> [{current_epoch}] [{user}] WITHDRAW FAILED (nothing to withdraw)"); + + suite.withdraw_after_unbond(user.clone(), token.clone(), |result| { + assert_eq!( + result.unwrap_err().downcast::().unwrap(), + ContractError::NothingToWithdraw + ); + }); + } } Action::Claim(user) => { let mut has_pending_rewards = false; @@ -465,8 +515,8 @@ proptest! { suite.claim_bonding_rewards(&user, |result| { assert_eq!( - result.unwrap_err().downcast::().unwrap(), - bonding_manager::ContractError::NothingToClaim + result.unwrap_err().downcast::().unwrap(), + ContractError::NothingToClaim ); }); } @@ -510,6 +560,7 @@ enum Action { Swap(Addr, String, String, u128), Bond(Addr, String, u128), Unbond(Addr, String, u128), + Withdraw(Addr, String), Claim(Addr), } @@ -536,7 +587,7 @@ fn action_strategy(users: Vec) -> impl Strategy { prop_oneof![Just(BWHALE.to_string()), Just(AMPWHALE.to_string())]; const MIN_AMOUNT: u128 = 10_000; - let amount_strategy = MIN_AMOUNT..1_000_000_u128; + let amount_strategy = MIN_AMOUNT..100_000_000_u128; prop_oneof![ ( @@ -560,6 +611,8 @@ fn action_strategy(users: Vec) -> impl Strategy { amount_strategy.clone() ) .prop_map(|(user, token, amount)| Action::Unbond(user, token, amount)), + (user_strategy.clone(), bond_unbond_token_strategy.clone()) + .prop_map(|(user, token)| Action::Withdraw(user, token)), user_strategy.clone().prop_map(|user| Action::Claim(user)), ] } From bf28bfb10251134d7730972486ddc4db98195654 Mon Sep 17 00:00:00 2001 From: nahem Date: Fri, 16 Aug 2024 08:51:11 +0200 Subject: [PATCH 19/19] fix: remove filter that was restricting the amount of epochs to 21 --- integration-tests/tests/common/suite.rs | 2 +- integration-tests/tests/integration.rs | 26 ++++++++++++++----------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/integration-tests/tests/common/suite.rs b/integration-tests/tests/common/suite.rs index 1be5c48bc..7b0bc1ef1 100644 --- a/integration-tests/tests/common/suite.rs +++ b/integration-tests/tests/common/suite.rs @@ -232,7 +232,7 @@ impl TestingSuite { unbonding_period: 1u64, growth_rate: Decimal::one(), bonding_assets: vec![AMPWHALE.to_string(), BWHALE.to_string()], - grace_period: 21, + grace_period: 101, epoch_manager_addr, }; diff --git a/integration-tests/tests/integration.rs b/integration-tests/tests/integration.rs index f2f296aaa..7a114fdd3 100644 --- a/integration-tests/tests/integration.rs +++ b/integration-tests/tests/integration.rs @@ -57,9 +57,9 @@ fn epic_test() { result.unwrap(); }) // create 20 more epochs, should not let alice claim any rewards - .add_epochs(20) + .add_epochs(100) .query_current_epoch(|result| { - assert_eq!(result.unwrap().epoch.id, 22); + assert_eq!(result.unwrap().epoch.id, 102); }) .query_claimable_reward_buckets(Some(&alice), |response| { assert!(response.unwrap().1.is_empty()); @@ -67,7 +67,7 @@ fn epic_test() { // create 1 more epoch should let alice claim 19_000 uwhale from the initial setup .add_epochs(1) .query_current_epoch(|result| { - assert_eq!(result.unwrap().epoch.id, 23); + assert_eq!(result.unwrap().epoch.id, 103); }) .query_claimable_reward_buckets(Some(&alice), |response| { assert_eq!(response.unwrap().1[0].available, coins(19_000, "uwhale")); @@ -100,7 +100,7 @@ fn epic_test() { .add_one_epoch() // check we're on epoch 24 .query_current_epoch(|result| { - assert_eq!(result.unwrap().epoch.id, 24); + assert_eq!(result.unwrap().epoch.id, 104); }) .swap( carol.clone(), @@ -164,6 +164,12 @@ fn epic_test() { .query_claimable_reward_buckets(Some(&bob), |response| { println!("{:?}", response.unwrap().1); }); + + // check we're on epoch 200 + suite.add_epochs(93); + suite.query_current_epoch(|result| { + assert_eq!(result.unwrap().epoch.id, 200); + }); } proptest! { @@ -222,10 +228,14 @@ proptest! { let current_rewards = Rc::new(RefCell::new(0)); let bonded_amounts = Rc::new(RefCell::new(HashMap::>::new())); + // simple counter that increments every time a user unbonds let unbond_id_counter = Rc::new(RefCell::new(0)); + // user => (bonded_token, unbond_id_counter) => epoch let unbonding_amounts = Rc::new(RefCell::new(HashMap::>::new())); + // (user, epoch) => bool let claimable_rewards = Rc::new(RefCell::new(HashMap::<(Addr, u64), bool>::new())); let available_pools = suite.pool_identifiers.clone(); + // list of the users that claimed in the current epoch (either by executing claim or bond/unbond with pending rewards) let claimed = Rc::new(RefCell::new(HashSet::new())); let mut swaps_in_epoch = false; @@ -235,10 +245,6 @@ proptest! { suite.query_current_epoch(|response| { current_epoch = response.unwrap().epoch.id; }); - // TODO: >>> remove this once - if current_epoch > 121 { - break; - } match action { Action::Swap(user, from_token, to_token, amount) => { @@ -297,6 +303,7 @@ proptest! { for (user, token_amounts) in bonded_amounts.iter() { if token_amounts.values().any(|&amount| amount > 0) { claimable_rewards.borrow_mut().insert((user.clone(), current_epoch), true); + // } } } else { @@ -343,7 +350,6 @@ proptest! { } suite.query_bonding_rewards(user.to_string(), |response| { - // >>> TODO: MAKE SURE THE CONTRACT IS UPDATING STATE CORRECTLY AFTER BONDING WITH PENDING REWARDS let contract_rewards = response.unwrap().1.rewards; let has_contract_rewards = !contract_rewards.is_empty(); @@ -465,8 +471,6 @@ proptest! { }) .unwrap_or_default(); - println!(">>> user_unbonds: {:?}", user_unbonds); - if !user_unbonds.is_empty() { println!(">>> [{current_epoch}] [{user}] WITHDRAW [{} {}]", user_unbonds.len(), token.split('/').nth(2).unwrap());