From ff5a5c65258a48bf07b20eb0ae071f96d726272f Mon Sep 17 00:00:00 2001 From: Sturdy <91910406+apollo-sturdy@users.noreply.github.com> Date: Fri, 9 Feb 2024 19:41:15 +0100 Subject: [PATCH 01/22] feat: replace astroport generator with incentives contract --- Cargo.lock | 919 +++++++++--------- Cargo.toml | 7 +- cw-dex/Cargo.toml | 3 +- cw-dex/src/implementations/astroport/pool.rs | 16 +- .../src/implementations/astroport/staking.rs | 64 +- .../astroport-test-contract/src/contract.rs | 27 +- .../osmosis-test-contract/src/contract.rs | 12 +- test-contracts/package/src/msg.rs | 9 +- test-helpers/src/astroport.rs | 6 +- 9 files changed, 543 insertions(+), 520 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 625c345..a00efdf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -49,28 +49,28 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "423502406a307052f6877030f48b5fb4e9fb338fc5e7c8ca1064210def52876b" dependencies = [ - "astroport 2.9.0", + "astroport 2.9.3", "cosmwasm-std", - "cw-storage-plus 1.1.0", - "cw20 1.1.1", + "cw-storage-plus 1.2.0", + "cw20 1.1.2", "schemars", "serde", ] [[package]] name = "apollo-cw-multi-test" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b88d6037608a781a95ab1125941e2358c37272dcf0d4613de795b81b6ffbf3" +checksum = "f79f4204575175473a9b7fff8083596d09e6edb07469d2a4176846b353b2d1ef" dependencies = [ "anyhow", "cosmwasm-std", - "cw-storage-plus 1.1.0", + "cw-storage-plus 1.2.0", "cw-utils 1.0.2", "derivative", - "itertools", + "itertools 0.10.5", "k256 0.11.6", - "osmosis-std", + "osmosis-std 0.22.0", "prost 0.9.0", "regex", "schemars", @@ -87,7 +87,7 @@ dependencies = [ "apollo-cw-asset", "cosmwasm-schema", "cosmwasm-std", - "cw20 1.1.1", + "cw20 1.1.2", "regex", ] @@ -104,33 +104,34 @@ dependencies = [ [[package]] name = "astroport" -version = "2.9.0" +version = "2.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b863a982595743e181f89540d7aaeda35c60b6b5cac9c36c9be30cf11a5ece" +checksum = "3b991ce88f077c1d12f850c1f8fba3671bd72784f43f1638731d6d28f9b79839" dependencies = [ "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", "cw-utils 0.15.1", "cw20 0.15.1", - "itertools", + "itertools 0.10.5", "uint", ] [[package]] name = "astroport" -version = "3.6.1" +version = "3.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "195a7441515817c0d114ec3bebe9faa21393781f796c179c38c75e3cfb9fb4ec" +checksum = "c001a7f97db88ffe6fc6cca97bbdbfe926e55599184921ff7e72cd47559440de" dependencies = [ "astroport-circular-buffer", "cosmwasm-schema", "cosmwasm-std", + "cw-asset", "cw-storage-plus 0.15.1", "cw-utils 1.0.2", "cw20 0.15.1", "cw3", - "itertools", + "itertools 0.10.5", "uint", ] @@ -152,12 +153,12 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ecf768e2d3153bebfbe0c502ffa4199a52598e9b6e89fca54339615b2de77eb" dependencies = [ - "astroport 2.9.0", + "astroport 2.9.3", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", "cw2 0.15.1", - "itertools", + "itertools 0.10.5", "protobuf", "thiserror", ] @@ -168,7 +169,7 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6144780ac014665b07616de0cfb35ca6a9411ed821e20c21e02f4f428c8ed51f" dependencies = [ - "astroport 2.9.0", + "astroport 2.9.3", "astroport-governance", "cosmwasm-schema", "cosmwasm-std", @@ -186,26 +187,43 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72806ace350e81c4e1cab7e275ef91f05bad830275d697d67ad1bd4acc6f016d" dependencies = [ - "astroport 2.9.0", + "astroport 2.9.3", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", "cw20 0.15.1", ] +[[package]] +name = "astroport-incentives" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba05c27479d2885ba313086aa0b7d09284f1393f1ebb6d385f96d93b3c6fb72a" +dependencies = [ + "astroport 3.11.1", + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus 0.15.1", + "cw-utils 1.0.2", + "cw2 1.1.1", + "cw20 1.1.2", + "itertools 0.11.0", + "thiserror", +] + [[package]] name = "astroport-liquidity-manager" -version = "1.0.3" +version = "1.0.3-astroport-v2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5673fe63b0284e30d1b456dea067cfaa82d2be6eafe5468cc0442917d49a04" +checksum = "ae4bf7689e7c37cfecc200aab3401c1ff6a507cccc9fb1baadfa71a73addaa2f" dependencies = [ - "astroport 3.6.1", + "astroport 2.9.3", "astroport-factory", "astroport-pair", - "astroport-pair-stable 3.3.0", + "astroport-pair-stable", "cosmwasm-schema", "cosmwasm-std", - "cw-storage-plus 1.1.0", + "cw-storage-plus 1.2.0", "cw20 0.15.1", "cw20-base 0.15.1", "thiserror", @@ -218,7 +236,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92403e5d00e3c77d13d9616661ea9d9308d493fff6bec5e6e5e7bd7b7e0ff6af" dependencies = [ "astro-satellite-package", - "astroport 2.9.0", + "astroport 2.9.3", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", @@ -233,7 +251,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "648ed6827a8f11012c0377fb60329204e8511fe46c86db3220113e70bdc57826" dependencies = [ - "astroport 2.9.0", + "astroport 2.9.3", "cosmwasm-schema", "cosmwasm-std", "cosmwasm-storage", @@ -244,15 +262,14 @@ dependencies = [ [[package]] name = "astroport-pair" -version = "1.5.0" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd96bc64722440636ed6267a6945ccce076231a08467d6d46a4af4c4ff062c69" +checksum = "e760b91eaf269bb2843b75b34eb73d474374bd2ebefbbe3cdb0a58d69959573b" dependencies = [ - "astroport 3.6.1", + "astroport 2.9.3", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", - "cw-utils 1.0.2", "cw2 0.15.1", "cw20 0.15.1", "integer-sqrt", @@ -266,7 +283,7 @@ version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04a90ce51403c81af3acf8e7028bb0eb095fce802365453b7e4a13bc0eb0d6d7" dependencies = [ - "astroport 2.9.0", + "astroport 2.9.3", "astroport-factory", "cosmwasm-schema", "cosmwasm-std", @@ -274,42 +291,24 @@ dependencies = [ "cw-utils 0.15.1", "cw2 0.15.1", "cw20 0.15.1", - "itertools", + "itertools 0.10.5", "thiserror", ] [[package]] name = "astroport-pair-stable" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3a262f2b6916e2a83808b246ff16cb2306a416e88b15a47ddbea5f8b666b1a4" +checksum = "d052966163fc2dd3eb46ae3c948ee7032a28726e046bc44431f9b488cb1dba90" dependencies = [ - "astroport 2.9.0", + "astroport 2.9.3", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", "cw-utils 1.0.2", "cw2 0.15.1", "cw20 0.15.1", - "itertools", - "thiserror", -] - -[[package]] -name = "astroport-pair-stable" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ac52657fa25194936d5218a258c2c041df00f0647e954a23f35e99b730f92b" -dependencies = [ - "astroport 3.6.1", - "astroport-circular-buffer", - "cosmwasm-schema", - "cosmwasm-std", - "cw-storage-plus 0.15.1", - "cw-utils 1.0.2", - "cw2 0.15.1", - "cw20 0.15.1", - "itertools", + "itertools 0.10.5", "thiserror", ] @@ -319,7 +318,7 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e3bbb33c00370bd194cf3a166f1e3f4029a2add2bea01a5eb61e886aefbc85b" dependencies = [ - "astroport 2.9.0", + "astroport 2.9.3", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", @@ -335,7 +334,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67adbc4240794e886ca1edbc7d46bc8a54c7aca7217d73ddcfbc90e1dbb030e7" dependencies = [ - "astroport 2.9.0", + "astroport 2.9.3", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", @@ -354,7 +353,7 @@ dependencies = [ "cosmwasm-std", "cw-dex", "cw-dex-test-contract", - "cw-storage-plus 1.1.0", + "cw-storage-plus 1.2.0", "thiserror", ] @@ -364,7 +363,7 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3360383a2e585211da9a455ad57eb100578253b5d18a387f025cadd666604d99" dependencies = [ - "astroport 2.9.0", + "astroport 2.9.3", "cosmwasm-schema", "cosmwasm-std", "cw2 0.15.1", @@ -379,7 +378,7 @@ version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dffce7cf86bf4d4f177ef941145352499e802abc4b898032af7808d16cca6371" dependencies = [ - "astroport 2.9.0", + "astroport 2.9.3", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", @@ -395,7 +394,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44156757bfab3d4bd208d9b86b890d1478f45d07c8f8d3d1c3e3da91081cb54d" dependencies = [ - "astroport 2.9.0", + "astroport 2.9.3", "cosmwasm-schema", "cosmwasm-std", "cw1-whitelist", @@ -411,18 +410,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", + "syn 2.0.48", ] [[package]] @@ -476,40 +464,44 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + [[package]] name = "bindgen" -version = "0.60.1" +version = "0.69.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" +checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.1", "cexpr", "clang-sys", - "clap", - "env_logger", + "itertools 0.10.5", "lazy_static", "lazycell", "log", - "peeking_take_while", + "prettyplease", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", + "syn 2.0.48", "which", ] [[package]] name = "bip32" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b30ed1d6f8437a487a266c8293aeb95b61a23261273e3e02912cdb8b68bf798b" +checksum = "7e141fb0f8be1c7b45887af94c88b182472b57c96b56773250ae00cd6a14a164" dependencies = [ "bs58", "hmac", - "k256 0.11.6", - "once_cell", - "pbkdf2", + "k256 0.13.1", "rand_core 0.6.4", "ripemd", "sha2 0.10.8", @@ -564,17 +556,17 @@ dependencies = [ [[package]] name = "bnum" -version = "0.8.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128a44527fc0d6abf05f9eda748b9027536e12dff93f5acc8449f51583309350" +checksum = "56953345e39537a3e18bdaeba4cb0c58a78c1f61f361dc0fa7c5c7340ae87c5f" [[package]] name = "bs58" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" +checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" dependencies = [ - "sha2 0.9.9", + "sha2 0.10.8", ] [[package]] @@ -594,6 +586,9 @@ name = "bytes" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +dependencies = [ + "serde", +] [[package]] name = "cc" @@ -639,30 +634,6 @@ dependencies = [ "libloading", ] -[[package]] -name = "clap" -version = "3.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" -dependencies = [ - "atty", - "bitflags 1.3.2", - "clap_lex", - "indexmap", - "strsim", - "termcolor", - "textwrap", -] - -[[package]] -name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] - [[package]] name = "config" version = "0.13.3" @@ -706,30 +677,30 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cosmos-sdk-proto" -version = "0.14.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20b42021d8488665b1a0d9748f1f81df7235362d194f44481e2e61bf376b77b4" +checksum = "32560304ab4c365791fd307282f76637213d8083c1a98490c35159cd67852237" dependencies = [ - "prost 0.11.9", - "prost-types", + "prost 0.12.3", + "prost-types 0.12.3", "tendermint-proto", ] [[package]] name = "cosmrs" -version = "0.9.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3903590099dcf1ea580d9353034c9ba1dbf55d1389a5bd2ade98535c3445d1f9" +checksum = "47126f5364df9387b9d8559dcef62e99010e1d4098f39eb3f7ee4b5c254e40ea" dependencies = [ "bip32", "cosmos-sdk-proto", - "ecdsa 0.14.8", + "ecdsa 0.16.8", "eyre", - "getrandom", - "k256 0.11.6", + "k256 0.13.1", "rand_core 0.6.4", "serde", "serde_json", + "signature 2.1.0", "subtle-encoding", "tendermint", "tendermint-rpc", @@ -738,11 +709,12 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.4.1" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6fb22494cf7d23d0c348740e06e5c742070b2991fd41db77bba0bcfbae1a723" +checksum = "9934c79e58d9676edfd592557dee765d2a6ef54c09d5aa2edb06156b00148966" dependencies = [ "digest 0.10.7", + "ecdsa 0.16.8", "ed25519-zebra", "k256 0.13.1", "rand_core 0.6.4", @@ -751,18 +723,18 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.4.1" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e199424486ea97d6b211db6387fd72e26b4a439d40cc23140b2d8305728055b" +checksum = "bc5e72e330bd3bdab11c52b5ecbdeb6a8697a004c57964caeb5d876f0b088b3c" dependencies = [ "syn 1.0.109", ] [[package]] name = "cosmwasm-schema" -version = "1.4.1" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fef683a9c1c4eabd6d31515719d0d2cc66952c4c87f7eb192bfc90384517dc34" +checksum = "ac3e3a2136e2a60e8b6582f5dffca5d1a683ed77bf38537d330bc1dfccd69010" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -773,9 +745,9 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.4.1" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9567025acbb4c0c008178393eb53b3ac3c2e492c25949d3bf415b9cbe80772d8" +checksum = "f5d803bea6bd9ed61bd1ee0b4a2eb09ee20dbb539cc6e0b8795614d20952ebb1" dependencies = [ "proc-macro2", "quote", @@ -784,11 +756,12 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.4.1" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d89d680fb60439b7c5947b15f9c84b961b88d1f8a3b20c4bd178a3f87db8bae" +checksum = "ef8666e572a3a2519010dde88c04d16e9339ae751b56b2bb35081fe3f7d6be74" dependencies = [ "base64 0.21.5", + "bech32", "bnum", "cosmwasm-crypto", "cosmwasm-derive", @@ -799,6 +772,7 @@ dependencies = [ "serde", "serde-json-wasm", "sha2 0.10.8", + "static_assertions", "thiserror", ] @@ -861,15 +835,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "ct-logs" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1a816186fa68d9e426e3cb4ae4dff1fcd8e4a2c34b781bf7a822574a0d0aac8" -dependencies = [ - "sct", -] - [[package]] name = "curve25519-dalek" version = "3.2.0" @@ -883,13 +848,50 @@ dependencies = [ "zeroize", ] +[[package]] +name = "curve25519-dalek-ng" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.6.4", + "subtle-ng", + "zeroize", +] + +[[package]] +name = "cw-address-like" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "451a4691083a88a3c0630a8a88799e9d4cd6679b7ce8ff22b8da2873ff31d380" +dependencies = [ + "cosmwasm-std", +] + +[[package]] +name = "cw-asset" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "431e57314dceabd29a682c78bb3ff7c641f8bdc8b915400bb9956cb911e8e571" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-address-like", + "cw-storage-plus 1.2.0", + "cw20 1.1.2", + "thiserror", +] + [[package]] name = "cw-dex" version = "0.5.1" dependencies = [ "apollo-cw-asset", "apollo-utils", - "astroport 2.9.0", + "astroport 2.9.3", + "astroport 3.11.1", "cosmwasm-schema", "cosmwasm-std", "cw-dex-test-contract", @@ -897,9 +899,9 @@ dependencies = [ "cw-it", "cw-utils 1.0.2", "cw2 1.1.1", - "cw20 1.1.1", + "cw20 1.1.2", "cw20-base 1.1.1", - "osmosis-std", + "osmosis-std 0.19.2", "proptest", "test-case", "thiserror", @@ -921,33 +923,35 @@ version = "0.1.0" dependencies = [ "apollo-cw-asset", "apollo-utils", - "astroport 2.9.0", + "astroport 2.9.3", "astroport-test-contract", "cosmwasm-std", "cw-dex-test-contract", "cw-it", - "cw20 1.1.1", + "cw20 1.1.2", "cw20-base 1.1.1", ] [[package]] name = "cw-it" -version = "0.2.3" +version = "0.3.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f452b759fc448ec05d20dc70f25dda8b83ba0a7c994049d27556fd1813a5ad0d" +checksum = "066d874d7976142d2ec44c80666214816fcfcef02432b2e1f92aade4f0e1e2be" dependencies = [ "anyhow", "apollo-cw-multi-test", "apollo-utils", - "astroport 2.9.0", + "astroport 2.9.3", + "astroport 3.11.1", "astroport-factory", "astroport-generator", + "astroport-incentives", "astroport-liquidity-manager", "astroport-maker", "astroport-native-coin-registry", "astroport-pair", "astroport-pair-concentrated", - "astroport-pair-stable 2.1.2", + "astroport-pair-stable", "astroport-router", "astroport-staking", "astroport-token", @@ -958,14 +962,13 @@ dependencies = [ "cosmwasm-schema", "cosmwasm-std", "cw20 0.15.1", - "osmosis-std", + "osmosis-std 0.22.0", "osmosis-test-tube", "paste", "proptest", - "prost 0.11.9", + "prost 0.12.3", "regex", "serde", - "serde_json", "strum", "test-tube", "thiserror", @@ -984,9 +987,9 @@ dependencies = [ [[package]] name = "cw-storage-plus" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f0e92a069d62067f3472c62e30adedb4cab1754725c0f2a682b3128d2bf3c79" +checksum = "d5ff29294ee99373e2cd5fd21786a3c0ced99a52fec2ca347d565489c61b723c" dependencies = [ "cosmwasm-std", "schemars", @@ -1073,7 +1076,7 @@ checksum = "9431d14f64f49e41c6ef5561ed11a5391c417d0cb16455dea8cdcb9037a8d197" dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-storage-plus 1.1.0", + "cw-storage-plus 1.2.0", "schemars", "serde", "thiserror", @@ -1094,9 +1097,9 @@ dependencies = [ [[package]] name = "cw20" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786e9da5e937f473cecd2463e81384c1af65d0f6398bbd851be7655487c55492" +checksum = "526e39bb20534e25a1cd0386727f0038f4da294e5e535729ba3ef54055246abd" dependencies = [ "cosmwasm-schema", "cosmwasm-std", @@ -1131,10 +1134,10 @@ checksum = "09558f87fd3d5e4a479761051b3f98ee2fa723d9e484b5679b6058ad0eadf8f1" dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-storage-plus 1.1.0", + "cw-storage-plus 1.2.0", "cw-utils 1.0.2", "cw2 1.1.1", - "cw20 1.1.1", + "cw20 1.1.2", "schemars", "semver", "serde", @@ -1150,7 +1153,7 @@ dependencies = [ "cosmwasm-schema", "cosmwasm-std", "cw-utils 1.0.2", - "cw20 1.1.1", + "cw20 1.1.2", "schemars", "serde", "thiserror", @@ -1254,21 +1257,23 @@ dependencies = [ [[package]] name = "ed25519" -version = "1.5.3" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ - "signature 1.6.4", + "pkcs8 0.10.2", + "signature 2.1.0", ] [[package]] -name = "ed25519-dalek" -version = "1.0.1" +name = "ed25519-consensus" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +checksum = "3c8465edc8ee7436ffea81d21a019b16676ee3db267aa8d5a8d729581ecf998b" dependencies = [ - "curve25519-dalek", - "ed25519", + "curve25519-dalek-ng", + "hex", + "rand_core 0.6.4", "sha2 0.9.9", "zeroize", ] @@ -1334,16 +1339,12 @@ dependencies = [ ] [[package]] -name = "env_logger" -version = "0.9.3" +name = "encoding_rs" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", + "cfg-if", ] [[package]] @@ -1431,7 +1432,6 @@ checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" dependencies = [ "futures-channel", "futures-core", - "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -1454,34 +1454,12 @@ version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" -[[package]] -name = "futures-executor" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - [[package]] name = "futures-io" version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" -[[package]] -name = "futures-macro" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - [[package]] name = "futures-sink" version = "0.3.29" @@ -1500,16 +1478,11 @@ version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ - "futures-channel", "futures-core", - "futures-io", - "futures-macro", "futures-sink", "futures-task", - "memchr", "pin-project-lite", "pin-utils", - "slab", ] [[package]] @@ -1598,45 +1571,12 @@ dependencies = [ "ahash", ] -[[package]] -name = "headers" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" -dependencies = [ - "base64 0.21.5", - "bytes", - "headers-core", - "http", - "httpdate", - "mime", - "sha1", -] - -[[package]] -name = "headers-core" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" -dependencies = [ - "http", -] - [[package]] name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.3.3" @@ -1701,12 +1641,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "hyper" version = "0.14.27" @@ -1731,41 +1665,18 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-proxy" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca815a891b24fdfb243fa3239c86154392b0953ee584aa1a2a1f66d20cbe75cc" -dependencies = [ - "bytes", - "futures", - "headers", - "http", - "hyper", - "hyper-rustls", - "rustls-native-certs", - "tokio", - "tokio-rustls", - "tower-service", - "webpki", -] - [[package]] name = "hyper-rustls" -version = "0.22.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ - "ct-logs", "futures-util", + "http", "hyper", - "log", "rustls", - "rustls-native-certs", "tokio", "tokio-rustls", - "webpki", - "webpki-roots", ] [[package]] @@ -1803,6 +1714,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + [[package]] name = "itertools" version = "0.10.5" @@ -1812,6 +1729,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.9" @@ -1848,7 +1774,6 @@ dependencies = [ "ecdsa 0.14.8", "elliptic-curve 0.12.3", "sha2 0.10.8", - "sha3", ] [[package]] @@ -1865,15 +1790,6 @@ dependencies = [ "signature 2.1.0", ] -[[package]] -name = "keccak" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" -dependencies = [ - "cpufeatures", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -2001,7 +1917,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.3", + "hermit-abi", "libc", ] @@ -2051,12 +1967,6 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "os_str_bytes" -version = "6.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" - [[package]] name = "osmosis-std" version = "0.19.2" @@ -2065,9 +1975,25 @@ checksum = "798fade51443a0e07eb25b59a11b320b9e8f03e6e8fbe14c520258f04742fe13" dependencies = [ "chrono", "cosmwasm-std", - "osmosis-std-derive", + "osmosis-std-derive 0.16.2", "prost 0.11.9", - "prost-types", + "prost-types 0.11.9", + "schemars", + "serde", + "serde-cw-value", +] + +[[package]] +name = "osmosis-std" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8641c376f01f5af329dc2a34e4f5527eaeb0bde18cda8d86fed958d04c86159c" +dependencies = [ + "chrono", + "cosmwasm-std", + "osmosis-std-derive 0.20.1", + "prost 0.12.3", + "prost-types 0.12.3", "schemars", "serde", "serde-cw-value", @@ -2079,9 +2005,22 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f47f0b2f22adb341bb59e5a3a1b464dde033181954bd055b9ae86d6511ba465b" dependencies = [ - "itertools", + "itertools 0.10.5", + "proc-macro2", + "prost-types 0.11.9", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "osmosis-std-derive" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5ebdfd1bc8ed04db596e110c6baa9b174b04f6ed1ec22c666ddc5cb3fa91bd7" +dependencies = [ + "itertools 0.10.5", "proc-macro2", - "prost-types", + "prost-types 0.11.9", "quote", "syn 1.0.109", ] @@ -2095,22 +2034,22 @@ dependencies = [ "cosmwasm-std", "cw-dex", "cw-dex-test-contract", - "cw-storage-plus 1.1.0", + "cw-storage-plus 1.2.0", "thiserror", ] [[package]] name = "osmosis-test-tube" -version = "19.2.0" +version = "22.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0dde0a21f1323e7c78f46da4bd0b24149d26483785fb5b39f74016f3f524aad" +checksum = "a082b97136d15470a37aa758f227c865594590b69d74721248ed5adf59bf1ca2" dependencies = [ - "base64 0.13.1", + "base64 0.21.5", "bindgen", "cosmrs", "cosmwasm-std", - "osmosis-std", - "prost 0.11.9", + "osmosis-std 0.22.0", + "prost 0.12.3", "serde", "serde_json", "test-tube", @@ -2129,21 +2068,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" -[[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - [[package]] name = "peg" version = "0.7.0" @@ -2208,7 +2132,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -2239,7 +2163,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -2280,6 +2204,16 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "prettyplease" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" +dependencies = [ + "proc-macro2", + "syn 2.0.48", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -2306,9 +2240,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -2353,6 +2287,16 @@ dependencies = [ "prost-derive 0.11.9", ] +[[package]] +name = "prost" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" +dependencies = [ + "bytes", + "prost-derive 0.12.3", +] + [[package]] name = "prost-derive" version = "0.9.0" @@ -2360,7 +2304,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" dependencies = [ "anyhow", - "itertools", + "itertools 0.10.5", "proc-macro2", "quote", "syn 1.0.109", @@ -2373,12 +2317,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", - "itertools", + "itertools 0.10.5", "proc-macro2", "quote", "syn 1.0.109", ] +[[package]] +name = "prost-derive" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" +dependencies = [ + "anyhow", + "itertools 0.10.5", + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "prost-types" version = "0.11.9" @@ -2388,6 +2345,15 @@ dependencies = [ "prost 0.11.9", ] +[[package]] +name = "prost-types" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" +dependencies = [ + "prost 0.12.3", +] + [[package]] name = "protobuf" version = "2.28.0" @@ -2405,9 +2371,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -2501,6 +2467,47 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "reqwest" +version = "0.11.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" +dependencies = [ + "base64 0.21.5", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-native-certs", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-rustls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + [[package]] name = "rfc6979" version = "0.3.1" @@ -2524,17 +2531,16 @@ dependencies = [ [[package]] name = "ring" -version = "0.16.20" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", + "getrandom", "libc", - "once_cell", "spin", "untrusted", - "web-sys", - "winapi", + "windows-sys", ] [[package]] @@ -2546,17 +2552,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "ripemd160" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eca4ecc81b7f313189bf73ce724400a07da2a6dac19588b03c8bd76a2dcc251" -dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "opaque-debug", -] - [[package]] name = "ron" version = "0.7.1" @@ -2605,29 +2600,47 @@ dependencies = [ [[package]] name = "rustls" -version = "0.19.1" +version = "0.21.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ - "base64 0.13.1", "log", "ring", + "rustls-webpki", "sct", - "webpki", ] [[package]] name = "rustls-native-certs" -version = "0.5.0" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a07b7c1885bd8ed3831c289b7870b13ef46fe0e856d288c30d9cc17d75a2092" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", - "rustls", + "rustls-pemfile", "schannel", "security-framework", ] +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.5", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.14" @@ -2696,9 +2709,9 @@ dependencies = [ [[package]] name = "sct" -version = "0.6.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ "ring", "untrusted", @@ -2781,9 +2794,9 @@ dependencies = [ [[package]] name = "serde-json-wasm" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16a62a1fad1e1828b24acac8f2b468971dade7b8c3c2e672bcadefefb1f8c137" +checksum = "9e9213a07d53faa0b8dd81e767a54a8188a242fdb9be99ab75ec576a774bfdd7" dependencies = [ "serde", ] @@ -2805,7 +2818,7 @@ checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -2838,18 +2851,19 @@ checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] -name = "sha1" -version = "0.10.6" +name = "serde_urlencoded" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", + "form_urlencoded", + "itoa", + "ryu", + "serde", ] [[package]] @@ -2876,16 +2890,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "sha3" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" -dependencies = [ - "digest 0.10.7", - "keccak", -] - [[package]] name = "shlex" version = "1.2.0" @@ -2964,9 +2968,9 @@ dependencies = [ [[package]] name = "spin" -version = "0.5.2" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "spki" @@ -2994,12 +2998,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - [[package]] name = "strum" version = "0.24.1" @@ -3037,6 +3035,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "subtle-ng" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" + [[package]] name = "syn" version = "1.0.109" @@ -3050,15 +3054,42 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.38" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tempfile" version = "3.8.1" @@ -3074,28 +3105,28 @@ dependencies = [ [[package]] name = "tendermint" -version = "0.23.9" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "467f82178deeebcd357e1273a0c0b77b9a8a0313ef7c07074baebe99d87851f4" +checksum = "bc2294fa667c8b548ee27a9ba59115472d0a09c2ba255771092a7f1dcf03a789" dependencies = [ - "async-trait", "bytes", + "digest 0.10.7", "ed25519", - "ed25519-dalek", + "ed25519-consensus", "flex-error", "futures", - "k256 0.11.6", + "k256 0.13.1", "num-traits", "once_cell", - "prost 0.11.9", - "prost-types", - "ripemd160", + "prost 0.12.3", + "prost-types 0.12.3", + "ripemd", "serde", "serde_bytes", "serde_json", "serde_repr", - "sha2 0.9.9", - "signature 1.6.4", + "sha2 0.10.8", + "signature 2.1.0", "subtle", "subtle-encoding", "tendermint-proto", @@ -3105,9 +3136,9 @@ dependencies = [ [[package]] name = "tendermint-config" -version = "0.23.9" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d42ee0abc27ef5fc34080cce8d43c189950d331631546e7dfb983b6274fa327" +checksum = "5a25dbe8b953e80f3d61789fbdb83bf9ad6c0ef16df5ca6546f49912542cc137" dependencies = [ "flex-error", "serde", @@ -3119,16 +3150,16 @@ dependencies = [ [[package]] name = "tendermint-proto" -version = "0.23.9" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ce80bf536476db81ecc9ebab834dc329c9c1509a694f211a73858814bfe023" +checksum = "2cc728a4f9e891d71adf66af6ecaece146f9c7a11312288a3107b3e1d6979aaf" dependencies = [ "bytes", "flex-error", "num-derive", "num-traits", - "prost 0.11.9", - "prost-types", + "prost 0.12.3", + "prost-types 0.12.3", "serde", "serde_bytes", "subtle-encoding", @@ -3137,24 +3168,23 @@ dependencies = [ [[package]] name = "tendermint-rpc" -version = "0.23.9" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f14aafe3528a0f75e9f3f410b525617b2de16c4b7830a21f717eee62882ec60" +checksum = "dfbf0a4753b46a190f367337e0163d0b552a2674a6bac54e74f9f2cdcde2969b" dependencies = [ "async-trait", "bytes", "flex-error", "futures", "getrandom", - "http", - "hyper", - "hyper-proxy", - "hyper-rustls", "peg", "pin-project", + "reqwest", + "semver", "serde", "serde_bytes", "serde_json", + "subtle", "subtle-encoding", "tendermint", "tendermint-config", @@ -3168,15 +3198,6 @@ dependencies = [ "walkdir", ] -[[package]] -name = "termcolor" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" -dependencies = [ - "winapi-util", -] - [[package]] name = "test-case" version = "3.2.1" @@ -3196,7 +3217,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -3208,50 +3229,44 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", "test-case-core", ] [[package]] name = "test-tube" -version = "0.1.7" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04de0d85f2438f0b64a5c135a1524564f2b89263cfbce011542446b6681d006f" +checksum = "09184c7655b2bdaf4517b06141a2e4c44360904f2706a05b24c831bd97ad1db6" dependencies = [ - "base64 0.13.1", + "base64 0.21.5", "cosmrs", "cosmwasm-std", - "osmosis-std", - "prost 0.11.9", + "osmosis-std 0.22.0", + "prost 0.12.3", "serde", "serde_json", "thiserror", ] -[[package]] -name = "textwrap" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" - [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -3311,18 +3326,17 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] name = "tokio-rustls" -version = "0.22.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ "rustls", "tokio", - "webpki", ] [[package]] @@ -3432,9 +3446,9 @@ dependencies = [ [[package]] name = "untrusted" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" @@ -3514,10 +3528,22 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.87" @@ -3536,7 +3562,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3557,25 +3583,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki" -version = "0.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "webpki-roots" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" -dependencies = [ - "webpki", -] - [[package]] name = "which" version = "4.4.2" @@ -3685,6 +3692,16 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys", +] + [[package]] name = "yaml-rust" version = "0.4.5" @@ -3711,5 +3728,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] diff --git a/Cargo.toml b/Cargo.toml index 46d5bf4..883ef9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ rust-version = "1.64.0" [workspace.dependencies] cosmwasm-schema = "1.2.1" -cosmwasm-std = "1.2.1" +cosmwasm-std = "1.5.3" cosmwasm-storage = "1.2.1" cw-storage-plus = "1.0" cw2 = "1.0" @@ -26,13 +26,14 @@ serde = { version = "1.0.145", default-features = false, features = ["derive"] } thiserror = { version = "1.0.31" } apollo-cw-asset = "0.1.1" osmosis-std = "0.19.2" -cw-it = "0.2.3" +cw-it = "0.3.0-rc.3" cw-dex = { path = "cw-dex" } cw-dex-test-contract = { path = "test-contracts/package" } astroport-test-contract = { path = "test-contracts/astroport-test-contract" } cw-dex-test-helpers = { path = "test-helpers" } apollo-utils = "0.1.0" -astroport = "=2.9.0" +astroport = "=2.9.3" +astroport_v3 = { package = "astroport", version = "=3.11.1" } [profile.release] codegen-units = 1 diff --git a/cw-dex/Cargo.toml b/cw-dex/Cargo.toml index 7568a42..cb74126 100644 --- a/cw-dex/Cargo.toml +++ b/cw-dex/Cargo.toml @@ -12,7 +12,7 @@ readme = "README.md" default = [] osmosis = ["osmosis-std", "osmosis-test-tube"] osmosis-test-tube = ["cw-it/osmosis-test-tube"] -astroport = ["dep:astroport", "apollo-cw-asset/astroport", "dep:cw2", "cw-it/astroport", "cw-it/astroport-multi-test"] +astroport = ["dep:astroport", "dep:astroport_v3", "apollo-cw-asset/astroport", "dep:cw2", "cw-it/astroport", "cw-it/astroport-multi-test"] # backtraces = ["cosmwasm-std/backtraces", "osmosis-std/backtraces"] [package.metadata.docs.rs] @@ -33,6 +33,7 @@ osmosis-std = { workspace = true, optional = true } # Astroport astroport = { workspace = true, optional = true } +astroport_v3 = { workspace = true, optional = true } cw2 = { workspace = true, optional = true } [dev-dependencies] diff --git a/cw-dex/src/implementations/astroport/pool.rs b/cw-dex/src/implementations/astroport/pool.rs index 0642354..1c0606a 100644 --- a/cw-dex/src/implementations/astroport/pool.rs +++ b/cw-dex/src/implementations/astroport/pool.rs @@ -7,7 +7,7 @@ use apollo_utils::iterators::IntoElementwise; use astroport::liquidity_manager; use cosmwasm_schema::cw_serde; use cosmwasm_std::{ - to_binary, wasm_execute, Addr, CosmosMsg, Decimal, Deps, Env, Event, QuerierWrapper, + to_json_binary, wasm_execute, Addr, CosmosMsg, Decimal, Deps, Env, Event, QuerierWrapper, QueryRequest, Response, StdError, StdResult, Uint128, WasmMsg, WasmQuery, }; use cw20::Cw20ExecuteMsg; @@ -77,7 +77,7 @@ impl AstroportPool { pub fn query_pool_info(&self, querier: &QuerierWrapper) -> StdResult { querier.query::(&QueryRequest::Wasm(WasmQuery::Smart { contract_addr: self.pair_addr.to_string(), - msg: to_binary(&PairQueryMsg::Pool {})?, + msg: to_json_binary(&PairQueryMsg::Pool {})?, })) } } @@ -98,7 +98,7 @@ impl Pool for AstroportPool { .map(|asset| { Ok(CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: asset.address, - msg: to_binary(&Cw20ExecuteMsg::IncreaseAllowance { + msg: to_json_binary(&Cw20ExecuteMsg::IncreaseAllowance { spender: self.liquidity_manager.to_string(), amount: asset.amount, expires: Some(Expiration::AtHeight(env.block.height + 1)), @@ -119,7 +119,7 @@ impl Pool for AstroportPool { // Create the provide liquidity message let provide_liquidity_msg = CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: self.liquidity_manager.to_string(), - msg: to_binary(&liquidity_manager::ExecuteMsg::ProvideLiquidity { + msg: to_json_binary(&liquidity_manager::ExecuteMsg::ProvideLiquidity { pair_addr: self.pair_addr.to_string(), min_lp_to_receive: Some(min_out), pair_msg: astroport::pair::ExecuteMsg::ProvideLiquidity { @@ -161,10 +161,10 @@ impl Pool for AstroportPool { let withdraw_liquidity = CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: token_addr.to_string(), - msg: to_binary(&Cw20ExecuteMsg::Send { + msg: to_json_binary(&Cw20ExecuteMsg::Send { contract: self.liquidity_manager.to_string(), amount: asset.amount, - msg: to_binary(&liquidity_manager::Cw20HookMsg::WithdrawLiquidity { + msg: to_json_binary(&liquidity_manager::Cw20HookMsg::WithdrawLiquidity { pair_msg: astroport::pair::Cw20HookMsg::WithdrawLiquidity { // This field is currently not used... assets: vec![], @@ -220,7 +220,7 @@ impl Pool for AstroportPool { &Cw20ExecuteMsg::Send { contract: self.pair_addr.to_string(), amount: offer_asset.amount, - msg: to_binary(&PairCw20HookMsg::Swap { + msg: to_json_binary(&PairCw20HookMsg::Swap { belief_price, max_spread: Some(Decimal::zero()), to: Some(env.contract.address.to_string()), @@ -296,7 +296,7 @@ impl Pool for AstroportPool { .querier .query::(&QueryRequest::Wasm(WasmQuery::Smart { contract_addr: self.pair_addr.to_string(), - msg: to_binary(&PairQueryMsg::Simulation { + msg: to_json_binary(&PairQueryMsg::Simulation { offer_asset: offer_asset.into(), ask_asset_info: Some(ask_asset_info.into()), })?, diff --git a/cw-dex/src/implementations/astroport/staking.rs b/cw-dex/src/implementations/astroport/staking.rs index 2e9fa13..935a8c5 100644 --- a/cw-dex/src/implementations/astroport/staking.rs +++ b/cw-dex/src/implementations/astroport/staking.rs @@ -3,16 +3,16 @@ use apollo_utils::assets::separate_natives_and_cw20s; use cosmwasm_schema::cw_serde; use cosmwasm_std::{ - to_binary, Addr, CosmosMsg, Deps, Empty, Env, Event, QuerierWrapper, QueryRequest, Response, - Uint128, WasmMsg, WasmQuery, + to_json_binary, Addr, CosmosMsg, Deps, Empty, Env, Event, QuerierWrapper, QueryRequest, + Response, Uint128, WasmMsg, WasmQuery, }; use cw20::Cw20ExecuteMsg; -use apollo_cw_asset::{Asset, AssetInfo, AssetList}; +use apollo_cw_asset::{AssetInfo, AssetList}; use astroport::asset::Asset as AstroAsset; -use astroport::generator::{ - Cw20HookMsg as GeneratorCw20HookMsg, ExecuteMsg as GeneratorExecuteMsg, PendingTokenResponse, - QueryMsg as GeneratorQueryMsg, +use astroport_v3::incentives::{ + Cw20Msg as IncentivesCw20Msg, ExecuteMsg as IncentivesExecuteMsg, + QueryMsg as IncentivesQueryMsg, }; use crate::traits::{Rewards, Stake, Staking, Unstake}; @@ -23,8 +23,8 @@ use crate::CwDexError; pub struct AstroportStaking { /// The address of the associated LP token contract pub lp_token_addr: Addr, - /// The address of the associated generator contract - pub generator_addr: Addr, + /// The address of the astroport incentives contract + pub incentives: Addr, /// The address of the ASTRO token contract pub astro_token: AssetInfo, } @@ -35,10 +35,10 @@ impl Stake for AstroportStaking { fn stake(&self, _deps: Deps, _env: &Env, amount: Uint128) -> Result { let stake_msg = CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: self.lp_token_addr.to_string(), - msg: to_binary(&Cw20ExecuteMsg::Send { - contract: self.generator_addr.to_string(), + msg: to_json_binary(&Cw20ExecuteMsg::Send { + contract: self.incentives.to_string(), amount, - msg: to_binary(&GeneratorCw20HookMsg::Deposit {})?, + msg: to_json_binary(&IncentivesCw20Msg::Deposit { recipient: None })?, })?, funds: vec![], }); @@ -46,7 +46,7 @@ impl Stake for AstroportStaking { let event = Event::new("apollo/cw-dex/stake") .add_attribute("type", "astroport_staking") .add_attribute("asset", self.lp_token_addr.to_string()) - .add_attribute("generator_address", self.generator_addr.to_string()); + .add_attribute("incentives contract address", self.incentives.to_string()); Ok(Response::new().add_message(stake_msg).add_event(event)) } @@ -65,8 +65,8 @@ impl Rewards for AstroportStaking { } let claim_rewards_msg = CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: self.generator_addr.to_string(), - msg: to_binary(&GeneratorExecuteMsg::ClaimRewards { + contract_addr: self.incentives.to_string(), + msg: to_json_binary(&IncentivesExecuteMsg::ClaimRewards { lp_tokens: vec![self.lp_token_addr.to_string()], })?, funds: vec![], @@ -97,10 +97,10 @@ impl Rewards for AstroportStaking { // Unwrap the native token let unwrap_msg: CosmosMsg = CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: cw20.address.to_string(), - msg: to_binary(&cw20::Cw20ExecuteMsg::Send { + msg: to_json_binary(&cw20::Cw20ExecuteMsg::Send { contract: wrapper_contract.to_string(), amount: cw20.amount, - msg: to_binary(&astroport::native_coin_wrapper::Cw20HookMsg::Unwrap {})?, + msg: to_json_binary(&astroport::native_coin_wrapper::Cw20HookMsg::Unwrap {})?, })?, funds: vec![], }); @@ -115,25 +115,17 @@ impl Rewards for AstroportStaking { querier: &QuerierWrapper, user: &Addr, ) -> Result { - let PendingTokenResponse { - pending: pending_astro, - pending_on_proxy, - } = querier.query(&QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: self.generator_addr.to_string(), - msg: to_binary(&GeneratorQueryMsg::PendingToken { - lp_token: self.lp_token_addr.to_string(), - user: user.to_string(), - })?, - }))?; - - let pending_rewards: Vec = pending_on_proxy - .unwrap_or_default() + let pending_rewards: Vec = querier + .query::>(&QueryRequest::Wasm(WasmQuery::Smart { + contract_addr: self.incentives.to_string(), + msg: to_json_binary(&IncentivesQueryMsg::PendingRewards { + lp_token: self.lp_token_addr.to_string(), + user: user.to_string(), + })?, + }))? .into_iter() - .chain(vec![ - Asset::new(self.astro_token.clone(), pending_astro).into() - ]) - .filter(|asset| !asset.amount.is_zero()) - .collect::>(); + .filter(|asset| !asset.amount.is_zero()) //TODO: Is this necessary? + .collect(); Ok(pending_rewards.into()) } @@ -142,8 +134,8 @@ impl Rewards for AstroportStaking { impl Unstake for AstroportStaking { fn unstake(&self, _deps: Deps, _env: &Env, amount: Uint128) -> Result { let unstake_msg = CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: self.generator_addr.to_string(), - msg: to_binary(&GeneratorExecuteMsg::Withdraw { + contract_addr: self.incentives.to_string(), + msg: to_json_binary(&IncentivesExecuteMsg::Withdraw { lp_token: self.lp_token_addr.to_string(), amount, })?, diff --git a/test-contracts/astroport-test-contract/src/contract.rs b/test-contracts/astroport-test-contract/src/contract.rs index ae85bc8..5c25d69 100644 --- a/test-contracts/astroport-test-contract/src/contract.rs +++ b/test-contracts/astroport-test-contract/src/contract.rs @@ -4,10 +4,11 @@ use apollo_cw_asset::{Asset, AssetInfo, AssetList}; #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - to_binary, Addr, Binary, Deps, DepsMut, Env, MessageInfo, Reply, Response, StdResult, Uint128, + to_json_binary, Addr, Binary, Deps, DepsMut, Env, MessageInfo, Reply, Response, StdResult, + Uint128, }; use cw_dex::astroport::{AstroportPool, AstroportStaking}; -use cw_dex::traits::{Pool, Stake, Unstake}; +use cw_dex::traits::{Pool, Rewards, Stake, Unstake}; use cw_dex_test_contract::msg::{ AstroportContractInstantiateMsg as InstantiateMsg, AstroportExecuteMsg as ExecuteMsg, QueryMsg, }; @@ -29,7 +30,7 @@ pub fn instantiate( &AstroportStaking { lp_token_addr: Addr::unchecked(msg.lp_token_addr), - generator_addr: Addr::unchecked(msg.generator_addr), + incentives: Addr::unchecked(msg.incentives_addr), astro_token: msg.astro_token, }, @@ -54,6 +55,7 @@ pub fn execute( } ExecuteMsg::Stake { amount } => execute_stake(deps, env, info, amount), ExecuteMsg::Unstake { amount } => execute_unstake(deps, env, info, amount), + ExecuteMsg::ClaimRewards {} => execute_claim_rewards(deps, env, info), ExecuteMsg::Swap { offer, ask, @@ -111,6 +113,15 @@ pub fn execute_unstake( Ok(staking.unstake(deps.as_ref(), &env, amount)?) } +pub fn execute_claim_rewards( + deps: DepsMut, + env: Env, + _info: MessageInfo, +) -> Result { + let staking = STAKING.load(deps.storage)?; + Ok(staking.claim_rewards(deps.as_ref(), &env)?) +} + pub fn execute_swap( deps: DepsMut, env: Env, @@ -127,15 +138,15 @@ pub fn execute_swap( pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { let pool = POOL.load(deps.storage)?; match msg { - QueryMsg::PoolLiquidity {} => to_binary(&pool.get_pool_liquidity(deps)?), + QueryMsg::PoolLiquidity {} => to_json_binary(&pool.get_pool_liquidity(deps)?), QueryMsg::SimulateProvideLiquidity { assets } => { - to_binary(&pool.simulate_provide_liquidity(deps, &env, assets)?.amount) + to_json_binary(&pool.simulate_provide_liquidity(deps, &env, assets)?.amount) } - QueryMsg::SimulateWithdrawLiquidty { amount } => to_binary( + QueryMsg::SimulateWithdrawLiquidty { amount } => to_json_binary( &pool.simulate_withdraw_liquidity(deps, &Asset::new(pool.lp_token(), amount))?, ), QueryMsg::SimulateSwap { offer, ask } => query_simulate_swap(deps, offer, ask), - QueryMsg::GetPoolForLpToken { lp_token } => to_binary( + QueryMsg::GetPoolForLpToken { lp_token } => to_json_binary( &cw_dex::Pool::get_pool_for_lp_token(deps, &lp_token, Some(pool.liquidity_manager))?, ), } @@ -143,7 +154,7 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { pub fn query_simulate_swap(deps: Deps, offer: Asset, ask: AssetInfo) -> StdResult { let pool = POOL.load(deps.storage)?; - to_binary(&pool.simulate_swap(deps, offer, ask)?) + to_json_binary(&pool.simulate_swap(deps, offer, ask)?) } #[cfg_attr(not(feature = "library"), entry_point)] diff --git a/test-contracts/osmosis-test-contract/src/contract.rs b/test-contracts/osmosis-test-contract/src/contract.rs index aeaf751..9ec8301 100644 --- a/test-contracts/osmosis-test-contract/src/contract.rs +++ b/test-contracts/osmosis-test-contract/src/contract.rs @@ -2,7 +2,7 @@ use apollo_cw_asset::{Asset, AssetInfo, AssetList}; #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Reply, Response, StdError, StdResult, + to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, Reply, Response, StdError, StdResult, Uint128, }; use cw_dex::osmosis::{OsmosisPool, OsmosisStaking, OsmosisSuperfluidStaking}; @@ -204,23 +204,23 @@ pub fn execute_swap( pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { let pool = POOL.load(deps.storage)?; match msg { - QueryMsg::PoolLiquidity {} => to_binary(&pool.get_pool_liquidity(deps)?), + QueryMsg::PoolLiquidity {} => to_json_binary(&pool.get_pool_liquidity(deps)?), QueryMsg::SimulateProvideLiquidity { assets } => { - to_binary(&pool.simulate_provide_liquidity(deps, &env, assets)?.amount) + to_json_binary(&pool.simulate_provide_liquidity(deps, &env, assets)?.amount) } - QueryMsg::SimulateWithdrawLiquidty { amount } => to_binary( + QueryMsg::SimulateWithdrawLiquidty { amount } => to_json_binary( &pool.simulate_withdraw_liquidity(deps, &Asset::new(pool.lp_token(), amount))?, ), QueryMsg::SimulateSwap { offer, ask } => query_simulate_swap(deps, offer, ask), QueryMsg::GetPoolForLpToken { lp_token } => { - to_binary(&cw_dex::Pool::get_pool_for_lp_token(deps, &lp_token, None)?) + to_json_binary(&cw_dex::Pool::get_pool_for_lp_token(deps, &lp_token, None)?) } } } pub fn query_simulate_swap(deps: Deps, offer: Asset, ask: AssetInfo) -> StdResult { let pool = POOL.load(deps.storage)?; - to_binary(&pool.simulate_swap(deps, offer, ask)?) + to_json_binary(&pool.simulate_swap(deps, offer, ask)?) } #[cfg_attr(not(feature = "library"), entry_point)] diff --git a/test-contracts/package/src/msg.rs b/test-contracts/package/src/msg.rs index 06c30e7..71cc5e6 100644 --- a/test-contracts/package/src/msg.rs +++ b/test-contracts/package/src/msg.rs @@ -1,6 +1,6 @@ use apollo_cw_asset::{Asset, AssetInfo, AssetList}; use cosmwasm_schema::{cw_serde, QueryResponses}; -use cosmwasm_std::{to_binary, Addr, Coin, CosmosMsg, Uint128, WasmMsg}; +use cosmwasm_std::{to_json_binary, Addr, Coin, CosmosMsg, Uint128, WasmMsg}; #[cw_serde] pub struct OsmosisTestContractInstantiateMsg { @@ -14,7 +14,7 @@ pub struct OsmosisTestContractInstantiateMsg { pub struct AstroportContractInstantiateMsg { pub pair_addr: String, pub lp_token_addr: String, - pub generator_addr: String, + pub incentives_addr: String, pub astro_token: AssetInfo, pub liquidity_manager_addr: String, } @@ -59,7 +59,7 @@ impl ExecuteMsg { pub fn into_cosmos_msg(&self, contract_addr: String, funds: Vec) -> CosmosMsg { CosmosMsg::Wasm(WasmMsg::Execute { contract_addr, - msg: to_binary(self).unwrap(), + msg: to_json_binary(self).unwrap(), funds, }) } @@ -96,6 +96,7 @@ pub enum AstroportExecuteMsg { Unstake { amount: Uint128, }, + ClaimRewards {}, Swap { offer: Asset, ask: AssetInfo, @@ -107,7 +108,7 @@ impl AstroportExecuteMsg { pub fn into_cosmos_msg(&self, contract_addr: String, funds: Vec) -> CosmosMsg { CosmosMsg::Wasm(WasmMsg::Execute { contract_addr, - msg: to_binary(self).unwrap(), + msg: to_json_binary(self).unwrap(), funds, }) } diff --git a/test-helpers/src/astroport.rs b/test-helpers/src/astroport.rs index 860efbb..33186a6 100644 --- a/test-helpers/src/astroport.rs +++ b/test-helpers/src/astroport.rs @@ -261,7 +261,7 @@ pub fn setup_pool_and_test_contract<'a>( runner, code_id, pair_addr.clone(), - astroport_contracts.generator.address, + astroport_contracts.incentives.address, AssetInfo::cw20(Addr::unchecked(astroport_contracts.astro_token.address)), lp_token_addr.clone(), astroport_contracts.liquidity_manager.address, @@ -276,7 +276,7 @@ pub fn instantiate_test_astroport_contract<'a, R: Runner<'a>>( runner: &'a R, code_id: u64, pair_addr: String, - generator_addr: String, + incentives_addr: String, astro_token: AssetInfo, lp_token_addr: String, liquidity_manager_addr: String, @@ -285,7 +285,7 @@ pub fn instantiate_test_astroport_contract<'a, R: Runner<'a>>( let init_msg = AstroportContractInstantiateMsg { pair_addr, lp_token_addr, - generator_addr, + incentives_addr, astro_token, liquidity_manager_addr, }; From 7f2f14214b53f6b4c3bdf0f7f6cf854225f3af1f Mon Sep 17 00:00:00 2001 From: Sturdy <91910406+apollo-sturdy@users.noreply.github.com> Date: Fri, 9 Feb 2024 19:46:24 +0100 Subject: [PATCH 02/22] chore: use to_json_binary --- test-helpers/src/astroport.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test-helpers/src/astroport.rs b/test-helpers/src/astroport.rs index 33186a6..e021b49 100644 --- a/test-helpers/src/astroport.rs +++ b/test-helpers/src/astroport.rs @@ -3,7 +3,7 @@ use apollo_utils::assets::separate_natives_and_cw20s; use astroport::asset::{Asset as AstroAsset, AssetInfo as AstroAssetInfo}; use astroport::factory::PairType; use astroport::pair::{ExecuteMsg as PairExecuteMsg, StablePoolParams}; -use cosmwasm_std::{to_binary, Addr, Coin, Decimal, Uint128}; +use cosmwasm_std::{to_json_binary, Addr, Coin, Decimal, Uint128}; use cw20::{Cw20ExecuteMsg, MinterResponse}; use cw20_base::msg::InstantiateMsg as Cw20InstantiateMsg; use cw_dex_test_contract::msg::AstroportContractInstantiateMsg; @@ -190,14 +190,14 @@ pub fn setup_pool_and_test_contract<'a>( // Create pool let init_params = match &pool_type { PairType::Stable {} => Some( - to_binary(&StablePoolParams { + to_json_binary(&StablePoolParams { amp: 10u64, owner: None, }) .unwrap(), ), PairType::Custom(t) => match t.as_str() { - "concentrated" => Some(to_binary(&common_pcl_params()).unwrap()), + "concentrated" => Some(to_json_binary(&common_pcl_params()).unwrap()), _ => None, }, _ => None, From cddd2ec61cc7486d639d87684489aa3b315ebbca Mon Sep 17 00:00:00 2001 From: Pacman Date: Fri, 9 Feb 2024 21:50:31 +0100 Subject: [PATCH 03/22] chore: bump cw-dex version to 0.6.0-rc.1 --- Cargo.lock | 2 +- cw-dex/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a00efdf..fd0b816 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -886,7 +886,7 @@ dependencies = [ [[package]] name = "cw-dex" -version = "0.5.1" +version = "0.6.0-rc.1" dependencies = [ "apollo-cw-asset", "apollo-utils", diff --git a/cw-dex/Cargo.toml b/cw-dex/Cargo.toml index cb74126..6050841 100644 --- a/cw-dex/Cargo.toml +++ b/cw-dex/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" license = "MPL-2.0" name = "cw-dex" repository = "https://github.com/apollodao/cw-dex" -version = "0.5.1" +version = "0.6.0-rc.1" readme = "README.md" [features] From 3d2ded39347ce648f1d26ff2690cb3e2bf1fe3e6 Mon Sep 17 00:00:00 2001 From: Pacman Date: Fri, 9 Feb 2024 22:28:07 +0100 Subject: [PATCH 04/22] chore: set astroport dep to 2.9.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 883ef9a..a4b0f9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ cw-dex-test-contract = { path = "test-contracts/package" } astroport-test-contract = { path = "test-contracts/astroport-test-contract" } cw-dex-test-helpers = { path = "test-helpers" } apollo-utils = "0.1.0" -astroport = "=2.9.3" +astroport = "=2.9.0" astroport_v3 = { package = "astroport", version = "=3.11.1" } [profile.release] From f217f61d5658e8710fc0d7aa4c27ec124f960bbf Mon Sep 17 00:00:00 2001 From: Pacman Date: Fri, 9 Feb 2024 22:52:38 +0100 Subject: [PATCH 05/22] chore: bump cw-it --- Cargo.lock | 48 ++++++++++++++++++++++++------------------------ Cargo.toml | 2 +- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fd0b816..1abb527 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -49,7 +49,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "423502406a307052f6877030f48b5fb4e9fb338fc5e7c8ca1064210def52876b" dependencies = [ - "astroport 2.9.3", + "astroport 2.9.0", "cosmwasm-std", "cw-storage-plus 1.2.0", "cw20 1.1.2", @@ -104,9 +104,9 @@ dependencies = [ [[package]] name = "astroport" -version = "2.9.3" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b991ce88f077c1d12f850c1f8fba3671bd72784f43f1638731d6d28f9b79839" +checksum = "78b863a982595743e181f89540d7aaeda35c60b6b5cac9c36c9be30cf11a5ece" dependencies = [ "cosmwasm-schema", "cosmwasm-std", @@ -153,7 +153,7 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ecf768e2d3153bebfbe0c502ffa4199a52598e9b6e89fca54339615b2de77eb" dependencies = [ - "astroport 2.9.3", + "astroport 2.9.0", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", @@ -169,7 +169,7 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6144780ac014665b07616de0cfb35ca6a9411ed821e20c21e02f4f428c8ed51f" dependencies = [ - "astroport 2.9.3", + "astroport 2.9.0", "astroport-governance", "cosmwasm-schema", "cosmwasm-std", @@ -187,7 +187,7 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72806ace350e81c4e1cab7e275ef91f05bad830275d697d67ad1bd4acc6f016d" dependencies = [ - "astroport 2.9.3", + "astroport 2.9.0", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", @@ -217,7 +217,7 @@ version = "1.0.3-astroport-v2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae4bf7689e7c37cfecc200aab3401c1ff6a507cccc9fb1baadfa71a73addaa2f" dependencies = [ - "astroport 2.9.3", + "astroport 2.9.0", "astroport-factory", "astroport-pair", "astroport-pair-stable", @@ -236,7 +236,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92403e5d00e3c77d13d9616661ea9d9308d493fff6bec5e6e5e7bd7b7e0ff6af" dependencies = [ "astro-satellite-package", - "astroport 2.9.3", + "astroport 2.9.0", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", @@ -251,7 +251,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "648ed6827a8f11012c0377fb60329204e8511fe46c86db3220113e70bdc57826" dependencies = [ - "astroport 2.9.3", + "astroport 2.9.0", "cosmwasm-schema", "cosmwasm-std", "cosmwasm-storage", @@ -266,7 +266,7 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e760b91eaf269bb2843b75b34eb73d474374bd2ebefbbe3cdb0a58d69959573b" dependencies = [ - "astroport 2.9.3", + "astroport 2.9.0", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", @@ -283,7 +283,7 @@ version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04a90ce51403c81af3acf8e7028bb0eb095fce802365453b7e4a13bc0eb0d6d7" dependencies = [ - "astroport 2.9.3", + "astroport 2.9.0", "astroport-factory", "cosmwasm-schema", "cosmwasm-std", @@ -301,7 +301,7 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d052966163fc2dd3eb46ae3c948ee7032a28726e046bc44431f9b488cb1dba90" dependencies = [ - "astroport 2.9.3", + "astroport 2.9.0", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", @@ -318,7 +318,7 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e3bbb33c00370bd194cf3a166f1e3f4029a2add2bea01a5eb61e886aefbc85b" dependencies = [ - "astroport 2.9.3", + "astroport 2.9.0", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", @@ -334,7 +334,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67adbc4240794e886ca1edbc7d46bc8a54c7aca7217d73ddcfbc90e1dbb030e7" dependencies = [ - "astroport 2.9.3", + "astroport 2.9.0", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", @@ -363,7 +363,7 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3360383a2e585211da9a455ad57eb100578253b5d18a387f025cadd666604d99" dependencies = [ - "astroport 2.9.3", + "astroport 2.9.0", "cosmwasm-schema", "cosmwasm-std", "cw2 0.15.1", @@ -378,7 +378,7 @@ version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dffce7cf86bf4d4f177ef941145352499e802abc4b898032af7808d16cca6371" dependencies = [ - "astroport 2.9.3", + "astroport 2.9.0", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", @@ -394,7 +394,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44156757bfab3d4bd208d9b86b890d1478f45d07c8f8d3d1c3e3da91081cb54d" dependencies = [ - "astroport 2.9.3", + "astroport 2.9.0", "cosmwasm-schema", "cosmwasm-std", "cw1-whitelist", @@ -479,7 +479,7 @@ dependencies = [ "bitflags 2.4.1", "cexpr", "clang-sys", - "itertools 0.10.5", + "itertools 0.11.0", "lazy_static", "lazycell", "log", @@ -890,7 +890,7 @@ version = "0.6.0-rc.1" dependencies = [ "apollo-cw-asset", "apollo-utils", - "astroport 2.9.3", + "astroport 2.9.0", "astroport 3.11.1", "cosmwasm-schema", "cosmwasm-std", @@ -923,7 +923,7 @@ version = "0.1.0" dependencies = [ "apollo-cw-asset", "apollo-utils", - "astroport 2.9.3", + "astroport 2.9.0", "astroport-test-contract", "cosmwasm-std", "cw-dex-test-contract", @@ -934,14 +934,14 @@ dependencies = [ [[package]] name = "cw-it" -version = "0.3.0-rc.3" +version = "0.3.0-rc.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "066d874d7976142d2ec44c80666214816fcfcef02432b2e1f92aade4f0e1e2be" +checksum = "8323a657163a204179a9a7a4a418794aa71f9c789b58b8c91974e2691f7db408" dependencies = [ "anyhow", "apollo-cw-multi-test", "apollo-utils", - "astroport 2.9.3", + "astroport 2.9.0", "astroport 3.11.1", "astroport-factory", "astroport-generator", @@ -2330,7 +2330,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools 0.11.0", "proc-macro2", "quote", "syn 2.0.48", diff --git a/Cargo.toml b/Cargo.toml index a4b0f9a..e8d0faf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ serde = { version = "1.0.145", default-features = false, features = ["derive"] } thiserror = { version = "1.0.31" } apollo-cw-asset = "0.1.1" osmosis-std = "0.19.2" -cw-it = "0.3.0-rc.3" +cw-it = "0.3.0-rc.4" cw-dex = { path = "cw-dex" } cw-dex-test-contract = { path = "test-contracts/package" } astroport-test-contract = { path = "test-contracts/astroport-test-contract" } From 80d89721081c06350c31911224ed223eea8b1991 Mon Sep 17 00:00:00 2001 From: Pacman Date: Fri, 9 Feb 2024 22:53:17 +0100 Subject: [PATCH 06/22] chore: bump version to 0.6.0-rc.2 --- Cargo.lock | 2 +- cw-dex/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1abb527..555a52e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -886,7 +886,7 @@ dependencies = [ [[package]] name = "cw-dex" -version = "0.6.0-rc.1" +version = "0.6.0-rc.2" dependencies = [ "apollo-cw-asset", "apollo-utils", diff --git a/cw-dex/Cargo.toml b/cw-dex/Cargo.toml index 6050841..3da1fbf 100644 --- a/cw-dex/Cargo.toml +++ b/cw-dex/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" license = "MPL-2.0" name = "cw-dex" repository = "https://github.com/apollodao/cw-dex" -version = "0.6.0-rc.1" +version = "0.6.0-rc.2" readme = "README.md" [features] From 07e3b193541c7a3fbcd86fc702fb7140514139d9 Mon Sep 17 00:00:00 2001 From: Pacman Date: Sat, 10 Feb 2024 15:56:57 +0100 Subject: [PATCH 07/22] refactor!: remove astro_token from AstroportStaking --- cw-dex/src/implementations/astroport/staking.rs | 4 +--- test-contracts/astroport-test-contract/src/contract.rs | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/cw-dex/src/implementations/astroport/staking.rs b/cw-dex/src/implementations/astroport/staking.rs index 935a8c5..28bf9e9 100644 --- a/cw-dex/src/implementations/astroport/staking.rs +++ b/cw-dex/src/implementations/astroport/staking.rs @@ -8,7 +8,7 @@ use cosmwasm_std::{ }; use cw20::Cw20ExecuteMsg; -use apollo_cw_asset::{AssetInfo, AssetList}; +use apollo_cw_asset::AssetList; use astroport::asset::Asset as AstroAsset; use astroport_v3::incentives::{ Cw20Msg as IncentivesCw20Msg, ExecuteMsg as IncentivesExecuteMsg, @@ -25,8 +25,6 @@ pub struct AstroportStaking { pub lp_token_addr: Addr, /// The address of the astroport incentives contract pub incentives: Addr, - /// The address of the ASTRO token contract - pub astro_token: AssetInfo, } impl Staking for AstroportStaking {} diff --git a/test-contracts/astroport-test-contract/src/contract.rs b/test-contracts/astroport-test-contract/src/contract.rs index 5c25d69..23b25ea 100644 --- a/test-contracts/astroport-test-contract/src/contract.rs +++ b/test-contracts/astroport-test-contract/src/contract.rs @@ -31,8 +31,6 @@ pub fn instantiate( lp_token_addr: Addr::unchecked(msg.lp_token_addr), incentives: Addr::unchecked(msg.incentives_addr), - - astro_token: msg.astro_token, }, )?; From 5e1aa6730a9c30f798a11a17a2fd8eccaa65a45c Mon Sep 17 00:00:00 2001 From: Pacman Date: Sat, 10 Feb 2024 20:30:01 +0100 Subject: [PATCH 08/22] wip(astroport): add test for claim rewards --- cw-dex/Cargo.toml | 1 + cw-dex/tests/astroport_tests.rs | 316 +++++++++++++++++- .../astroport-test-contract/src/contract.rs | 4 + .../osmosis-test-contract/src/contract.rs | 1 + test-contracts/package/src/msg.rs | 2 + test-helpers/src/astroport.rs | 30 +- 6 files changed, 331 insertions(+), 23 deletions(-) diff --git a/cw-dex/Cargo.toml b/cw-dex/Cargo.toml index 3da1fbf..1ec1703 100644 --- a/cw-dex/Cargo.toml +++ b/cw-dex/Cargo.toml @@ -43,3 +43,4 @@ cw-dex-test-contract = { workspace = true } cw-dex-test-helpers = { workspace = true, features = ["osmosis", "astroport"] } proptest = "1.0.0" cw20-base = { workspace = true } +cw20 = { workspace = true } diff --git a/cw-dex/tests/astroport_tests.rs b/cw-dex/tests/astroport_tests.rs index 77d0f6a..bf01027 100644 --- a/cw-dex/tests/astroport_tests.rs +++ b/cw-dex/tests/astroport_tests.rs @@ -1,22 +1,29 @@ #![cfg(feature = "astroport")] mod tests { + use std::fs; + use apollo_cw_asset::{Asset, AssetInfo, AssetInfoBase, AssetList}; use apollo_utils::assets::separate_natives_and_cw20s; use apollo_utils::coins::coin_from_str; use apollo_utils::submessages::{find_event, parse_attribute_value}; use astroport::factory::PairType; - use cosmwasm_std::{Addr, Coin, SubMsgResponse, Uint128}; + use astroport_v3::asset::Asset as AstroportAsset; + use cosmwasm_std::{coin, Addr, Coin, Decimal, SubMsgResponse, Uint128}; + use cw20::AllAccountsResponse; use cw_dex::Pool; use cw_dex_test_contract::msg::{AstroportExecuteMsg, ExecuteMsg, QueryMsg}; use cw_dex_test_helpers::astroport::setup_pool_and_test_contract; use cw_dex_test_helpers::{cw20_balance_query, cw20_transfer, query_asset_balance}; + use cw_it::astroport::utils::AstroportContracts; + use cw_it::cw_multi_test::{Contract, ContractWrapper}; use cw_it::helpers::Unwrap; use cw_it::multi_test::MultiTestRunner; use cw_it::test_tube::cosmrs::proto::cosmwasm::wasm::v1::MsgExecuteContractResponse; use cw_it::test_tube::{ Account, ExecuteResponse, Module, Runner, RunnerResult, SigningAccount, Wasm, }; - use cw_it::{OwnedTestRunner, TestRunner}; + use cw_it::traits::CwItRunner; + use cw_it::{Artifact, OwnedTestRunner, TestRunner}; use test_case::test_case; #[cfg(feature = "osmosis-test-tube")] @@ -33,11 +40,18 @@ mod tests { const TEST_CONTRACT_WASM_FILE_PATH: &str = "../target/wasm32-unknown-unknown/release/astroport_test_contract.wasm"; - fn setup_pool_and_contract<'a>( + fn setup_pool_and_testing_contract<'a>( runner: &'a TestRunner<'a>, pool_type: PairType, initial_liquidity: Vec<(&str, u64)>, - ) -> RunnerResult<(Vec, String, String, String, AssetList)> { + ) -> RunnerResult<( + Vec, + String, + String, + String, + AssetList, + AstroportContracts, + )> { setup_pool_and_test_contract( runner, pool_type, @@ -58,8 +72,8 @@ mod tests { pub fn test_provide_liquidity(pool_type: PairType, initial_liquidity: Vec<(&str, u64)>) { let owned_runner = get_test_runner(); let runner = owned_runner.as_ref(); - let (accs, lp_token_addr, _pair_addr, contract_addr, asset_list) = - setup_pool_and_contract(&runner, pool_type.clone(), initial_liquidity).unwrap(); + let (accs, lp_token_addr, _pair_addr, contract_addr, asset_list, _) = + setup_pool_and_testing_contract(&runner, pool_type.clone(), initial_liquidity).unwrap(); let admin = &accs[0]; let wasm = Wasm::new(&runner); @@ -141,8 +155,8 @@ mod tests { fn test_withdraw_liquidity(pool_type: PairType, initial_liquidity: Vec<(&str, u64)>) { let owned_runner = get_test_runner(); let runner = owned_runner.as_ref(); - let (accs, lp_token_addr, _pair_addr, contract_addr, asset_list) = - setup_pool_and_contract(&runner, pool_type, initial_liquidity).unwrap(); + let (accs, lp_token_addr, _pair_addr, contract_addr, asset_list, _) = + setup_pool_and_testing_contract(&runner, pool_type, initial_liquidity).unwrap(); let admin = &accs[0]; let wasm = Wasm::new(&runner); @@ -255,8 +269,8 @@ mod tests { ) -> RunnerResult<()> { let owned_runner = get_test_runner(); let runner = owned_runner.as_ref(); - let (accs, lp_token_addr, _pair_addr, contract_addr, _asset_list) = - setup_pool_and_contract(&runner, pool_type, initial_liquidity).unwrap(); + let (accs, lp_token_addr, _pair_addr, contract_addr, _asset_list, _) = + setup_pool_and_testing_contract(&runner, pool_type, initial_liquidity).unwrap(); let admin = &accs[0]; @@ -342,8 +356,8 @@ mod tests { ) { let owned_runner = get_test_runner(); let runner = owned_runner.as_ref(); - let (accs, _lp_token_addr, _pair_addr, contract_addr, asset_list) = - setup_pool_and_contract(&runner, pool_type, initial_liquidity).unwrap(); + let (accs, _lp_token_addr, _pair_addr, contract_addr, asset_list, _) = + setup_pool_and_testing_contract(&runner, pool_type, initial_liquidity).unwrap(); let admin = &accs[0]; let wasm = Wasm::new(&runner); @@ -405,17 +419,285 @@ mod tests { assert_eq!(offer_balance, Uint128::zero()); } - #[test] - fn test_get_pool_for_lp_token() { + #[test_case(vec![(coin(2_000_000_000, "uluna"), 1)], vec![]; "one native incentive one period")] + #[test_case(vec![(coin(4_000_000_000, "uluna"), 2)], vec![]; "one native incentive two periods")] + #[test_case(vec![(coin(4_000_000_000, "uluna"), 2), (coin(2_000_000_000, "untrn"), 1)], vec![]; "two native incentive different periods")] + #[test_case(vec![(coin(4_000_000_000, "uluna"), 2), (coin(2_000_000_000, "untrn"), 1)], vec![(4_000_000_000u128.into(), 2)]; "two native incentive different periods one cw20 incentive")] + fn test_claim_rewards( + native_incentives: Vec<(Coin, u64)>, + cw20_incentives: Vec<(Uint128, u64)>, + ) -> RunnerResult<()> { + let pool_type = PairType::Xyk {}; + let initial_liquidity = vec![("uluna", 1_000_000), ("astro", 1_000_000)]; + let owned_runner = get_test_runner(); let runner = owned_runner.as_ref(); - let (_accs, lp_token_addr, pair_addr, contract_addr, asset_list) = setup_pool_and_contract( + let ( + accs, + lp_token_addr, + _pair_addr, + testing_contract_addr, + _asset_list, + astroport_contracts, + ) = setup_pool_and_testing_contract(&runner, pool_type, initial_liquidity).unwrap(); + + let admin = &accs[0]; + + // Increase time to current time. For some reason the start time of the incenitve + // epochs is hard coded in the astroport incentives contract and the logic doesn't + // work for earlier timestamps + let block_time = runner.query_block_time_nanos() / 1_000_000_000; + let current_time = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs(); + runner + .increase_time((current_time - block_time) as u64) + .unwrap(); + + // Setup wasm runner + let wasm = Wasm::new(&runner); + + // Initialize account with balances of all native incentives + let incentives_provider = runner + .init_account( + &native_incentives + .clone() + .into_iter() + .map(|(coin, _)| coin) + .collect::>(), + ) + .unwrap(); + + // Convert native incentives to AstroportAssets + let mut incentives: Vec<(AstroportAsset, u64)> = native_incentives + .clone() + .into_iter() + .map(|(coin, duration)| (coin.into(), duration)) + .collect(); + + // Upload cw20 code + let cw20_code_id = runner + .store_code( + cw_it::ContractType::MultiTestContract(Box::new(ContractWrapper::new_with_empty( + cw20_base::contract::execute, + cw20_base::contract::instantiate, + cw20_base::contract::query, + ))), + admin, + ) + .unwrap(); + + // Create Cw20 tokens for each Cw20 incentive, mint incentive amount to incentives_provider + // and add to incentives + for (i, (amount, duration)) in cw20_incentives.iter().enumerate() { + // Instantiate Cw20 token + let cw20_addr = wasm + .instantiate( + cw20_code_id, + &cw20_base::msg::InstantiateMsg { + name: format!("cw20_incentive_{}", i), + symbol: format!("incentive"), + decimals: 6, + initial_balances: vec![cw20::Cw20Coin { + address: incentives_provider.address(), + amount: *amount, + }], + mint: None, + marketing: None, + }, + Some(&admin.address()), + Some("incentive"), + &[], + admin, + ) + .unwrap() + .data + .address; + + // Add Cw20 incentive to incentives + incentives.push(( + AstroportAsset::cw20(Addr::unchecked(cw20_addr), *amount), + *duration, + )); + } + + // Setup incentives for the pool + for (incentive, periods) in incentives.clone() { + // Increase allowance for cw20 incentives and construct funds + let funds = match incentive.info.clone() { + astroport_v3::asset::AssetInfo::Token { contract_addr } => { + // Increase allowance for incentives contract + wasm.execute( + contract_addr.as_str(), + &cw20::Cw20ExecuteMsg::IncreaseAllowance { + spender: astroport_contracts.incentives.address.clone(), + amount: incentive.amount.clone(), + expires: None, + }, + &[], + &incentives_provider, + ) + .unwrap(); + vec![] + } + astroport_v3::asset::AssetInfo::NativeToken { denom } => { + vec![coin(incentive.amount.u128(), &denom)] + } + }; + wasm.execute( + &astroport_contracts.incentives.address, + &astroport_v3::incentives::ExecuteMsg::Incentivize { + lp_token: lp_token_addr.clone(), + schedule: astroport_v3::incentives::InputSchedule { + reward: incentive, + duration_periods: periods, + }, + }, + &funds, + &incentives_provider, + ) + .unwrap(); + } + + // Query LP token balance + let lp_token_balance = + cw20_balance_query(&runner, lp_token_addr.clone(), admin.address()).unwrap(); + + // Send LP tokens to the test contract + cw20_transfer( &runner, - PairType::Xyk {}, - vec![("uluna", 1_000_000), ("uatom", 1_000_000)], + lp_token_addr.clone(), + testing_contract_addr.clone(), + lp_token_balance, + admin, ) .unwrap(); + // Stake LP tokens + let events = stake_all_lp_tokens( + &runner, + testing_contract_addr.clone(), + lp_token_addr.clone(), + admin, + ) + .events; + + // Increase time by 1 week + runner.increase_time(60 * 60 * 24 * 1).unwrap(); + + // Query incentives contract for admin users pending rewards + let pending_rewards: Vec = wasm + .query( + &astroport_contracts.incentives.address, + &astroport_v3::incentives::QueryMsg::PendingRewards { + lp_token: lp_token_addr.clone(), + user: testing_contract_addr.clone(), + }, + ) + .unwrap(); + + // Query pending rewards through CwDex testing contract + let cw_dex_pending_rewards: AssetList = wasm + .query( + &testing_contract_addr, + &cw_dex_test_contract::msg::QueryMsg::PendingRewards {}, + ) + .unwrap(); + + // Assert that both pending rewards queries return the same result + for asset in pending_rewards.clone() { + // Convert astroport asset info to asset info + let asset_info = match asset.info { + astroport_v3::asset::AssetInfo::Token { contract_addr } => { + AssetInfo::Cw20(contract_addr) + } + astroport_v3::asset::AssetInfo::NativeToken { denom } => AssetInfo::Native(denom), + }; + + let amount = cw_dex_pending_rewards.find(&asset_info).unwrap().amount; + + assert_eq!(amount, asset.amount); + } + + println!("{:?}", incentives); + println!("{:?}", pending_rewards); + println!("{:?}", cw_dex_pending_rewards); + + // TODO: For some reason there are a lot of lp holders... + let lp_holders = wasm + .query::<_, AllAccountsResponse>( + &lp_token_addr, + &cw20::Cw20QueryMsg::AllAccounts { + start_after: None, + limit: None, + }, + ) + .unwrap() + .accounts; + + println!("{:?}", lp_holders); + println!("{:?}", testing_contract_addr); + + // Query total staked amount + let total_staked = wasm + .query::<_, astroport_v3::incentives::PoolInfoResponse>( + &astroport_contracts.incentives.address, + &astroport_v3::incentives::QueryMsg::PoolInfo { + lp_token: lp_token_addr.clone(), + }, + ) + .unwrap() + .total_lp; + + println!("{:?}", total_staked); + println!("{:?}", lp_token_balance); + + // // Assert that pending rewards are correct + // for pending_reward in pending_rewards { + // // Find corresponding incentive + // let (incentive, duration) = incentives + // .iter() + // .find(|(incentive, _)| incentive.info == pending_reward.info) + // .unwrap(); + + // // Calculate expected reward based on incentive amount and total duration + // let expected_reward = incentive.amount * Decimal::from_ratio(1u128, *duration); + + // // Assert that pending reward is correct + // assert_eq!(pending_reward.amount, expected_reward); + // } + + // Claim rewards + wasm.execute( + &testing_contract_addr, + &cw_dex_test_contract::msg::AstroportExecuteMsg::ClaimRewards {}, + &[], + admin, + ) + .unwrap(); + + // Assert that testing contract has correct asset balances + for reward in cw_dex_pending_rewards.to_vec() { + let asset_balance = query_asset_balance(&runner, &reward.info, &testing_contract_addr); + assert_eq!(asset_balance, reward.amount); + } + + Ok(()) + } + + #[test] + fn test_get_pool_for_lp_token() { + let owned_runner = get_test_runner(); + let runner = owned_runner.as_ref(); + let (_accs, lp_token_addr, pair_addr, contract_addr, asset_list, _) = + setup_pool_and_testing_contract( + &runner, + PairType::Xyk {}, + vec![("uluna", 1_000_000), ("uatom", 1_000_000)], + ) + .unwrap(); + let wasm = Wasm::new(&runner); let query = QueryMsg::GetPoolForLpToken { diff --git a/test-contracts/astroport-test-contract/src/contract.rs b/test-contracts/astroport-test-contract/src/contract.rs index 23b25ea..2c8d19d 100644 --- a/test-contracts/astroport-test-contract/src/contract.rs +++ b/test-contracts/astroport-test-contract/src/contract.rs @@ -147,6 +147,10 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { QueryMsg::GetPoolForLpToken { lp_token } => to_json_binary( &cw_dex::Pool::get_pool_for_lp_token(deps, &lp_token, Some(pool.liquidity_manager))?, ), + QueryMsg::PendingRewards {} => { + let staking = STAKING.load(deps.storage)?; + to_json_binary(&staking.query_pending_rewards(&deps.querier, &env.contract.address)?) + } } } diff --git a/test-contracts/osmosis-test-contract/src/contract.rs b/test-contracts/osmosis-test-contract/src/contract.rs index 9ec8301..77358e7 100644 --- a/test-contracts/osmosis-test-contract/src/contract.rs +++ b/test-contracts/osmosis-test-contract/src/contract.rs @@ -215,6 +215,7 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { QueryMsg::GetPoolForLpToken { lp_token } => { to_json_binary(&cw_dex::Pool::get_pool_for_lp_token(deps, &lp_token, None)?) } + QueryMsg::PendingRewards {} => unimplemented!(), } } diff --git a/test-contracts/package/src/msg.rs b/test-contracts/package/src/msg.rs index 71cc5e6..fb76719 100644 --- a/test-contracts/package/src/msg.rs +++ b/test-contracts/package/src/msg.rs @@ -78,6 +78,8 @@ pub enum QueryMsg { SimulateSwap { offer: Asset, ask: AssetInfo }, #[returns(cw_dex::Pool)] GetPoolForLpToken { lp_token: AssetInfo }, + #[returns(AssetList)] + PendingRewards {}, } #[cw_serde] diff --git a/test-helpers/src/astroport.rs b/test-helpers/src/astroport.rs index e021b49..c95c2c2 100644 --- a/test-helpers/src/astroport.rs +++ b/test-helpers/src/astroport.rs @@ -7,7 +7,9 @@ use cosmwasm_std::{to_json_binary, Addr, Coin, Decimal, Uint128}; use cw20::{Cw20ExecuteMsg, MinterResponse}; use cw20_base::msg::InstantiateMsg as Cw20InstantiateMsg; use cw_dex_test_contract::msg::AstroportContractInstantiateMsg; -use cw_it::astroport::utils::{create_astroport_pair, get_local_contracts, setup_astroport}; +use cw_it::astroport::utils::{ + create_astroport_pair, get_local_contracts, setup_astroport, AstroportContracts, +}; use cw_it::cw_multi_test::ContractWrapper; use cw_it::helpers::upload_wasm_file; use cw_it::test_tube::{Account, Module, Runner, RunnerResult, SigningAccount, Wasm}; @@ -28,7 +30,14 @@ pub fn setup_pool_and_test_contract<'a>( initial_liquidity: Vec<(&str, u64)>, native_denom_count: usize, wasm_file_path: &str, -) -> RunnerResult<(Vec, String, String, String, AssetList)> { +) -> RunnerResult<( + Vec, + String, + String, + String, + AssetList, + AstroportContracts, +)> { let wasm = Wasm::new(runner); // Initialize 10 accounts with max balance of each token @@ -261,14 +270,23 @@ pub fn setup_pool_and_test_contract<'a>( runner, code_id, pair_addr.clone(), - astroport_contracts.incentives.address, - AssetInfo::cw20(Addr::unchecked(astroport_contracts.astro_token.address)), + astroport_contracts.incentives.address.clone(), + AssetInfo::cw20(Addr::unchecked( + astroport_contracts.astro_token.address.clone(), + )), lp_token_addr.clone(), - astroport_contracts.liquidity_manager.address, + astroport_contracts.liquidity_manager.address.clone(), &accs[0], )?; - Ok((accs, lp_token_addr, pair_addr, contract_addr, asset_list)) + Ok(( + accs, + lp_token_addr, + pair_addr, + contract_addr, + asset_list, + astroport_contracts, + )) } #[allow(clippy::too_many_arguments)] From c79748cff14525d882b1935617cebca97f1af041 Mon Sep 17 00:00:00 2001 From: Pacman Date: Sun, 11 Feb 2024 20:03:07 +0100 Subject: [PATCH 09/22] chore: bump cw-dex version to 0.6.0-rc.3 --- Cargo.lock | 2 +- cw-dex/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 555a52e..ada90fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -886,7 +886,7 @@ dependencies = [ [[package]] name = "cw-dex" -version = "0.6.0-rc.2" +version = "0.6.0-rc.3" dependencies = [ "apollo-cw-asset", "apollo-utils", diff --git a/cw-dex/Cargo.toml b/cw-dex/Cargo.toml index 1ec1703..4f321a4 100644 --- a/cw-dex/Cargo.toml +++ b/cw-dex/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" license = "MPL-2.0" name = "cw-dex" repository = "https://github.com/apollodao/cw-dex" -version = "0.6.0-rc.2" +version = "0.6.0-rc.3" readme = "README.md" [features] From c195ed1360a4e9ed6578f94648de479a8f989104 Mon Sep 17 00:00:00 2001 From: Sturdy <91910406+apollo-sturdy@users.noreply.github.com> Date: Mon, 12 Feb 2024 12:46:24 +0100 Subject: [PATCH 10/22] fix: disable test-tube by default --- cw-dex/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cw-dex/Cargo.toml b/cw-dex/Cargo.toml index 4f321a4..f544b14 100644 --- a/cw-dex/Cargo.toml +++ b/cw-dex/Cargo.toml @@ -10,7 +10,7 @@ readme = "README.md" [features] default = [] -osmosis = ["osmosis-std", "osmosis-test-tube"] +osmosis = ["osmosis-std", "osmosis-test-tube", "cw-it/osmosis", "cw-dex-test-helpers/osmosis"] osmosis-test-tube = ["cw-it/osmosis-test-tube"] astroport = ["dep:astroport", "dep:astroport_v3", "apollo-cw-asset/astroport", "dep:cw2", "cw-it/astroport", "cw-it/astroport-multi-test"] # backtraces = ["cosmwasm-std/backtraces", "osmosis-std/backtraces"] @@ -37,10 +37,10 @@ astroport_v3 = { workspace = true, optional = true } cw2 = { workspace = true, optional = true } [dev-dependencies] -cw-it = { workspace = true, features = ["osmosis", "astroport", "multi-test", "astroport-multi-test"] } +cw-it = { workspace = true, features = ["astroport", "multi-test", "astroport-multi-test"] } test-case = "3.0.0" cw-dex-test-contract = { workspace = true } -cw-dex-test-helpers = { workspace = true, features = ["osmosis", "astroport"] } +cw-dex-test-helpers = { workspace = true, features = ["astroport"] } proptest = "1.0.0" cw20-base = { workspace = true } cw20 = { workspace = true } From c794fd3b6b7ffe17a66210c96634df6fcbbf5f30 Mon Sep 17 00:00:00 2001 From: Sturdy <91910406+apollo-sturdy@users.noreply.github.com> Date: Mon, 12 Feb 2024 12:49:19 +0100 Subject: [PATCH 11/22] build: bump rust version in makefile --- Makefile.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.toml b/Makefile.toml index 118b80a..d47e0bc 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -4,10 +4,10 @@ skip_core_tasks = true [env] # If you bump this version, verify RUST_VERSION correctness -RUST_OPTIMIZER_VERSION = "0.13.0" +RUST_OPTIMIZER_VERSION = "0.15.0" # Use rust version from rust-optimizer Dockerfile (see https://github.com/CosmWasm/rust-optimizer/blob/main/Dockerfile#L1) # to be sure that we compile / test against the same version -RUST_VERSION = "1.69.0" +RUST_VERSION = "1.75.0" NIGHTLY_VERSION = "nightly-2023-08-29" [tasks.install-stable] From 0b6479958d25dac3579fb880f2c12fa38ebdc899 Mon Sep 17 00:00:00 2001 From: Sturdy <91910406+apollo-sturdy@users.noreply.github.com> Date: Mon, 12 Feb 2024 16:41:46 +0100 Subject: [PATCH 12/22] fix: use astro_token codeid for cw20s --- cw-dex/tests/astroport_tests.rs | 38 +-------------------------------- 1 file changed, 1 insertion(+), 37 deletions(-) diff --git a/cw-dex/tests/astroport_tests.rs b/cw-dex/tests/astroport_tests.rs index bf01027..bfe5410 100644 --- a/cw-dex/tests/astroport_tests.rs +++ b/cw-dex/tests/astroport_tests.rs @@ -476,20 +476,9 @@ mod tests { .map(|(coin, duration)| (coin.into(), duration)) .collect(); - // Upload cw20 code - let cw20_code_id = runner - .store_code( - cw_it::ContractType::MultiTestContract(Box::new(ContractWrapper::new_with_empty( - cw20_base::contract::execute, - cw20_base::contract::instantiate, - cw20_base::contract::query, - ))), - admin, - ) - .unwrap(); - // Create Cw20 tokens for each Cw20 incentive, mint incentive amount to incentives_provider // and add to incentives + let cw20_code_id = astroport_contracts.astro_token.code_id; for (i, (amount, duration)) in cw20_incentives.iter().enumerate() { // Instantiate Cw20 token let cw20_addr = wasm @@ -620,10 +609,6 @@ mod tests { assert_eq!(amount, asset.amount); } - println!("{:?}", incentives); - println!("{:?}", pending_rewards); - println!("{:?}", cw_dex_pending_rewards); - // TODO: For some reason there are a lot of lp holders... let lp_holders = wasm .query::<_, AllAccountsResponse>( @@ -636,9 +621,6 @@ mod tests { .unwrap() .accounts; - println!("{:?}", lp_holders); - println!("{:?}", testing_contract_addr); - // Query total staked amount let total_staked = wasm .query::<_, astroport_v3::incentives::PoolInfoResponse>( @@ -650,24 +632,6 @@ mod tests { .unwrap() .total_lp; - println!("{:?}", total_staked); - println!("{:?}", lp_token_balance); - - // // Assert that pending rewards are correct - // for pending_reward in pending_rewards { - // // Find corresponding incentive - // let (incentive, duration) = incentives - // .iter() - // .find(|(incentive, _)| incentive.info == pending_reward.info) - // .unwrap(); - - // // Calculate expected reward based on incentive amount and total duration - // let expected_reward = incentive.amount * Decimal::from_ratio(1u128, *duration); - - // // Assert that pending reward is correct - // assert_eq!(pending_reward.amount, expected_reward); - // } - // Claim rewards wasm.execute( &testing_contract_addr, From e9a89cc1417f7cfacb750deff944dba5046fd8f9 Mon Sep 17 00:00:00 2001 From: Sturdy <91910406+apollo-sturdy@users.noreply.github.com> Date: Mon, 12 Feb 2024 18:19:36 +0100 Subject: [PATCH 13/22] ci: run tests with all features --- .github/workflows/test.yml | 4 ++-- Makefile.toml | 4 ++-- cw-dex/Cargo.toml | 2 +- deny.toml | 5 ++++- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4417af0..8c03962 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -51,7 +51,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: test - args: --locked --test osmosis_tests --features osmosis-test-tube + args: --locked --test osmosis_tests --all-features env: RUST_BACKTRACE: 1 @@ -59,7 +59,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: test - args: --locked --test astroport_tests --features osmosis-test-tube + args: --locked --test astroport_tests --all-features env: RUST_BACKTRACE: 1 diff --git a/Makefile.toml b/Makefile.toml index d47e0bc..19d2933 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -142,6 +142,7 @@ toolchain = "${RUST_VERSION}" command = "cargo" args = [ "test", + "--all-features", "--lib" ] @@ -154,8 +155,7 @@ toolchain = "${RUST_VERSION}" command = "cargo" args = [ "test", - "--features", - "osmosis-test-tube", + "--all-features", "--test", "*", ] diff --git a/cw-dex/Cargo.toml b/cw-dex/Cargo.toml index f544b14..b8f6646 100644 --- a/cw-dex/Cargo.toml +++ b/cw-dex/Cargo.toml @@ -11,7 +11,7 @@ readme = "README.md" [features] default = [] osmosis = ["osmosis-std", "osmosis-test-tube", "cw-it/osmosis", "cw-dex-test-helpers/osmosis"] -osmosis-test-tube = ["cw-it/osmosis-test-tube"] +osmosis-test-tube = ["cw-it/osmosis-test-tube", "cw-dex-test-helpers/osmosis-test-tube"] astroport = ["dep:astroport", "dep:astroport_v3", "apollo-cw-asset/astroport", "dep:cw2", "cw-it/astroport", "cw-it/astroport-multi-test"] # backtraces = ["cosmwasm-std/backtraces", "osmosis-std/backtraces"] diff --git a/deny.toml b/deny.toml index f769443..9a7a37c 100644 --- a/deny.toml +++ b/deny.toml @@ -33,4 +33,7 @@ copyleft = "deny" # We want really high confidence when inferring licenses from text confidence-threshold = 0.93 allow = ["Apache-2.0", "MIT", "BSD-3-Clause", "MPL-2.0"] -exceptions = [{ allow = ["Unicode-DFS-2016"], name = "unicode-ident" }] +exceptions = [ + { allow = ["Unicode-DFS-2016"], name = "unicode-ident" }, + { allow = ["GPL-3.0"], name = "cw-asset"} +] From f22d73ba4abe6f19f13570920ca6a153b8900e74 Mon Sep 17 00:00:00 2001 From: Sturdy <91910406+apollo-sturdy@users.noreply.github.com> Date: Mon, 12 Feb 2024 18:19:46 +0100 Subject: [PATCH 14/22] test: fix tests --- cw-dex/artifacts/astroport_incentives.wasm | Bin 0 -> 515599 bytes cw-dex/artifacts/checksums.txt | 1 + cw-dex/tests/astroport_tests.rs | 54 ++++++--------------- test-helpers/src/astroport.rs | 2 +- test-helpers/src/osmosis.rs | 2 +- 5 files changed, 18 insertions(+), 41 deletions(-) create mode 100644 cw-dex/artifacts/astroport_incentives.wasm diff --git a/cw-dex/artifacts/astroport_incentives.wasm b/cw-dex/artifacts/astroport_incentives.wasm new file mode 100644 index 0000000000000000000000000000000000000000..371ad055552afdb802f529a30ff0fb1d4c5c4816 GIT binary patch literal 515599 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

f4TsD@uL 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, ) .unwrap(); @@ -476,8 +475,8 @@ mod tests { .map(|(coin, duration)| (coin.into(), duration)) .collect(); - // Create Cw20 tokens for each Cw20 incentive, mint incentive amount to incentives_provider - // and add to incentives + // Create Cw20 tokens for each Cw20 incentive, mint incentive amount to + // incentives_provider and add to incentives let cw20_code_id = astroport_contracts.astro_token.code_id; for (i, (amount, duration)) in cw20_incentives.iter().enumerate() { // Instantiate Cw20 token @@ -486,7 +485,7 @@ mod tests { cw20_code_id, &cw20_base::msg::InstantiateMsg { name: format!("cw20_incentive_{}", i), - symbol: format!("incentive"), + symbol: "incentive".to_string(), decimals: 6, initial_balances: vec![cw20::Cw20Coin { address: incentives_provider.address(), @@ -521,7 +520,7 @@ mod tests { contract_addr.as_str(), &cw20::Cw20ExecuteMsg::IncreaseAllowance { spender: astroport_contracts.incentives.address.clone(), - amount: incentive.amount.clone(), + amount: incentive.amount, expires: None, }, &[], @@ -564,7 +563,7 @@ mod tests { .unwrap(); // Stake LP tokens - let events = stake_all_lp_tokens( + let _events = stake_all_lp_tokens( &runner, testing_contract_addr.clone(), lp_token_addr.clone(), @@ -573,7 +572,7 @@ mod tests { .events; // Increase time by 1 week - runner.increase_time(60 * 60 * 24 * 1).unwrap(); + runner.increase_time(60 * 60 * 24).unwrap(); // Query incentives contract for admin users pending rewards let pending_rewards: Vec = wasm @@ -609,29 +608,6 @@ mod tests { assert_eq!(amount, asset.amount); } - // TODO: For some reason there are a lot of lp holders... - let lp_holders = wasm - .query::<_, AllAccountsResponse>( - &lp_token_addr, - &cw20::Cw20QueryMsg::AllAccounts { - start_after: None, - limit: None, - }, - ) - .unwrap() - .accounts; - - // Query total staked amount - let total_staked = wasm - .query::<_, astroport_v3::incentives::PoolInfoResponse>( - &astroport_contracts.incentives.address, - &astroport_v3::incentives::QueryMsg::PoolInfo { - lp_token: lp_token_addr.clone(), - }, - ) - .unwrap() - .total_lp; - // Claim rewards wasm.execute( &testing_contract_addr, @@ -644,7 +620,7 @@ mod tests { // Assert that testing contract has correct asset balances for reward in cw_dex_pending_rewards.to_vec() { let asset_balance = query_asset_balance(&runner, &reward.info, &testing_contract_addr); - assert_eq!(asset_balance, reward.amount); + assert_approx_eq!(asset_balance, reward.amount, "0.0001"); // TODO: Why is there a diff here? } Ok(()) diff --git a/test-helpers/src/astroport.rs b/test-helpers/src/astroport.rs index c95c2c2..7653c01 100644 --- a/test-helpers/src/astroport.rs +++ b/test-helpers/src/astroport.rs @@ -310,7 +310,7 @@ pub fn instantiate_test_astroport_contract<'a, R: Runner<'a>>( let wasm = Wasm::new(runner); Ok(wasm - .instantiate(code_id, &init_msg, None, None, &[], signer)? + .instantiate(code_id, &init_msg, None, Some("test contract"), &[], signer)? .data .address) } diff --git a/test-helpers/src/osmosis.rs b/test-helpers/src/osmosis.rs index 95438f9..346fc23 100644 --- a/test-helpers/src/osmosis.rs +++ b/test-helpers/src/osmosis.rs @@ -86,7 +86,7 @@ pub fn instantiate_test_contract<'a, R: Runner<'a>>( let wasm = Wasm::new(runner); Ok(wasm - .instantiate(code_id, &init_msg, None, None, &[], signer)? + .instantiate(code_id, &init_msg, None, Some("test contract"), &[], signer)? .data .address) } From 386575be071c3f7749be5135ee25ae26ca2d6736 Mon Sep 17 00:00:00 2001 From: Sturdy <91910406+apollo-sturdy@users.noreply.github.com> Date: Mon, 12 Feb 2024 18:45:17 +0100 Subject: [PATCH 15/22] ci: Use go 1.21.6 on ci --- .github/workflows/lint-format.yml | 5 +++++ .github/workflows/test.yml | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/.github/workflows/lint-format.yml b/.github/workflows/lint-format.yml index 9bcf1ab..882c6aa 100644 --- a/.github/workflows/lint-format.yml +++ b/.github/workflows/lint-format.yml @@ -14,6 +14,11 @@ jobs: - name: Checkout sources uses: actions/checkout@v3 + - name: Set up Go 1.21.6 + uses: actions/setup-go@v5 + with: + go-version: "1.21.6" + - name: Install cargo make uses: davidB/rust-cargo-make@v1 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8c03962..aa9285f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,6 +15,11 @@ jobs: - name: Checkout sources uses: actions/checkout@v3 + - name: Set up Go 1.21.6 + uses: actions/setup-go@v5 + with: + go-version: "1.21.6" + - name: Install stable toolchain uses: actions-rs/toolchain@v1 with: From 8dad616129f3d8d18e2167cc3649cde43b8d3915 Mon Sep 17 00:00:00 2001 From: Sturdy <91910406+apollo-sturdy@users.noreply.github.com> Date: Mon, 12 Feb 2024 18:55:01 +0100 Subject: [PATCH 16/22] ci: use makefile rust version --- .github/workflows/test.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index aa9285f..cde032a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,13 +20,11 @@ jobs: with: go-version: "1.21.6" + - name: Install cargo make + uses: davidB/rust-cargo-make@v1 + - name: Install stable toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: 1.69.0 - target: wasm32-unknown-unknown - override: true + run: cargo make install-stable - name: Run unit tests uses: actions-rs/cargo@v1 From b7b026bb19ffd4fe413f89607ad0cc346592528c Mon Sep 17 00:00:00 2001 From: Sturdy <91910406+apollo-sturdy@users.noreply.github.com> Date: Tue, 13 Feb 2024 09:35:37 +0100 Subject: [PATCH 17/22] ci: run proptest with all features --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cde032a..ddf68c3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -70,6 +70,6 @@ jobs: uses: actions-rs/cargo@v1 with: command: test - args: --locked --test osmosis_proptests + args: --locked --test osmosis_proptests --all-features env: RUST_BACKTRACE: 1 From 55c28b96023ac8c48e389cbbf1991c2bba1107c0 Mon Sep 17 00:00:00 2001 From: Sturdy <91910406+apollo-sturdy@users.noreply.github.com> Date: Tue, 13 Feb 2024 09:43:39 +0100 Subject: [PATCH 18/22] chore: bump cw-asset dep --- Cargo.lock | 4 ++-- deny.toml | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ada90fe..d4aa59f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -872,9 +872,9 @@ dependencies = [ [[package]] name = "cw-asset" -version = "3.1.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "431e57314dceabd29a682c78bb3ff7c641f8bdc8b915400bb9956cb911e8e571" +checksum = "c999a12f8cd8736f6f86e9a4ede5905530cb23cfdef946b9da1c506ad1b70799" dependencies = [ "cosmwasm-schema", "cosmwasm-std", diff --git a/deny.toml b/deny.toml index 9a7a37c..10a6b5a 100644 --- a/deny.toml +++ b/deny.toml @@ -35,5 +35,4 @@ confidence-threshold = 0.93 allow = ["Apache-2.0", "MIT", "BSD-3-Clause", "MPL-2.0"] exceptions = [ { allow = ["Unicode-DFS-2016"], name = "unicode-ident" }, - { allow = ["GPL-3.0"], name = "cw-asset"} ] From 7614e24373294826f408de408d214ae2c5a10e98 Mon Sep 17 00:00:00 2001 From: Sturdy <91910406+apollo-sturdy@users.noreply.github.com> Date: Tue, 13 Feb 2024 10:14:39 +0100 Subject: [PATCH 19/22] build: run deny with all features --- Makefile.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.toml b/Makefile.toml index 19d2933..90d450e 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -54,7 +54,7 @@ args = ["fmt", "--all", "--","--verbose", "--check"] [tasks.deny] command = "cargo" -args = ["deny", "check"] +args = ["deny", "--all-features", "check"] [tasks.check] toolchain = "${RUST_VERSION}" From a65879b545fa06ecae4f0447aa3743849dc972cd Mon Sep 17 00:00:00 2001 From: Sturdy <91910406+apollo-sturdy@users.noreply.github.com> Date: Tue, 13 Feb 2024 12:57:35 +0100 Subject: [PATCH 20/22] feat: split out implementations to separate crates --- Cargo.lock | 51 ++- Cargo.toml | 16 +- cw-dex-astroport/Cargo.toml | 41 ++ .../artifacts/astroport_factory.wasm | Bin .../artifacts/astroport_generator.wasm | Bin .../artifacts/astroport_incentives.wasm | Bin .../artifacts/astroport_liquidity_helper.wasm | Bin .../astroport_liquidity_manager.wasm | Bin .../artifacts/astroport_maker.wasm | Bin .../astroport_native_coin_registry.wasm | Bin .../astroport_native_coin_wrapper.wasm | Bin .../artifacts/astroport_oracle.wasm | Bin .../artifacts/astroport_pair.wasm | Bin .../astroport_pair_astro_xastro.wasm | Bin .../astroport_pair_concentrated.wasm | Bin .../artifacts/astroport_pair_stable.wasm | Bin .../artifacts/astroport_router.wasm | Bin .../artifacts/astroport_staking.wasm | Bin .../artifacts/astroport_token.wasm | Bin .../artifacts/astroport_vault.wasm | Bin .../artifacts/astroport_vesting.wasm | Bin .../artifacts/astroport_whitelist.wasm | Bin .../artifacts/astroport_xastro_token.wasm | Bin .../artifacts/checksums.txt | 0 .../artifacts/checksums_intermediate.txt | 0 .../artifacts/cw_dex_router.wasm | Bin .../artifacts/cw_dex_test_contract.wasm | Bin cw-dex-astroport/src/lib.rs | 9 + cw-dex-astroport/src/pool.rs | 349 +++++++++++++++++ cw-dex-astroport/src/staking.rs | 147 ++++++++ .../tests/astroport_tests.rs | 34 +- cw-dex-osmosis/Cargo.toml | 37 ++ cw-dex-osmosis/src/helpers.rs | 14 + cw-dex-osmosis/src/lib.rs | 8 + cw-dex-osmosis/src/pool.rs | 351 ++++++++++++++++++ cw-dex-osmosis/src/staking.rs | 325 ++++++++++++++++ .../osmosis_proptests.proptest-regressions | 0 .../tests/osmosis_proptests.rs | 0 .../tests/osmosis_tests.rs | 0 cw-dex/Cargo.toml | 4 +- cw-dex/src/implementations/osmosis/pool.rs | 21 -- cw-dex/src/lib.rs | 17 +- cw-dex/tests/configs/terra.yaml | 97 ----- .../astroport-test-contract/Cargo.toml | 5 +- .../astroport-test-contract/src/contract.rs | 4 +- .../astroport-test-contract/src/state.rs | 2 +- .../osmosis-test-contract/Cargo.toml | 5 +- .../osmosis-test-contract/src/contract.rs | 4 +- .../osmosis-test-contract/src/state.rs | 2 +- test-contracts/package/Cargo.toml | 3 +- test-contracts/package/src/msg.rs | 8 +- test-helpers/Cargo.toml | 4 +- 52 files changed, 1389 insertions(+), 169 deletions(-) create mode 100644 cw-dex-astroport/Cargo.toml rename {cw-dex => cw-dex-astroport}/artifacts/astroport_factory.wasm (100%) rename {cw-dex => cw-dex-astroport}/artifacts/astroport_generator.wasm (100%) rename {cw-dex => cw-dex-astroport}/artifacts/astroport_incentives.wasm (100%) rename {cw-dex => cw-dex-astroport}/artifacts/astroport_liquidity_helper.wasm (100%) rename {cw-dex => cw-dex-astroport}/artifacts/astroport_liquidity_manager.wasm (100%) rename {cw-dex => cw-dex-astroport}/artifacts/astroport_maker.wasm (100%) rename {cw-dex => cw-dex-astroport}/artifacts/astroport_native_coin_registry.wasm (100%) rename {cw-dex => cw-dex-astroport}/artifacts/astroport_native_coin_wrapper.wasm (100%) rename {cw-dex => cw-dex-astroport}/artifacts/astroport_oracle.wasm (100%) rename {cw-dex => cw-dex-astroport}/artifacts/astroport_pair.wasm (100%) rename {cw-dex => cw-dex-astroport}/artifacts/astroport_pair_astro_xastro.wasm (100%) rename {cw-dex => cw-dex-astroport}/artifacts/astroport_pair_concentrated.wasm (100%) rename {cw-dex => cw-dex-astroport}/artifacts/astroport_pair_stable.wasm (100%) rename {cw-dex => cw-dex-astroport}/artifacts/astroport_router.wasm (100%) rename {cw-dex => cw-dex-astroport}/artifacts/astroport_staking.wasm (100%) rename {cw-dex => cw-dex-astroport}/artifacts/astroport_token.wasm (100%) rename {cw-dex => cw-dex-astroport}/artifacts/astroport_vault.wasm (100%) rename {cw-dex => cw-dex-astroport}/artifacts/astroport_vesting.wasm (100%) rename {cw-dex => cw-dex-astroport}/artifacts/astroport_whitelist.wasm (100%) rename {cw-dex => cw-dex-astroport}/artifacts/astroport_xastro_token.wasm (100%) rename {cw-dex => cw-dex-astroport}/artifacts/checksums.txt (100%) rename {cw-dex => cw-dex-astroport}/artifacts/checksums_intermediate.txt (100%) rename {cw-dex => cw-dex-astroport}/artifacts/cw_dex_router.wasm (100%) rename {cw-dex => cw-dex-astroport}/artifacts/cw_dex_test_contract.wasm (100%) create mode 100644 cw-dex-astroport/src/lib.rs create mode 100644 cw-dex-astroport/src/pool.rs create mode 100644 cw-dex-astroport/src/staking.rs rename {cw-dex => cw-dex-astroport}/tests/astroport_tests.rs (97%) create mode 100644 cw-dex-osmosis/Cargo.toml create mode 100644 cw-dex-osmosis/src/helpers.rs create mode 100644 cw-dex-osmosis/src/lib.rs create mode 100644 cw-dex-osmosis/src/pool.rs create mode 100644 cw-dex-osmosis/src/staking.rs rename {cw-dex => cw-dex-osmosis}/tests/osmosis_proptests.proptest-regressions (100%) rename {cw-dex => cw-dex-osmosis}/tests/osmosis_proptests.rs (100%) rename {cw-dex => cw-dex-osmosis}/tests/osmosis_tests.rs (100%) delete mode 100644 cw-dex/tests/configs/terra.yaml diff --git a/Cargo.lock b/Cargo.lock index d4aa59f..4e0d104 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -346,12 +346,13 @@ dependencies = [ [[package]] name = "astroport-test-contract" -version = "0.1.0" +version = "0.2.0" dependencies = [ "apollo-cw-asset", "cosmwasm-schema", "cosmwasm-std", "cw-dex", + "cw-dex-astroport", "cw-dex-test-contract", "cw-storage-plus 1.2.0", "thiserror", @@ -886,7 +887,7 @@ dependencies = [ [[package]] name = "cw-dex" -version = "0.6.0-rc.3" +version = "0.5.2" dependencies = [ "apollo-cw-asset", "apollo-utils", @@ -908,13 +909,54 @@ dependencies = [ ] [[package]] -name = "cw-dex-test-contract" +name = "cw-dex-astroport" +version = "0.1.0" +dependencies = [ + "apollo-cw-asset", + "apollo-utils", + "astroport 2.9.0", + "astroport 3.11.1", + "cosmwasm-schema", + "cosmwasm-std", + "cw-dex", + "cw-dex-test-contract", + "cw-dex-test-helpers", + "cw-it", + "cw-utils 1.0.2", + "cw2 1.1.1", + "cw20 1.1.2", + "cw20-base 1.1.1", + "proptest", + "test-case", +] + +[[package]] +name = "cw-dex-osmosis" version = "0.1.0" dependencies = [ "apollo-cw-asset", + "apollo-utils", "cosmwasm-schema", "cosmwasm-std", "cw-dex", + "cw-dex-test-contract", + "cw-dex-test-helpers", + "cw-it", + "cw-utils 1.0.2", + "cw20 1.1.2", + "cw20-base 1.1.1", + "osmosis-std 0.19.2", + "proptest", + "test-case", +] + +[[package]] +name = "cw-dex-test-contract" +version = "0.2.0" +dependencies = [ + "apollo-cw-asset", + "cosmwasm-schema", + "cosmwasm-std", ] [[package]] @@ -2027,12 +2069,13 @@ dependencies = [ [[package]] name = "osmosis-test-contract" -version = "0.1.0" +version = "0.2.0" dependencies = [ "apollo-cw-asset", "cosmwasm-schema", "cosmwasm-std", "cw-dex", + "cw-dex-osmosis", "cw-dex-test-contract", "cw-storage-plus 1.2.0", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index e8d0faf..cf0de53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["cw-dex", "test-contracts/*", "test-helpers"] +members = ["cw-dex", "cw-dex-astroport", "cw-dex-osmosis", "test-contracts/*", "test-helpers"] resolver = "2" [workspace.package] @@ -27,13 +27,19 @@ thiserror = { version = "1.0.31" } apollo-cw-asset = "0.1.1" osmosis-std = "0.19.2" cw-it = "0.3.0-rc.4" -cw-dex = { path = "cw-dex" } -cw-dex-test-contract = { path = "test-contracts/package" } -astroport-test-contract = { path = "test-contracts/astroport-test-contract" } -cw-dex-test-helpers = { path = "test-helpers" } apollo-utils = "0.1.0" astroport = "=2.9.0" astroport_v3 = { package = "astroport", version = "=3.11.1" } +test-case = "3.0.0" +proptest = "1.0.0" + +# Workspace packages +cw-dex = { path = "cw-dex", version = "0.5.2" } +cw-dex-astroport = { path = "cw-dex-astroport", version = "0.1.0" } +cw-dex-osmosis = { path = "cw-dex-osmosis", version = "0.1.0" } +cw-dex-test-contract = { path = "test-contracts/package" } +astroport-test-contract = { path = "test-contracts/astroport-test-contract" } +cw-dex-test-helpers = { path = "test-helpers" } [profile.release] codegen-units = 1 diff --git a/cw-dex-astroport/Cargo.toml b/cw-dex-astroport/Cargo.toml new file mode 100644 index 0000000..47fa60b --- /dev/null +++ b/cw-dex-astroport/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "cw-dex-astroport" +authors = ["Apollo Devs"] +description = "Implementation of the cw-dex API for the Astroport AMM" +edition = "2021" +license = "MPL-2.0" +repository = "https://github.com/apollodao/cw-dex" +version = "0.1.0" +readme = "README.md" + +[features] +default = [] +osmosis-test-tube = ["cw-it/osmosis-test-tube", "cw-dex-test-helpers/osmosis-test-tube"] +# backtraces = ["cosmwasm-std/backtraces", "osmosis-std/backtraces"] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[dependencies] +cw-dex = { workspace = true } +cosmwasm-schema = { workspace = true } +cosmwasm-std = { workspace = true } +apollo-cw-asset = { workspace = true, features = ["astroport"] } +cw-utils = { workspace = true } +cw20 = { workspace = true } +apollo-utils = { workspace = true } + +# Astroport +astroport = { workspace = true } +astroport_v3 = { workspace = true } +cw2 = { workspace = true } + +[dev-dependencies] +cw-it = { workspace = true, features = ["astroport", "multi-test", "astroport-multi-test"] } +test-case = { workspace = true } +cw-dex-test-contract = { workspace = true } +cw-dex-test-helpers = { workspace = true, features = ["astroport"] } +proptest = { workspace = true } +cw20-base = { workspace = true } +cw20 = { workspace = true } diff --git a/cw-dex/artifacts/astroport_factory.wasm b/cw-dex-astroport/artifacts/astroport_factory.wasm similarity index 100% rename from cw-dex/artifacts/astroport_factory.wasm rename to cw-dex-astroport/artifacts/astroport_factory.wasm diff --git a/cw-dex/artifacts/astroport_generator.wasm b/cw-dex-astroport/artifacts/astroport_generator.wasm similarity index 100% rename from cw-dex/artifacts/astroport_generator.wasm rename to cw-dex-astroport/artifacts/astroport_generator.wasm diff --git a/cw-dex/artifacts/astroport_incentives.wasm b/cw-dex-astroport/artifacts/astroport_incentives.wasm similarity index 100% rename from cw-dex/artifacts/astroport_incentives.wasm rename to cw-dex-astroport/artifacts/astroport_incentives.wasm diff --git a/cw-dex/artifacts/astroport_liquidity_helper.wasm b/cw-dex-astroport/artifacts/astroport_liquidity_helper.wasm similarity index 100% rename from cw-dex/artifacts/astroport_liquidity_helper.wasm rename to cw-dex-astroport/artifacts/astroport_liquidity_helper.wasm diff --git a/cw-dex/artifacts/astroport_liquidity_manager.wasm b/cw-dex-astroport/artifacts/astroport_liquidity_manager.wasm similarity index 100% rename from cw-dex/artifacts/astroport_liquidity_manager.wasm rename to cw-dex-astroport/artifacts/astroport_liquidity_manager.wasm diff --git a/cw-dex/artifacts/astroport_maker.wasm b/cw-dex-astroport/artifacts/astroport_maker.wasm similarity index 100% rename from cw-dex/artifacts/astroport_maker.wasm rename to cw-dex-astroport/artifacts/astroport_maker.wasm diff --git a/cw-dex/artifacts/astroport_native_coin_registry.wasm b/cw-dex-astroport/artifacts/astroport_native_coin_registry.wasm similarity index 100% rename from cw-dex/artifacts/astroport_native_coin_registry.wasm rename to cw-dex-astroport/artifacts/astroport_native_coin_registry.wasm diff --git a/cw-dex/artifacts/astroport_native_coin_wrapper.wasm b/cw-dex-astroport/artifacts/astroport_native_coin_wrapper.wasm similarity index 100% rename from cw-dex/artifacts/astroport_native_coin_wrapper.wasm rename to cw-dex-astroport/artifacts/astroport_native_coin_wrapper.wasm diff --git a/cw-dex/artifacts/astroport_oracle.wasm b/cw-dex-astroport/artifacts/astroport_oracle.wasm similarity index 100% rename from cw-dex/artifacts/astroport_oracle.wasm rename to cw-dex-astroport/artifacts/astroport_oracle.wasm diff --git a/cw-dex/artifacts/astroport_pair.wasm b/cw-dex-astroport/artifacts/astroport_pair.wasm similarity index 100% rename from cw-dex/artifacts/astroport_pair.wasm rename to cw-dex-astroport/artifacts/astroport_pair.wasm diff --git a/cw-dex/artifacts/astroport_pair_astro_xastro.wasm b/cw-dex-astroport/artifacts/astroport_pair_astro_xastro.wasm similarity index 100% rename from cw-dex/artifacts/astroport_pair_astro_xastro.wasm rename to cw-dex-astroport/artifacts/astroport_pair_astro_xastro.wasm diff --git a/cw-dex/artifacts/astroport_pair_concentrated.wasm b/cw-dex-astroport/artifacts/astroport_pair_concentrated.wasm similarity index 100% rename from cw-dex/artifacts/astroport_pair_concentrated.wasm rename to cw-dex-astroport/artifacts/astroport_pair_concentrated.wasm diff --git a/cw-dex/artifacts/astroport_pair_stable.wasm b/cw-dex-astroport/artifacts/astroport_pair_stable.wasm similarity index 100% rename from cw-dex/artifacts/astroport_pair_stable.wasm rename to cw-dex-astroport/artifacts/astroport_pair_stable.wasm diff --git a/cw-dex/artifacts/astroport_router.wasm b/cw-dex-astroport/artifacts/astroport_router.wasm similarity index 100% rename from cw-dex/artifacts/astroport_router.wasm rename to cw-dex-astroport/artifacts/astroport_router.wasm diff --git a/cw-dex/artifacts/astroport_staking.wasm b/cw-dex-astroport/artifacts/astroport_staking.wasm similarity index 100% rename from cw-dex/artifacts/astroport_staking.wasm rename to cw-dex-astroport/artifacts/astroport_staking.wasm diff --git a/cw-dex/artifacts/astroport_token.wasm b/cw-dex-astroport/artifacts/astroport_token.wasm similarity index 100% rename from cw-dex/artifacts/astroport_token.wasm rename to cw-dex-astroport/artifacts/astroport_token.wasm diff --git a/cw-dex/artifacts/astroport_vault.wasm b/cw-dex-astroport/artifacts/astroport_vault.wasm similarity index 100% rename from cw-dex/artifacts/astroport_vault.wasm rename to cw-dex-astroport/artifacts/astroport_vault.wasm diff --git a/cw-dex/artifacts/astroport_vesting.wasm b/cw-dex-astroport/artifacts/astroport_vesting.wasm similarity index 100% rename from cw-dex/artifacts/astroport_vesting.wasm rename to cw-dex-astroport/artifacts/astroport_vesting.wasm diff --git a/cw-dex/artifacts/astroport_whitelist.wasm b/cw-dex-astroport/artifacts/astroport_whitelist.wasm similarity index 100% rename from cw-dex/artifacts/astroport_whitelist.wasm rename to cw-dex-astroport/artifacts/astroport_whitelist.wasm diff --git a/cw-dex/artifacts/astroport_xastro_token.wasm b/cw-dex-astroport/artifacts/astroport_xastro_token.wasm similarity index 100% rename from cw-dex/artifacts/astroport_xastro_token.wasm rename to cw-dex-astroport/artifacts/astroport_xastro_token.wasm diff --git a/cw-dex/artifacts/checksums.txt b/cw-dex-astroport/artifacts/checksums.txt similarity index 100% rename from cw-dex/artifacts/checksums.txt rename to cw-dex-astroport/artifacts/checksums.txt diff --git a/cw-dex/artifacts/checksums_intermediate.txt b/cw-dex-astroport/artifacts/checksums_intermediate.txt similarity index 100% rename from cw-dex/artifacts/checksums_intermediate.txt rename to cw-dex-astroport/artifacts/checksums_intermediate.txt diff --git a/cw-dex/artifacts/cw_dex_router.wasm b/cw-dex-astroport/artifacts/cw_dex_router.wasm similarity index 100% rename from cw-dex/artifacts/cw_dex_router.wasm rename to cw-dex-astroport/artifacts/cw_dex_router.wasm diff --git a/cw-dex/artifacts/cw_dex_test_contract.wasm b/cw-dex-astroport/artifacts/cw_dex_test_contract.wasm similarity index 100% rename from cw-dex/artifacts/cw_dex_test_contract.wasm rename to cw-dex-astroport/artifacts/cw_dex_test_contract.wasm diff --git a/cw-dex-astroport/src/lib.rs b/cw-dex-astroport/src/lib.rs new file mode 100644 index 0000000..b48062f --- /dev/null +++ b/cw-dex-astroport/src/lib.rs @@ -0,0 +1,9 @@ +//! Pool and Staking implementations for Astroport + +mod pool; +mod staking; + +pub use pool::AstroportPool; +pub use staking::AstroportStaking; + +pub use astroport; diff --git a/cw-dex-astroport/src/pool.rs b/cw-dex-astroport/src/pool.rs new file mode 100644 index 0000000..de74780 --- /dev/null +++ b/cw-dex-astroport/src/pool.rs @@ -0,0 +1,349 @@ +//! Pool trait implementation for Astroport + +use std::str::FromStr; + +use apollo_cw_asset::{Asset, AssetInfo, AssetInfoBase, AssetList}; +use apollo_utils::iterators::IntoElementwise; +use astroport::liquidity_manager; +use cosmwasm_schema::cw_serde; +use cosmwasm_std::{ + to_json_binary, wasm_execute, Addr, CosmosMsg, Decimal, Deps, Env, Event, QuerierWrapper, + QueryRequest, Response, StdError, StdResult, Uint128, WasmMsg, WasmQuery, +}; +use cw20::Cw20ExecuteMsg; +use cw_utils::Expiration; + +use apollo_utils::assets::separate_natives_and_cw20s; +use astroport::asset::{Asset as AstroAsset, PairInfo}; +use astroport::factory::PairType; +use astroport::pair::{ + Cw20HookMsg as PairCw20HookMsg, ExecuteMsg as PairExecuteMsg, PoolResponse, + QueryMsg as PairQueryMsg, SimulationResponse, MAX_ALLOWED_SLIPPAGE, +}; +use astroport::querier::query_supply; +use cw_dex::traits::Pool; +use cw_dex::CwDexError; + +/// Represents an AMM pool on Astroport +#[cw_serde] +pub struct AstroportPool { + /// The address of the associated pair contract + pub pair_addr: Addr, + /// The address of the associated LP token contract + pub lp_token_addr: Addr, + /// The assets of the pool + pub pool_assets: Vec, + /// The type of pool represented: Constant product (*Xyk*) or *Stableswap* + pub pair_type: PairType, + /// The address of the Astroport liquidity manager contract + pub liquidity_manager: Addr, +} + +impl AstroportPool { + /// Creates a new instance of `AstroportPool` + /// + /// Arguments: + /// - `pair_addr`: The address of the pair contract associated with the pool + pub fn new(deps: Deps, pair_addr: Addr, liquidity_manager: Addr) -> StdResult { + let pair_info = deps + .querier + .query_wasm_smart::(pair_addr.clone(), &PairQueryMsg::Pair {})?; + + // Validate pair type. We only support XYK, stable swap, and PCL pools + match &pair_info.pair_type { + PairType::Custom(t) => match t.as_str() { + "concentrated" => Ok(()), + "astroport-pair-xyk-sale-tax" => Ok(()), + _ => Err(StdError::generic_err("Custom pair type is not supported")), + }, + _ => Ok(()), + }?; + + Ok(Self { + pair_addr, + lp_token_addr: pair_info.liquidity_token, + pool_assets: pair_info.asset_infos.into_elementwise(), + pair_type: pair_info.pair_type, + liquidity_manager, + }) + } + + /// Returns the matching pool given a LP token. + /// + /// Arguments: + /// - `lp_token`: Said LP token + /// - `astroport_liquidity_manager`: The Astroport liquidity manager + /// address. + #[allow(unused_variables)] + #[allow(unreachable_patterns)] + pub fn get_pool_for_lp_token( + deps: Deps, + lp_token: &AssetInfo, + astroport_liquidity_manager: Addr, + ) -> Result { + match lp_token { + AssetInfo::Cw20(address) => { + // To figure out if the CW20 is a LP token, we need to check which address + // instantiated the CW20 and check if that address is an Astroport pair + // contract. + let contract_info = deps.querier.query_wasm_contract_info(address)?; + let creator_addr = deps.api.addr_validate(&contract_info.creator)?; + + // Try to create an `AstroportPool` object with the creator address. This will + // query the contract and assume that it is an Astroport pair + // contract. If it succeeds, the pool object will be returned. + // + // NB: This does NOT validate that the pool is registered with the Astroport + // factory, and that it is an "official" Astroport pool. + let pool = AstroportPool::new(deps, creator_addr, astroport_liquidity_manager)?; + + Ok(pool) + } + _ => Err(CwDexError::NotLpToken {}), + } + } + + /// Returns the total supply of the associated LP token + pub fn query_lp_token_supply(&self, querier: &QuerierWrapper) -> StdResult { + query_supply(querier, self.lp_token_addr.to_owned()) + } + + /// Queries the pair contract for the current pool state + pub fn query_pool_info(&self, querier: &QuerierWrapper) -> StdResult { + querier.query::(&QueryRequest::Wasm(WasmQuery::Smart { + contract_addr: self.pair_addr.to_string(), + msg: to_json_binary(&PairQueryMsg::Pool {})?, + })) + } +} + +impl Pool for AstroportPool { + fn provide_liquidity( + &self, + _deps: Deps, + env: &Env, + assets: AssetList, + min_out: Uint128, + ) -> Result { + let (funds, cw20s) = separate_natives_and_cw20s(&assets); + + // Increase allowance on all Cw20s + let allowance_msgs: Vec = cw20s + .into_iter() + .map(|asset| { + Ok(CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: asset.address, + msg: to_json_binary(&Cw20ExecuteMsg::IncreaseAllowance { + spender: self.liquidity_manager.to_string(), + amount: asset.amount, + expires: Some(Expiration::AtHeight(env.block.height + 1)), + })?, + funds: vec![], + })) + }) + .collect::>>()?; + + // Liquidity manager requires assets vec to contain all assets in the pool + let mut assets_vec = assets.to_vec(); + for pool_asset_info in &self.pool_assets { + if !assets_vec.iter().any(|x| &x.info == pool_asset_info) { + assets_vec.push(Asset::new(pool_asset_info.clone(), Uint128::zero())); + } + } + + // Create the provide liquidity message + let provide_liquidity_msg = CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: self.liquidity_manager.to_string(), + msg: to_json_binary(&liquidity_manager::ExecuteMsg::ProvideLiquidity { + pair_addr: self.pair_addr.to_string(), + min_lp_to_receive: Some(min_out), + pair_msg: astroport::pair::ExecuteMsg::ProvideLiquidity { + assets: assets_vec.into_elementwise(), + slippage_tolerance: Some(Decimal::from_str(MAX_ALLOWED_SLIPPAGE)?), + auto_stake: Some(false), + receiver: None, + }, + })?, + funds, + }); + + let event = Event::new("apollo/cw-dex/provide_liquidity") + .add_attribute("pair_addr", &self.pair_addr) + .add_attribute("assets", format!("{:?}", assets)); + + Ok(Response::new() + .add_messages(allowance_msgs) + .add_message(provide_liquidity_msg) + .add_event(event)) + } + + fn withdraw_liquidity( + &self, + _deps: Deps, + _env: &Env, + asset: Asset, + mut min_out: AssetList, + ) -> Result { + if let AssetInfoBase::Cw20(token_addr) = &asset.info { + // Liquidity manager requires min_out to contain all assets in the pool + for asset in &self.pool_assets { + if min_out.find(asset).is_none() { + // Add one unit as AssetList does not allow zero amounts (calls self.purge on + // add) + min_out.add(&Asset::new(asset.clone(), Uint128::one()))?; + } + } + + let withdraw_liquidity = CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: token_addr.to_string(), + msg: to_json_binary(&Cw20ExecuteMsg::Send { + contract: self.liquidity_manager.to_string(), + amount: asset.amount, + msg: to_json_binary(&liquidity_manager::Cw20HookMsg::WithdrawLiquidity { + pair_msg: astroport::pair::Cw20HookMsg::WithdrawLiquidity { + // This field is currently not used... + assets: vec![], + }, + min_assets_to_receive: min_out.to_vec().into_elementwise(), + })?, + })?, + funds: vec![], + }); + + let event = Event::new("apollo/cw-dex/withdraw_liquidity") + .add_attribute("pair_addr", &self.pair_addr) + .add_attribute("asset", format!("{:?}", asset)) + .add_attribute("token_amount", asset.amount); + + Ok(Response::new() + .add_message(withdraw_liquidity) + .add_event(event)) + } else { + Err(CwDexError::InvalidInAsset { a: asset }) + } + } + + fn swap( + &self, + _deps: Deps, + env: &Env, + offer_asset: Asset, + ask_asset_info: AssetInfo, + min_out: Uint128, + ) -> Result { + // Setting belief price to the minimium acceptable return and max spread to zero + // simplifies things Astroport will make the best possible swap that + // returns at least `min_out`. + let belief_price = Some(Decimal::from_ratio(offer_asset.amount, min_out)); + let swap_msg = match &offer_asset.info { + AssetInfo::Native(_) => { + let asset = offer_asset.clone().into(); + wasm_execute( + self.pair_addr.to_string(), + &PairExecuteMsg::Swap { + offer_asset: asset, + belief_price, + max_spread: Some(Decimal::zero()), + to: Some(env.contract.address.to_string()), + ask_asset_info: Some(ask_asset_info.to_owned().into()), + }, + vec![offer_asset.clone().try_into()?], + ) + } + AssetInfo::Cw20(addr) => wasm_execute( + addr.to_string(), + &Cw20ExecuteMsg::Send { + contract: self.pair_addr.to_string(), + amount: offer_asset.amount, + msg: to_json_binary(&PairCw20HookMsg::Swap { + belief_price, + max_spread: Some(Decimal::zero()), + to: Some(env.contract.address.to_string()), + ask_asset_info: Some(ask_asset_info.to_owned().into()), + })?, + }, + vec![], + ), + }?; + let event = Event::new("apollo/cw-dex/swap") + .add_attribute("pair_addr", &self.pair_addr) + .add_attribute("ask_asset", format!("{:?}", ask_asset_info)) + .add_attribute("offer_asset", format!("{:?}", offer_asset.info)) + .add_attribute("minimum_out_amount", min_out); + Ok(Response::new().add_message(swap_msg).add_event(event)) + } + + fn get_pool_liquidity(&self, deps: Deps) -> Result { + let resp = self.query_pool_info(&deps.querier)?; + Ok(resp.assets.to_vec().into()) + } + + fn simulate_provide_liquidity( + &self, + deps: Deps, + _env: &Env, + assets: AssetList, + ) -> Result { + let amount: Uint128 = deps.querier.query_wasm_smart( + self.liquidity_manager.to_string(), + &liquidity_manager::QueryMsg::SimulateProvide { + pair_addr: self.pair_addr.to_string(), + pair_msg: astroport::pair::ExecuteMsg::ProvideLiquidity { + assets: assets.into(), + slippage_tolerance: Some(Decimal::from_str(MAX_ALLOWED_SLIPPAGE)?), + auto_stake: Some(false), + receiver: None, + }, + }, + )?; + + let lp_token = Asset { + info: AssetInfo::Cw20(self.lp_token_addr.clone()), + amount, + }; + + Ok(lp_token) + } + + fn simulate_withdraw_liquidity( + &self, + deps: Deps, + lp_token: &Asset, + ) -> Result { + let assets: Vec = deps.querier.query_wasm_smart( + self.liquidity_manager.to_string(), + &liquidity_manager::QueryMsg::SimulateWithdraw { + pair_addr: self.pair_addr.to_string(), + lp_tokens: lp_token.amount, + }, + )?; + + Ok(assets.into()) + } + + fn simulate_swap( + &self, + deps: Deps, + offer_asset: Asset, + ask_asset_info: AssetInfo, + ) -> StdResult { + Ok(deps + .querier + .query::(&QueryRequest::Wasm(WasmQuery::Smart { + contract_addr: self.pair_addr.to_string(), + msg: to_json_binary(&PairQueryMsg::Simulation { + offer_asset: offer_asset.into(), + ask_asset_info: Some(ask_asset_info.into()), + })?, + }))? + .return_amount) + } + + fn lp_token(&self) -> AssetInfo { + AssetInfoBase::Cw20(self.lp_token_addr.clone()) + } + + fn pool_assets(&self, _deps: Deps) -> StdResult> { + Ok(self.pool_assets.clone()) + } +} diff --git a/cw-dex-astroport/src/staking.rs b/cw-dex-astroport/src/staking.rs new file mode 100644 index 0000000..f073938 --- /dev/null +++ b/cw-dex-astroport/src/staking.rs @@ -0,0 +1,147 @@ +//! Staking/rewards traits implementations for Astroport + +use apollo_utils::assets::separate_natives_and_cw20s; +use cosmwasm_schema::cw_serde; +use cosmwasm_std::{ + to_json_binary, Addr, CosmosMsg, Deps, Empty, Env, Event, QuerierWrapper, QueryRequest, + Response, Uint128, WasmMsg, WasmQuery, +}; +use cw20::Cw20ExecuteMsg; + +use apollo_cw_asset::AssetList; +use astroport::asset::Asset as AstroAsset; +use astroport_v3::incentives::{ + Cw20Msg as IncentivesCw20Msg, ExecuteMsg as IncentivesExecuteMsg, + QueryMsg as IncentivesQueryMsg, +}; + +use cw_dex::traits::{Rewards, Stake, Staking, Unstake}; +use cw_dex::CwDexError; + +/// Represents staking of tokens on Astroport +#[cw_serde] +pub struct AstroportStaking { + /// The address of the associated LP token contract + pub lp_token_addr: Addr, + /// The address of the astroport incentives contract + pub incentives: Addr, +} + +impl Staking for AstroportStaking {} + +impl Stake for AstroportStaking { + fn stake(&self, _deps: Deps, _env: &Env, amount: Uint128) -> Result { + let stake_msg = CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: self.lp_token_addr.to_string(), + msg: to_json_binary(&Cw20ExecuteMsg::Send { + contract: self.incentives.to_string(), + amount, + msg: to_json_binary(&IncentivesCw20Msg::Deposit { recipient: None })?, + })?, + funds: vec![], + }); + + let event = Event::new("apollo/cw-dex/stake") + .add_attribute("type", "astroport_staking") + .add_attribute("asset", self.lp_token_addr.to_string()) + .add_attribute("incentives contract address", self.incentives.to_string()); + + Ok(Response::new().add_message(stake_msg).add_event(event)) + } +} + +impl Rewards for AstroportStaking { + fn claim_rewards(&self, deps: Deps, env: &Env) -> Result { + let claimable_rewards: AssetList = + self.query_pending_rewards(&deps.querier, &env.contract.address)?; + + let event = + Event::new("apollo/cw-dex/claim_rewards").add_attribute("type", "astroport_staking"); + + if claimable_rewards.len() == 0 { + return Ok(Response::new().add_event(event)); + } + + let claim_rewards_msg = CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: self.incentives.to_string(), + msg: to_json_binary(&IncentivesExecuteMsg::ClaimRewards { + lp_tokens: vec![self.lp_token_addr.to_string()], + })?, + funds: vec![], + }); + + let mut res = Response::new().add_message(claim_rewards_msg); + + // Astroport generator only supports CW20 tokens as proxy rewards and wraps + // native tokens in their "CW20 wrapper". We need to unwrap them here. + let (_, cw20s) = separate_natives_and_cw20s(&claimable_rewards); + for cw20 in cw20s { + // Query the cw20s creator to get the address of the wrapper contract + let contract_info = deps.querier.query_wasm_contract_info(&cw20.address)?; + let wrapper_contract = deps.api.addr_validate(&contract_info.creator)?; + + // Query the wrapper contract's cw2 info to check if it is a native token + // wrapper, otherwise skip it + let contract_version = cw2::query_contract_info(&deps.querier, &wrapper_contract).ok(); + match contract_version { + Some(contract_version) => { + if &contract_version.contract != "astroport-native-coin-wrapper" { + continue; + } + } + None => continue, + } + + // Unwrap the native token + let unwrap_msg: CosmosMsg = CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: cw20.address.to_string(), + msg: to_json_binary(&cw20::Cw20ExecuteMsg::Send { + contract: wrapper_contract.to_string(), + amount: cw20.amount, + msg: to_json_binary(&astroport::native_coin_wrapper::Cw20HookMsg::Unwrap {})?, + })?, + funds: vec![], + }); + res = res.add_message(unwrap_msg); + } + + Ok(res.add_event(event)) + } + + fn query_pending_rewards( + &self, + querier: &QuerierWrapper, + user: &Addr, + ) -> Result { + let pending_rewards: Vec = querier + .query::>(&QueryRequest::Wasm(WasmQuery::Smart { + contract_addr: self.incentives.to_string(), + msg: to_json_binary(&IncentivesQueryMsg::PendingRewards { + lp_token: self.lp_token_addr.to_string(), + user: user.to_string(), + })?, + }))? + .into_iter() + .filter(|asset| !asset.amount.is_zero()) //TODO: Is this necessary? + .collect(); + + Ok(pending_rewards.into()) + } +} + +impl Unstake for AstroportStaking { + fn unstake(&self, _deps: Deps, _env: &Env, amount: Uint128) -> Result { + let unstake_msg = CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: self.incentives.to_string(), + msg: to_json_binary(&IncentivesExecuteMsg::Withdraw { + lp_token: self.lp_token_addr.to_string(), + amount, + })?, + funds: vec![], + }); + + let event = Event::new("apollo/cw-dex/unstake").add_attribute("type", "astroport_staking"); + + Ok(Response::new().add_message(unstake_msg).add_event(event)) + } +} diff --git a/cw-dex/tests/astroport_tests.rs b/cw-dex-astroport/tests/astroport_tests.rs similarity index 97% rename from cw-dex/tests/astroport_tests.rs rename to cw-dex-astroport/tests/astroport_tests.rs index f14d9a2..f155311 100644 --- a/cw-dex/tests/astroport_tests.rs +++ b/cw-dex-astroport/tests/astroport_tests.rs @@ -1,6 +1,4 @@ -#![cfg(feature = "astroport")] mod tests { - use apollo_cw_asset::{Asset, AssetInfo, AssetInfoBase, AssetList}; use apollo_utils::assets::separate_natives_and_cw20s; use apollo_utils::coins::coin_from_str; @@ -9,7 +7,6 @@ mod tests { use astroport_v3::asset::Asset as AstroportAsset; use cosmwasm_std::{assert_approx_eq, coin, coins, Addr, Coin, SubMsgResponse, Uint128}; - use cw_dex::Pool; use cw_dex_test_contract::msg::{AstroportExecuteMsg, ExecuteMsg, QueryMsg}; use cw_dex_test_helpers::astroport::setup_pool_and_test_contract; use cw_dex_test_helpers::{cw20_balance_query, cw20_transfer, query_asset_balance}; @@ -24,6 +21,8 @@ mod tests { use cw_it::{OwnedTestRunner, TestRunner}; use test_case::test_case; + use cw_dex_astroport::AstroportPool; + #[cfg(feature = "osmosis-test-tube")] use cw_it::osmosis_test_tube::OsmosisTestApp; @@ -643,21 +642,18 @@ mod tests { let query = QueryMsg::GetPoolForLpToken { lp_token: AssetInfo::Cw20(Addr::unchecked(lp_token_addr.clone())), }; - let pool = wasm.query::<_, Pool>(&contract_addr, &query).unwrap(); - - match pool { - Pool::Astroport(pool) => { - assert_eq!(pool.lp_token_addr, Addr::unchecked(lp_token_addr)); - assert_eq!(pool.pair_addr, Addr::unchecked(pair_addr)); - assert_eq!( - pool.pool_assets, - asset_list - .into_iter() - .map(|x| x.info.clone()) - .collect::>() - ); - } - _ => panic!("Wrong pool type"), - } + let pool = wasm + .query::<_, AstroportPool>(&contract_addr, &query) + .unwrap(); + + assert_eq!(pool.lp_token_addr, Addr::unchecked(lp_token_addr)); + assert_eq!(pool.pair_addr, Addr::unchecked(pair_addr)); + assert_eq!( + pool.pool_assets, + asset_list + .into_iter() + .map(|x| x.info.clone()) + .collect::>() + ); } } diff --git a/cw-dex-osmosis/Cargo.toml b/cw-dex-osmosis/Cargo.toml new file mode 100644 index 0000000..6625dec --- /dev/null +++ b/cw-dex-osmosis/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "cw-dex-osmosis" +authors = ["Apollo Devs"] +description = "Implementation of the cw-dex API for the Osmosis AMM" +edition = "2021" +license = "MPL-2.0" +repository = "https://github.com/apollodao/cw-dex" +version = "0.1.0" +readme = "README.md" + +[features] +default = [] +osmosis-test-tube = ["cw-it/osmosis-test-tube", "cw-dex-test-helpers/osmosis-test-tube"] +# backtraces = ["cosmwasm-std/backtraces", "osmosis-std/backtraces"] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[dependencies] +cw-dex = { workspace = true } +cosmwasm-schema = { workspace = true } +cosmwasm-std = { workspace = true } +apollo-cw-asset = { workspace = true } +cw-utils = { workspace = true } +apollo-utils = { workspace = true } +osmosis-std = { workspace = true } + + +[dev-dependencies] +cw-it = { workspace = true } +test-case = { workspace = true } +cw-dex-test-contract = { workspace = true } +cw-dex-test-helpers = { workspace = true, features = ["osmosis"] } +proptest = { workspace = true } +cw20-base = { workspace = true } +cw20 = { workspace = true } diff --git a/cw-dex-osmosis/src/helpers.rs b/cw-dex-osmosis/src/helpers.rs new file mode 100644 index 0000000..b1c031e --- /dev/null +++ b/cw-dex-osmosis/src/helpers.rs @@ -0,0 +1,14 @@ +use std::time::Duration; + +pub(crate) trait ToProtobufDuration { + fn to_protobuf_duration(&self) -> osmosis_std::shim::Duration; +} + +impl ToProtobufDuration for Duration { + fn to_protobuf_duration(&self) -> osmosis_std::shim::Duration { + osmosis_std::shim::Duration { + seconds: self.as_secs() as i64, + nanos: self.subsec_nanos() as i32, + } + } +} diff --git a/cw-dex-osmosis/src/lib.rs b/cw-dex-osmosis/src/lib.rs new file mode 100644 index 0000000..4274ca8 --- /dev/null +++ b/cw-dex-osmosis/src/lib.rs @@ -0,0 +1,8 @@ +//! Contains cw-dex Pool and Staking implementations for Osmosis + +mod helpers; +mod pool; +mod staking; + +pub use pool::*; +pub use staking::*; diff --git a/cw-dex-osmosis/src/pool.rs b/cw-dex-osmosis/src/pool.rs new file mode 100644 index 0000000..5b2c517 --- /dev/null +++ b/cw-dex-osmosis/src/pool.rs @@ -0,0 +1,351 @@ +//! Pool trait implementation for Osmosis + +use std::ops::Deref; +use std::str::FromStr; + +use apollo_utils::assets::{ + assert_native_asset_info, assert_native_coin, assert_only_native_coins, merge_assets, +}; +use apollo_utils::iterators::{IntoElementwise, TryIntoElementwise}; +use osmosis_std::types::osmosis::gamm::v1beta1::{ + GammQuerier, MsgExitPool, MsgJoinPool, MsgJoinSwapExternAmountIn, MsgSwapExactAmountIn, +}; + +use apollo_cw_asset::{Asset, AssetInfo, AssetList}; +use cosmwasm_schema::cw_serde; +use cosmwasm_std::{ + Coin, CosmosMsg, Deps, Env, Event, QuerierWrapper, Response, StdResult, Uint128, +}; +use osmosis_std::types::osmosis::poolmanager::v1beta1::{PoolmanagerQuerier, SwapAmountInRoute}; + +use cw_dex::traits::Pool; +use cw_dex::CwDexError; + +/// Struct for interacting with Osmosis v1beta1 balancer pools. If `pool_id` +/// maps to another type of pool this will fail. +#[cw_serde] +#[derive(Copy)] +pub struct OsmosisPool { + /// The pool id of the pool to interact with + pool_id: u64, +} + +impl OsmosisPool { + /// Creates a new `OsmosisPool` instance with the given `pool_id` and + /// validates that the pool exists. + pub fn new(pool_id: u64, deps: Deps) -> StdResult { + let pool = Self { pool_id }; + // If this query succeeds then the pool exists + pool.get_pool_liquidity(deps)?; + Ok(pool) + } + + /// Creates an unchecked pool for use in testing. + pub fn unchecked(pool_id: u64) -> Self { + Self { pool_id } + } + + /// Returns the matching pool given a LP token. + /// + /// Arguments: + /// - `lp_token`: Said LP token + pub fn get_pool_for_lp_token(deps: Deps, lp_token: &AssetInfo) -> Result { + match lp_token { + AssetInfo::Native(lp_token_denom) => { + if !lp_token_denom.starts_with("gamm/pool/") { + return Err(CwDexError::NotLpToken {}); + } + + let pool_id_str = lp_token_denom + .strip_prefix("gamm/pool/") + .ok_or(CwDexError::NotLpToken {})?; + + let pool_id = u64::from_str(pool_id_str).map_err(|_| CwDexError::NotLpToken {})?; + + Ok(OsmosisPool::new(pool_id, deps)?) + } + _ => Err(CwDexError::NotLpToken {}), + } + } + + /// Returns the pool id of the pool + pub fn pool_id(&self) -> u64 { + self.pool_id + } + + /// Simulates a single sided join and returns `Uint128` amount of LP tokens + /// returned. A single sided join will use all of the provided asset. + pub fn simulate_single_sided_join( + &self, + querier: &QuerierWrapper, + asset: &Asset, + ) -> StdResult { + let querier = GammQuerier::new(querier); + let share_out_amount = Uint128::from_str( + &querier + .calc_join_pool_shares(self.pool_id, vec![assert_native_coin(asset)?.into()])? + .share_out_amount, + )?; + Ok(share_out_amount) + } + + /// Simulates a liquidity provision with all of the assets of the pool. + /// Returns `(Uint128, AssetList)` amount of LP tokens returned and the + /// tokens used to join the pool. + pub fn simulate_noswap_join( + &self, + querier: &QuerierWrapper, + assets: &AssetList, + ) -> StdResult<(Uint128, AssetList)> { + let querier = GammQuerier::new(querier); + let response = &querier.calc_join_pool_no_swap_shares( + self.pool_id, + assert_only_native_coins(assets)?.into_elementwise(), + )?; + let lp_tokens_returned = Uint128::from_str(&response.shares_out)?; + let tokens_used: Vec = response + .tokens_out + .iter() + .map(|x| { + Ok(Coin { + denom: x.denom.clone(), + amount: Uint128::from_str(&x.amount)?, + }) + }) + .collect::>()?; + + Ok((lp_tokens_returned, AssetList::from(tokens_used))) + } +} + +impl Pool for OsmosisPool { + fn provide_liquidity( + &self, + deps: Deps, + env: &Env, + assets: AssetList, + min_out: Uint128, + ) -> Result { + let mut assets = assets; + + // Remove all zero amount Coins, merge duplicates and assert that all assets are + // native. + let mut assets = assert_only_native_coins(&merge_assets(assets.purge().deref())?)?; + + let expected_shares = self + .simulate_provide_liquidity(deps, env, assets.to_owned().into())? + .amount; + + // Assert slippage tolerance + if min_out > expected_shares { + return Err(CwDexError::MinOutNotReceived { + min_out, + received: expected_shares, + }); + } + + // sort assets + assets.sort_by(|a, b| a.denom.to_string().cmp(&b.denom)); + + let join_pool: CosmosMsg = if assets.len() == 1 { + MsgJoinSwapExternAmountIn { + sender: env.contract.address.to_string(), + pool_id: self.pool_id, + share_out_min_amount: expected_shares.to_string(), + token_in: Some(assets[0].clone().into()), + } + .into() + } else { + MsgJoinPool { + sender: env.contract.address.to_string(), + pool_id: self.pool_id, + share_out_amount: expected_shares.to_string(), + token_in_maxs: assets.into_elementwise(), + } + .into() + }; + + let event = Event::new("apollo/cw-dex/provide_liquidity") + .add_attribute("pool_id", self.pool_id.to_string()) + .add_attribute("min_out", min_out) + .add_attribute("expected_shares", expected_shares); + + Ok(Response::new().add_message(join_pool).add_event(event)) + } + + fn withdraw_liquidity( + &self, + _deps: Deps, + env: &Env, + lp_token: Asset, + min_out: AssetList, + ) -> Result { + let min_out_coins = assert_only_native_coins(&min_out)?.try_into_elementwise()?; + + let exit_msg = MsgExitPool { + sender: env.contract.address.to_string(), + pool_id: self.pool_id, + share_in_amount: lp_token.amount.to_string(), + token_out_mins: min_out_coins, + }; + + let mut event = Event::new("apollo/cw-dex/withdraw_liquidity") + .add_attribute("pool_id", self.pool_id.to_string()) + .add_attribute("shares_in", lp_token.to_string()); + + // We're not allowed to add empty values as attributes. + if !min_out.len() == 0 { + event = event.add_attribute("min_out", min_out.to_string()); + } + + Ok(Response::new().add_message(exit_msg).add_event(event)) + } + + fn swap( + &self, + _deps: Deps, + env: &Env, + offer_asset: Asset, + ask_asset_info: AssetInfo, + min_out: Uint128, + ) -> Result { + let offer = assert_native_coin(&offer_asset)?; + let ask_denom = assert_native_asset_info(&ask_asset_info)?; + + // Min out must be greater than 0 for osmosis. + let min_out = if min_out == Uint128::zero() { + Uint128::one() + } else { + min_out + }; + + let swap_msg = MsgSwapExactAmountIn { + sender: env.contract.address.to_string(), + routes: vec![SwapAmountInRoute { + pool_id: self.pool_id, + token_out_denom: ask_denom.clone(), + }], + token_in: Some(offer.clone().into()), + token_out_min_amount: min_out.to_string(), + }; + + let event = Event::new("apollo/cw-dex/swap") + .add_attribute("pool_id", self.pool_id.to_string()) + .add_attribute("offer", offer.to_string()) + .add_attribute("ask", ask_denom) + .add_attribute("token_out_min_amount", min_out); + + Ok(Response::new().add_message(swap_msg).add_event(event)) + } + + /// Allowing deprecated functions here because + /// `osmosis.gamm.v1beta1.Query/TotalPoolLiquidity` has been deprecated, + /// but `osmosis.poolmanager.v1beta1.Query/TotalPoolLiquidity` has not yet + /// been whitelisted in the stargate queries whitelist. + /// See issue: + #[allow(deprecated)] + fn get_pool_liquidity(&self, deps: Deps) -> Result { + let pool_assets = GammQuerier::new(&deps.querier).total_pool_liquidity(self.pool_id)?; + + let asset_list: AssetList = pool_assets + .liquidity + .into_iter() + .map(|coin| { + Ok(Asset { + info: AssetInfo::Native(coin.denom), + amount: Uint128::from_str(&coin.amount)?, + }) + }) + .collect::>>()? + .into(); + + Ok(asset_list) + } + + fn simulate_provide_liquidity( + &self, + deps: Deps, + _env: &Env, + assets: AssetList, + ) -> Result { + let shares_out_amount: Uint128; + if assets.len() == 1 { + shares_out_amount = + self.simulate_single_sided_join(&deps.querier, &assets.to_vec()[0])?; + } else { + (shares_out_amount, _) = self.simulate_noswap_join(&deps.querier, &assets)?; + } + + Ok(Asset::new(self.lp_token(), shares_out_amount)) + } + + fn simulate_withdraw_liquidity( + &self, + deps: Deps, + lp_token: &Asset, + ) -> Result { + let querier = GammQuerier::new(&deps.querier); + let lp_denom = self.lp_token(); + + if lp_denom != lp_token.info { + return Err(CwDexError::InvalidLpToken {}); + } + + let tokens_out: Vec = querier + .calc_exit_pool_coins_from_shares(self.pool_id, lp_token.amount.to_string())? + .tokens_out + .iter() + .map(|c| { + Ok(Coin { + denom: c.denom.clone(), + amount: Uint128::from_str(&c.amount)?, + }) + }) + .collect::>()?; + + Ok(tokens_out.into()) + } + + fn simulate_swap( + &self, + deps: Deps, + offer: Asset, + ask_asset_info: AssetInfo, + ) -> StdResult { + let offer: Coin = offer.try_into()?; + let swap_response = PoolmanagerQuerier::new(&deps.querier).estimate_swap_exact_amount_in( + self.pool_id, + offer.to_string(), + vec![SwapAmountInRoute { + pool_id: self.pool_id, + token_out_denom: assert_native_asset_info(&ask_asset_info)?, + }], + )?; + Uint128::from_str(swap_response.token_out_amount.as_str()) + } + + fn lp_token(&self) -> AssetInfo { + AssetInfo::Native(format!("gamm/pool/{}", self.pool_id)) + } +} + +#[cfg(test)] +mod tests { + use apollo_cw_asset::AssetInfo; + + use cw_dex::traits::Pool; + + use super::OsmosisPool; + + #[test] + fn test_lp_token() { + let pool = OsmosisPool::unchecked(1337u64); + + let lp_token = pool.lp_token(); + + match lp_token { + AssetInfo::Native(denom) => assert_eq!(denom, format!("gamm/pool/{}", 1337u64)), + AssetInfo::Cw20(_) => panic!("Unexpected cw20 token"), + } + } +} diff --git a/cw-dex-osmosis/src/staking.rs b/cw-dex-osmosis/src/staking.rs new file mode 100644 index 0000000..9442a96 --- /dev/null +++ b/cw-dex-osmosis/src/staking.rs @@ -0,0 +1,325 @@ +//! Staking/rewards traits implementations for Osmosis + +use apollo_cw_asset::AssetList; +use cosmwasm_schema::cw_serde; +use cosmwasm_std::{ + Addr, Coin, Deps, Env, Event, QuerierWrapper, ReplyOn, Response, StdError, StdResult, SubMsg, + Uint128, +}; +use cw_utils::Duration as CwDuration; +use osmosis_std::types::osmosis::lockup::{MsgBeginUnlocking, MsgForceUnlock, MsgLockTokens}; +use osmosis_std::types::osmosis::superfluid::{ + MsgLockAndSuperfluidDelegate, MsgSuperfluidUnbondLock, MsgSuperfluidUndelegate, +}; +use std::time::Duration; + +use cw_dex::traits::{ForceUnlock, LockedStaking, Rewards, Stake, Unlock}; +use cw_dex::CwDexError; + +use super::helpers::ToProtobufDuration; + +/// Implementation of locked staking on osmosis. Using the Staking trait. +/// `lockup_duration` is the duration of the lockup period in nano seconds. +#[cw_serde] +pub struct OsmosisStaking { + /// Lockup duration in nano seconds. Allowed values 1 day, 1 week or 2 + /// weeks. + pub lockup_duration: Duration, + /// ID for the lockup record + pub lock_id: Option, + /// Denomination of the associated LP token + pub lp_token_denom: String, +} + +impl OsmosisStaking { + /// Creates a new OsmosisStaking instance with lock up duration set to + /// `lockup_duration`. + /// + /// Arguments: + /// - `lockup_duration` is the duration of the lockup period in seconds. + /// + /// Returns an error if `lockup_duration` is not one of the allowed values, + /// 86400, 604800 or 1209600, representing 1 day, 1 week or 2 weeks + /// respectively. + pub fn new( + lockup_duration: u64, + lock_id: Option, + lp_token_denom: String, + ) -> StdResult { + if !([86400u64, 604800u64, 1209600u64].contains(&lockup_duration)) { + return Err(StdError::generic_err( + "osmosis error: invalid lockup duration", + )); + } + Ok(Self { + lockup_duration: Duration::from_secs(lockup_duration), + lock_id, + lp_token_denom, + }) + } +} + +/// Reply ID for locking tokens +pub const OSMOSIS_LOCK_TOKENS_REPLY_ID: u64 = 123; +/// Reply ID for unlocking tokens +pub const OSMOSIS_UNLOCK_TOKENS_REPLY_ID: u64 = 124; + +impl Rewards for OsmosisStaking { + fn claim_rewards(&self, _deps: Deps, _env: &Env) -> Result { + // Rewards are automatically distributed to stakers every epoch. + let event = + Event::new("apollo/cw-dex/claim_rewards").add_attribute("type", "osmosis_staking"); + Ok(Response::new().add_event(event)) + } + + fn query_pending_rewards( + &self, + _querier: &QuerierWrapper, + _user: &Addr, + ) -> Result { + // Rewards are automatically distributed to stakers every epoch. + // There is no currently no way to query how many have accumulated since + // last epoch. + Ok(AssetList::new()) + } +} + +impl Stake for OsmosisStaking { + fn stake(&self, _deps: Deps, env: &Env, amount: Uint128) -> Result { + let asset = Coin::new(amount.u128(), self.lp_token_denom.clone()); + + let stake_msg = MsgLockTokens { + owner: env.contract.address.to_string(), + duration: Some(self.lockup_duration.to_protobuf_duration()), + coins: vec![asset.clone().into()], + }; + + let event = Event::new("apollo/cw-dex/stake") + .add_attribute("type", "osmosis_staking") + .add_attribute("asset", asset.to_string()) + .add_attribute( + "lockup_duration_secs", + self.lockup_duration.as_secs().to_string(), + ); + + Ok(Response::new() + .add_submessage(SubMsg { + id: OSMOSIS_LOCK_TOKENS_REPLY_ID, + msg: stake_msg.into(), + gas_limit: None, + reply_on: ReplyOn::Success, + }) + .add_event(event)) + } +} + +impl Unlock for OsmosisStaking { + fn unlock(&self, _deps: Deps, env: &Env, amount: Uint128) -> Result { + let asset = Coin::new(amount.u128(), self.lp_token_denom.clone()); + + let id = self + .lock_id + .ok_or_else(|| StdError::generic_err("osmosis error: lock id not set"))?; + + let unstake_msg = MsgBeginUnlocking { + owner: env.contract.address.to_string(), + id, + coins: vec![asset.clone().into()], + }; + + let event = Event::new("apollo/cw-dex/unstake") + .add_attribute("type", "osmosis_staking") + .add_attribute("asset", asset.to_string()) + .add_attribute( + "lockup_duration_secs", + self.lockup_duration.as_secs().to_string(), + ) + .add_attribute("lock_id", id.to_string()); + + Ok(Response::new() + .add_submessage(SubMsg { + id: OSMOSIS_UNLOCK_TOKENS_REPLY_ID, + msg: unstake_msg.into(), + gas_limit: None, + reply_on: ReplyOn::Success, + }) + .add_event(event)) + } + + fn withdraw_unlocked( + &self, + _deps: Deps, + _env: &Env, + _amount: Uint128, + ) -> Result { + // Osmosis automatically sends the unlocked tokens after the lockup duration + let event = + Event::new("apollo/cw-dex/withdraw_unlocked").add_attribute("type", "osmosis_staking"); + Ok(Response::new().add_event(event)) + } +} + +impl LockedStaking for OsmosisStaking { + fn get_lockup_duration(&self, _deps: Deps) -> Result { + Ok(CwDuration::Time(self.lockup_duration.as_secs())) + } +} + +impl ForceUnlock for OsmosisStaking { + fn force_unlock( + &self, + _deps: Deps, + env: &Env, + lockup_id: Option, + amount: Uint128, + ) -> Result { + let lockup_id = match lockup_id { + Some(id) => Ok(id), + None => self + .lock_id + .ok_or_else(|| StdError::generic_err("osmosis error: lock id not set")), + }?; + + let coin_to_unlock = Coin::new(amount.u128(), self.lp_token_denom.clone()); + + let force_unlock_msg = MsgForceUnlock { + owner: env.contract.address.to_string(), + id: lockup_id, + coins: vec![coin_to_unlock.into()], + }; + + let event = Event::new("apollo/cw-dex/force-unlock") + .add_attribute("type", "osmosis_staking") + .add_attribute("amount", amount) + .add_attribute("lockup_id", lockup_id.to_string()); + + Ok(Response::new() + .add_message(force_unlock_msg) + .add_event(event)) + } +} + +/// Implementation of superfluid staking for osmosis. +#[cw_serde] +pub struct OsmosisSuperfluidStaking { + /// Address of the validator to delegate to. + pub validator_address: Addr, + /// ID of the lockup record. + pub lock_id: Option, + /// Denomination of the associated LP token. + pub lp_token_denom: String, +} + +const TWO_WEEKS_IN_SECS: u64 = 14 * 24 * 60 * 60; + +impl OsmosisSuperfluidStaking { + /// Creates a new instance of `OsmosisSuperfluidStaking`. + /// + /// Arguments: + /// - `validator_address`: Address of the associated validator + /// - `lock_id`: ID of the lockup record + /// - `lp_token_denom`: LP token denomination + pub fn new( + validator_address: Addr, + lock_id: Option, + lp_token_denom: String, + ) -> StdResult { + Ok(Self { + validator_address, + lock_id, + lp_token_denom, + }) + } +} + +impl Rewards for OsmosisSuperfluidStaking { + fn claim_rewards(&self, _deps: Deps, _env: &Env) -> Result { + // Rewards are automatically distributed to stakers every epoch. + let event = Event::new("apollo/cw-dex/claim_rewards") + .add_attribute("type", "osmosis_superfluid_staking"); + Ok(Response::new().add_event(event)) + } + + fn query_pending_rewards( + &self, + _querier: &QuerierWrapper, + _user: &Addr, + ) -> Result { + // Rewards are automatically distributed to stakers every epoch. + // There is no currently no way to query how many have accumulated since + // last epoch. + Ok(AssetList::new()) + } +} + +impl Stake for OsmosisSuperfluidStaking { + fn stake(&self, _deps: Deps, env: &Env, amount: Uint128) -> Result { + let asset = Coin::new(amount.u128(), self.lp_token_denom.clone()); + + let stake_msg = MsgLockAndSuperfluidDelegate { + sender: env.contract.address.to_string(), + coins: vec![asset.clone().into()], + val_addr: self.validator_address.to_string(), + }; + + let event = Event::new("apollo/cw-dex/stake") + .add_attribute("type", "osmosis_superfluid_staking") + .add_attribute("asset", asset.to_string()) + .add_attribute("validator_address", self.validator_address.to_string()); + + Ok(Response::new() + .add_submessage(SubMsg { + id: OSMOSIS_LOCK_TOKENS_REPLY_ID, + msg: stake_msg.into(), + gas_limit: None, + reply_on: ReplyOn::Success, + }) + .add_event(event)) + } +} + +impl Unlock for OsmosisSuperfluidStaking { + fn unlock(&self, _deps: Deps, env: &Env, _amount: Uint128) -> Result { + let lock_id = self + .lock_id + .ok_or_else(|| StdError::generic_err("osmosis error: lock id not set"))?; + + let undelegate_msg = MsgSuperfluidUndelegate { + sender: env.contract.address.to_string(), + lock_id, + }; + let unstake_msg = MsgSuperfluidUnbondLock { + sender: env.contract.address.to_string(), + lock_id, + }; + + let event = Event::new("apollo/cw-dex/unstake") + .add_attribute("type", "osmosis_superfluid_staking") + .add_attribute("validator_address", self.validator_address.to_string()) + .add_attribute("lock_id", lock_id.to_string()); + + Ok(Response::new() + .add_message(undelegate_msg) + .add_message(unstake_msg) + .add_event(event)) + } + + fn withdraw_unlocked( + &self, + _deps: Deps, + _env: &Env, + _amount: Uint128, + ) -> Result { + // Osmosis automatically sends the unlocked tokens after the lockup duration + let event = Event::new("apollo/cw-dex/withdraw_unlocked") + .add_attribute("type", "osmosis_superfluid_staking"); + Ok(Response::new().add_event(event)) + } +} + +impl LockedStaking for OsmosisSuperfluidStaking { + fn get_lockup_duration(&self, _deps: Deps) -> Result { + // Lockup time for superfluid staking is always 14 days. + Ok(CwDuration::Time(TWO_WEEKS_IN_SECS)) + } +} diff --git a/cw-dex/tests/osmosis_proptests.proptest-regressions b/cw-dex-osmosis/tests/osmosis_proptests.proptest-regressions similarity index 100% rename from cw-dex/tests/osmosis_proptests.proptest-regressions rename to cw-dex-osmosis/tests/osmosis_proptests.proptest-regressions diff --git a/cw-dex/tests/osmosis_proptests.rs b/cw-dex-osmosis/tests/osmosis_proptests.rs similarity index 100% rename from cw-dex/tests/osmosis_proptests.rs rename to cw-dex-osmosis/tests/osmosis_proptests.rs diff --git a/cw-dex/tests/osmosis_tests.rs b/cw-dex-osmosis/tests/osmosis_tests.rs similarity index 100% rename from cw-dex/tests/osmosis_tests.rs rename to cw-dex-osmosis/tests/osmosis_tests.rs diff --git a/cw-dex/Cargo.toml b/cw-dex/Cargo.toml index b8f6646..9c1a64a 100644 --- a/cw-dex/Cargo.toml +++ b/cw-dex/Cargo.toml @@ -5,11 +5,11 @@ edition = "2021" license = "MPL-2.0" name = "cw-dex" repository = "https://github.com/apollodao/cw-dex" -version = "0.6.0-rc.3" +version = "0.5.2" readme = "README.md" [features] -default = [] +default = ["astroport", "osmosis", "osmosis-test-tube"] osmosis = ["osmosis-std", "osmosis-test-tube", "cw-it/osmosis", "cw-dex-test-helpers/osmosis"] osmosis-test-tube = ["cw-it/osmosis-test-tube", "cw-dex-test-helpers/osmosis-test-tube"] astroport = ["dep:astroport", "dep:astroport_v3", "apollo-cw-asset/astroport", "dep:cw2", "cw-it/astroport", "cw-it/astroport-multi-test"] diff --git a/cw-dex/src/implementations/osmosis/pool.rs b/cw-dex/src/implementations/osmosis/pool.rs index 1a5dc43..621a896 100644 --- a/cw-dex/src/implementations/osmosis/pool.rs +++ b/cw-dex/src/implementations/osmosis/pool.rs @@ -305,24 +305,3 @@ impl Pool for OsmosisPool { AssetInfo::Native(format!("gamm/pool/{}", self.pool_id)) } } - -#[cfg(test)] -mod tests { - use apollo_cw_asset::AssetInfo; - - use crate::traits::Pool; - - use super::OsmosisPool; - - #[test] - fn test_lp_token() { - let pool = OsmosisPool::unchecked(1337u64); - - let lp_token = pool.lp_token(); - - match lp_token { - AssetInfo::Native(denom) => assert_eq!(denom, format!("gamm/pool/{}", 1337u64)), - AssetInfo::Cw20(_) => panic!("Unexpected cw20 token"), - } - } -} diff --git a/cw-dex/src/lib.rs b/cw-dex/src/lib.rs index c085566..863ff5a 100644 --- a/cw-dex/src/lib.rs +++ b/cw-dex/src/lib.rs @@ -10,15 +10,20 @@ //! interact with any of them. //! //! The currently supported decentralized exchanges are: -//! - [Osmosis](crate::implementations::osmosis) -//! - [Astroport](crate::implementations::astroport) +//! - [Osmosis] +//! - Via crate `cw-dex-osmosis` +//! - [Astroport] +//! - Via crate `cw-dex-astroport` pub mod error; -pub mod implementations; pub mod traits; +#[deprecated( + since = "0.5.2", + note = "Please use separate implementation crates such as `cw-dex-astroport`, and `cw-dex-osmosis` instead" +)] +pub mod implementations; + pub use error::*; +#[allow(deprecated)] pub use implementations::*; - -// #[cfg(test)] -// pub mod tests; diff --git a/cw-dex/tests/configs/terra.yaml b/cw-dex/tests/configs/terra.yaml deleted file mode 100644 index 34c33a9..0000000 --- a/cw-dex/tests/configs/terra.yaml +++ /dev/null @@ -1,97 +0,0 @@ -folder: "./tests/configs" -artifacts_folder: "./artifacts" -chain_config: - name: "terra" - chain_id: "localterra" - prefix: "terra" - denom: "uluna" - gas_price: 1000000 - gas_adjustment: 1.2 - # https://github.com/confio/cosmos-hd-key-derivation-spec#the-cosmos-hub-path - derivation_path: "m/44'/330'/0'/0/0" - - # leave this empty if using test_containers - rpc_endpoint: "" - grpc_endpoint: "" -container: - name: "terramoney/localterra-core" - tag: "2.0.1" - entrypoint: "/entrypoint.sh" - volumes: - [ - ["tests/configs/terra/config", "/root/.terra/config"], - ["tests/configs/terra/entrypoint.sh", "/entrypoint.sh"], - ] - ports: [26657, 1317, 9090, 9091] - -# Chain to download contracts from -contract_chain_download_rpc: "https://terra-rpc.polkachu.com" - -# contracts list to download -# Do not repeat names -contracts: - astroport_liquidity_helper: - url: "https://github.com/apollodao/astroport-liquidity-helper.git" - branch: "master" - artifact: astroport_liquidity_helper.wasm - preferred_source: "url" - - astro_token: - url: "https://github.com/astroport-fi/astroport-core.git" - branch: "c216ecd4f350113316be44d06a95569f451ac681" # TODO: Allow commit instead of branch - artifact: "astro_token.wasm" - preferred_source: "chain" # Where to prefer getting contract, can be either "chain" or "url". - chain_address: "terra1nsuqsk6kh58ulczatwev87ttq2z6r3pusulg9r24mfj2fvtzd4uq3exn26" - - astroport_factory: - artifact: "astroport_factory.wasm" - preferred_source: "chain" - chain_address: "terra14x9fr055x5hvr48hzy2t4q7kvjvfttsvxusa4xsdcy702mnzsvuqprer8r" - - astroport_maker: - artifact: "astroport_maker.wasm" - preferred_source: "chain" - chain_address: "terra1ygcvxp9s054q8u2q4hvl52ke393zvgj0sllahlycm4mj8dm96zjsa45rzk" - - astroport_router: - artifact: "astroport_router.wasm" - preferred_source: "chain" - chain_address: "terra1j8hayvehh3yy02c2vtw5fdhz9f4drhtee8p5n5rguvg3nyd6m83qd2y90a" - - astroport_generator: - artifact: "astroport_generator.wasm" - preferred_source: "chain" - chain_address: "terra1ksvlfex49desf4c452j6dewdjs6c48nafemetuwjyj6yexd7x3wqvwa7j9" - - astroport_pair_stable: - artifact: "astroport_pair_stable.wasm" - preferred_source: "chain" - chain_code_id: 428 - - astroport_pair_xyk: - artifact: "astroport_pair_xyk.wasm" - preferred_source: "chain" - chain_code_id: 392 - - astroport_whitelist: - artifact: "astroport_whitelist.wasm" - preferred_source: "chain" - chain_code_id: 70 - - astroport_staking: - artifact: "astroport_staking.wasm" - preferred_source: "chain" - chain_address: "terra1nyu6sk9rvtvsltm7tjjrp6rlavnm3e4sq03kltde6kesam260f8szar8ze" - - astroport_vesting: - artifact: "astroport_vesting.wasm" - preferred_source: "chain" - chain_address: "terra1qyuarnzcc6uuft9n9mltraprreke4v8gvxd8u3nslngxhflhru9qw34nc3" - - cw_dex_router: - artifact: "cw_dex_router.wasm" - preferred_source: "chain" - - astroport_vault: - artifact: "astroport_vault.wasm" - preferred_source: "chain" diff --git a/test-contracts/astroport-test-contract/Cargo.toml b/test-contracts/astroport-test-contract/Cargo.toml index 0a4028c..027a0ce 100644 --- a/test-contracts/astroport-test-contract/Cargo.toml +++ b/test-contracts/astroport-test-contract/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "astroport-test-contract" description = "Contract to test the cw-dex library" -version = "0.1.0" +version = "0.2.0" authors = ["Pacman "] edition = "2021" license = { workspace = true } @@ -36,5 +36,6 @@ cosmwasm-std = { workspace = true } cw-storage-plus = { workspace = true } thiserror = { workspace = true } apollo-cw-asset = { workspace = true } -cw-dex = { workspace = true, features = ["astroport"] } +cw-dex = { workspace = true } +cw-dex-astroport = { workspace = true } cw-dex-test-contract = { workspace = true } diff --git a/test-contracts/astroport-test-contract/src/contract.rs b/test-contracts/astroport-test-contract/src/contract.rs index 2c8d19d..b2c2a86 100644 --- a/test-contracts/astroport-test-contract/src/contract.rs +++ b/test-contracts/astroport-test-contract/src/contract.rs @@ -7,8 +7,8 @@ use cosmwasm_std::{ to_json_binary, Addr, Binary, Deps, DepsMut, Env, MessageInfo, Reply, Response, StdResult, Uint128, }; -use cw_dex::astroport::{AstroportPool, AstroportStaking}; use cw_dex::traits::{Pool, Rewards, Stake, Unstake}; +use cw_dex_astroport::{AstroportPool, AstroportStaking}; use cw_dex_test_contract::msg::{ AstroportContractInstantiateMsg as InstantiateMsg, AstroportExecuteMsg as ExecuteMsg, QueryMsg, }; @@ -145,7 +145,7 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { ), QueryMsg::SimulateSwap { offer, ask } => query_simulate_swap(deps, offer, ask), QueryMsg::GetPoolForLpToken { lp_token } => to_json_binary( - &cw_dex::Pool::get_pool_for_lp_token(deps, &lp_token, Some(pool.liquidity_manager))?, + &AstroportPool::get_pool_for_lp_token(deps, &lp_token, pool.liquidity_manager)?, ), QueryMsg::PendingRewards {} => { let staking = STAKING.load(deps.storage)?; diff --git a/test-contracts/astroport-test-contract/src/state.rs b/test-contracts/astroport-test-contract/src/state.rs index 7a4ff83..49a2d85 100644 --- a/test-contracts/astroport-test-contract/src/state.rs +++ b/test-contracts/astroport-test-contract/src/state.rs @@ -1,4 +1,4 @@ -use cw_dex::astroport::{AstroportPool, AstroportStaking}; +use cw_dex_astroport::{AstroportPool, AstroportStaking}; use cw_storage_plus::Item; pub const POOL: Item = Item::new("pool"); diff --git a/test-contracts/osmosis-test-contract/Cargo.toml b/test-contracts/osmosis-test-contract/Cargo.toml index 95a9ddb..f078b64 100644 --- a/test-contracts/osmosis-test-contract/Cargo.toml +++ b/test-contracts/osmosis-test-contract/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "osmosis-test-contract" description = "Contract to test the cw-dex library" -version = "0.1.0" +version = "0.2.0" authors = ["Pacman "] edition = "2021" license = { workspace = true } @@ -36,5 +36,6 @@ cosmwasm-std = { workspace = true } cw-storage-plus = { workspace = true } thiserror = { workspace = true } apollo-cw-asset = { workspace = true } -cw-dex = { workspace = true, features = ["osmosis"] } +cw-dex = { workspace = true } +cw-dex-osmosis = { workspace = true } cw-dex-test-contract = { workspace = true } diff --git a/test-contracts/osmosis-test-contract/src/contract.rs b/test-contracts/osmosis-test-contract/src/contract.rs index 77358e7..4fa83aa 100644 --- a/test-contracts/osmosis-test-contract/src/contract.rs +++ b/test-contracts/osmosis-test-contract/src/contract.rs @@ -5,8 +5,8 @@ use cosmwasm_std::{ to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, Reply, Response, StdError, StdResult, Uint128, }; -use cw_dex::osmosis::{OsmosisPool, OsmosisStaking, OsmosisSuperfluidStaking}; use cw_dex::traits::{ForceUnlock, Pool, Stake, Unlock}; +use cw_dex_osmosis::{OsmosisPool, OsmosisStaking, OsmosisSuperfluidStaking}; // use cw2::set_contract_version; use crate::error::ContractError; @@ -213,7 +213,7 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { ), QueryMsg::SimulateSwap { offer, ask } => query_simulate_swap(deps, offer, ask), QueryMsg::GetPoolForLpToken { lp_token } => { - to_json_binary(&cw_dex::Pool::get_pool_for_lp_token(deps, &lp_token, None)?) + to_json_binary(&OsmosisPool::get_pool_for_lp_token(deps, &lp_token)?) } QueryMsg::PendingRewards {} => unimplemented!(), } diff --git a/test-contracts/osmosis-test-contract/src/state.rs b/test-contracts/osmosis-test-contract/src/state.rs index fbbbff1..66c16f9 100644 --- a/test-contracts/osmosis-test-contract/src/state.rs +++ b/test-contracts/osmosis-test-contract/src/state.rs @@ -1,4 +1,4 @@ -use cw_dex::osmosis::{OsmosisPool, OsmosisStaking, OsmosisSuperfluidStaking}; +use cw_dex_osmosis::{OsmosisPool, OsmosisStaking, OsmosisSuperfluidStaking}; use cw_storage_plus::Item; pub const POOL: Item = Item::new("pool"); diff --git a/test-contracts/package/Cargo.toml b/test-contracts/package/Cargo.toml index fc9cc0f..c944f29 100644 --- a/test-contracts/package/Cargo.toml +++ b/test-contracts/package/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cw-dex-test-contract" description = "Contract to test the cw-dex library" -version = "0.1.0" +version = "0.2.0" authors = ["Pacman "] edition = "2021" license = { workspace = true } @@ -21,4 +21,3 @@ crate-type = ["cdylib", "rlib"] cosmwasm-schema = { workspace = true } cosmwasm-std = { workspace = true } apollo-cw-asset = { workspace = true } -cw-dex = { workspace = true } diff --git a/test-contracts/package/src/msg.rs b/test-contracts/package/src/msg.rs index fb76719..dffec8d 100644 --- a/test-contracts/package/src/msg.rs +++ b/test-contracts/package/src/msg.rs @@ -65,6 +65,12 @@ impl ExecuteMsg { } } +#[cw_serde] +/// Represents an unknown type as the response of a query. +/// This is due to the API being used by different contracts which will return +/// different types. +pub struct Unknown {} + #[cw_serde] #[derive(QueryResponses)] pub enum QueryMsg { @@ -76,7 +82,7 @@ pub enum QueryMsg { SimulateWithdrawLiquidty { amount: Uint128 }, #[returns(Uint128)] SimulateSwap { offer: Asset, ask: AssetInfo }, - #[returns(cw_dex::Pool)] + #[returns(Unknown)] GetPoolForLpToken { lp_token: AssetInfo }, #[returns(AssetList)] PendingRewards {}, diff --git a/test-helpers/Cargo.toml b/test-helpers/Cargo.toml index 163535b..e6de23e 100644 --- a/test-helpers/Cargo.toml +++ b/test-helpers/Cargo.toml @@ -16,7 +16,7 @@ exclude = [ [features] default = [] osmosis = ["cw-it/osmosis"] -astroport = ["cw-it/astroport", "cw-it/astroport-multi-test", "astroport-test-contract"] +astroport = ["cw-it/astroport", "cw-it/astroport-multi-test", "astroport-test-contract", "apollo-cw-asset/astroport"] osmosis-test-tube = ["cw-it/osmosis-test-tube"] [lib] @@ -31,7 +31,7 @@ optimize = """docker run --rm -v "$(pwd)":/code \ [dependencies] cosmwasm-std = { workspace = true } -apollo-cw-asset = { workspace = true, features = ["astroport"] } +apollo-cw-asset = { workspace = true } apollo-utils = { workspace = true } cw-dex-test-contract = { workspace = true } astroport-test-contract = { workspace = true, optional = true } From c681444f7c186a4675d1e1aa8e15e551d950b5a5 Mon Sep 17 00:00:00 2001 From: Sturdy <91910406+apollo-sturdy@users.noreply.github.com> Date: Tue, 13 Feb 2024 14:26:43 +0100 Subject: [PATCH 21/22] fix: review comments --- Cargo.lock | 2 +- Cargo.toml | 6 +++--- cw-dex-astroport/src/lib.rs | 2 +- cw-dex-astroport/src/pool.rs | 2 -- cw-dex-osmosis/src/lib.rs | 1 + cw-dex-osmosis/src/pool.rs | 15 +++++++-------- cw-dex/Cargo.toml | 14 +++++++------- .../osmosis-test-contract/src/contract.rs | 7 ------- 8 files changed, 20 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4e0d104..d22ffaa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -945,7 +945,7 @@ dependencies = [ "cw-utils 1.0.2", "cw20 1.1.2", "cw20-base 1.1.1", - "osmosis-std 0.19.2", + "osmosis-std 0.22.0", "proptest", "test-case", ] diff --git a/Cargo.toml b/Cargo.toml index cf0de53..ab15557 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,11 +25,11 @@ schemars = "0.8.10" serde = { version = "1.0.145", default-features = false, features = ["derive"] } thiserror = { version = "1.0.31" } apollo-cw-asset = "0.1.1" -osmosis-std = "0.19.2" +osmosis-std = "0.22.0" cw-it = "0.3.0-rc.4" apollo-utils = "0.1.0" -astroport = "=2.9.0" -astroport_v3 = { package = "astroport", version = "=3.11.1" } +astroport = "2.9.0" +astroport_v3 = { package = "astroport", version = "3.11.1" } test-case = "3.0.0" proptest = "1.0.0" diff --git a/cw-dex-astroport/src/lib.rs b/cw-dex-astroport/src/lib.rs index b48062f..66173e1 100644 --- a/cw-dex-astroport/src/lib.rs +++ b/cw-dex-astroport/src/lib.rs @@ -6,4 +6,4 @@ mod staking; pub use pool::AstroportPool; pub use staking::AstroportStaking; -pub use astroport; +pub use {astroport, astroport_v3}; diff --git a/cw-dex-astroport/src/pool.rs b/cw-dex-astroport/src/pool.rs index de74780..84d255f 100644 --- a/cw-dex-astroport/src/pool.rs +++ b/cw-dex-astroport/src/pool.rs @@ -74,8 +74,6 @@ impl AstroportPool { /// - `lp_token`: Said LP token /// - `astroport_liquidity_manager`: The Astroport liquidity manager /// address. - #[allow(unused_variables)] - #[allow(unreachable_patterns)] pub fn get_pool_for_lp_token( deps: Deps, lp_token: &AssetInfo, diff --git a/cw-dex-osmosis/src/lib.rs b/cw-dex-osmosis/src/lib.rs index 4274ca8..2013d31 100644 --- a/cw-dex-osmosis/src/lib.rs +++ b/cw-dex-osmosis/src/lib.rs @@ -4,5 +4,6 @@ mod helpers; mod pool; mod staking; +pub use osmosis_std; pub use pool::*; pub use staking::*; diff --git a/cw-dex-osmosis/src/pool.rs b/cw-dex-osmosis/src/pool.rs index 5b2c517..e481917 100644 --- a/cw-dex-osmosis/src/pool.rs +++ b/cw-dex-osmosis/src/pool.rs @@ -16,7 +16,9 @@ use cosmwasm_schema::cw_serde; use cosmwasm_std::{ Coin, CosmosMsg, Deps, Env, Event, QuerierWrapper, Response, StdResult, Uint128, }; -use osmosis_std::types::osmosis::poolmanager::v1beta1::{PoolmanagerQuerier, SwapAmountInRoute}; +use osmosis_std::types::osmosis::poolmanager::v1beta1::{ + PoolmanagerQuerier, SwapAmountInRoute, TotalPoolLiquidityRequest, +}; use cw_dex::traits::Pool; use cw_dex::CwDexError; @@ -238,14 +240,11 @@ impl Pool for OsmosisPool { Ok(Response::new().add_message(swap_msg).add_event(event)) } - /// Allowing deprecated functions here because - /// `osmosis.gamm.v1beta1.Query/TotalPoolLiquidity` has been deprecated, - /// but `osmosis.poolmanager.v1beta1.Query/TotalPoolLiquidity` has not yet - /// been whitelisted in the stargate queries whitelist. - /// See issue: - #[allow(deprecated)] fn get_pool_liquidity(&self, deps: Deps) -> Result { - let pool_assets = GammQuerier::new(&deps.querier).total_pool_liquidity(self.pool_id)?; + let pool_assets = TotalPoolLiquidityRequest { + pool_id: self.pool_id, + } + .query(&deps.querier)?; let asset_list: AssetList = pool_assets .liquidity diff --git a/cw-dex/Cargo.toml b/cw-dex/Cargo.toml index 9c1a64a..a445c18 100644 --- a/cw-dex/Cargo.toml +++ b/cw-dex/Cargo.toml @@ -9,10 +9,10 @@ version = "0.5.2" readme = "README.md" [features] -default = ["astroport", "osmosis", "osmosis-test-tube"] +default = [] osmosis = ["osmosis-std", "osmosis-test-tube", "cw-it/osmosis", "cw-dex-test-helpers/osmosis"] osmosis-test-tube = ["cw-it/osmosis-test-tube", "cw-dex-test-helpers/osmosis-test-tube"] -astroport = ["dep:astroport", "dep:astroport_v3", "apollo-cw-asset/astroport", "dep:cw2", "cw-it/astroport", "cw-it/astroport-multi-test"] +astroport = ["dep:astroport", "dep:astroport_v3", "apollo-cw-asset/astroport", "dep:cw2", "cw-it/astroport", "cw-it/astroport-multi-test", "cw-dex-test-helpers/astroport"] # backtraces = ["cosmwasm-std/backtraces", "osmosis-std/backtraces"] [package.metadata.docs.rs] @@ -29,7 +29,7 @@ cw20 = { workspace = true } apollo-utils = { workspace = true } # Osmosis -osmosis-std = { workspace = true, optional = true } +osmosis-std = { version = "0.19.2", optional = true } # Astroport astroport = { workspace = true, optional = true } @@ -37,10 +37,10 @@ astroport_v3 = { workspace = true, optional = true } cw2 = { workspace = true, optional = true } [dev-dependencies] -cw-it = { workspace = true, features = ["astroport", "multi-test", "astroport-multi-test"] } -test-case = "3.0.0" +cw-it = { workspace = true, features = ["multi-test"] } +test-case = { workspace = true } cw-dex-test-contract = { workspace = true } -cw-dex-test-helpers = { workspace = true, features = ["astroport"] } -proptest = "1.0.0" +cw-dex-test-helpers = { workspace = true } +proptest = { workspace = true } cw20-base = { workspace = true } cw20 = { workspace = true } diff --git a/test-contracts/osmosis-test-contract/src/contract.rs b/test-contracts/osmosis-test-contract/src/contract.rs index 4fa83aa..f04594f 100644 --- a/test-contracts/osmosis-test-contract/src/contract.rs +++ b/test-contracts/osmosis-test-contract/src/contract.rs @@ -7,18 +7,11 @@ use cosmwasm_std::{ }; use cw_dex::traits::{ForceUnlock, Pool, Stake, Unlock}; use cw_dex_osmosis::{OsmosisPool, OsmosisStaking, OsmosisSuperfluidStaking}; -// use cw2::set_contract_version; use crate::error::ContractError; use crate::state::{POOL, STAKING, SUPERFLUID}; use cw_dex_test_contract::msg::{ExecuteMsg, OsmosisTestContractInstantiateMsg, QueryMsg}; -/* -// version info for migration info -const CONTRACT_NAME: &str = "crates.io:cw-dex-test-contract"; -const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); -*/ - #[cfg_attr(not(feature = "library"), entry_point)] pub fn instantiate( deps: DepsMut, From 23dc0df93ea7bdbaae6ab81b3b828fc6eb5993eb Mon Sep 17 00:00:00 2001 From: Sturdy <91910406+apollo-sturdy@users.noreply.github.com> Date: Tue, 13 Feb 2024 14:39:41 +0100 Subject: [PATCH 22/22] chore: update changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b383845..9ab5a7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +# [0.5.2] - 2024-02-13 + +### Changed + +- Deprecated `implemenations` module in favor of new crates `cw-dex-astroport` and `cw-dex-osmosis`. + - This is to avoid breaking changes in `cw-dex` when one of the implementations change. + # [0.5.1] - 2024-02-06 ### Changed