diff --git a/.github/workflows/lint-format.yml b/.github/workflows/lint-format.yml index 882c6aad..7e338af6 100644 --- a/.github/workflows/lint-format.yml +++ b/.github/workflows/lint-format.yml @@ -25,6 +25,9 @@ jobs: - name: Install nightly toolchain run: cargo make install-nightly + - name: Install stable toolchain + run: cargo make install-stable + - name: Run cargo clippy run: cargo make clippy-check diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ddf68c3f..426b57c4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,11 +15,6 @@ 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/CHANGELOG.md b/CHANGELOG.md index 124363e7..49ff5a35 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.6.0] - 2024-08-28 + +### Changed + +- Removed `implementations` module in favor of new crates `cw-dex-astroport` and `cw-dex-osmosis`. +- Added two variants to `CwDexError` that are needed in `cw-dex-astroport`. + # [0.5.3] - 2024-02-13 ### Changed diff --git a/Cargo.lock b/Cargo.lock index 91cfe2e2..42addf4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,9 +39,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "apollo-cw-asset" @@ -49,7 +49,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "423502406a307052f6877030f48b5fb4e9fb338fc5e7c8ca1064210def52876b" dependencies = [ - "astroport 2.9.0", + "astroport 2.9.5", "cosmwasm-std", "cw-storage-plus 1.2.0", "cw20 1.1.2", @@ -59,9 +59,9 @@ dependencies = [ [[package]] name = "apollo-cw-multi-test" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79f4204575175473a9b7fff8083596d09e6edb07469d2a4176846b353b2d1ef" +checksum = "c4d9d50055381538d90ed418227d5cf4906db896f5db26fd0a77e45aaa3f7fc7" dependencies = [ "anyhow", "cosmwasm-std", @@ -75,6 +75,7 @@ dependencies = [ "regex", "schemars", "serde", + "sha2 0.10.8", "thiserror", ] @@ -93,9 +94,9 @@ dependencies = [ [[package]] name = "astro-satellite-package" -version = "0.1.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cf737cf762c341a9575ee8fc6da47cc0c4ec11725c9fd0fc5fbb2c31ce0d61a" +checksum = "893363819104a2a4685d99f19e35e5d81102fb782e622619ac643e54ff65d638" dependencies = [ "astroport-governance", "cosmwasm-schema", @@ -104,9 +105,9 @@ dependencies = [ [[package]] name = "astroport" -version = "2.9.0" +version = "2.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b863a982595743e181f89540d7aaeda35c60b6b5cac9c36c9be30cf11a5ece" +checksum = "d102b618016b3c1f1ebb5750617a73dbd294a3c941e54b12deabc931d771bc6e" dependencies = [ "cosmwasm-schema", "cosmwasm-std", @@ -123,7 +124,7 @@ version = "3.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c001a7f97db88ffe6fc6cca97bbdbfe926e55599184921ff7e72cd47559440de" dependencies = [ - "astroport-circular-buffer", + "astroport-circular-buffer 0.1.0", "cosmwasm-schema", "cosmwasm-std", "cw-asset", @@ -135,6 +136,42 @@ dependencies = [ "uint", ] +[[package]] +name = "astroport" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5ec8dd4298b362361b0e118107a060e5e58501a68273b3257059c96b723b57c" +dependencies = [ + "astroport-circular-buffer 0.2.0", + "cosmwasm-schema", + "cosmwasm-std", + "cw-asset", + "cw-storage-plus 1.2.0", + "cw-utils 1.0.3", + "cw20 1.1.2", + "itertools 0.12.1", + "uint", +] + +[[package]] +name = "astroport" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b3b225e86694e2fd1adbf230581bce1690a871585aec9edd64b022a313a8493" +dependencies = [ + "astroport-circular-buffer 0.2.0", + "cosmos-sdk-proto 0.19.0", + "cosmwasm-schema", + "cosmwasm-std", + "cw-asset", + "cw-storage-plus 1.2.0", + "cw-utils 1.0.3", + "cw20 1.1.2", + "itertools 0.12.1", + "prost 0.11.9", + "uint", +] + [[package]] name = "astroport-circular-buffer" version = "0.1.0" @@ -148,36 +185,30 @@ dependencies = [ ] [[package]] -name = "astroport-factory" -version = "1.5.1" +name = "astroport-circular-buffer" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ecf768e2d3153bebfbe0c502ffa4199a52598e9b6e89fca54339615b2de77eb" +checksum = "31c7369d3c4126804f861620db2221c15b5fa7b7718f12180e265b087c933fb6" dependencies = [ - "astroport 2.9.0", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", - "cw2 0.15.1", - "itertools 0.10.5", - "protobuf", "thiserror", ] [[package]] -name = "astroport-generator" -version = "2.3.0" +name = "astroport-factory" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6144780ac014665b07616de0cfb35ca6a9411ed821e20c21e02f4f428c8ed51f" +checksum = "68abcc896255acba2f4aa39f239a1e8361a6035d7bc712442da122dc31f6f959" dependencies = [ - "astroport 2.9.0", - "astroport-governance", + "astroport 5.3.0", "cosmwasm-schema", "cosmwasm-std", - "cw-storage-plus 0.15.1", - "cw1-whitelist", - "cw2 0.15.1", - "cw20 0.15.1", - "protobuf", + "cw-storage-plus 1.2.0", + "cw-utils 1.0.3", + "cw2 1.1.2", + "itertools 0.12.1", "thiserror", ] @@ -187,7 +218,7 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72806ace350e81c4e1cab7e275ef91f05bad830275d697d67ad1bd4acc6f016d" dependencies = [ - "astroport 2.9.0", + "astroport 2.9.5", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", @@ -196,31 +227,31 @@ dependencies = [ [[package]] name = "astroport-incentives" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba05c27479d2885ba313086aa0b7d09284f1393f1ebb6d385f96d93b3c6fb72a" +checksum = "0faeda17ac97ec8bc9d20cde1df9e036bfc723e3287f749ee9267fde5701f648" dependencies = [ - "astroport 3.11.1", + "astroport 4.0.3", "cosmwasm-schema", "cosmwasm-std", - "cw-storage-plus 0.15.1", + "cw-storage-plus 1.2.0", "cw-utils 1.0.3", "cw2 1.1.2", "cw20 1.1.2", - "itertools 0.11.0", + "itertools 0.12.1", "thiserror", ] [[package]] name = "astroport-liquidity-manager" -version = "1.0.3-astroport-v2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae4bf7689e7c37cfecc200aab3401c1ff6a507cccc9fb1baadfa71a73addaa2f" +checksum = "add163cbe65b61f57c427c57bbfaef5a0848ac5dd822835c94b76587584c36ca" dependencies = [ - "astroport 2.9.0", + "astroport 3.11.1", "astroport-factory", - "astroport-pair", - "astroport-pair-stable", + "astroport-pair 1.5.1", + "astroport-pair-stable 3.4.0", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 1.2.0", @@ -231,17 +262,17 @@ dependencies = [ [[package]] name = "astroport-maker" -version = "1.3.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92403e5d00e3c77d13d9616661ea9d9308d493fff6bec5e6e5e7bd7b7e0ff6af" +checksum = "38fac94577669cb3cb5ce961bb942ea22f0901fded50dcbfdefd5b765edef081" dependencies = [ "astro-satellite-package", - "astroport 2.9.0", + "astroport 4.0.3", "cosmwasm-schema", "cosmwasm-std", - "cw-storage-plus 0.15.1", - "cw2 0.15.1", - "cw20 0.15.1", + "cw-storage-plus 1.2.0", + "cw2 1.1.2", + "cw20 1.1.2", "thiserror", ] @@ -251,7 +282,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.5", "cosmwasm-schema", "cosmwasm-std", "cosmwasm-storage", @@ -262,46 +293,67 @@ dependencies = [ [[package]] name = "astroport-pair" -version = "1.3.2" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e760b91eaf269bb2843b75b34eb73d474374bd2ebefbbe3cdb0a58d69959573b" +checksum = "4336db82506bc3aaf52e194711ed0785896ad92825eb18d870d535023e33b666" dependencies = [ - "astroport 2.9.0", + "astroport 3.11.1", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", + "cw-utils 1.0.3", "cw2 0.15.1", "cw20 0.15.1", "integer-sqrt", - "protobuf", + "protobuf 2.28.0", + "thiserror", +] + +[[package]] +name = "astroport-pair" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a5e6cd4508d45d89f9f44b607eb482aa614fa54274c46746d6f251bf10b27ae" +dependencies = [ + "astroport 5.3.0", + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus 1.2.0", + "cw-utils 1.0.3", + "cw2 1.1.2", + "cw20 1.1.2", + "integer-sqrt", "thiserror", ] [[package]] name = "astroport-pair-concentrated" -version = "1.2.7" +version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04a90ce51403c81af3acf8e7028bb0eb095fce802365453b7e4a13bc0eb0d6d7" +checksum = "a85a79c523843d180a7ca3c1607c12f9d6146ab332fc7209dee3907c191ebb04" dependencies = [ - "astroport 2.9.0", + "astroport 5.3.0", + "astroport-circular-buffer 0.2.0", "astroport-factory", + "astroport-pcl-common", "cosmwasm-schema", "cosmwasm-std", - "cw-storage-plus 0.15.1", - "cw-utils 0.15.1", - "cw2 0.15.1", - "cw20 0.15.1", - "itertools 0.10.5", + "cw-storage-plus 1.2.0", + "cw-utils 1.0.3", + "cw2 1.1.2", + "cw20 1.1.2", + "itertools 0.12.1", "thiserror", ] [[package]] name = "astroport-pair-stable" -version = "2.1.3" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d052966163fc2dd3eb46ae3c948ee7032a28726e046bc44431f9b488cb1dba90" +checksum = "45c0557efba343a120a68209770e4ee4caa28f74283828eb01089d4080bd4384" dependencies = [ - "astroport 2.9.0", + "astroport 3.11.1", + "astroport-circular-buffer 0.1.0", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", @@ -312,13 +364,47 @@ dependencies = [ "thiserror", ] +[[package]] +name = "astroport-pair-stable" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3386d5771faedd33fc7741cb0a7082cbdc0416d42f1bd051d4f1a0b987248e3c" +dependencies = [ + "astroport 5.3.0", + "astroport-circular-buffer 0.2.0", + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus 1.2.0", + "cw-utils 1.0.3", + "cw2 1.1.2", + "cw20 1.1.2", + "itertools 0.12.1", + "thiserror", +] + +[[package]] +name = "astroport-pcl-common" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a810d9ff3459d62a6288314c01201b4270e96fa518bfa36ef759a4c76b87334f" +dependencies = [ + "astroport 5.3.0", + "astroport-factory", + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus 1.2.0", + "cw20 1.1.2", + "itertools 0.12.1", + "thiserror", +] + [[package]] name = "astroport-router" -version = "1.1.1" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e3bbb33c00370bd194cf3a166f1e3f4029a2add2bea01a5eb61e886aefbc85b" +checksum = "c2aa8511eeb2fde51a070ccc7a93259e88c0d88c4380930dd307e89f09d84fda" dependencies = [ - "astroport 2.9.0", + "astroport 3.11.1", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", @@ -330,17 +416,16 @@ dependencies = [ [[package]] name = "astroport-staking" -version = "1.1.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67adbc4240794e886ca1edbc7d46bc8a54c7aca7217d73ddcfbc90e1dbb030e7" +checksum = "315e43350f20d04f8d65bbb4d29ae423eea2fb12e292f0185b983a210d1c6d1a" dependencies = [ - "astroport 2.9.0", - "cosmwasm-schema", + "astroport 4.0.3", "cosmwasm-std", - "cw-storage-plus 0.15.1", - "cw2 0.15.1", - "cw20 0.15.1", - "protobuf", + "cw-storage-plus 1.2.0", + "cw-utils 1.0.3", + "cw2 1.1.2", + "osmosis-std 0.21.0", "thiserror", ] @@ -364,7 +449,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.5", "cosmwasm-schema", "cosmwasm-std", "cw2 0.15.1", @@ -375,31 +460,31 @@ dependencies = [ [[package]] name = "astroport-vesting" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dffce7cf86bf4d4f177ef941145352499e802abc4b898032af7808d16cca6371" +checksum = "871f8f0f390245642ccc1ec10c7f79b440979187a98aa8b0246269d6a4e0172c" dependencies = [ - "astroport 2.9.0", + "astroport 4.0.3", "cosmwasm-schema", "cosmwasm-std", - "cw-storage-plus 0.15.1", - "cw-utils 0.15.1", - "cw2 0.15.1", - "cw20 0.15.1", + "cw-storage-plus 1.2.0", + "cw-utils 1.0.3", + "cw2 1.1.2", + "cw20 1.1.2", "thiserror", ] [[package]] name = "astroport-whitelist" -version = "1.0.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44156757bfab3d4bd208d9b86b890d1478f45d07c8f8d3d1c3e3da91081cb54d" +checksum = "ecc56be98fb0fad68549e2af01b03322476b5b163f2ebbb579d19a96eec73e6f" dependencies = [ - "astroport 2.9.0", "cosmwasm-schema", "cosmwasm-std", "cw1-whitelist", - "cw2 0.15.1", + "cw2 1.1.2", + "neutron-sdk", "thiserror", ] @@ -447,12 +532,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "base64" version = "0.21.7" @@ -471,6 +550,12 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" +[[package]] +name = "bech32" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" + [[package]] name = "bindgen" version = "0.69.4" @@ -536,6 +621,9 @@ name = "bitflags" version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +dependencies = [ + "serde", +] [[package]] name = "block-buffer" @@ -637,11 +725,12 @@ dependencies = [ [[package]] name = "config" -version = "0.13.4" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23738e11972c7643e4ec947840fc463b6a571afcd3e735bdfce7d03c7a784aca" +checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be" dependencies = [ "async-trait", + "convert_case", "json5", "lazy_static", "nom", @@ -650,7 +739,7 @@ dependencies = [ "rust-ini", "serde", "serde_json", - "toml", + "toml 0.8.19", "yaml-rust", ] @@ -660,6 +749,35 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -676,15 +794,26 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +[[package]] +name = "cosmos-sdk-proto" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73c9d2043a9e617b0d602fbc0a0ecd621568edbf3a9774890a6d562389bd8e1c" +dependencies = [ + "prost 0.11.9", + "prost-types 0.11.9", + "tendermint-proto 0.32.2", +] + [[package]] name = "cosmos-sdk-proto" version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32560304ab4c365791fd307282f76637213d8083c1a98490c35159cd67852237" dependencies = [ - "prost 0.12.3", + "prost 0.12.6", "prost-types 0.12.3", - "tendermint-proto", + "tendermint-proto 0.34.0", ] [[package]] @@ -694,7 +823,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47126f5364df9387b9d8559dcef62e99010e1d4098f39eb3f7ee4b5c254e40ea" dependencies = [ "bip32", - "cosmos-sdk-proto", + "cosmos-sdk-proto 0.20.0", "ecdsa 0.16.9", "eyre", "k256 0.13.1", @@ -710,9 +839,9 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.5.3" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9934c79e58d9676edfd592557dee765d2a6ef54c09d5aa2edb06156b00148966" +checksum = "dd50718a2b6830ce9eb5d465de5a018a12e71729d66b70807ce97e6dd14f931d" dependencies = [ "digest 0.10.7", "ecdsa 0.16.9", @@ -724,9 +853,9 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.5.3" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5e72e330bd3bdab11c52b5ecbdeb6a8697a004c57964caeb5d876f0b088b3c" +checksum = "242e98e7a231c122e08f300d9db3262d1007b51758a8732cd6210b3e9faa4f3a" dependencies = [ "syn 1.0.109", ] @@ -757,12 +886,12 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.5.3" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8666e572a3a2519010dde88c04d16e9339ae751b56b2bb35081fe3f7d6be74" +checksum = "78c1556156fdf892a55cced6115968b961eaaadd6f724a2c2cb7d1e168e32dd3" dependencies = [ - "base64 0.21.7", - "bech32", + "base64", + "bech32 0.9.1", "bnum", "cosmwasm-crypto", "cosmwasm-derive", @@ -771,7 +900,7 @@ dependencies = [ "hex", "schemars", "serde", - "serde-json-wasm", + "serde-json-wasm 0.5.2", "sha2 0.10.8", "static_assertions", "thiserror", @@ -887,21 +1016,15 @@ dependencies = [ [[package]] name = "cw-dex" -version = "0.5.3" +version = "0.6.0" dependencies = [ "apollo-cw-asset", - "apollo-utils", - "astroport 2.9.0", - "cosmwasm-schema", "cosmwasm-std", "cw-dex-test-contract", - "cw-dex-test-helpers", "cw-it", "cw-utils 1.0.3", - "cw2 1.1.2", "cw20 1.1.2", "cw20-base 1.1.2", - "osmosis-std 0.19.2", "proptest", "test-case", "thiserror", @@ -909,18 +1032,20 @@ dependencies = [ [[package]] name = "cw-dex-astroport" -version = "0.1.1" +version = "0.2.0" dependencies = [ "apollo-cw-asset", + "apollo-cw-multi-test", "apollo-utils", - "astroport 2.9.0", - "astroport 3.11.1", + "astroport 2.9.5", + "astroport 5.3.0", "cosmwasm-schema", "cosmwasm-std", "cw-dex", "cw-dex-test-contract", "cw-dex-test-helpers", "cw-it", + "cw-multi-test", "cw-utils 1.0.3", "cw2 1.1.2", "cw20 1.1.2", @@ -931,7 +1056,7 @@ dependencies = [ [[package]] name = "cw-dex-osmosis" -version = "0.1.0" +version = "0.2.0" dependencies = [ "apollo-cw-asset", "apollo-utils", @@ -964,7 +1089,7 @@ version = "0.1.0" dependencies = [ "apollo-cw-asset", "apollo-utils", - "astroport 2.9.0", + "astroport 5.3.0", "astroport-test-contract", "cosmwasm-std", "cw-dex-test-contract", @@ -975,46 +1100,67 @@ dependencies = [ [[package]] name = "cw-it" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1bd88c423ae22eefe99b1b008c8b2d7936def56cfb0c65f6ccf634a0988d7b0" +checksum = "b20b25efb4f3dc5b085d16b3bd086276dd3410cca6fcabe1485569a23f821b9e" dependencies = [ "anyhow", "apollo-cw-multi-test", "apollo-utils", - "astroport 2.9.0", - "astroport 3.11.1", + "astroport 2.9.5", + "astroport 5.3.0", "astroport-factory", - "astroport-generator", "astroport-incentives", "astroport-liquidity-manager", "astroport-maker", "astroport-native-coin-registry", - "astroport-pair", + "astroport-pair 2.0.1", "astroport-pair-concentrated", - "astroport-pair-stable", + "astroport-pair-stable 4.0.0", "astroport-router", "astroport-staking", "astroport-token", "astroport-vesting", "astroport-whitelist", + "bech32 0.11.0", "config", "cosmrs", "cosmwasm-schema", "cosmwasm-std", "cw20 0.15.1", - "osmosis-std 0.22.0", + "osmosis-std 0.25.0", "osmosis-test-tube", "paste", "proptest", - "prost 0.12.3", + "prost 0.12.6", "regex", "serde", - "strum", + "sha2 0.10.8", + "strum 0.24.1", "test-tube", "thiserror", ] +[[package]] +name = "cw-multi-test" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91fc33b1d65c102d72f46548c64dca423c337e528d6747d0c595316aa65f887b" +dependencies = [ + "anyhow", + "bech32 0.11.0", + "cosmwasm-std", + "cw-storage-plus 1.2.0", + "cw-utils 1.0.3", + "derivative", + "itertools 0.13.0", + "prost 0.12.6", + "schemars", + "serde", + "sha2 0.10.8", + "thiserror", +] + [[package]] name = "cw-storage-plus" version = "0.15.1" @@ -1069,9 +1215,9 @@ dependencies = [ [[package]] name = "cw1" -version = "0.15.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe0783ec4210ba4e0cdfed9874802f469c6db0880f742ad427cb950e940b21c" +checksum = "f1605722190afd93bfea6384b88224d1cfe50ebf70d2e10641535da79fa70e83" dependencies = [ "cosmwasm-schema", "cosmwasm-std", @@ -1081,16 +1227,16 @@ dependencies = [ [[package]] name = "cw1-whitelist" -version = "0.15.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233dd13f61495f1336da57c8bdca0536fa9f8dd59c12d2bbfc59928ea580e478" +checksum = "81bb3e9dc87f4ff26547f4e27e0ba3c82034372f21b2f55527fb52b542637d8d" dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-storage-plus 0.15.1", - "cw-utils 0.15.1", + "cw-storage-plus 1.2.0", + "cw-utils 1.0.3", "cw1", - "cw2 0.15.1", + "cw2 1.1.2", "schemars", "serde", "thiserror", @@ -1263,9 +1409,12 @@ dependencies = [ [[package]] name = "dlv-list" -version = "0.3.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" +dependencies = [ + "const-random", +] [[package]] name = "doc-comment" @@ -1627,6 +1776,12 @@ dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" + [[package]] name = "hashbrown" version = "0.14.3" @@ -1793,18 +1948,18 @@ dependencies = [ [[package]] name = "itertools" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] [[package]] name = "itertools" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] @@ -1951,6 +2106,27 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "neutron-sdk" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46f60e477bd71007d9ff78ae020ec1c6b3b47798578af6151429434d86472efc" +dependencies = [ + "bech32 0.9.1", + "cosmos-sdk-proto 0.20.0", + "cosmwasm-schema", + "cosmwasm-std", + "prost 0.12.6", + "prost-types 0.12.3", + "protobuf 3.5.1", + "schemars", + "serde", + "serde-json-wasm 1.0.1", + "speedate", + "tendermint-proto 0.34.0", + "thiserror", +] + [[package]] name = "nom" version = "7.1.3" @@ -2027,25 +2203,25 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "ordered-multimap" -version = "0.4.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" +checksum = "4ed8acf08e98e744e5384c8bc63ceb0364e68a6854187221c18df61c4797690e" dependencies = [ "dlv-list", - "hashbrown 0.12.3", + "hashbrown 0.13.2", ] [[package]] name = "osmosis-std" -version = "0.19.2" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "798fade51443a0e07eb25b59a11b320b9e8f03e6e8fbe14c520258f04742fe13" +checksum = "e87adf61f03306474ce79ab322d52dfff6b0bcf3aed1e12d8864ac0400dec1bf" dependencies = [ "chrono", "cosmwasm-std", - "osmosis-std-derive 0.16.2", - "prost 0.11.9", - "prost-types 0.11.9", + "osmosis-std-derive", + "prost 0.12.6", + "prost-types 0.12.3", "schemars", "serde", "serde-cw-value", @@ -2059,8 +2235,8 @@ checksum = "8641c376f01f5af329dc2a34e4f5527eaeb0bde18cda8d86fed958d04c86159c" dependencies = [ "chrono", "cosmwasm-std", - "osmosis-std-derive 0.20.1", - "prost 0.12.3", + "osmosis-std-derive", + "prost 0.12.6", "prost-types 0.12.3", "schemars", "serde", @@ -2068,16 +2244,19 @@ dependencies = [ ] [[package]] -name = "osmosis-std-derive" -version = "0.16.2" +name = "osmosis-std" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f47f0b2f22adb341bb59e5a3a1b464dde033181954bd055b9ae86d6511ba465b" +checksum = "ca66dca7e8c9b11b995cd41a44c038134ccca4469894d663d8a9452d6e716241" dependencies = [ - "itertools 0.10.5", - "proc-macro2", - "prost-types 0.11.9", - "quote", - "syn 1.0.109", + "chrono", + "cosmwasm-std", + "osmosis-std-derive", + "prost 0.12.6", + "prost-types 0.12.3", + "schemars", + "serde", + "serde-cw-value", ] [[package]] @@ -2109,16 +2288,16 @@ dependencies = [ [[package]] name = "osmosis-test-tube" -version = "22.1.0" +version = "25.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a082b97136d15470a37aa758f227c865594590b69d74721248ed5adf59bf1ca2" +checksum = "5eb35dcc9adc1b39e23dfae07c9f04a60187fde57a52b7762434ea6548581a1a" dependencies = [ - "base64 0.21.7", + "base64", "bindgen", "cosmrs", "cosmwasm-std", - "osmosis-std 0.22.0", - "prost 0.12.3", + "osmosis-std 0.25.0", + "prost 0.12.6", "serde", "serde_json", "test-tube", @@ -2340,12 +2519,12 @@ dependencies = [ [[package]] name = "prost" -version = "0.12.3" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" +checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" dependencies = [ "bytes", - "prost-derive 0.12.3", + "prost-derive 0.12.6", ] [[package]] @@ -2376,12 +2555,12 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.12.3" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" +checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.12.1", "proc-macro2", "quote", "syn 2.0.48", @@ -2402,7 +2581,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" dependencies = [ - "prost 0.12.3", + "prost 0.12.6", ] [[package]] @@ -2414,6 +2593,26 @@ dependencies = [ "bytes", ] +[[package]] +name = "protobuf" +version = "3.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bcc343da15609eaecd65f8aa76df8dc4209d325131d8219358c0aaaebab0bf6" +dependencies = [ + "once_cell", + "protobuf-support", + "thiserror", +] + +[[package]] +name = "protobuf-support" +version = "3.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0766e3675a627c327e4b3964582594b0e8741305d628a98a5de75a1d15f99b9" +dependencies = [ + "thiserror", +] + [[package]] name = "quick-error" version = "1.2.3" @@ -2509,7 +2708,7 @@ version = "0.11.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" dependencies = [ - "base64 0.21.7", + "base64", "bytes", "encoding_rs", "futures-core", @@ -2590,20 +2789,21 @@ dependencies = [ [[package]] name = "ron" -version = "0.7.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88073939a61e5b7680558e6be56b419e208420c2adb92be54921fa6b72283f1a" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ - "base64 0.13.1", - "bitflags 1.3.2", + "base64", + "bitflags 2.4.2", "serde", + "serde_derive", ] [[package]] name = "rust-ini" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df" +checksum = "7e2a3bcec1f113553ef1c88aae6c020a369d03d55b58de9869a0908930385091" dependencies = [ "cfg-if", "ordered-multimap", @@ -2664,7 +2864,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.21.7", + "base64", ] [[package]] @@ -2721,9 +2921,9 @@ dependencies = [ [[package]] name = "schemars" -version = "0.8.16" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" dependencies = [ "dyn-clone", "schemars_derive", @@ -2733,14 +2933,14 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.16" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" +checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 1.0.109", + "syn 2.0.48", ] [[package]] @@ -2812,9 +3012,9 @@ checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" [[package]] name = "serde" -version = "1.0.196" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] @@ -2837,6 +3037,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde-json-wasm" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05da0d153dd4595bdffd5099dc0e9ce425b205ee648eb93437ff7302af8c9a5" +dependencies = [ + "serde", +] + [[package]] name = "serde_bytes" version = "0.11.14" @@ -2848,9 +3057,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", @@ -2859,13 +3068,13 @@ dependencies = [ [[package]] name = "serde_derive_internals" -version = "0.26.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.48", ] [[package]] @@ -2890,6 +3099,15 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "serde_spanned" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -2992,6 +3210,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "speedate" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "242f76c50fd18cbf098607090ade73a08d39cfd84ea835f3796a2c855223b19b" +dependencies = [ + "strum 0.25.0", + "strum_macros 0.25.3", +] + [[package]] name = "spin" version = "0.9.8" @@ -3030,7 +3258,16 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" dependencies = [ - "strum_macros", + "strum_macros 0.24.3", +] + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros 0.25.3", ] [[package]] @@ -3046,6 +3283,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.48", +] + [[package]] name = "subtle" version = "2.5.0" @@ -3143,7 +3393,7 @@ dependencies = [ "k256 0.13.1", "num-traits", "once_cell", - "prost 0.12.3", + "prost 0.12.6", "prost-types 0.12.3", "ripemd", "serde", @@ -3154,7 +3404,7 @@ dependencies = [ "signature 2.2.0", "subtle", "subtle-encoding", - "tendermint-proto", + "tendermint-proto 0.34.0", "time", "zeroize", ] @@ -3169,10 +3419,28 @@ dependencies = [ "serde", "serde_json", "tendermint", - "toml", + "toml 0.5.11", "url", ] +[[package]] +name = "tendermint-proto" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0cec054567d16d85e8c3f6a3139963d1a66d9d3051ed545d31562550e9bcc3d" +dependencies = [ + "bytes", + "flex-error", + "num-derive", + "num-traits", + "prost 0.11.9", + "prost-types 0.11.9", + "serde", + "serde_bytes", + "subtle-encoding", + "time", +] + [[package]] name = "tendermint-proto" version = "0.34.0" @@ -3183,7 +3451,7 @@ dependencies = [ "flex-error", "num-derive", "num-traits", - "prost 0.12.3", + "prost 0.12.6", "prost-types 0.12.3", "serde", "serde_bytes", @@ -3213,7 +3481,7 @@ dependencies = [ "subtle-encoding", "tendermint", "tendermint-config", - "tendermint-proto", + "tendermint-proto 0.34.0", "thiserror", "time", "tokio", @@ -3258,15 +3526,15 @@ dependencies = [ [[package]] name = "test-tube" -version = "0.5.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09184c7655b2bdaf4517b06141a2e4c44360904f2706a05b24c831bd97ad1db6" +checksum = "804bb9bda992b6cda6f883e7973cb999d4da90d21257fb918d6a693407148681" dependencies = [ - "base64 0.21.7", + "base64", "cosmrs", "cosmwasm-std", - "osmosis-std 0.22.0", - "prost 0.12.3", + "osmosis-std 0.25.0", + "prost 0.12.6", "serde", "serde_json", "thiserror", @@ -3274,18 +3542,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", @@ -3294,9 +3562,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.34" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "num-conv", @@ -3314,14 +3582,23 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ "num-conv", "time-core", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -3398,6 +3675,40 @@ dependencies = [ "serde", ] +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tower-service" version = "0.3.2" @@ -3480,6 +3791,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + [[package]] name = "untrusted" version = "0.9.0" @@ -3794,6 +4111,15 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +[[package]] +name = "winnow" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.50.0" diff --git a/Cargo.toml b/Cargo.toml index f4a2de1b..1e15ae83 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.5.3" +cosmwasm-std = "1.5.4" cosmwasm-storage = "1.2.1" cw-storage-plus = "1.0" cw2 = "1.0" @@ -26,17 +26,19 @@ serde = { version = "1.0.145", default-features = false, features = ["derive"] } thiserror = { version = "1.0.31" } apollo-cw-asset = "0.1.1" osmosis-std = "0.22.0" -cw-it = "0.3.0" +cw-it = { version = "0.4.0", features = ["multi-test"]} apollo-utils = "0.1.0" -astroport = "2.9.0" -astroport_v3 = { package = "astroport", version = "3.11.1" } +astroport_v2 = { package = "astroport", version = "2.9.0" } +astroport = { package = "astroport", version = "5.3.0" } test-case = "3.0.0" proptest = "1.0.0" +cw-multi-test = "=1.2.0" +apollo-cw-multi-test = { version = "0.19.0" ,features = ["stargate"] } # Workspace packages -cw-dex = { path = "cw-dex", version = "0.5.3" } -cw-dex-astroport = { path = "cw-dex-astroport", version = "0.1.1" } -cw-dex-osmosis = { path = "cw-dex-osmosis", version = "0.1.0" } +cw-dex = { path = "cw-dex", version = "0.6.0" } +cw-dex-astroport = { path = "cw-dex-astroport", version = "0.2.0" } +cw-dex-osmosis = { path = "cw-dex-osmosis", version = "0.2.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" } diff --git a/Makefile.toml b/Makefile.toml index 90d450e4..894f0e96 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -62,11 +62,11 @@ command = "cargo" args = ["check"] [tasks.clippy-check] -toolchain = "${NIGHTLY_VERSION}" +toolchain = "${RUST_VERSION}" command = "cargo" args = ["clippy","--all-features","--","-D","warnings"] [tasks.clippy-fix] -toolchain = "${NIGHTLY_VERSION}" +toolchain = "${RUST_VERSION}" command = "cargo" args = ["clippy","--all-features", "--fix","--allow-staged", "--allow-dirty", "--","-D","warnings"] @@ -106,7 +106,7 @@ args = [ # This task requires the `cargo-machete` package: https://crates.io/crates/cargo-machete [tasks.machete-check] -toolchain = "${NIGHTLY_VERSION}" +toolchain = "${RUST_VERSION}" command = "cargo" args = ["machete"] [tasks.machete-fix] diff --git a/cw-dex-astroport/CHANGELOG.md b/cw-dex-astroport/CHANGELOG.md new file mode 100644 index 00000000..b668f311 --- /dev/null +++ b/cw-dex-astroport/CHANGELOG.md @@ -0,0 +1,17 @@ +# Changelog + +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.2.0] - 2024-08-28 + +### Changed + +- Added support for Astroport native LP tokens. +- Bumped `astroport_v3` dependency alias of `astroport` package to `5.3.0` and renamed it to `astroport`. Renamed `astroport` to `astroport_v2`. +- Changed `AstroportStaking` field `lp_token_addr: Addr` to `lp_token: AssetInfo`. +- Changed `AstroportPool` field `lp_token_addr: Addr` to `lp_token: AssetInfo`. +- Changed `AstroportPool` field `liquidity_manager: Addr` to `liquidity_manager: Option`. + - This is to keep backwards compatibility with Astroport pools that use CW20 LP tokens. Note that the field must be set if the LP token is a CW20 token. diff --git a/cw-dex-astroport/Cargo.toml b/cw-dex-astroport/Cargo.toml index 4122a02d..93052536 100644 --- a/cw-dex-astroport/Cargo.toml +++ b/cw-dex-astroport/Cargo.toml @@ -5,7 +5,7 @@ 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.1" +version = "0.2.0" readme = "README.md" [features] @@ -20,7 +20,7 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] cw-dex = { workspace = true } cosmwasm-schema = { workspace = true } -cosmwasm-std = { workspace = true } +cosmwasm-std = { workspace = true, features = ["cosmwasm_1_1"] } apollo-cw-asset = { workspace = true, features = ["astroport"] } cw-utils = { workspace = true } cw20 = { workspace = true } @@ -28,7 +28,7 @@ apollo-utils = { workspace = true } # Astroport astroport = { workspace = true } -astroport_v3 = { workspace = true } +astroport_v2 = { workspace = true } cw2 = { workspace = true } [dev-dependencies] @@ -39,3 +39,5 @@ cw-dex-test-helpers = { workspace = true, features = ["astroport", "osmosis-test proptest = { workspace = true } cw20-base = { workspace = true } cw20 = { workspace = true } +cw-multi-test = { workspace = true } +apollo-cw-multi-test = { workspace = true } diff --git a/cw-dex-astroport/artifacts/astro_token_converter.wasm b/cw-dex-astroport/artifacts/astro_token_converter.wasm new file mode 100644 index 00000000..867c22da Binary files /dev/null and b/cw-dex-astroport/artifacts/astro_token_converter.wasm differ diff --git a/cw-dex-astroport/artifacts/astro_token_converter_neutron.wasm b/cw-dex-astroport/artifacts/astro_token_converter_neutron.wasm new file mode 100644 index 00000000..986249cb Binary files /dev/null and b/cw-dex-astroport/artifacts/astro_token_converter_neutron.wasm differ diff --git a/cw-dex-astroport/artifacts/astroport_factory.wasm b/cw-dex-astroport/artifacts/astroport_factory.wasm index 7a5bdd8f..b7d261b0 100644 Binary files a/cw-dex-astroport/artifacts/astroport_factory.wasm and b/cw-dex-astroport/artifacts/astroport_factory.wasm differ diff --git a/cw-dex-astroport/artifacts/astroport_fee_granter.wasm b/cw-dex-astroport/artifacts/astroport_fee_granter.wasm new file mode 100644 index 00000000..f31c519d Binary files /dev/null and b/cw-dex-astroport/artifacts/astroport_fee_granter.wasm differ diff --git a/cw-dex-astroport/artifacts/astroport_generator.wasm b/cw-dex-astroport/artifacts/astroport_generator.wasm index 2fd7e866..e90abaff 100644 Binary files a/cw-dex-astroport/artifacts/astroport_generator.wasm and b/cw-dex-astroport/artifacts/astroport_generator.wasm differ diff --git a/cw-dex-astroport/artifacts/astroport_incentives.wasm b/cw-dex-astroport/artifacts/astroport_incentives.wasm index 371ad055..d6a7cb61 100644 Binary files a/cw-dex-astroport/artifacts/astroport_incentives.wasm and b/cw-dex-astroport/artifacts/astroport_incentives.wasm differ diff --git a/cw-dex-astroport/artifacts/astroport_liquidity_helper.wasm b/cw-dex-astroport/artifacts/astroport_liquidity_helper.wasm deleted file mode 100644 index 6e6385cf..00000000 Binary files a/cw-dex-astroport/artifacts/astroport_liquidity_helper.wasm and /dev/null differ diff --git a/cw-dex-astroport/artifacts/astroport_maker.wasm b/cw-dex-astroport/artifacts/astroport_maker.wasm index 7dcc4d39..bfb1277d 100644 Binary files a/cw-dex-astroport/artifacts/astroport_maker.wasm and b/cw-dex-astroport/artifacts/astroport_maker.wasm differ diff --git a/cw-dex-astroport/artifacts/astroport_native_coin_registry.wasm b/cw-dex-astroport/artifacts/astroport_native_coin_registry.wasm index c93a3d44..04a8d6f0 100644 Binary files a/cw-dex-astroport/artifacts/astroport_native_coin_registry.wasm and b/cw-dex-astroport/artifacts/astroport_native_coin_registry.wasm differ diff --git a/cw-dex-astroport/artifacts/astroport_native_coin_wrapper.wasm b/cw-dex-astroport/artifacts/astroport_native_coin_wrapper.wasm deleted file mode 100644 index 742521a5..00000000 Binary files a/cw-dex-astroport/artifacts/astroport_native_coin_wrapper.wasm and /dev/null differ diff --git a/cw-dex-astroport/artifacts/astroport_oracle.wasm b/cw-dex-astroport/artifacts/astroport_oracle.wasm index eb9e52a5..11851410 100644 Binary files a/cw-dex-astroport/artifacts/astroport_oracle.wasm and b/cw-dex-astroport/artifacts/astroport_oracle.wasm differ diff --git a/cw-dex-astroport/artifacts/astroport_pair.wasm b/cw-dex-astroport/artifacts/astroport_pair.wasm index a86fda06..2d8d89af 100644 Binary files a/cw-dex-astroport/artifacts/astroport_pair.wasm and b/cw-dex-astroport/artifacts/astroport_pair.wasm differ diff --git a/cw-dex-astroport/artifacts/astroport_pair_astro_xastro.wasm b/cw-dex-astroport/artifacts/astroport_pair_astro_xastro.wasm deleted file mode 100644 index 3d08bb1d..00000000 Binary files a/cw-dex-astroport/artifacts/astroport_pair_astro_xastro.wasm and /dev/null differ diff --git a/cw-dex-astroport/artifacts/astroport_pair_concentrated.wasm b/cw-dex-astroport/artifacts/astroport_pair_concentrated.wasm index cd6a9e0c..3d56f54e 100644 Binary files a/cw-dex-astroport/artifacts/astroport_pair_concentrated.wasm and b/cw-dex-astroport/artifacts/astroport_pair_concentrated.wasm differ diff --git a/cw-dex-astroport/artifacts/astroport_pair_converter.wasm b/cw-dex-astroport/artifacts/astroport_pair_converter.wasm new file mode 100644 index 00000000..005f3d37 Binary files /dev/null and b/cw-dex-astroport/artifacts/astroport_pair_converter.wasm differ diff --git a/cw-dex-astroport/artifacts/astroport_pair_stable.wasm b/cw-dex-astroport/artifacts/astroport_pair_stable.wasm index 3b345176..13443c96 100644 Binary files a/cw-dex-astroport/artifacts/astroport_pair_stable.wasm and b/cw-dex-astroport/artifacts/astroport_pair_stable.wasm differ diff --git a/cw-dex-astroport/artifacts/astroport_pair_transmuter.wasm b/cw-dex-astroport/artifacts/astroport_pair_transmuter.wasm new file mode 100644 index 00000000..4893c31b Binary files /dev/null and b/cw-dex-astroport/artifacts/astroport_pair_transmuter.wasm differ diff --git a/cw-dex-astroport/artifacts/astroport_pair_xyk_sale_tax.wasm b/cw-dex-astroport/artifacts/astroport_pair_xyk_sale_tax.wasm new file mode 100644 index 00000000..34e8717b Binary files /dev/null and b/cw-dex-astroport/artifacts/astroport_pair_xyk_sale_tax.wasm differ diff --git a/cw-dex-astroport/artifacts/astroport_router.wasm b/cw-dex-astroport/artifacts/astroport_router.wasm index 8f30b820..bdab712e 100644 Binary files a/cw-dex-astroport/artifacts/astroport_router.wasm and b/cw-dex-astroport/artifacts/astroport_router.wasm differ diff --git a/cw-dex-astroport/artifacts/astroport_staking.wasm b/cw-dex-astroport/artifacts/astroport_staking.wasm index a19b721e..373d1e2e 100644 Binary files a/cw-dex-astroport/artifacts/astroport_staking.wasm and b/cw-dex-astroport/artifacts/astroport_staking.wasm differ diff --git a/cw-dex-astroport/artifacts/astroport_token.wasm b/cw-dex-astroport/artifacts/astroport_token.wasm index ac2e5606..68940a39 100644 Binary files a/cw-dex-astroport/artifacts/astroport_token.wasm and b/cw-dex-astroport/artifacts/astroport_token.wasm differ diff --git a/cw-dex-astroport/artifacts/astroport_tokenfactory_tracker.wasm b/cw-dex-astroport/artifacts/astroport_tokenfactory_tracker.wasm new file mode 100644 index 00000000..ad334e93 Binary files /dev/null and b/cw-dex-astroport/artifacts/astroport_tokenfactory_tracker.wasm differ diff --git a/cw-dex-astroport/artifacts/astroport_vault.wasm b/cw-dex-astroport/artifacts/astroport_vault.wasm deleted file mode 100644 index 889f5de4..00000000 Binary files a/cw-dex-astroport/artifacts/astroport_vault.wasm and /dev/null differ diff --git a/cw-dex-astroport/artifacts/astroport_vesting.wasm b/cw-dex-astroport/artifacts/astroport_vesting.wasm index c92cee72..8b523fef 100644 Binary files a/cw-dex-astroport/artifacts/astroport_vesting.wasm and b/cw-dex-astroport/artifacts/astroport_vesting.wasm differ diff --git a/cw-dex-astroport/artifacts/astroport_whitelist.wasm b/cw-dex-astroport/artifacts/astroport_whitelist.wasm index 6019a192..c6776efb 100644 Binary files a/cw-dex-astroport/artifacts/astroport_whitelist.wasm and b/cw-dex-astroport/artifacts/astroport_whitelist.wasm differ diff --git a/cw-dex-astroport/artifacts/astroport_xastro_token.wasm b/cw-dex-astroport/artifacts/astroport_xastro_token.wasm index 3fc39a75..e0245279 100644 Binary files a/cw-dex-astroport/artifacts/astroport_xastro_token.wasm and b/cw-dex-astroport/artifacts/astroport_xastro_token.wasm differ diff --git a/cw-dex-astroport/artifacts/cw_dex_router.wasm b/cw-dex-astroport/artifacts/cw_dex_router.wasm old mode 100644 new mode 100755 index 7d36091c..f185a63e Binary files a/cw-dex-astroport/artifacts/cw_dex_router.wasm and b/cw-dex-astroport/artifacts/cw_dex_router.wasm differ diff --git a/cw-dex-astroport/src/lib.rs b/cw-dex-astroport/src/lib.rs index 66173e16..dc3466ec 100644 --- a/cw-dex-astroport/src/lib.rs +++ b/cw-dex-astroport/src/lib.rs @@ -6,4 +6,7 @@ mod staking; pub use pool::AstroportPool; pub use staking::AstroportStaking; -pub use {astroport, astroport_v3}; +pub use {astroport, astroport_v2}; + +/// Re-export `cw-dex` for convenience +pub use cw_dex; diff --git a/cw-dex-astroport/src/pool.rs b/cw-dex-astroport/src/pool.rs index 84d255fd..8caac01f 100644 --- a/cw-dex-astroport/src/pool.rs +++ b/cw-dex-astroport/src/pool.rs @@ -4,17 +4,17 @@ use std::str::FromStr; use apollo_cw_asset::{Asset, AssetInfo, AssetInfoBase, AssetList}; use apollo_utils::iterators::IntoElementwise; -use astroport::liquidity_manager; +use astroport_v2::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, + coins, 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::asset::{Asset as AstroAsset, AssetInfo as AstroAssetInfo, PairInfo}; use astroport::factory::PairType; use astroport::pair::{ Cw20HookMsg as PairCw20HookMsg, ExecuteMsg as PairExecuteMsg, PoolResponse, @@ -30,13 +30,13 @@ 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, + pub lp_token: AssetInfo, /// 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, + pub liquidity_manager: Option, } impl AstroportPool { @@ -44,14 +44,38 @@ impl 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 { + pub fn new(deps: Deps, pair_addr: Addr, liquidity_manager: Option) -> StdResult { let pair_info = deps .querier .query_wasm_smart::(pair_addr.clone(), &PairQueryMsg::Pair {})?; + let lp_token = AssetInfo::from_str(deps.api, &pair_info.liquidity_token); + + Self { + pair_addr, + lp_token, + pool_assets: pair_info + .asset_infos + .into_iter() + .map(astroport_v5_assetinfo_to_assetinfo) + .collect(), + pair_type: pair_info.pair_type, + liquidity_manager, + } + .validate(deps) + } + + pub fn validate(&self, deps: Deps) -> StdResult { + let pair_info = deps + .querier + .query_wasm_smart::( + self.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() { + astroport::factory::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")), @@ -59,13 +83,20 @@ impl AstroportPool { _ => 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, - }) + // Only allow using liquidity manager if LP token is a CW20 token + if self.lp_token.is_native() && self.liquidity_manager.is_some() { + return Err(StdError::generic_err( + "Liquidity manager is not supported for native LP tokens", + )); + } + // Require liquidity manager to be set if LP token is a CW20 token + if !self.lp_token.is_native() && self.liquidity_manager.is_none() { + return Err(StdError::generic_err( + "Liquidity manager must be set for CW20 LP tokens", + )); + } + + Ok(self.clone()) } /// Returns the matching pool given a LP token. @@ -77,7 +108,7 @@ impl AstroportPool { pub fn get_pool_for_lp_token( deps: Deps, lp_token: &AssetInfo, - astroport_liquidity_manager: Addr, + astroport_liquidity_manager: Option, ) -> Result { match lp_token { AssetInfo::Cw20(address) => { @@ -97,13 +128,31 @@ impl AstroportPool { Ok(pool) } - _ => Err(CwDexError::NotLpToken {}), + AssetInfo::Native(native_denom) => { + // To figure out if the native denom is a LP token, we need to check which + // address created the native denom and check if that address is + // an Astroport pair contract. + let pair_addr = parse_pair_address_from_lp_denom(deps, native_denom)?; + + // 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, pair_addr, astroport_liquidity_manager)?; + + Ok(pool) + } } } /// 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()) + match &self.lp_token { + AssetInfo::Native(denom) => Ok(querier.query_supply(denom)?.amount), + AssetInfo::Cw20(token_addr) => query_supply(querier, token_addr), + } } /// Queries the pair contract for the current pool state @@ -118,13 +167,35 @@ impl AstroportPool { impl Pool for AstroportPool { fn provide_liquidity( &self, - _deps: Deps, + deps: Deps, env: &Env, assets: AssetList, min_out: Uint128, ) -> Result { + self.validate(deps)?; + let (funds, cw20s) = separate_natives_and_cw20s(&assets); + let contract_address = if let Some(liquidity_manager) = &self.liquidity_manager { + liquidity_manager + } else { + // Ensure min_out is not set for concentrated liquidity pools, as they + // do not support min_out + match &self.pair_type { + PairType::Custom(custom) if custom == "concentrated" => { + if min_out != Uint128::zero() { + return Err(CwDexError::UnsupportedArguments { + reason: "Min out is not supported for concentrated liquidity pools" + .to_string(), + }); + } + } + _ => {} + } + + &self.pair_addr + }; + // Increase allowance on all Cw20s let allowance_msgs: Vec = cw20s .into_iter() @@ -132,7 +203,7 @@ impl Pool for AstroportPool { Ok(CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: asset.address, msg: to_json_binary(&Cw20ExecuteMsg::IncreaseAllowance { - spender: self.liquidity_manager.to_string(), + spender: contract_address.to_string(), amount: asset.amount, expires: Some(Expiration::AtHeight(env.block.height + 1)), })?, @@ -150,24 +221,38 @@ 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_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(), + let provide_liquidity_msg = match &self.liquidity_manager { + Some(liquidity_manager) => CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: 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_v2::pair::ExecuteMsg::ProvideLiquidity { + assets: assets_vec.into_elementwise(), + slippage_tolerance: Some(Decimal::from_str(MAX_ALLOWED_SLIPPAGE)?), + auto_stake: Some(false), + receiver: None, + }, + })?, + funds, + }), + None => CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: self.pair_addr.to_string(), + msg: to_json_binary(&PairExecuteMsg::ProvideLiquidity { + assets: assets_vec.iter().map(asset_to_astroport_v5_asset).collect(), slippage_tolerance: Some(Decimal::from_str(MAX_ALLOWED_SLIPPAGE)?), auto_stake: Some(false), receiver: None, - }, - })?, - funds, - }); + min_lp_to_receive: Some(min_out), + })?, + funds, + }), + }; let event = Event::new("apollo/cw-dex/provide_liquidity") .add_attribute("pair_addr", &self.pair_addr) - .add_attribute("assets", format!("{:?}", assets)); + .add_attribute("assets", format!("{:?}", assets)) + .add_attribute("lp_token", format!("{:?}", &self.lp_token())); Ok(Response::new() .add_messages(allowance_msgs) @@ -177,12 +262,14 @@ impl Pool for AstroportPool { fn withdraw_liquidity( &self, - _deps: Deps, + deps: Deps, _env: &Env, asset: Asset, mut min_out: AssetList, ) -> Result { - if let AssetInfoBase::Cw20(token_addr) = &asset.info { + self.validate(deps)?; + + if let Some(liquidity_manager) = &self.liquidity_manager { // 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() { @@ -193,12 +280,12 @@ impl Pool for AstroportPool { } let withdraw_liquidity = CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: token_addr.to_string(), + contract_addr: self.lp_token.to_string(), msg: to_json_binary(&Cw20ExecuteMsg::Send { - contract: self.liquidity_manager.to_string(), + contract: liquidity_manager.to_string(), amount: asset.amount, msg: to_json_binary(&liquidity_manager::Cw20HookMsg::WithdrawLiquidity { - pair_msg: astroport::pair::Cw20HookMsg::WithdrawLiquidity { + pair_msg: astroport_v2::pair::Cw20HookMsg::WithdrawLiquidity { // This field is currently not used... assets: vec![], }, @@ -208,6 +295,53 @@ impl Pool for AstroportPool { 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 if let AssetInfoBase::Native(token_denom) = &asset.info { + // Ensure min_out is not set for concentrated liquidity pools, as they + // do not support min_out + match &self.pair_type { + PairType::Custom(custom) if custom == "concentrated" => { + if min_out.into_iter().any(|x| x.amount > Uint128::zero()) { + return Err(CwDexError::UnsupportedArguments { + reason: "Min out is not supported for concentrated liquidity pools" + .to_string(), + }); + } + } + _ => {} + } + + let min_assets_to_receive = if min_out.len() > 0 { + let mut min_assets: Vec = vec![]; + // Astroport requires min_assets_to_receive to contain all assets in the pool + for asset_info in &self.pool_assets { + let asset = match min_out.find(asset_info) { + Some(asset) => asset.clone(), + None => Asset::new(asset_info.clone(), Uint128::zero()), + }; + min_assets.push(asset_to_astroport_v5_asset(&asset)); + } + Some(min_assets) + } else { + None + }; + + let withdraw_liquidity = CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: self.pair_addr.to_string(), + msg: to_json_binary(&PairExecuteMsg::WithdrawLiquidity { + assets: vec![], + min_assets_to_receive, + })?, + funds: coins(asset.amount.u128(), token_denom), + }); + let event = Event::new("apollo/cw-dex/withdraw_liquidity") .add_attribute("pair_addr", &self.pair_addr) .add_attribute("asset", format!("{:?}", asset)) @@ -223,31 +357,30 @@ impl Pool for AstroportPool { fn swap( &self, - _deps: Deps, + deps: Deps, env: &Env, offer_asset: Asset, ask_asset_info: AssetInfo, min_out: Uint128, ) -> Result { + self.validate(deps)?; + // 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::Native(_) => wasm_execute( + self.pair_addr.to_string(), + &PairExecuteMsg::Swap { + offer_asset: asset_to_astroport_v5_asset(&offer_asset), + belief_price, + max_spread: Some(Decimal::zero()), + to: Some(env.contract.address.to_string()), + ask_asset_info: Some(asset_info_to_astroport_v5_assetinfo(&ask_asset_info)), + }, + vec![offer_asset.clone().try_into()?], + ), AssetInfo::Cw20(addr) => wasm_execute( addr.to_string(), &Cw20ExecuteMsg::Send { @@ -257,7 +390,7 @@ impl Pool for AstroportPool { belief_price, max_spread: Some(Decimal::zero()), to: Some(env.contract.address.to_string()), - ask_asset_info: Some(ask_asset_info.to_owned().into()), + ask_asset_info: Some(asset_info_to_astroport_v5_assetinfo(&ask_asset_info)), })?, }, vec![], @@ -273,7 +406,7 @@ impl Pool for AstroportPool { fn get_pool_liquidity(&self, deps: Deps) -> Result { let resp = self.query_pool_info(&deps.querier)?; - Ok(resp.assets.to_vec().into()) + Ok(astroport_v5_vec_asset_to_assetlist(resp.assets)) } fn simulate_provide_liquidity( @@ -282,25 +415,44 @@ impl Pool for AstroportPool { _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(), + self.validate(deps)?; + + if let Some(liquidity_manager) = &self.liquidity_manager { + let amount: Uint128 = deps.querier.query_wasm_smart( + liquidity_manager.to_string(), + &liquidity_manager::QueryMsg::SimulateProvide { + pair_addr: self.pair_addr.to_string(), + pair_msg: astroport_v2::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: self.lp_token.clone(), + amount, + }; + + Ok(lp_token) + } else { + let amount: Uint128 = deps.querier.query_wasm_smart( + self.pair_addr.to_string(), + &PairQueryMsg::SimulateProvide { + assets: assets.iter().map(asset_to_astroport_v5_asset).collect(), 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, - }; + let lp_token = Asset { + info: self.lp_token.clone(), + amount, + }; - Ok(lp_token) + Ok(lp_token) + } } fn simulate_withdraw_liquidity( @@ -308,15 +460,26 @@ impl Pool for AstroportPool { 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, - }, - )?; + self.validate(deps)?; + + let assets: Vec = if let Some(liquidity_manager) = &self.liquidity_manager { + deps.querier.query_wasm_smart( + liquidity_manager.to_string(), + &liquidity_manager::QueryMsg::SimulateWithdraw { + pair_addr: self.pair_addr.to_string(), + lp_tokens: lp_token.amount, + }, + )? + } else { + deps.querier.query_wasm_smart( + self.pair_addr.to_string(), + &PairQueryMsg::SimulateWithdraw { + lp_amount: lp_token.amount, + }, + )? + }; - Ok(assets.into()) + Ok(astroport_v5_vec_asset_to_assetlist(assets)) } fn simulate_swap( @@ -325,23 +488,80 @@ impl Pool for AstroportPool { offer_asset: Asset, ask_asset_info: AssetInfo, ) -> StdResult { + self.validate(deps)?; + 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()), + offer_asset: asset_to_astroport_v5_asset(&offer_asset), + ask_asset_info: Some(asset_info_to_astroport_v5_assetinfo(&ask_asset_info)), })?, }))? .return_amount) } fn lp_token(&self) -> AssetInfo { - AssetInfoBase::Cw20(self.lp_token_addr.clone()) + self.lp_token.clone() } fn pool_assets(&self, _deps: Deps) -> StdResult> { Ok(self.pool_assets.clone()) } } + +pub fn astroport_v5_assetinfo_to_assetinfo(asset: AstroAssetInfo) -> AssetInfo { + match asset { + AstroAssetInfo::NativeToken { denom } => AssetInfo::native(denom), + AstroAssetInfo::Token { contract_addr } => AssetInfo::cw20(contract_addr), + } +} + +pub fn astroport_v5_asset_to_asset(asset: AstroAsset) -> Asset { + match asset.info { + AstroAssetInfo::NativeToken { denom } => Asset::new(AssetInfo::native(denom), asset.amount), + AstroAssetInfo::Token { contract_addr } => { + Asset::new(AssetInfo::cw20(contract_addr), asset.amount) + } + } +} + +pub fn asset_to_astroport_v5_asset(asset: &Asset) -> AstroAsset { + match &asset.info { + AssetInfoBase::Native(denom) => AstroAsset::native(denom, asset.amount), + AssetInfo::Cw20(contract_addr) => AstroAsset::cw20(contract_addr.clone(), asset.amount), + } +} + +pub fn asset_info_to_astroport_v5_assetinfo(asset: &AssetInfo) -> AstroAssetInfo { + match asset { + AssetInfo::Native(denom) => AstroAssetInfo::NativeToken { + denom: denom.clone(), + }, + AssetInfo::Cw20(contract_addr) => AstroAssetInfo::Token { + contract_addr: contract_addr.clone(), + }, + } +} + +pub fn astroport_v5_vec_asset_to_assetlist(assets: Vec) -> AssetList { + AssetList::from( + assets + .into_iter() + .map(astroport_v5_asset_to_asset) + .collect::>(), + ) +} + +fn parse_pair_address_from_lp_denom(deps: Deps, input_string: &str) -> Result { + let parts: Vec<&str> = input_string.split('/').collect(); + + if parts.len() < 3 { + return Err(CwDexError::AddressParsingErrors { + token_denom: input_string.to_string(), + }); + } + + Ok(deps.api.addr_validate(parts[1])?) +} diff --git a/cw-dex-astroport/src/staking.rs b/cw-dex-astroport/src/staking.rs index f073938e..f00f298d 100644 --- a/cw-dex-astroport/src/staking.rs +++ b/cw-dex-astroport/src/staking.rs @@ -1,28 +1,23 @@ //! Staking/rewards traits implementations for Astroport - +use apollo_cw_asset::{AssetInfo, AssetList}; use apollo_utils::assets::separate_natives_and_cw20s; +use astroport::asset::Asset as AstroAsset; use cosmwasm_schema::cw_serde; use cosmwasm_std::{ - to_json_binary, Addr, CosmosMsg, Deps, Empty, Env, Event, QuerierWrapper, QueryRequest, + coins, 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; +use crate::pool::astroport_v5_vec_asset_to_assetlist; + /// 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 cw20 or token factory denom of the associated LP token + pub lp_token: AssetInfo, /// The address of the astroport incentives contract pub incentives: Addr, } @@ -31,19 +26,30 @@ 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 stake_msg = match &self.lp_token { + AssetInfo::Cw20(cw20_addr) => CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: cw20_addr.to_string(), + msg: to_json_binary(&Cw20ExecuteMsg::Send { + contract: self.incentives.to_string(), + amount, + msg: to_json_binary(&astroport::incentives::Cw20Msg::Deposit { + recipient: None, + })?, + })?, + funds: vec![], + }), + AssetInfo::Native(denom) => CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: self.incentives.to_string(), + msg: to_json_binary(&astroport::incentives::ExecuteMsg::Deposit { + recipient: None, + })?, + funds: coins(amount.into(), denom), + }), + }; let event = Event::new("apollo/cw-dex/stake") .add_attribute("type", "astroport_staking") - .add_attribute("asset", self.lp_token_addr.to_string()) + .add_attribute("asset", self.lp_token.to_string()) .add_attribute("incentives contract address", self.incentives.to_string()); Ok(Response::new().add_message(stake_msg).add_event(event)) @@ -64,8 +70,8 @@ impl Rewards for AstroportStaking { 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()], + msg: to_json_binary(&astroport::incentives::ExecuteMsg::ClaimRewards { + lp_tokens: vec![self.lp_token.to_string()], })?, funds: vec![], }); @@ -98,7 +104,9 @@ impl Rewards for AstroportStaking { 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 {})?, + msg: to_json_binary( + &astroport_v2::native_coin_wrapper::Cw20HookMsg::Unwrap {}, + )?, })?, funds: vec![], }); @@ -116,8 +124,8 @@ impl Rewards for AstroportStaking { 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(), + msg: to_json_binary(&astroport::incentives::QueryMsg::PendingRewards { + lp_token: self.lp_token.to_string(), user: user.to_string(), })?, }))? @@ -125,7 +133,7 @@ impl Rewards for AstroportStaking { .filter(|asset| !asset.amount.is_zero()) //TODO: Is this necessary? .collect(); - Ok(pending_rewards.into()) + Ok(astroport_v5_vec_asset_to_assetlist(pending_rewards)) } } @@ -133,8 +141,8 @@ 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(), + msg: to_json_binary(&astroport::incentives::ExecuteMsg::Withdraw { + lp_token: self.lp_token.to_string(), amount, })?, funds: vec![], diff --git a/cw-dex-astroport/tests/astroport_tests.rs b/cw-dex-astroport/tests/astroport_tests.rs index f1553110..4cf0af8c 100644 --- a/cw-dex-astroport/tests/astroport_tests.rs +++ b/cw-dex-astroport/tests/astroport_tests.rs @@ -3,15 +3,18 @@ mod tests { 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::asset::{Asset as AstroportAsset, PairInfo}; use astroport::factory::PairType; - use astroport_v3::asset::Asset as AstroportAsset; + use astroport::pair::QueryMsg as PairQueryMsg; use cosmwasm_std::{assert_approx_eq, coin, coins, Addr, Coin, SubMsgResponse, Uint128}; - + use cw_dex_astroport::AstroportPool; 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_dex_test_helpers::{cw20_transfer, query_asset_balance, send_asset}; use cw_it::astroport::utils::AstroportContracts; - use cw_it::helpers::Unwrap; + use cw_it::cw_multi_test::{StargateKeeper, StargateMessageHandler}; + use cw_it::helpers::{bank_balance_query, Unwrap}; + use cw_it::multi_test::modules::TokenFactory; use cw_it::multi_test::MultiTestRunner; use cw_it::test_tube::cosmrs::proto::cosmwasm::wasm::v1::MsgExecuteContractResponse; use cw_it::test_tube::{ @@ -19,16 +22,26 @@ mod tests { }; use cw_it::traits::CwItRunner; use cw_it::{OwnedTestRunner, TestRunner}; + use std::str::FromStr; use test_case::test_case; - use cw_dex_astroport::AstroportPool; - #[cfg(feature = "osmosis-test-tube")] use cw_it::osmosis_test_tube::OsmosisTestApp; + pub const DENOM_CREATION_FEE: &str = "10000000uosmo"; + const TOKEN_FACTORY: &TokenFactory = + &TokenFactory::new("factory", 32, 16, 59 + 16, DENOM_CREATION_FEE); pub fn get_test_runner<'a>() -> OwnedTestRunner<'a> { match option_env!("TEST_RUNNER").unwrap_or("multi-test") { - "multi-test" => OwnedTestRunner::MultiTest(MultiTestRunner::new("osmo")), + "multi-test" => { + let mut stargate_keeper = StargateKeeper::new(); + TOKEN_FACTORY.register_msgs(&mut stargate_keeper); + + OwnedTestRunner::MultiTest(MultiTestRunner::new_with_stargate( + "osmo", + stargate_keeper, + )) + } #[cfg(feature = "osmosis-test-tube")] "osmosis-test-tube" => OwnedTestRunner::OsmosisTestApp(OsmosisTestApp::new()), _ => panic!("Unsupported test runner type"), @@ -40,6 +53,7 @@ mod tests { fn setup_pool_and_testing_contract<'a>( runner: &'a TestRunner<'a>, pool_type: PairType, + use_liquidity_manager: bool, initial_liquidity: Vec<(&str, u64)>, ) -> RunnerResult<( Vec, @@ -52,44 +66,60 @@ mod tests { setup_pool_and_test_contract( runner, pool_type, + use_liquidity_manager, initial_liquidity, 2, TEST_CONTRACT_WASM_FILE_PATH, + &[Coin::from_str(DENOM_CREATION_FEE).unwrap()], ) } - #[test_case(PairType::Xyk { }, vec![("uluna",1_000_000), ("astro", 1_000_000)]; "provide_liquidity: native-cw20")] - #[test_case(PairType::Xyk { }, vec![("apollo",1_000_000), ("astro", 1_000_000)]; "provide_liquidity: cw20-cw20")] - #[test_case(PairType::Stable { }, vec![("uluna",1_000_000), ("astro", 1_000_000)]; "provide_liquidity: stableswap native-cw20")] - #[test_case(PairType::Stable { }, vec![("apollo",1_000_000), ("astro", 1_000_000)]; "provide_liquidity: stableswap cw20-cw20")] - #[test_case(PairType::Stable { }, vec![("uluna",1_000_000), ("uatom", 1_000_000)]; "provide_liquidity: stableswap native-native")] - #[test_case(PairType::Custom("concentrated".to_string()), vec![("uluna",1_000_000), ("astro", 1_000_000)]; "provide_liquidity: concentrated native-cw20")] - #[test_case(PairType::Custom("concentrated".to_string()), vec![("apollo",1_000_000), ("astro", 1_000_000)]; "provide_liquidity: concentrated cw20-cw20")] - #[test_case(PairType::Custom("concentrated".to_string()), vec![("uluna",1_000_000), ("uatom", 1_000_000)]; "provide_liquidity: concentrated native-native")] - pub fn test_provide_liquidity(pool_type: PairType, initial_liquidity: Vec<(&str, u64)>) { + #[test_case(PairType::Xyk { }, vec![("uluna",1_000_000), ("astro", 1_000_000)], false; "provide_liquidity: native-cw20, no liq manager")] + #[test_case(PairType::Xyk { }, vec![("apollo",1_000_000), ("astro", 1_000_000)], false; "provide_liquidity: cw20-cw20, no liq manager")] + #[test_case(PairType::Xyk { }, vec![("uluna",1_000_000), ("uatom", 1_000_000)], false; "provide_liquidity: native-native, no liq manager")] + #[test_case(PairType::Stable { }, vec![("uluna",1_000_000), ("astro", 1_000_000)], false; "provide_liquidity: stableswap native-cw20, no liq manager")] + #[test_case(PairType::Stable { }, vec![("apollo",1_000_000), ("astro", 1_000_000)], false; "provide_liquidity: stableswap cw20-cw20, no liq manager")] + #[test_case(PairType::Stable { }, vec![("uluna",1_000_000), ("uatom", 1_000_000)], false; "provide_liquidity: stableswap native-native, no liq manager")] + #[test_case(PairType::Custom("concentrated".to_string()), vec![("uluna",1_000_000), ("astro", 1_000_000)], false; "provide_liquidity: concentrated native-cw20, no liq manager")] + #[test_case(PairType::Custom("concentrated".to_string()), vec![("apollo",1_000_000), ("astro", 1_000_000)], false; "provide_liquidity: concentrated cw20-cw20, no liq manager")] + #[test_case(PairType::Custom("concentrated".to_string()), vec![("uluna",1_000_000), ("uatom", 1_000_000)], false; "provide_liquidity: concentrated native-native, no liq manager")] + pub fn test_provide_liquidity( + pool_type: PairType, + initial_liquidity: Vec<(&str, u64)>, + use_liquidity_manager: bool, + ) { 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, pool_type.clone(), initial_liquidity).unwrap(); + let (accs, lp_token, pair_addr, contract_addr, asset_list, _) = + setup_pool_and_testing_contract( + &runner, + pool_type.clone(), + use_liquidity_manager, + initial_liquidity, + ) + .unwrap(); let admin = &accs[0]; let wasm = Wasm::new(&runner); + let _pair_config_res: PairInfo = wasm.query(&pair_addr, &PairQueryMsg::Pair {}).unwrap(); + let lp_token = if lp_token.starts_with(admin.prefix()) || lp_token.starts_with("contract") { + AssetInfo::cw20(Addr::unchecked(&lp_token)) + } else { + AssetInfo::native(lp_token.clone()) + }; // Check contract's LP token balance before providing liquidity - let lp_token_before = - cw20_balance_query(&runner, lp_token_addr.clone(), contract_addr.clone()).unwrap(); + let lp_token_before = query_asset_balance(&runner, &lp_token, &contract_addr); + assert_eq!(lp_token_before, Uint128::zero()); - // Simulate Provide Liquidity. Not supported for concentrated liquidity, so we - // just make sure to use the right amounts of input assets - let expected_out = match &pool_type { - PairType::Custom(_) => Uint128::new(1000000), - _ => { - let simulate_query = QueryMsg::SimulateProvideLiquidity { + let expected_out = wasm + .query( + &contract_addr, + &QueryMsg::SimulateProvideLiquidity { assets: asset_list.clone(), - }; - wasm.query(&contract_addr, &simulate_query).unwrap() - } - }; + }, + ) + .unwrap(); let (funds, cw20s) = separate_natives_and_cw20s(&asset_list); @@ -105,9 +135,16 @@ mod tests { .unwrap(); } + let error_msg = match &pool_type { + PairType::Custom(t) if t == "concentrated" => { + "Min out is not supported for concentrated liquidity pools" + } + _ => "Slippage is more than expected", + }; + // Provide liquidity with min_out one more than expected_out. Should fail. - let unwrap = Unwrap::Err("Slippage is more than expected"); - let min_out = expected_out + Uint128::one(); + let unwrap = Unwrap::Err(error_msg); + let min_out = expected_out + Uint128::new(1); let provide_msg = ExecuteMsg::ProvideLiquidity { assets: asset_list.clone(), min_out, @@ -117,10 +154,15 @@ mod tests { admin, )); + let min_out = match &pool_type { + PairType::Custom(t) if t == "concentrated" => Uint128::zero(), + _ => expected_out, + }; + // Provide liquidity with expected_out as min_out. Should succeed. let provide_msg = ExecuteMsg::ProvideLiquidity { assets: asset_list.clone(), - min_out: expected_out, + min_out, }; let _res = runner .execute_cosmos_msgs::( @@ -130,8 +172,7 @@ mod tests { .unwrap(); // Query LP token balance after - let lp_token_after = - cw20_balance_query(&runner, lp_token_addr, contract_addr.clone()).unwrap(); + let lp_token_after = query_asset_balance(&runner, &lp_token, &contract_addr); assert_eq!(lp_token_after, expected_out); // Query asset balances in contract, assert that all were used @@ -141,48 +182,68 @@ mod tests { } } - #[test_case(PairType::Xyk { }, vec![("uluna",1_000_000), ("astro", 1_000_000)]; "withdraw_liquidity: xyk native-cw20")] - #[test_case(PairType::Xyk { }, vec![("apollo",1_000_000), ("astro", 1_000_000)]; "withdraw_liquidity: xyk cw20-cw20")] - #[test_case(PairType::Stable { }, vec![("uluna",1_000_000), ("astro", 1_000_000)]; "withdraw_liquidity: stableswap native-cw20")] - #[test_case(PairType::Stable { }, vec![("apollo",1_000_000), ("astro", 1_000_000)]; "withdraw_liquidity: stableswap cw20-cw20")] - #[test_case(PairType::Stable { }, vec![("uluna",1_000_000), ("uatom", 1_000_000)]; "withdraw_liquidity: stableswap native-native")] - #[test_case(PairType::Custom("concentrated".to_string()), vec![("uluna",1_000_000), ("astro", 1_000_000)]; "withdraw_liquidity: concentrated native-cw20")] - #[test_case(PairType::Custom("concentrated".to_string()), vec![("apollo",1_000_000), ("astro", 1_000_000)]; "withdraw_liquidity: concentrated cw20-cw20")] - #[test_case(PairType::Custom("concentrated".to_string()), vec![("uluna",1_000_000), ("uatom", 1_000_000)]; "withdraw_liquidity: concentrated native-native")] - fn test_withdraw_liquidity(pool_type: PairType, initial_liquidity: Vec<(&str, u64)>) { + #[test_case(PairType::Xyk { }, vec![("uluna",1_000_000), ("astro", 1_000_000)], false; "withdraw_liquidity: xyk native-cw20")] + #[test_case(PairType::Xyk { }, vec![("apollo",1_000_000), ("astro", 1_000_000)], false; "withdraw_liquidity: xyk cw20-cw20")] + #[test_case(PairType::Stable { }, vec![("uluna",1_000_000), ("astro", 1_000_000)], false; "withdraw_liquidity: stableswap native-cw20")] + #[test_case(PairType::Stable { }, vec![("apollo",1_000_000), ("astro", 1_000_000)], false; "withdraw_liquidity: stableswap cw20-cw20")] + #[test_case(PairType::Stable { }, vec![("uluna",1_000_000), ("uatom", 1_000_000)], false; "withdraw_liquidity: stableswap native-native")] + #[test_case(PairType::Custom("concentrated".to_string()), vec![("uluna",1_000_000), ("astro", 1_000_000)], false; "withdraw_liquidity: concentrated native-cw20")] + #[test_case(PairType::Custom("concentrated".to_string()), vec![("apollo",1_000_000), ("astro", 1_000_000)], false; "withdraw_liquidity: concentrated cw20-cw20")] + #[test_case(PairType::Custom("concentrated".to_string()), vec![("uluna",1_000_000), ("uatom", 1_000_000)], false; "withdraw_liquidity: concentrated native-native")] + fn test_withdraw_liquidity( + pool_type: PairType, + initial_liquidity: Vec<(&str, u64)>, + use_liquidity_manager: bool, + ) { 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, pool_type, initial_liquidity).unwrap(); + let (accs, lp_token, _pair_addr, contract_addr, asset_list, _) = + setup_pool_and_testing_contract( + &runner, + pool_type.clone(), + use_liquidity_manager, + initial_liquidity, + ) + .unwrap(); let admin = &accs[0]; let wasm = Wasm::new(&runner); - //Query admin LP token balance - let admin_lp_token_balance = - cw20_balance_query(&runner, lp_token_addr.clone(), admin.address()).unwrap(); - let amount_to_send = admin_lp_token_balance / Uint128::from(2u128); + let lp_token = if lp_token.starts_with(admin.prefix()) || lp_token.starts_with("contract") { + AssetInfo::cw20(Addr::unchecked(&lp_token)) + } else { + AssetInfo::native(lp_token.clone()) + }; + let admin_lp_token_balance = query_asset_balance(&runner, &lp_token, &admin.address()); + + let amount_to_send = admin_lp_token_balance / Uint128::from(2u128); // Send LP tokens to contract - cw20_transfer( + send_asset( &runner, - lp_token_addr.clone(), + Asset::new(lp_token.clone(), amount_to_send), contract_addr.clone(), - amount_to_send, admin, - ) - .unwrap(); - let contract_lp_token_balance = - cw20_balance_query(&runner, lp_token_addr.clone(), contract_addr.clone()).unwrap(); + ); + + let contract_lp_token_balance = query_asset_balance(&runner, &lp_token, &contract_addr); assert_eq!(contract_lp_token_balance, amount_to_send); + let withdraw_amount = contract_lp_token_balance / Uint128::from(2u128); + // Simulate withdraw liquidity to get expected out assets let simulate_query = QueryMsg::SimulateWithdrawLiquidty { - amount: contract_lp_token_balance, + amount: withdraw_amount, }; let expected_out: AssetList = wasm.query(&contract_addr, &simulate_query).unwrap(); // Withdraw liquidity with min_out one more than expected_out. Should fail. - let unwrap = Unwrap::Err("but expected"); + let error_msg = match &pool_type { + PairType::Custom(t) if t == "concentrated" => { + "Min out is not supported for concentrated liquidity pools" + } + _ => "but expected", + }; + let unwrap = Unwrap::Err(error_msg); let min_out: AssetList = expected_out .to_vec() .into_iter() @@ -193,7 +254,7 @@ mod tests { .collect::>() .into(); let withdraw_msg = ExecuteMsg::WithdrawLiquidity { - amount: contract_lp_token_balance, + amount: withdraw_amount, min_out, }; unwrap.unwrap(runner.execute_cosmos_msgs::( @@ -201,10 +262,15 @@ mod tests { admin, )); + let min_out = match &pool_type { + PairType::Custom(t) if t == "concentrated" => AssetList::new(), + _ => expected_out.clone(), + }; + // Withdraw liquidity with expected_out as min_out. Should succeed. let withdraw_msg = ExecuteMsg::WithdrawLiquidity { - amount: contract_lp_token_balance, - min_out: expected_out.clone(), + amount: withdraw_amount, + min_out, }; runner .execute_cosmos_msgs::( @@ -214,11 +280,13 @@ mod tests { .unwrap(); // Query LP token balance after - let lp_token_balance_after = - cw20_balance_query(&runner, lp_token_addr, contract_addr.clone()).unwrap(); + let lp_token_balance_after = query_asset_balance(&runner, &lp_token, &contract_addr); - // Assert that LP token balance is zero after withdrawing all liquidity - assert_eq!(lp_token_balance_after, Uint128::zero()); + // Assert that LP token balance is correct + assert_eq!( + lp_token_balance_after, + contract_lp_token_balance - withdraw_amount + ); // Query contract asset balances, assert that all were returned for asset in asset_list.into_iter() { @@ -226,17 +294,35 @@ mod tests { let expected_balance = expected_out.find(&asset.info).unwrap().amount; assert_eq!(asset_balance, expected_balance); } + + // Withdraw liquidity with min_out equal to zero. Should succeed. + let withdraw_msg = ExecuteMsg::WithdrawLiquidity { + amount: withdraw_amount, + min_out: AssetList::new(), + }; + runner + .execute_cosmos_msgs::( + &[withdraw_msg.into_cosmos_msg(contract_addr.clone(), vec![])], + admin, + ) + .unwrap(); + + // Query LP token balance after + let lp_token_balance_after = query_asset_balance(&runner, &lp_token, &contract_addr); + + // Assert that LP token balance is zero after withdrawing all liquidity + assert_eq!(lp_token_balance_after, Uint128::zero()); } - fn stake_all_lp_tokens<'a, R: Runner<'a>>( + fn stake_all_native_lp_tokens<'a, R: Runner<'a>>( runner: &'a R, contract_addr: String, - lp_token_addr: String, + lp_token_denom: String, signer: &SigningAccount, ) -> ExecuteResponse { // Query LP token balance let lp_token_balance = - cw20_balance_query(runner, lp_token_addr, contract_addr.clone()).unwrap(); + bank_balance_query(runner, signer.address().clone(), lp_token_denom.clone()).unwrap(); // Stake LP tokens let stake_msg = ExecuteMsg::Stake { @@ -245,7 +331,10 @@ mod tests { runner .execute_cosmos_msgs::( - &[stake_msg.into_cosmos_msg(contract_addr, vec![])], + &[stake_msg.into_cosmos_msg( + contract_addr, + coins(lp_token_balance.u128(), lp_token_denom), + )], signer, ) .unwrap() @@ -260,35 +349,29 @@ mod tests { #[test_case(PairType::Custom("concentrated".to_string()), vec![("uluna",1_000_000), ("astro", 1_000_000)]; "stake_and_unstake: concentrated native-cw20")] #[test_case(PairType::Custom("concentrated".to_string()), vec![("apollo",1_000_000), ("astro", 1_000_000)]; "stake_and_unstake: concentrated cw20-cw20")] #[test_case(PairType::Custom("concentrated".to_string()), vec![("uluna",1_000_000), ("uatom", 1_000_000)]; "stake_and_unstake: concentrated native-native")] - fn test_stake_and_unstake( + fn test_stake_and_unstake_native_lp_tokens( pool_type: PairType, initial_liquidity: Vec<(&str, u64)>, ) -> 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_testing_contract(&runner, pool_type, initial_liquidity).unwrap(); + let (accs, lp_token_denom, _pair_addr, contract_addr, _asset_list, _) = + setup_pool_and_testing_contract(&runner, pool_type, false, initial_liquidity).unwrap(); let admin = &accs[0]; // Query LP token balance let lp_token_balance = - cw20_balance_query(&runner, lp_token_addr.clone(), admin.address()).unwrap(); + bank_balance_query(&runner, admin.address().clone(), lp_token_denom.clone()).unwrap(); - // Send LP tokens to the test contract - cw20_transfer( + // Stake LP tokens + let events = stake_all_native_lp_tokens( &runner, - lp_token_addr.clone(), contract_addr.clone(), - lp_token_balance, + lp_token_denom.clone(), admin, ) - .unwrap(); - - // Stake LP tokens - let events = - stake_all_lp_tokens(&runner, contract_addr.clone(), lp_token_addr.clone(), admin) - .events; + .events; // Parse the event data let response = SubMsgResponse { events, data: None }; @@ -301,7 +384,7 @@ mod tests { // Query LP token balance after let lp_token_balance_after = - cw20_balance_query(&runner, lp_token_addr.clone(), contract_addr.to_string()).unwrap(); + bank_balance_query(&runner, contract_addr.clone(), lp_token_denom.clone()).unwrap(); // Assert that LP token balance is 0 assert_eq!(lp_token_balance_after, Uint128::zero()); @@ -319,7 +402,7 @@ mod tests { // Query LP token balance let lp_token_balance_after_unstake = - cw20_balance_query(&runner, lp_token_addr, contract_addr).unwrap(); + bank_balance_query(&runner, contract_addr.clone(), lp_token_denom).unwrap(); // Assert that LP tokens have been unstakeed assert_eq!(lp_token_balance_after_unstake, lp_token_balance); @@ -346,7 +429,7 @@ mod tests { #[test_case(PairType::Custom("concentrated".to_string()),vec![("uluna",1_000_000), ("uatom", 1_000_000)], Uint128::new(1_000_000); "swap_and_simulate_swap: concentrated pool, native-native")] #[test_case(PairType::Custom("concentrated".to_string()),vec![("uluna",1_000_000), ("uatom", 1_000_000)], Uint128::new(100_000_000); "swap_and_simulate_swap: concentrated pool, high slippage, native-native")] #[test_case(PairType::Custom("concentrated".to_string()),vec![("uluna",68_582_147), ("uatom", 3_467_256)], Uint128::new(1_000_000); "swap_and_simulate_swap: concentrated pool, random prices, native-native")] - fn test_swap_and_simulate_swap( + fn test_swap_and_simulate_swap_native_lp_tokens( pool_type: PairType, initial_liquidity: Vec<(&str, u64)>, amount: Uint128, @@ -354,7 +437,7 @@ 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_testing_contract(&runner, pool_type, initial_liquidity).unwrap(); + setup_pool_and_testing_contract(&runner, pool_type, false, initial_liquidity).unwrap(); let admin = &accs[0]; let wasm = Wasm::new(&runner); @@ -431,12 +514,12 @@ mod tests { let runner = owned_runner.as_ref(); let ( accs, - lp_token_addr, + lp_token_denom, _pair_addr, testing_contract_addr, _asset_list, astroport_contracts, - ) = setup_pool_and_testing_contract(&runner, pool_type, initial_liquidity).unwrap(); + ) = setup_pool_and_testing_contract(&runner, pool_type, false, initial_liquidity).unwrap(); let admin = &accs[0]; @@ -476,7 +559,7 @@ mod tests { // 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; + let cw20_code_id = astroport_contracts.astro_cw20_token.code_id; for (i, (amount, duration)) in cw20_incentives.iter().enumerate() { // Instantiate Cw20 token let cw20_addr = wasm @@ -513,7 +596,7 @@ mod tests { 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 } => { + astroport::asset::AssetInfo::Token { contract_addr } => { // Increase allowance for incentives contract wasm.execute( contract_addr.as_str(), @@ -528,15 +611,15 @@ mod tests { .unwrap(); vec![] } - astroport_v3::asset::AssetInfo::NativeToken { denom } => { + astroport::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 { + &astroport::incentives::ExecuteMsg::Incentivize { + lp_token: lp_token_denom.clone(), + schedule: astroport::incentives::InputSchedule { reward: incentive, duration_periods: periods, }, @@ -547,25 +630,11 @@ mod tests { .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, - lp_token_addr.clone(), - testing_contract_addr.clone(), - lp_token_balance, - admin, - ) - .unwrap(); - // Stake LP tokens - let _events = stake_all_lp_tokens( + let _events = stake_all_native_lp_tokens( &runner, testing_contract_addr.clone(), - lp_token_addr.clone(), + lp_token_denom.clone(), admin, ) .events; @@ -577,8 +646,8 @@ mod tests { let pending_rewards: Vec = wasm .query( &astroport_contracts.incentives.address, - &astroport_v3::incentives::QueryMsg::PendingRewards { - lp_token: lp_token_addr.clone(), + &astroport::incentives::QueryMsg::PendingRewards { + lp_token: lp_token_denom.clone(), user: testing_contract_addr.clone(), }, ) @@ -596,10 +665,10 @@ mod tests { 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 } => { + astroport::asset::AssetInfo::Token { contract_addr } => { AssetInfo::Cw20(contract_addr) } - astroport_v3::asset::AssetInfo::NativeToken { denom } => AssetInfo::Native(denom), + astroport::asset::AssetInfo::NativeToken { denom } => AssetInfo::Native(denom), }; let amount = cw_dex_pending_rewards.find(&asset_info).unwrap().amount; @@ -629,10 +698,11 @@ mod tests { 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, _) = + let (_accs, lp_token_denom, pair_addr, contract_addr, asset_list, _) = setup_pool_and_testing_contract( &runner, PairType::Xyk {}, + false, vec![("uluna", 1_000_000), ("uatom", 1_000_000)], ) .unwrap(); @@ -640,13 +710,13 @@ mod tests { let wasm = Wasm::new(&runner); let query = QueryMsg::GetPoolForLpToken { - lp_token: AssetInfo::Cw20(Addr::unchecked(lp_token_addr.clone())), + lp_token: AssetInfo::Native(lp_token_denom.clone()), }; let pool = wasm .query::<_, AstroportPool>(&contract_addr, &query) .unwrap(); - assert_eq!(pool.lp_token_addr, Addr::unchecked(lp_token_addr)); + assert_eq!(pool.lp_token, AssetInfo::native(lp_token_denom)); assert_eq!(pool.pair_addr, Addr::unchecked(pair_addr)); assert_eq!( pool.pool_assets, diff --git a/cw-dex-osmosis/CHANGELOG.md b/cw-dex-osmosis/CHANGELOG.md new file mode 100644 index 00000000..a4d27c55 --- /dev/null +++ b/cw-dex-osmosis/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +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.2.0] - 2024-08-28 + +### Changed + +- Use `cw-dex` 0.6.0 diff --git a/cw-dex-osmosis/Cargo.toml b/cw-dex-osmosis/Cargo.toml index 6625dec6..2c979290 100644 --- a/cw-dex-osmosis/Cargo.toml +++ b/cw-dex-osmosis/Cargo.toml @@ -5,12 +5,12 @@ 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" +version = "0.2.0" readme = "README.md" [features] default = [] -osmosis-test-tube = ["cw-it/osmosis-test-tube", "cw-dex-test-helpers/osmosis-test-tube"] +osmosis-test-tube = ["cw-it/osmosis-test-tube"] # backtraces = ["cosmwasm-std/backtraces", "osmosis-std/backtraces"] [package.metadata.docs.rs] @@ -31,7 +31,7 @@ osmosis-std = { workspace = true } cw-it = { workspace = true } test-case = { workspace = true } cw-dex-test-contract = { workspace = true } -cw-dex-test-helpers = { workspace = true, features = ["osmosis"] } +cw-dex-test-helpers = { workspace = true, features = ["osmosis", "osmosis-test-tube"] } proptest = { workspace = true } cw20-base = { workspace = true } cw20 = { workspace = true } diff --git a/cw-dex-osmosis/README.md b/cw-dex-osmosis/README.md new file mode 100644 index 00000000..61af914b --- /dev/null +++ b/cw-dex-osmosis/README.md @@ -0,0 +1,3 @@ +# cw-dex-osmosis + +This crate contains [cw-dex](https://crates.io/crates/cw-dex) implementations for Osmosis. diff --git a/cw-dex-osmosis/src/lib.rs b/cw-dex-osmosis/src/lib.rs index 2013d312..ca30e28c 100644 --- a/cw-dex-osmosis/src/lib.rs +++ b/cw-dex-osmosis/src/lib.rs @@ -7,3 +7,6 @@ mod staking; pub use osmosis_std; pub use pool::*; pub use staking::*; + +/// Re-export `cw-dex` for convenience +pub use cw_dex; diff --git a/cw-dex/Cargo.toml b/cw-dex/Cargo.toml index 81022c80..7fc9fa0d 100644 --- a/cw-dex/Cargo.toml +++ b/cw-dex/Cargo.toml @@ -5,14 +5,11 @@ edition = "2021" license = "MPL-2.0" name = "cw-dex" repository = "https://github.com/apollodao/cw-dex" -version = "0.5.3" +version = "0.6.0" readme = "README.md" [features] default = [] -osmosis = ["osmosis-std", "osmosis-test-tube", "cw-it/osmosis"] -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"] # backtraces = ["cosmwasm-std/backtraces", "osmosis-std/backtraces"] [package.metadata.docs.rs] @@ -20,26 +17,17 @@ all-features = true rustdoc-args = ["--cfg", "docsrs"] [dependencies] -cosmwasm-schema = { workspace = true } cosmwasm-std = { workspace = true } thiserror = { workspace = true } apollo-cw-asset = { workspace = true } cw-utils = { workspace = true } -cw20 = { workspace = true } -apollo-utils = { workspace = true } - -# Osmosis -osmosis-std = { version = "0.19.2", optional = true } - -# Astroport -astroport = { workspace = true, optional = true } -cw2 = { workspace = true, optional = true } [dev-dependencies] 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", "osmosis", "osmosis-test-tube"] } +# These features are needed here to run the tests. They cannot be put in the features section +# because cw-dex-test-helpers is not a dependency, so then it can not be published. proptest = { workspace = true } cw20-base = { workspace = true } cw20 = { workspace = true } diff --git a/cw-dex/src/error.rs b/cw-dex/src/error.rs index 5ab0d7ff..941018bf 100644 --- a/cw-dex/src/error.rs +++ b/cw-dex/src/error.rs @@ -84,6 +84,21 @@ pub enum CwDexError { /// The actual amount of tokens received received: Uint128, }, + + /// For when the token_denom can't be parsed + #[error("Could not parse address: {token_denom}")] + AddressParsingErrors { + /// The token_denom that couldn't be parsed + token_denom: String, + }, + + /// For when min_out is set for concentrated liquidity pools, as they do not + /// support min_out + #[error("Unsupported arguments. Reason: {reason}")] + UnsupportedArguments { + /// The reason that explains why the arguments are unsupported + reason: String, + }, } impl From for StdError { diff --git a/cw-dex/src/implementations/astroport/README.md b/cw-dex/src/implementations/astroport/README.md deleted file mode 100644 index 31ca5592..00000000 --- a/cw-dex/src/implementations/astroport/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Astroport - -This implements support for Astroport constant product and stable swap pairs, as well as staking through the astro generator. This supports only the specific versions of the astroport contracts available [here](https://github.com/astroport-fi/astroport-changelog/blob/4d8685a18341eb5bf207a9dff8f95fec14a28781/terra-2/phoenix-1/contract_commits.json) diff --git a/cw-dex/src/implementations/astroport/mod.rs b/cw-dex/src/implementations/astroport/mod.rs deleted file mode 100644 index 43ac921c..00000000 --- a/cw-dex/src/implementations/astroport/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! Module containing Pool and Staking implementations for Osmosis - -mod pool; -mod staking; - -pub use pool::AstroportPool; -pub use staking::AstroportStaking; - -pub use astroport; diff --git a/cw-dex/src/implementations/astroport/pool.rs b/cw-dex/src/implementations/astroport/pool.rs deleted file mode 100644 index 1c0606a6..00000000 --- a/cw-dex/src/implementations/astroport/pool.rs +++ /dev/null @@ -1,314 +0,0 @@ -//! 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 crate::traits::Pool; -use crate::CwDexError; -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; - -/// 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 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/src/implementations/astroport/staking.rs b/cw-dex/src/implementations/astroport/staking.rs deleted file mode 100644 index 7e105295..00000000 --- a/cw-dex/src/implementations/astroport/staking.rs +++ /dev/null @@ -1,157 +0,0 @@ -//! 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::{Asset, AssetInfo, AssetList}; -use astroport::asset::Asset as AstroAsset; -use astroport::generator::{ - Cw20HookMsg as GeneratorCw20HookMsg, ExecuteMsg as GeneratorExecuteMsg, PendingTokenResponse, - QueryMsg as GeneratorQueryMsg, -}; - -use crate::traits::{Rewards, Stake, Staking, Unstake}; -use crate::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 associated generator contract - pub generator_addr: Addr, - /// The address of the ASTRO token contract - pub astro_token: AssetInfo, -} - -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.generator_addr.to_string(), - amount, - msg: to_json_binary(&GeneratorCw20HookMsg::Deposit {})?, - })?, - 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("generator_address", self.generator_addr.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.generator_addr.to_string(), - msg: to_json_binary(&GeneratorExecuteMsg::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 PendingTokenResponse { - pending: pending_astro, - pending_on_proxy, - } = querier.query(&QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: self.generator_addr.to_string(), - msg: to_json_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() - .into_iter() - .chain(vec![ - Asset::new(self.astro_token.clone(), pending_astro).into() - ]) - .filter(|asset| !asset.amount.is_zero()) - .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.generator_addr.to_string(), - msg: to_json_binary(&GeneratorExecuteMsg::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/src/implementations/mod.rs b/cw-dex/src/implementations/mod.rs deleted file mode 100644 index 3ce8995f..00000000 --- a/cw-dex/src/implementations/mod.rs +++ /dev/null @@ -1,14 +0,0 @@ -//! Contains exchange-specific implementations of the traits in the -//! `traits::pool` and `traits::staking` modules - -#[cfg(feature = "astroport")] -#[cfg_attr(docsrs, doc(cfg(feature = "astroport")))] -pub mod astroport; - -#[cfg(feature = "osmosis")] -#[cfg_attr(docsrs, doc(cfg(feature = "osmosis")))] -pub mod osmosis; - -pub mod pool; - -pub use pool::*; diff --git a/cw-dex/src/implementations/osmosis/helpers.rs b/cw-dex/src/implementations/osmosis/helpers.rs deleted file mode 100644 index b1c031ea..00000000 --- a/cw-dex/src/implementations/osmosis/helpers.rs +++ /dev/null @@ -1,14 +0,0 @@ -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/src/implementations/osmosis/mod.rs b/cw-dex/src/implementations/osmosis/mod.rs deleted file mode 100644 index 21bafa93..00000000 --- a/cw-dex/src/implementations/osmosis/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! Module containing Pool and Staking implementations for Osmosis - -mod helpers; -mod pool; -mod staking; - -pub use pool::*; -pub use staking::*; diff --git a/cw-dex/src/implementations/osmosis/pool.rs b/cw-dex/src/implementations/osmosis/pool.rs deleted file mode 100644 index 621a896a..00000000 --- a/cw-dex/src/implementations/osmosis/pool.rs +++ /dev/null @@ -1,307 +0,0 @@ -//! 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 crate::traits::Pool; -use crate::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 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)) - } -} diff --git a/cw-dex/src/implementations/osmosis/staking.rs b/cw-dex/src/implementations/osmosis/staking.rs deleted file mode 100644 index 1468f5d4..00000000 --- a/cw-dex/src/implementations/osmosis/staking.rs +++ /dev/null @@ -1,325 +0,0 @@ -//! 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 crate::traits::{ForceUnlock, LockedStaking, Rewards, Stake, Unlock}; -use crate::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/src/implementations/pool.rs b/cw-dex/src/implementations/pool.rs deleted file mode 100644 index f7230407..00000000 --- a/cw-dex/src/implementations/pool.rs +++ /dev/null @@ -1,184 +0,0 @@ -//! Contains an enum with variants for Pool implementations. -//! For use in serialization. - -use crate::error::CwDexError; -use crate::traits::pool::Pool as PoolTrait; -use apollo_cw_asset::{Asset, AssetInfo, AssetList}; -use cosmwasm_schema::cw_serde; -use cosmwasm_std::{Addr, Deps, Env, Response, StdResult, Uint128}; - -#[cfg(feature = "astroport")] -use crate::astroport::AstroportPool; -#[cfg(feature = "astroport")] -use cosmwasm_std::StdError; - -#[cfg(feature = "osmosis")] -use {crate::implementations::osmosis::OsmosisPool, std::str::FromStr}; - -/// An enum with all known variants that implement the Pool trait. -/// The ideal solution would of course instead be to use a trait object so that -/// the caller can pass in any type that implements the Pool trait, but trait -/// objects require us not to implement the Sized trait, which cw_serde -/// requires. -#[cw_serde] -#[non_exhaustive] -pub enum Pool { - /// Contains an Osmosis pool implementation - #[cfg(feature = "osmosis")] - Osmosis(OsmosisPool), - /// Contains an Astroport pool implementation - #[cfg(feature = "astroport")] - Astroport(AstroportPool), -} - -impl Pool { - /// Returns a specific `Pool` instance as a boxed generic `Pool` trait - pub fn as_trait(&self) -> Box { - // This is needed to avoid a warning when compiling with all features - #[allow(unreachable_patterns)] - match self { - #[cfg(feature = "osmosis")] - Pool::Osmosis(x) => Box::new(*x), - #[cfg(feature = "astroport")] - Pool::Astroport(x) => Box::new(x.clone()), - _ => { - panic!("Pool variant not supported"); - } - } - } - - /// Returns the matching pool given a LP token. - /// - /// Arguments: - /// - `lp_token`: Said LP token - /// - `astroport_liquidity_manager`: The Astroport liquidity manager - /// address. This must be set - /// if the LP token is an Astroport LP token. - #[allow(unused_variables)] - #[allow(unreachable_patterns)] - pub fn get_pool_for_lp_token( - deps: Deps, - lp_token: &AssetInfo, - astroport_liquidity_manager: Option, - ) -> Result { - match lp_token { - #[cfg(feature = "osmosis")] - AssetInfo::Native(lp_token_denom) => { - // The only Pool implementation that uses native denoms right now is Osmosis - 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(Pool::Osmosis(OsmosisPool::new(pool_id, deps)?)) - } - #[cfg(feature = "astroport")] - AssetInfo::Cw20(address) => { - // The only Pool implementation that uses CW20 tokens right now is Astroport. - // 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)?; - - // Unwrap the Astroport liquidity manager address. - let liquidity_manager = astroport_liquidity_manager.ok_or( - StdError::generic_err("Must provide liquidity manager address"), - )?; - - // 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, liquidity_manager)?; - - Ok(Pool::Astroport(pool)) - } - _ => Err(CwDexError::NotLpToken {}), - } - } -} - -// Implement the Pool trait for the Pool enum so we can use all the trait -// methods directly on the enum type. -impl PoolTrait for Pool { - fn provide_liquidity( - &self, - deps: Deps, - env: &Env, - assets: AssetList, - min_out: Uint128, - ) -> Result { - self.as_trait() - .provide_liquidity(deps, env, assets, min_out) - } - - fn withdraw_liquidity( - &self, - deps: Deps, - env: &Env, - asset: Asset, - min_out: AssetList, - ) -> Result { - self.as_trait() - .withdraw_liquidity(deps, env, asset, min_out) - } - - fn swap( - &self, - deps: Deps, - env: &Env, - offer_asset: Asset, - ask_asset_info: AssetInfo, - min_out: Uint128, - ) -> Result { - self.as_trait() - .swap(deps, env, offer_asset, ask_asset_info, min_out) - } - - fn get_pool_liquidity(&self, deps: Deps) -> Result { - self.as_trait().get_pool_liquidity(deps) - } - - fn simulate_provide_liquidity( - &self, - deps: Deps, - env: &Env, - asset: AssetList, - ) -> Result { - self.as_trait().simulate_provide_liquidity(deps, env, asset) - } - - fn simulate_withdraw_liquidity( - &self, - deps: Deps, - asset: &Asset, - ) -> Result { - self.as_trait().simulate_withdraw_liquidity(deps, asset) - } - - fn simulate_swap( - &self, - deps: Deps, - offer_asset: Asset, - ask_asset_info: AssetInfo, - ) -> StdResult { - self.as_trait() - .simulate_swap(deps, offer_asset, ask_asset_info) - } - - fn lp_token(&self) -> AssetInfo { - self.as_trait().lp_token() - } - - fn pool_assets(&self, deps: Deps) -> StdResult> { - self.as_trait().pool_assets(deps) - } -} diff --git a/cw-dex/src/lib.rs b/cw-dex/src/lib.rs index 863ff5a7..34ead5e3 100644 --- a/cw-dex/src/lib.rs +++ b/cw-dex/src/lib.rs @@ -18,12 +18,4 @@ pub mod error; 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::*; diff --git a/deny.toml b/deny.toml index 10a6b5a3..69e3b79c 100644 --- a/deny.toml +++ b/deny.toml @@ -13,7 +13,9 @@ vulnerability = "deny" unmaintained = "deny" notice = "deny" unsound = "deny" -ignore = [] +ignore = [ + "RUSTSEC-2024-0344" # Confirmed as not applicable to CosmWasm: https://github.com/CosmWasm/cosmwasm/issues/2175#issuecomment-2180960022 +] [bans] multiple-versions = "allow" diff --git a/test-contracts/astroport-test-contract/src/contract.rs b/test-contracts/astroport-test-contract/src/contract.rs index c6608e50..fa81c9dc 100644 --- a/test-contracts/astroport-test-contract/src/contract.rs +++ b/test-contracts/astroport-test-contract/src/contract.rs @@ -21,14 +21,17 @@ pub fn instantiate( msg: InstantiateMsg, ) -> Result { let pair_addr = deps.api.addr_validate(&msg.pair_addr)?; - let liquidity_manager = deps.api.addr_validate(&msg.liquidity_manager_addr)?; + let liquidity_manager = msg + .liquidity_manager_addr + .map(|addr| deps.api.addr_validate(&addr)) + .transpose()?; let pool = AstroportPool::new(deps.as_ref(), pair_addr, liquidity_manager)?; POOL.save(deps.storage, &pool)?; STAKING.save( deps.storage, &AstroportStaking { - lp_token_addr: Addr::unchecked(msg.lp_token_addr), + lp_token: AssetInfo::from_str(deps.api, &msg.lp_token), incentives: Addr::unchecked(msg.incentives_addr), }, )?; diff --git a/test-contracts/astroport-test-contract/src/error.rs b/test-contracts/astroport-test-contract/src/error.rs index 440de750..39cd05b5 100644 --- a/test-contracts/astroport-test-contract/src/error.rs +++ b/test-contracts/astroport-test-contract/src/error.rs @@ -11,6 +11,6 @@ pub enum ContractError { Unauthorized {}, // Add any other custom errors you like here. // Look at https://docs.rs/thiserror/1.0.21/thiserror/ for details. - #[error("cw-dex")] + #[error("{0}")] CwDex(#[from] CwDexError), } diff --git a/test-contracts/package/src/msg.rs b/test-contracts/package/src/msg.rs index dffec8d3..5f53b686 100644 --- a/test-contracts/package/src/msg.rs +++ b/test-contracts/package/src/msg.rs @@ -13,10 +13,10 @@ pub struct OsmosisTestContractInstantiateMsg { #[cw_serde] pub struct AstroportContractInstantiateMsg { pub pair_addr: String, - pub lp_token_addr: String, + pub lp_token: String, pub incentives_addr: String, pub astro_token: AssetInfo, - pub liquidity_manager_addr: String, + pub liquidity_manager_addr: Option, } #[cw_serde] diff --git a/test-helpers/src/astroport.rs b/test-helpers/src/astroport.rs index 7653c014..8e85b9b2 100644 --- a/test-helpers/src/astroport.rs +++ b/test-helpers/src/astroport.rs @@ -27,9 +27,11 @@ use crate::{common_pcl_params, cw20_mint, instantiate_cw20}; pub fn setup_pool_and_test_contract<'a>( runner: &'a TestRunner<'a>, pool_type: PairType, + use_liquidity_manager: bool, initial_liquidity: Vec<(&str, u64)>, native_denom_count: usize, wasm_file_path: &str, + denom_creation_fee: &[Coin], ) -> RunnerResult<( Vec, String, @@ -94,7 +96,7 @@ pub fn setup_pool_and_test_contract<'a>( // Instantiate Apollo token (to have second CW20 to test CW20-CW20 pools) let apollo_token = instantiate_cw20( runner, - astroport_contracts.astro_token.code_id, + astroport_contracts.astro_cw20_token.code_id, &Cw20InstantiateMsg { name: "APOLLO".to_string(), symbol: "APOLLO".to_string(), @@ -115,7 +117,7 @@ pub fn setup_pool_and_test_contract<'a>( // Mint Astro tokens cw20_mint( runner, - astroport_contracts.clone().astro_token.address, + astroport_contracts.clone().astro_cw20_token.address, account.address().clone(), Uint128::from(1_000_000_000_000_000_000u128), admin, @@ -139,7 +141,7 @@ pub fn setup_pool_and_test_contract<'a>( asset_list .add(&Asset::new( AssetInfo::Cw20(Addr::unchecked( - astroport_contracts.clone().astro_token.address, + astroport_contracts.clone().astro_cw20_token.address, )), Uint128::new(amount.into()), )) @@ -211,7 +213,8 @@ pub fn setup_pool_and_test_contract<'a>( }, _ => None, }; - let (pair_addr, lp_token_addr) = create_astroport_pair( + + let (pair_addr, lp_token) = create_astroport_pair( runner, &astroport_contracts.factory.address, pool_type, @@ -219,6 +222,7 @@ pub fn setup_pool_and_test_contract<'a>( init_params, admin, None, + denom_creation_fee, ); // Increase allowance of CW20's for Pair contract @@ -241,9 +245,10 @@ pub fn setup_pool_and_test_contract<'a>( slippage_tolerance: Some(Decimal::from_str("0.02").unwrap()), auto_stake: Some(false), receiver: None, + min_lp_to_receive: None, }; let (native_coins, _) = separate_natives_and_cw20s(&asset_list); - let _res = wasm + let res = wasm .execute(&pair_addr, &provide_liq_msg, &native_coins, admin) .unwrap(); @@ -265,6 +270,12 @@ pub fn setup_pool_and_test_contract<'a>( }; let code_id = upload_wasm_file(runner, &accs[0], contract).unwrap(); + let liquidity_manager = if use_liquidity_manager { + Some(astroport_contracts.liquidity_manager.address.clone()) + } else { + None + }; + // Instantiate the test contract let contract_addr = instantiate_test_astroport_contract( runner, @@ -272,16 +283,16 @@ pub fn setup_pool_and_test_contract<'a>( pair_addr.clone(), astroport_contracts.incentives.address.clone(), AssetInfo::cw20(Addr::unchecked( - astroport_contracts.astro_token.address.clone(), + astroport_contracts.astro_cw20_token.address.clone(), )), - lp_token_addr.clone(), - astroport_contracts.liquidity_manager.address.clone(), + lp_token.clone(), + liquidity_manager, &accs[0], )?; Ok(( accs, - lp_token_addr, + lp_token, pair_addr, contract_addr, asset_list, @@ -296,13 +307,13 @@ pub fn instantiate_test_astroport_contract<'a, R: Runner<'a>>( pair_addr: String, incentives_addr: String, astro_token: AssetInfo, - lp_token_addr: String, - liquidity_manager_addr: String, + lp_token: String, + liquidity_manager_addr: Option, signer: &SigningAccount, ) -> RunnerResult { let init_msg = AstroportContractInstantiateMsg { pair_addr, - lp_token_addr, + lp_token, incentives_addr, astro_token, liquidity_manager_addr, diff --git a/test-helpers/src/helpers.rs b/test-helpers/src/helpers.rs index 909c9e5b..db130dac 100644 --- a/test-helpers/src/helpers.rs +++ b/test-helpers/src/helpers.rs @@ -1,14 +1,14 @@ use std::error::Error; use std::str::FromStr; -use apollo_cw_asset::{AssetInfo, AssetList}; +use apollo_cw_asset::{Asset, AssetInfo, AssetList}; use apollo_utils::assets::separate_natives_and_cw20s; use astroport::pair_concentrated::ConcentratedPoolParams; -use cosmwasm_std::{Decimal, StdResult, Uint128}; +use cosmwasm_std::{coins, Decimal, StdResult, Uint128}; use cw20::{BalanceResponse, Cw20ExecuteMsg, Cw20QueryMsg}; use cw20_base::msg::InstantiateMsg as Cw20InstantiateMsg; use cw_dex_test_contract::msg::ExecuteMsg; -use cw_it::helpers::bank_balance_query; +use cw_it::helpers::{bank_balance_query, bank_send}; use cw_it::osmosis_std::types::cosmwasm::wasm::v1::MsgExecuteContractResponse; use cw_it::test_tube::{Account, Module, Runner, RunnerExecuteResult, SigningAccount, Wasm}; @@ -75,6 +75,36 @@ pub fn cw20_transfer<'a, R: Runner<'a>>( ) } +/// Send a cw_asset::Asset to a recipient +pub fn send_asset<'a, R: Runner<'a>>( + runner: &'a R, + asset: Asset, + recipient: String, + signer: &SigningAccount, +) { + match asset.info { + AssetInfo::Cw20(cw20_addr) => { + cw20_transfer( + runner, + cw20_addr.to_string(), + recipient, + asset.amount, + signer, + ) + .unwrap(); + } + AssetInfo::Native(denom) => { + bank_send( + runner, + signer, + &recipient, + coins(asset.amount.u128(), denom), + ) + .unwrap(); + } + } +} + /// Query the balance of a cw20 token pub fn cw20_balance_query<'a>( runner: &'a impl Runner<'a>, @@ -143,5 +173,6 @@ pub fn common_pcl_params() -> ConcentratedPoolParams { price_scale: Decimal::one(), ma_half_time: 600, track_asset_balances: None, + fee_share: None, } }